2017-02-10 12 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): были обнаружены не все линии, линия обнаруживает не в центре, но на сторон и несколько раз только в левой или правой части, но мне нужно получить центр полужирной линии, потому что это будет использовано в последующих вычислениях.

Итак, каков правильный способ найти все строки (и каждая строка только один раз в центре жирной линии)?

Update

пытался 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) делают линии тонкие как можно (после трансформации Канни):

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) рассчитать угол линии и групповые идентификаторы по углу:

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