0

I want to crop the image between two lines, as shown in the image below. But the bottom line is not recognized well with HoughLinesP. The bottom line points are not really edged because of eroding, but is it important?

How can I detect the bottom line, and then crop the image according to these 2 lines?

Original image:

enter image description here

Processed image:

enter image description here

Canny edged:

enter image description here

Lines detected:

enter image description here

Code For Line Detection :

Mat dst, cdst,src2;
cv::blur( src, src2, cv::Size(5,5) );
Canny(src2, dst, 150, 300, 5);
cvtColor(dst, cdst, CV_GRAY2BGR);

//Mat original = imread("final_sample1.png",0);

vector<Vec4i> lines;
HoughLinesP(dst, lines, 1, 2*CV_PI/180, 100,1000, 50 );

For for displaying lines :

   for( size_t i = 0; i < lines.size(); i++ )
{
    Vec4i l = lines[i];

   // oran = float(l[1] / col_size );
    double angle = atan2(l[3] - l[1], l[2] - l[0]) * 180.0 / CV_PI;

    if(angle  < 5  && angle >=-5   ){
    //if(1){
        cout << l[0] << "," << l[1] << "," << l[2] << "," << l[3] << endl;
        line( cdst, Point(l[0], l[1]), Point(l[2], l[3]), Scalar(0,0,255), 3, CV_AA);
    }
}

EDIT:

For line detection appliying adaptive tresholding to original image gives more reliable results.

adaptiveThreshold(img,adaptiveTresholded,255,ADAPTIVE_THRESH_GAUSSIAN_C,CV_THRESH_BINARY,75,15);

I tested on 20 samples which has different number of rows , and thanks to Micka, with his modification, I got good results. To detect the right lines I put an if statement.

"ratio" variable is the y1 / row size of the image. And checking the line angle to prevent irrelevant lines.

for( size_t i = 0; i < lines.size(); i++ )
{
    Vec4i l = lines[i];

    raito = float(l[1] / row_size );
    double angle = atan2(l[3] - l[1], l[2] - l[0]) * 180.0 / CV_PI;

  if(angle  < 10 && angle >=- 10 && ratio > 0.15 && ratio< 0.8){
    //if(1){
        cout <<"Here: " <<  l[0] << "," << l[1] << "," << l[2] << "," << l[3] <<
        ", Oran: " << oran <<  endl;
        line( cdst, Point(l[0], l[1]), Point(l[2], l[3]), Scalar(0,0,255), 3);
    }
}
happy
  • 21
  • 1
  • 5
  • Thanks a lot , it looks better... – happy Sep 09 '15 at 10:32
  • your lower "line" in the image is much less well structured. If you reduce the minimum line length (half or sth), you will probably detect the right part of that line. Can you try to `dilate` once or twice and detect long lines in the dilated image? – Micka Sep 09 '15 at 10:38
  • When I reduce minimum length it tends to find irrelevant lines, dilating may be an option , but what I am wondering is if it is possible recognize the whole bad structured line. – happy Sep 09 '15 at 10:43
  • Post also the original image. Probably with a better preprocessing you'll get a better edge mask and thus better lines – Miki Sep 09 '15 at 10:48
  • is it possible to remove the clutter at the bottom part of the image? I get good results for dilating several times and reducing the maximum line gap, which you've chosen very big... – Micka Sep 09 '15 at 10:49
  • I chosed this parameters to detect only these two lines , after that I will read the numbers with tesseract. – happy Sep 09 '15 at 10:59
  • 1
    Is it really useful to perform edge detection ? Your line is already of the ridge type and can be detected by straight Hough. And it there is no skew, just accumulate horizontally and detect the major peaks in the 1D profile. –  Sep 09 '15 at 12:36
  • I would prefer thresholding instead of canny edges, too! – Micka Sep 09 '15 at 12:42
  • Ok, I will try this. – happy Sep 09 '15 at 13:37
  • Only tresholding seems enough for line detection , but I think this processing was both for tesseract and line detection. With just tresholding , some numbers become unrecognizable for tesseract ocr. I will prepare 2 different image processor code for tesseract and line detection . – happy Sep 09 '15 at 14:33
  • Applying houghlines straigthly , didn't work well, it takes 2 sec per sample to compute. – happy Sep 09 '15 at 16:39

2 Answers2

1

using your image and this code (basically yours but reduced the maximum line gap and used some dilates to actually make connected straigt parts out of the non-straight bottom line:

int main()
{
    cv::Mat input = cv::imread("../inputData/LongLine.jpg");

    cv::Mat gray;
    cv::cvtColor(input,gray,CV_BGR2GRAY);

    // threshold because of loaded jpeg artifacts
    cv::Mat edges = gray > 100;

    cv::dilate(edges, edges, cv::Mat());
    cv::dilate(edges, edges, cv::Mat());
    cv::dilate(edges, edges, cv::Mat());

    std::vector<cv::Vec4i> lines;
    cv::HoughLinesP(edges, lines, 1, 2*CV_PI/180, 100,1000, 10 );

    for( size_t i = 0; i < lines.size(); i++ )
    {
        cv::Vec4i l = lines[i];

        cv::line( input, cv::Point(l[0], l[1]), cv::Point(l[2], l[3]), cv::Scalar(0,0,255), 3);

    }


    cv::imwrite("../outputData/LongLine.png", input);
    cv::resize(input, input, cv::Size(), 0.1, 0.1);
    cv::imshow("input",input);
    cv::waitKey(0);
    return 0;
}

getting this result:

enter image description here

For HoughLinesP is is important that the line is really straight, because the summed lines are expected to have thickness 1. So if the accumulator misses lines by just one pixel, it fails. Since the bottom lines aren't as straight as the first ones, this might be the problem.

Micka
  • 19,585
  • 4
  • 56
  • 74
  • This will be an android application where user takes picture of its lottery coupon , and application will check if he hit something , so eroding less may be a solution . I am trying to generalize the method so that it will be more reliable. – happy Sep 09 '15 at 11:12
  • if your setting will include that the coupon isnt completely plane and parallel to the image plane you'll most likely get more trouble... – Micka Sep 09 '15 at 11:16
  • Well, it is assumed that image is taken decently for the purpose. – happy Sep 09 '15 at 11:20
  • 1
    I have tried your method on more than 10 samples , and it gave way better results . Thank you very much .. – happy Sep 09 '15 at 12:00
  • Just a guess, but probably with `adaptiveThreshold` you can get rid of the noise in the bottom part. – Miki Sep 09 '15 at 12:27
0

Here are the plots of the accumulated raw intensities along horizontals, in ROIs around the top and bottom line pairs.

enter image description here

enter image description here

Needless to say, detecting the peaks isn't a real problem.

If there can be limited skew, you can repeat the process with a little rotation.