2016-07-05 3 views
0

Хитрое сегодня, но определенно умело, и я думаю, что я на правильном пути. Я пытаюсь обнаружить пунктирную линию в изображении. Я делаю это, находя пары наилучших контуров, чьи наклоны также выравниваются с углом, созданным друг другом. См пример фрагмент кода ниже:Обнаружение пунктирной линии среди контуров в OpenCV

//Get canny mat 
Mat frame, framegray, detectededges, dummyimg, cannyedges; 
cvtColor(frame, framegray, CV_BGR2GRAY); 
blur(framegray, detectededges, Size(3,3)); 
double otsu_thresh_val = cv::threshold(detectededges, dummyimg,0, 255, CV_THRESH_BINARY | CV_THRESH_OTSU); 
cv::Canny(detectededges, cannyedges, otsu_thresh_val*0.5, otsu_thresh_val); 

// 
Scalar color(255,255,0,255); 

//Find contours 
vector<vector<Point>> contours; 
vector<Vec4i> hierarchy; 
findContours(cannyedges,contours,hierarchy,CV_RETR_CCOMP,CV_CHAIN_APPROX_SIMPLE); 
double contourlength = arcLength(contours[idx], false); 
vector<Vec4f> vectorofbestfits; 

//Find dotted lines 
for (vector<Point> contour : contours){ 
    //Some filtering 
    if ((contourlength > 70.0) && (contours[idx].size() > 5)){ 
     Vec4f bestfitline; 
     fitLine(contour, bestfitline,CV_DIST_L2,0,0.01,0.01); 
     vectorofbestfits.push_back(bestfitline); 
    } 
} 

float mtol = 0.05; 
for (Vec4f veci : vectorofbestfits){ 
    float mi = veci[1]/veci[0]; 
    for (Vec4f vecj : vectorofbestfits){ 
     float mj = vecj[1]/vecj[0]; 
     double length = cv::norm(Mat(Point(veci[2],veci[3])),Mat(Point(vecj[2],vecj[3]))); 
     if (length < 30){ 
      continue; 
     } 
     float mk = (veci[3]-vecj[3])/(veci[2]-vecj[2]); 
     mi = abs(mi); 
     mj = abs(mj); 
     mk = abs(mk); 
     float mij = abs(mi - mj); 
     float mjk = abs(mj - mk); 
     float mki = abs(mk - mi); 
     if ((mij < mtol) && (mjk < mtol) && (mki < mtol)){ 
      line(frame,Point(veci[2],veci[3]),Point(vecj[2],vecj[3]),color,2); 
     } 
    } 
} 

Методология: 1) Создать массив лучших линий подходят к контурам 2) Шаг через массив и получить наклон линии 3) Шаг через массив снова и наклону любой другой линии 4) Вычислить наклон линии, созданной двумя линии центров 5) Сравнить все 3 наклоны друг против друга и фильтр со значением допуска

Приведенный ниже код генерирует тонну линий моего изображения, но ни один из них не попал в очевидную пунктирную линию. Я думаю, что что-то не так с расчетами наклона. Сейчас это настолько неэффективно, что мне нужно создать несколько изображений и протестировать вместо работы с реальной графикой. Что-то выпрыгивает?

Кроме того, приведенный ниже код довольно сложный, приложение предназначено для интерпретации видео, а частота кадров критична, поэтому любые предложения по повышению производительности оцениваются.

В поисках спичек, как так: image


Edit:

Вот некоторые чистый код для чтения. Я также понял, что беру абсолютную ценность склонов, прежде чем найти разницу не имеет никакого смысла и просто создать кучу более случайных контуров, которые совпадают. Мне нужно, чтобы играть с ним еще немного, чтобы увидеть, если это помогло:

//Get canny mat 
Mat frame, framegray, detectededges, dummyimg, cannyedges; 
cvtColor(frame, framegray, CV_BGR2GRAY); 
blur(framegray, detectededges, Size(3,3)); 
double otsu_thresh_val = cv::threshold(detectededges, dummyimg,0, 255, 
    CV_THRESH_BINARY | CV_THRESH_OTSU); 
cv::Canny(detectededges, cannyedges, otsu_thresh_val*0.5, otsu_thresh_val); 

//Set color for Lines 
Scalar color(255,255,0,255); 

//Find contours 
vector<vector<Point>> contours; 
vector<Vec4i> hierarchy; 
findContours(cannyedges,contours,hierarchy,CV_RETR_CCOMP,CV_CHAIN_APPROX_SIMPLE); 
double contourlength = arcLength(contours[idx], false); 
vector<Vec4f> arrayofbestfits; 

//Create an array of best fit Lines 
for (vector<Point> contour : contours){ 
    //Filter out contours that are too small 
    if ((contourlength > 70.0) && (contours[idx].size() > 5)){ 
     Vec4f bestfitLine; 
     fitLine(contour, bestfitLine,CV_DIST_L2,0,0.01,0.01); 
     arrayofbestfits.push_back(bestfitLine); 
    } 
} 

float SlopeTolerance = 0.05; 
for (Vec4f firstIterationLine : arrayofbestfits){ 
    float firstIterationSlope = firstIterationLine[1]/firstIterationLine[0]; 
    for (Vec4f secondIterationLine : arrayofbestfits){ 
     //Filter out Lines too close in proxmity 
     double length = cv::norm(Mat(Point(firstIterationLine[2],firstIterationLine[3])), 
      Mat(Point(secondIterationLine[2],secondIterationLine[3]))); 
     if (length < 30){ 
      continue; 
     } 
     //Find slope between two points 
     float commonSlope = (firstIterationLine[3]-secondIterationLine[3]) 
      /(firstIterationLine[2]-secondIterationLine[2]); 
     //Find absolute value of differences (makes comparison simpler) 
     float commonSlopediff = abs(firstIterationSlope - secondIterationSlope); 
     float secondtocommonSlopediff = abs(secondIterationSlope - commonSlope); 
     float commontofirstSlopediff = abs(commonSlope - firstIterationSlope); 
     //If within tolerances draw the line bridging the two best fit lines together 
     if ((commonSlopediff < SlopeTolerance) && (secondtocommonSlopediff < SlopeTolerance) && (commontofirstSlopediff < SlopeTolerance)){ 
      Line(frame,Point(firstIterationLine[2],firstIterationLine[3]), 
       Point(secondIterationLine[2],secondIterationLine[3]),color,2); 
     } 
    } 
} 
+0

Возможно, я должен был быть более ясным, «сегментированная» линия - это то, что я ищу среди контуров. Вот почему я рассматриваю наклон самого контура. – DrTarr

+0

tbh Я бы не разделил нижнюю левую линию так, как вы делали. Но я бы разделил еще одну строку внизу слева. О вашем коде: можете ли вы прокомментировать или переименовать переменные, чтобы быстрее понять их предполагаемое значение? – Micka

ответ

0

Основываясь на вашем примере изображения, это выглядит, как вы пытаетесь обнаружить сегменты линии со следующими ограничениями:

  1. сегментов имеют похожие наклоны (или ориентации)
  2. сегменты падают вдоль аналогичной линии.

Эта проблема кажется действительно хорошо подходящей для решения RANSAC.


С помощью простого 2D RANSAC вы находите линию, с которой согласны большинство ваших точек данных.

  1. Вы решаете эту строку случайными выборками подмножеств (в данном случае подмножеств 2) и соединяете точки в подмножествах.
  2. Затем вы устанавливаете размер окна и включаете все остальные точки, которые лежат в строке, соединяющей ваш поднабор +/- размер окна. Эти точки называются ярусами.
  3. Вы хотите найти сегмент линии, который максимизирует количество линеек.

Для получения дополнительной информации см these slides on RANSAC


В вашем случае, вы хотите немного изменить эту проблему, чтобы отразить тот факт, что вы ищете отрезки, а не точки. Существует множество способов достижения этого.

Одним из решений является скопление сегментов на основе наклона, а затем применение простого 2D RANSAC к каждому кластеру и обработка сегментов, как если бы они были точками.

Надеюсь, это поможет.

+0

Спасибо Эрик, что очень полезно. Кроме того, внешние ссылки на ссылку в Википедии содержат много примеров opencv. Кроме того, мой код действительно работает после удаления ABS() перед сравнением склона, но RANSAC может быть более проверенным решением. – DrTarr

+0

Спасибо за отзыв! Рад, что вы смогли заставить свой код работать. –

 Смежные вопросы

  • Нет связанных вопросов^_^