Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

OpenCV lines/ruler detection

I'm trying to detect ruler on the image, and I'm going to follow the next process:

1) prepare image (blur,Canny, ect.)

2) detect lines

3) prepare set of parallel lines

so, I have an image: enter image description here

that app converts to this: enter image description here

next I've tried HoughLinesP method and looks I cannot apply it in my case, because I don't know the angle of lines, so it isn't found ruler vertical lines, but found horizontal (for example) and every ruler line consists of many thin lines, that will be a problem to process: enter image description here

the code:

std::vector<cv::Vec4i> lines_std;
cv::HoughLinesP( grayMat, lines_std, 1, CV_PI/90,  50, 10, 0 );

// drawing lines (with random color)
for( size_t i = 0; i < lines_std.size(); i++ )
{
    cv::line( originalMat, cv::Point(lines_std[i][0], lines_std[i][1]),
             cv::Point(lines_std[i][2], lines_std[i][3]), cv::Scalar(arc4random_uniform(155)+100,
                                                             arc4random_uniform(155)+100,
                                                             arc4random_uniform(155)+100), 1);
}

also I've tried LineSegmentDetector, and got more closer result I expected: enter image description here

code:

vector<Vec4f> lines_std;
Ptr<LineSegmentDetector> ls = createLineSegmentDetector(LSD_REFINE_NONE);
ls->detect(grayMat, lines_std);

but here I faced with some problems (and looks there is no way to customize createLineSegmentDetector) : not all lines were detected;lines detects not in center but on the sides and some times in left or right side only, but I need to get the center of bold line, because this will be used in calculations next.

So, what is the right way to find all lines (and every line only one time at the center of bold line)?

Update

tried HoughLines also:

vector lines;

cv::HoughLines(grayMat, lines, 1, CV_PI/90, 100 , 100, 0 );

for( size_t i = 0; i < lines.size(); i++ )
{
    float rho = lines[i][0], theta = lines[i][1];
    cv::Point pt1, pt2;
    double a = cos(theta), b = sin(theta);
    double x0 = a*rho, y0 = b*rho;

    pt1.x = cvRound(x0 + 1000*(-b));
    pt1.y = cvRound(y0 + 1000*(a));
    pt2.x = cvRound(x0 - 1000*(-b));
    pt2.y = cvRound(y0 - 1000*(a));

    cv::line( originalMat, pt1, pt2, cv::Scalar(0,255,0), 3, CV_AA);
}

but the result also looks strange (and calculations takes a lot of time): enter image description here

like image 451
Siarhei Avatar asked Feb 10 '17 14:02

Siarhei


People also ask

How to detect a straight line in OpenCV?

Before going into the lines road detection, we need to understand using opencv what is a line and what isn’t a line. The Houg lines transform is an algorythm used to detect straight lines.

What is the OpenCV line detection function?

The OpenCV line detection function is a very useful function that is utilized in a plethora of applications especially related to image detection. This inbuilt function is used to isolate specific features with respect to uh particular shape, which is present within the image specified for processing.

How to detect lines in an image using houghlines in OpenCV?

The HoughLines () function of OpenCV is used to detect lines present in an image using the standard Hough line transform. To detect the lines present in an image, we have to read the image using the imread () function and convert it into grayscale if it’s not in grayscale already.

Why am I getting 2 detected lines in the output?

For every line in the picture you get 2 detected lines in the output. This even happens if the original line width is 1 pixel, i.e. previous thinning/skeletonization does not help. How to adapt that instead of 2 lines only the central line of them is returned? Here is my pipeline, maybe it can give you some help.


1 Answers

Guess I found the way I should follow for:

1) make lines thin as possible (after Canny transformation):

cv::Mat skel(grayMat.size(), CV_8UC1, cv::Scalar(0));
cv::Mat temp(grayMat.size(), CV_8UC1);
cv::Mat elementSkel = cv::getStructuringElement(cv::MORPH_CROSS, cv::Size(3, 3));

bool done;
do
{
    cv::morphologyEx(grayMat, temp, cv::MORPH_OPEN, elementSkel);
    cv::bitwise_not(temp, temp);
    cv::bitwise_and(grayMat, temp, temp);
    cv::bitwise_or(skel, temp, skel);
    cv::erode(grayMat, grayMat, elementSkel);

    double max;
    cv::minMaxLoc(grayMat, 0, &max);
    done = (max == 0);
} while (!done);

it looks like this:

enter image description here

2) detect lines with LineSigmentDetector:

vector<Vec4f> lines_std;
Ptr<LineSegmentDetector> ls = createLineSegmentDetector(LSD_REFINE_NONE);
ls->detect(skel, lines_std);

3)calculate line angle and group ids by angle:

NSMutableDictionary *testHashMap = [[NSMutableDictionary alloc]init];

for( size_t i = 0; i < lines_std.size(); i++ )
{
    cv::Point p1 = cv::Point(lines_std[i][0], lines_std[i][1]);
    cv::Point p2 = cv::Point(lines_std[i][2], lines_std[i][3]);
    int angle = abs(atan2(p1.y - p2.y, p1.x - p2.x)); // int for rounding (for test only)

    NSMutableArray *idArray=testHashMap[[NSString stringWithFormat:@"%i", angle]];
    if(idArray == nil) {
        idArray = [[NSMutableArray alloc] init];
    }

    [idArray addObject:[NSNumber numberWithInt:i]];
    [testHashMap setObject:idArray forKey:[NSString stringWithFormat:@"%i", angle] ];
}

4) found the ruler line set and draw it:

for( NSInteger i = 0; i < [rulerIds count]; i++ )
{
    int itemId =   [[rulerIds objectAtIndex:i] integerValue];
    cv::Point p1 = cv::Point(lines_std[itemId][0], lines_std[itemId][1]);
    cv::Point p2 = cv::Point(lines_std[itemId][2], lines_std[itemId][3]);
    cv::line( originalMat, p1 ,  p2, cv::Scalar(0,255,0), 1);
}

result I got:

enter image description here

Update

but if we zoom this image well still see duplicated lines to remove duplications I've made simple logic that merges lines by founding average value for each point, for instance in case of 3 lines(green) we have 3 dots on the end:

enter image description here

like image 177
Siarhei Avatar answered Sep 28 '22 08:09

Siarhei