2017-02-10 155 views
9

我试图检测图像上的统治者,我要按照下面的过程:OpenCV的线/尺检测

1)准备图像(模糊,康力,ECT)

2)检测线

3)制备组平行线

所以,我有一个图像: enter image description here

该应用转换成这样的: enter image description here

下一个我试图HoughLinesP方法,看起来我不能在我的案件,不适用,因为我不知道线的角度,所以它没有找到尺子垂直线,却发现水平(例如)和每一个标尺线由许多细线,那将是对过程的一个问题: enter image description here

代码:

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); 
} 

也是我试过LineSegmentDetector,并获得更接近的结果我的预期: enter image description here

代码:

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

但在这里,我面临着一些问题(而且看上去也没有办法来定制createLineSegmentDetector:检测 不是所有的线;线检测不在中心,而是在双方,有时只在左侧或右侧,但我需要得到粗线的中心,因为这将在下一次计算中使用。

那么,找到所有行(每行只有一次在粗体行的中心)的正确方法是什么?

更新

试图HoughLines也:

矢量线;

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); 
} 

但结果也看起来很奇怪(和计算需要花费大量的时间)enter image description here

回答

4

猜我发现我应该遵循的方式:

1)使线薄尽可能(Canny转换后)

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); 

它看起来像这样:

enter image description here

2)检测线与LineSigmentDetector:由角度

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

3)计算线的角度和组ID:

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)发现标尺线设置并画出:

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); 
} 

结果我:

enter image description here

更新

但如果我们放大这一形象也依然看到重复的行 去除重复我做了通过建立融合线简单的逻辑平均值对于每个点,例如,在3行(绿)的情况下,我们有在端3点:

enter image description here