4

I'm trying to read the following kWh numbers from the counter. The problem is the tesseract OCR doesn't recognize the analog digits.

counter

The question is: will it be a better idea to make the photos of all of the digits (from 0 to 9) at different positions (I mean when digit is in the center, when it is a little at the top and the number 2 is appearing etc.) and to try image recognition instead of text recognition?

As far as I understood the difference is, that the image recognition compares the photos, while the text recognition... well I don't know...

Any advice?

Community
  • 1
  • 1
denis631
  • 1,765
  • 3
  • 17
  • 38

2 Answers2

3

Since the counter is not digital, but analog, we have problems at the transitions. The text/number recognition libraries can not recognize smth like that. The solution, that I've found is: Machine Learning.

Firstly I've made user to make the picture, where the numbers take 70-80% of the image (in order to remove the unneeded details).

Then I'm looking for parallel lines (if there are any) and cut the picture, that is between them (if the distance is big enough).

After that I'm filtering the picture (playing with contrast, brightness, set it grayscale) and then use the filter, that makes the image to contain only two colours (#000000 (black) and #ffffff (white)). In order to find the contours easier.

Then I find the contours by using Canny algorithm and filter them, by removing the unneeded details.

After that I use K-Nearest-Neighbour algorithm in order to recognize the digits.

But before I can recognize anything, I need to teach the algorithm, how the digits look like and what are they.

I hope it was useful!

denis631
  • 1,765
  • 3
  • 17
  • 38
2

Maybe you are not configuring tesseract right. I made a code using it that solves your problem:

#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;
}
Jäger
  • 71
  • 10
  • @denis631 Yes, then I think it's better to try [template matching](http://docs.opencv.org/doc/tutorials/imgproc/histograms/template_matching/template_matching.html). About applying to single digits, you can split the counter with vertical histogram, for example ([here](http://stackoverflow.com/a/12785869/2156861) there is a good example). – Jäger Aug 05 '15 at 11:59
  • I'm working now with template matching and it suits me neither. The problem is: people who are making the photos can be far or near to counter, so that the template may be too small/big for template matching. Is there smth like pattern matching ?, where it can find the match even when the pattern is too small/big. Or I need to dynamically adapt the size of my pattern for the size of the photo of the counter ? – denis631 Aug 05 '15 at 12:11
  • Maybe you can try to correct the perspective distortion based on the numbers you already detected, and do the same with scale and rotation. I tried findHomography from opencv, but the lack of keypoints on the template led to poor results. – Jäger Aug 06 '15 at 17:10
  • exactly! I also 've tried the scale/transform invariant algorithms, but it doesn't detect any keypoints/features... Now I'm trying to force the user to make the photo of almost exactly same size as my template, so that I can make simple template matching ... I don't have any other ideas – denis631 Aug 06 '15 at 18:04
  • I suggest you to change the image in the question to the one you linked here in the comments, so maybe someone else has a better idea. – Jäger Aug 07 '15 at 01:10