Reputation: 2436
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
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:
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:
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):
Upvotes: 12
Views: 3231
Reputation: 2436
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:
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:
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:
Upvotes: 5