c++ - 从图像中近似数字厚度的快速算法

标签 c++ image algorithm image-processing

<分区>

我正在学习一些 C++ 并尝试开发一个简单的软件来检测哪种类型的 数字已由用户写入。

我知道我想要它看起来像什么,但我不知道如何测量手指的粗细。测量不需要非常准确,几个像素太多或不够并不重要。

示例 iamge 如下所示: sample image
图像总是以这样的方式裁剪,即它是可能的最小分辨率。它以灰度保存,但技术细节在这里并没有真正的意义。

那么,是否有一种有效的算法可以确定用于绘制图像的笔划大小?如果它可以每秒处理约 100 张图像(从内存中),那就太好了。



最佳答案

可以计算出数字轮廓的面积(A)和周长(P),则宽度~= A/(0.5*P)。请注意,对于数字“4,6,8,9,0”,轮廓内有孔,周长应包括孔的值。 (我也测试了骨架化的方法,即width ~= [area of​​ object]/[area of​​ skeleton],效果比较好,但是在github上找到的骨架化实现比较耗时。)

代码如下,速度够快

main.cpp

#include <iostream>
#include <string>
#include "digit_width.hpp"
using namespace std;
using namespace cv;

int main(int argc, char* argv[])
{
    // string filename = "all.jpg";
    string filename = "SRmyi.png";
    Mat img_raw = imread(filename, IMREAD_GRAYSCALE);
    threshold(img_raw,img_raw,128,255,THRESH_BINARY);
    vector<double> width_list;
    vector<Point2f> center_list;

    digit_width(img_raw, width_list, center_list);

    for (size_t idx = 0; idx < width_list.size(); idx++)
    {
        cout << width_list[idx] << endl;
        ostringstream oss;
        oss << setprecision(4) << width_list[idx];
        putText(img_raw, oss.str(), center_list[idx], FONT_HERSHEY_DUPLEX, 1.0, 128);
    }

    imwrite("new_"+filename, img_raw);
    imshow("img",img_raw);
    waitKey(0);

    return 0;
}

digit_width.hpp

#include <opencv2/opencv.hpp>
#include <cmath>
using namespace std;
using namespace cv;

void digit_width(const Mat & img_bin, vector<double>& width_list, vector<Point2f>& center_list)
{
    vector<std::vector<Point> > contours;
    vector<Vec4i> hierarchy;

    findContours(img_bin, contours, hierarchy, RETR_CCOMP, CHAIN_APPROX_NONE );

    vector<vector<int> > contours_child;
    for (size_t idx = 0; idx < hierarchy.size(); idx++)
    {
        if(hierarchy[idx][3] == -1)
        {
            vector<int> child;
            child.push_back(idx);

            if(hierarchy[idx][2] != -1)
            {
                int child_idx = hierarchy[idx][2];
                child.push_back(child_idx);
                while(hierarchy[child_idx][0] != -1)
                {
                    child_idx = hierarchy[child_idx][0];
                    child.push_back(child_idx);
                }
            }

            contours_child.push_back(child);
        }
    }

    for(size_t idx = 0; idx < contours_child.size(); idx++)
    {
        double width = 0;

        double perimeter = arcLength(contours[ contours_child[idx][0] ], true);
        double area = contourArea(contours[ contours_child[idx][0] ]);

        auto M = moments(contours[ contours_child[idx][0] ]);
        float cX = M.m10 / M.m00;
        float cY = M.m01 / M.m00;
        Point2f pt = Point2f(cX, cY);


        if( contours_child.size() > 1 )
        {
            for(size_t jdx=1; jdx<contours_child[idx].size(); jdx++)
            {
                perimeter += arcLength(contours[ contours_child[idx][jdx] ], true);
                area     -= contourArea(contours[ contours_child[idx][jdx] ]);
            }
        } 

        width = area / (0.5 * perimeter);
        width_list.push_back( width );
        center_list.push_back(pt);
    }

}

结果如下图所示。

enter image description here enter image description here enter image description here enter image description here

关于c++ - 从图像中近似数字厚度的快速算法,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/59001590/

相关文章:

c++ - 替换 __LINE__ 宏

c++ - 为什么删除指向堆栈的指针是错误的?

java - 如何克隆图像?

javascript - 通过在图像选择器中悬停来 Bootstrap 弹出窗口

algorithm - 查找文本所需的工具或 API 包含大型词典中的任何单词

c++ - Linux 上的命令提示符教程

c++ - 如何解决Windows上的编译错误C2079

java - 加载并显示文件夹中的所有图像

sql - 未显示检索队列算法

c++ - 删除 max 并添加新元素时的单个 'Heapify' 调用 c++ std::make_heap