如何从模拟计数器中识别数字?

4
我正在尝试从计数器中读取以下kWh数字。问题是tesseract OCR无法识别模拟数字。

counter

问题是:将所有数字(从0到9)的照片放在不同的位置上(我的意思是当数字处于中心位置时,当它稍微靠上时以及数字2出现时等等),并尝试使用图像识别而不是文本识别是否更好呢?
据我所知,区别在于图像识别比较照片,而文本识别...嗯,我不知道...
有什么建议吗?
2个回答

3
由于计数器不是数字,而是模拟的,因此我们在转换时遇到了问题。 文本/数字识别库无法识别像这样的内容。 我找到的解决方案是:机器学习
首先,我让用户制作图片,其中数字占图像的70-80%(以便删除不必要的细节)。
然后,我寻找平行线(如果有的话)并裁剪位于它们之间的图片(如果距离足够大)。
之后,我对图片进行过滤(调整对比度,亮度,将其设置为灰度),然后使用仅包含两种颜色(#000000(黑色)和#ffffff(白色))的过滤器。 为了更容易地找到轮廓。
然后,我使用Canny算法来找到轮廓,并通过删除不需要的细节来过滤它们。
之后,我使用K-最近邻算法来识别数字。 但在我能识别任何内容之前,我需要教会算法如何查看数字以及它们是什么。 希望这很有用!

2
也许您没有正确配置tesseract。我使用它编写了一个代码来解决您的问题:
#include <opencv2/highgui/highgui.hpp>
#include <opencv2/imgproc/imgproc.hpp>
#include <tesseract/baseapi.h>
#include <iostream>

using namespace cv;

int main(int argc, char** argv)
{
    cv::Mat input = cv::imread("img.jpg");

    //rectangle containing just the kWh numbers
    Rect roi(358,327,532,89);

    //convert to gray scale
    Mat input_gray;
    cvtColor(input(roi),input_gray,CV_BGR2GRAY);

    //threshold image
    Mat binary_img = input_gray>200;

    //make a copy to use on findcontours
    Mat copy_binary_img = binary_img.clone();

    vector<vector<Point> > contours;
    vector<Vec4i> hierarchy;

    //identify each blob in order to eliminate the small ones 
    findContours(copy_binary_img, contours, hierarchy, CV_RETR_TREE, CV_CHAIN_APPROX_SIMPLE, Point(0,0));

    //filter blobs by their sizes
    for (vector<vector<Point> >::iterator it = contours.begin(); it!=contours.end(); )
    {
        if (it->size()>20)
            it=contours.erase(it);
        else
            ++it;
    }

    //Erase blobs which have countour size smaller than 20
    for( int i = 0; i< contours.size(); i++ )
    {
        drawContours( binary_img, contours, i, 0, -1, 8, hierarchy, 0, Point() );
    }

    //initialize tesseract OCR
    tesseract::TessBaseAPI tess;
    tess.Init(NULL, "eng", tesseract::OEM_DEFAULT);

    tess.SetVariable("tessedit_char_whitelist", "0123456789-.");

    tess.SetPageSegMode(tesseract::PSM_SINGLE_BLOCK);

    //set input 
    tess.SetImage((uchar*)binary_img.data
            , binary_img.cols
            , binary_img.rows
            , 1
            , binary_img.cols);

    // Get the text
    char* out = tess.GetUTF8Text();
    std::cout << out << std::endl;
    waitKey();
    return 0;
}

@denis631 是的,我认为最好尝试模板匹配。关于应用于单个数字,您可以使用垂直直方图拆分计数器,例如(这里有一个很好的例子)。 - Jäger
我现在正在使用模板匹配,但它并不适合我。问题是:拍照的人可能远离或靠近柜台,因此模板可能过小/过大,无法进行匹配。是否有类似于模式匹配的东西?即使模式太小/太大,它也可以找到匹配。还是我需要动态地调整我的模式大小以适应柜台照片的大小? - denis631
也许你可以基于已检测到的数字尝试矫正透视畸变,然后再进行尺度和旋转的调整。我尝试使用OpenCV中的findHomography函数,但模板图像上关键点的缺乏导致结果不佳。 - Jäger
没错!我也尝试过尺度/变换不变算法,但它无法检测到任何关键点/特征...现在我正在尝试强制用户拍摄几乎与我的模板大小完全相同的照片,以便我可以进行简单的模板匹配...我没有其他想法。 - denis631
我建议你将问题中的图片更改为你在评论中链接的那个,这样也许会有其他人有更好的想法。 - Jäger

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接