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