OpenCV Comment tracer des vecteurs de vitesse sous forme de flèches lors de l’utilisation d’une seule image statique

J’essaie de tracer des vecteurs de vitesse, comme dans Matlab, nous utilisons la fonction “Quiver” http://www.mathworks.com/help/techdoc/ref/quiver.html

J’ai besoin de porter la même méthodologie en C ++ en utilisant la bibliothèque OpenCV.

J’ai entendu dire qu’il existe quelques méthodes de stream optique, à savoir Lucas et Kanade (cvCalOpticalFlowLK) ou Horn et Schunck (cvCalOpticalFlowHS) ou une méthode de correspondance de blocs (cvCalOpticalFlowBM)

mais toutes ces fonctions prennent deux images, alors que je dois utiliser une image parce que je travaille sur les empreintes digitales.

Aidez-moi gentiment …

[Modifier] Solution trouvée

void cvQuiver(IplImage*Image,int x,int y,int u,int v,CvScalar Color, int Size,int Thickness){ cv::Point pt1,pt2; double Theta; double PI = 3.1416; if(u==0) Theta=PI/2; else Theta=atan2(double(v),(double)(u)); pt1.x=x; pt1.y=y; pt2.x=x+u; pt2.y=y+v; cv::line(Image,pt1,pt2,Color,Thickness,8); //Draw Line Size=(int)(Size*0.707); if(Theta==PI/2 && pt1.y > pt2.y) { pt1.x=(int)(Size*cos(Theta)-Size*sin(Theta)+pt2.x); pt1.y=(int)(Size*sin(Theta)+Size*cos(Theta)+pt2.y); cv::line(Image,pt1,pt2,Color,Thickness,8); //Draw Line pt1.x=(int)(Size*cos(Theta)+Size*sin(Theta)+pt2.x); pt1.y=(int)(Size*sin(Theta)-Size*cos(Theta)+pt2.y); cv::line(Image,pt1,pt2,Color,Thickness,8); //Draw Line } else{ pt1.x=(int)(-Size*cos(Theta)-Size*sin(Theta)+pt2.x); pt1.y=(int)(-Size*sin(Theta)+Size*cos(Theta)+pt2.y); cv::line(Image,pt1,pt2,Color,Thickness,8); //Draw Line pt1.x=(int)(-Size*cos(Theta)+Size*sin(Theta)+pt2.x); pt1.y=(int)(-Size*sin(Theta)-Size*cos(Theta)+pt2.y); cv::line(Image,pt1,pt2,Color,Thickness,8); //Draw Line } } 

Je suis en quelque sorte en train de compléter la réponse actuelle ici, qui ne permet pas de donner la bonne taille de chaque pointe des flèches. MATLAB le fait de manière à ce que lorsqu’une flèche est presque un point, elle ne comporte aucune astuce, alors que pour les longues flèches, elle affiche un gros pourboire, comme le montre l’image suivante.

entrez la description de l'image ici

Pour obtenir cet effet, nous devons normaliser la “taille de la pointe” de chacune des flèches sur la plage de longueur des flèches. Le code suivant fait l’affaire

  double l_max = -10; for (int y = 0; y < img_sz.height; y+=10) // First iteration, to compute the maximum l (longest flow) { for (int x = 0; x < img_sz.width; x+=10) { double dx = cvGetReal2D(velx, y, x); // Gets X component of the flow double dy = cvGetReal2D(vely, y, x); // Gets Y component of the flow CvPoint p = cvPoint(x, y); double l = sqrt(dx*dx + dy*dy); // This function sets a basic threshold for drawing on the image if(l>l_max) l_max = l; } } for (int y = 0; y < img_sz.height; y+=10) { for (int x = 0; x < img_sz.width; x+=10) { double dx = cvGetReal2D(velx, y, x); // Gets X component of the flow double dy = cvGetReal2D(vely, y, x); // Gets Y component of the flow CvPoint p = cvPoint(x, y); double l = sqrt(dx*dx + dy*dy); // This function sets a basic threshold for drawing on the image if (l > 0) { double spinSize = 5.0 * l/l_max; // Factor to normalise the size of the spin depeding on the length of the arrow CvPoint p2 = cvPoint(px + (int)(dx), py + (int)(dy)); cvLine(resultDenseOpticalFlow, p, p2, CV_RGB(0,255,0), 1, CV_AA); double angle; // Draws the spin of the arrow angle = atan2( (double) py - p2.y, (double) px - p2.x ); px = (int) (p2.x + spinSize * cos(angle + 3.1416 / 4)); py = (int) (p2.y + spinSize * sin(angle + 3.1416 / 4)); cvLine( resultDenseOpticalFlow, p, p2, CV_RGB(0,255,0), 1, CV_AA, 0 ); px = (int) (p2.x + spinSize * cos(angle - 3.1416 / 4)); py = (int) (p2.y + spinSize * sin(angle - 3.1416 / 4)); cvLine( resultDenseOpticalFlow, p, p2, CV_RGB(0,255,0), 1, CV_AA, 0 ); } } } 

Et ceci est un exemple de la façon dont ce code OpenCV ressemblerait

entrez la description de l'image ici

J’espère que cela aidera d’autres personnes à googler pour le même problème.

Basé sur le code de Dan et la suggestion de mkuse, voici une fonction avec la même syntaxe que cv :: line ():

 static void arrowedLine(InputOutputArray img, Point pt1, Point pt2, const Scalar& color, int thickness=1, int line_type=8, int shift=0, double tipLength=0.1) { const double tipSize = norm(pt1-pt2)*tipLength; // Factor to normalize the size of the tip depending on the length of the arrow line(img, pt1, pt2, color, thickness, line_type, shift); const double angle = atan2( (double) pt1.y - pt2.y, (double) pt1.x - pt2.x ); Point p(cvRound(pt2.x + tipSize * cos(angle + CV_PI / 4)), cvRound(pt2.y + tipSize * sin(angle + CV_PI / 4))); line(img, p, pt2, color, thickness, line_type, shift); px = cvRound(pt2.x + tipSize * cos(angle - CV_PI / 4)); py = cvRound(pt2.y + tipSize * sin(angle - CV_PI / 4)); line(img, p, pt2, color, thickness, line_type, shift); } 

Nous verrons si ceux qui maintiennent le référentiel OpenCV l’aimeront 🙂

Le cvCalOpticalFlowLK ne trace pas les vecteurs de vitesse, il calcule ces vecteurs de vitesse. Si vous ne disposez pas de ces vecteurs, vous devez appeler cette fonction avec deux images. Je suppose que vous avez déjà ces vecteurs et que vous voulez juste les tracer.

Dans ce cas, vous pouvez utiliser la fonction cv :: line , par exemple:

 cv::line(yourImage, cv::Point(baseX, baseY), cv::Point(endX, endY)); 

J’espère que cela t’aidera!