2016-07-05 1 views
0

Tricky one aujourd'hui, mais définitivement faisable et je pense que je suis sur la bonne voie. J'essaie de détecter une ligne pointillée dans une image. Je fais ceci en trouvant des paires des contours les mieux ajustés dont les pentes s'alignent aussi avec l'angle créé par l'un l'autre. Voir l'exemple morceau de code ci-dessous:Détection d'une ligne pointillée parmi les contours dans 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); 
     } 
    } 
} 

Méthodologie est: 1) Créer un tableau des meilleures lignes d'ajustement aux contours 2) Étape par tableau et obtenir la pente de la ligne 3) Étape à travers le tableau à nouveau et la pente de toutes les autres lignes 4) Calculer la pente de la ligne créée par les deux centres ligne 5) Comparer les 3 pistes les unes contre les autres et un filtrage à une valeur de tolérance

le code suivant génère une tonne de lignes de mon image, mais aucun d'eux n'a frappé la ligne pointillée évidente. Je pense que quelque chose ne va pas avec les calculs de pente. En ce moment, c'est tellement inefficace que j'ai besoin de créer des images et des tests au lieu de travailler avec des graphismes réels. Quelque chose saute?

De plus, le code ci-dessous est assez lourd en termes de calcul, l'application est pour l'interprétation vidéo et le framerate est critique, de sorte que toutes les suggestions pour améliorer les performances sont appréciées.

Vous cherchez des matchs comme ceci: image


Edit:

Voici quelques code plus propre à lire. Je me suis également rendu compte de prendre la valeur absolue des pentes AVANT de trouver la différence n'a pas de sens et de créer juste un tas de contours plus accidentés qui correspondent. Je dois jouer avec un peu plus pour voir si cela a aidé:

//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

Peut-être que j'aurais dû être plus clair, une ligne «segmentée» est ce que je cherche parmi les contours. C'est pourquoi j'examine la pente du contour lui-même. – DrTarr

+0

tbh Je n'aurais pas segmenté la ligne en bas à gauche comme vous l'avez fait. Mais j'aurais segmenté une ligne de plus en bas à gauche. À propos de votre code: pouvez-vous commenter ou renommer les variables pour obtenir une compréhension plus rapide de leur signification? – Micka

Répondre

0

Sur la base de votre image par exemple, il semble que vous essayez de détecter des segments de ligne avec les contraintes suivantes:

  1. segments ont des pentes (ou orientations) similaires
  2. les segments tombent le long d'une ligne similaire.

Ce problème semble vraiment bien adapté à une solution RANSAC. Avec simple RANSAC 2D, vous trouvez la ligne avec laquelle la plupart de vos points de données s'alignent.

  1. vous résolvez pour cette ligne par des sous-ensembles d'échantillonnage au hasard (dans ce cas, des sous-ensembles de 2) et reliant les points dans les sous-ensembles.
  2. Puis, vous définissez une taille de fenêtre, et incluez tous les autres points qui se trouvent dans la ligne joignant votre sous-ensemble +/- la taille de la fenêtre. Ces points sont appelés inliers.
  3. Vous souhaitez rechercher le segment de ligne qui maximise le nombre d'inliers.

Pour plus d'informations, voir these slides on RANSAC


Dans votre cas, vous souhaitez modifier le problème légèrement pour tenir compte du fait que vous êtes à la recherche de segments de ligne, pas de points. Il y a plusieurs façons d'accomplir cela.

Une solution consiste à regrouper vos segments en fonction de la pente, puis à appliquer une RANSAC 2D simple à chaque cluster et à traiter les segments comme s'ils étaient des points.

J'espère que cela aide.

+0

Merci Eric, ce qui est extrêmement utile, Aussi, les liens externes sur le lien wikipedia ont beaucoup d'exemples opencv. De plus, mon code semble effectivement fonctionner après la suppression de l'ABS() avant la comparaison de pente, mais le RANSAC peut être une solution plus éprouvée. – DrTarr

+0

Merci pour les commentaires! Je suis content que vous ayez réussi à faire fonctionner votre code. –