OpenCV中如何绘制速度矢量为箭头使用单个静态图像

问题描述:

我试图绘制速度矢量像MATLAB中我们使用“颤动”功能http://www.mathworks.com/help/techdoc/ref/quiver.htmlOpenCV中如何绘制速度矢量为箭头使用单个静态图像

我需要移植相同的方法在C++中使用OpenCV库。

我听说过有几个光流法,即卢卡斯和金出武雄(cvCalOpticalFlowLK)或非洲之角和Schunck(cvCalOpticalFlowHS)或块匹配方法(cvCalOpticalFlowBM)

,但所有的这些功能需要两个图像,而我需要使用一个图像,因为我正在处理指纹。

请帮我...

[编辑] 发现的解决方案

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 
    } 

} 

我在这里完成当前的答案,这不能给出每个箭头的提示的正确大小。 MATLAB以一种方式实现它,当一个箭头几乎是一个点时,它没有任何提示,而对于长箭头,它显示了一个很大的提示,如下图所示。

enter image description here

为了得到这种效果,我们需要在箭头长度的范围内归一化每个箭头的“针尖大小”。下面的代码做的伎俩

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(p.x + (int)(dx), p.y + (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) p.y - p2.y, (double) p.x - p2.x); 

      p.x = (int) (p2.x + spinSize * cos(angle + 3.1416/4)); 
      p.y = (int) (p2.y + spinSize * sin(angle + 3.1416/4)); 
      cvLine(resultDenseOpticalFlow, p, p2, CV_RGB(0,255,0), 1, CV_AA, 0); 

      p.x = (int) (p2.x + spinSize * cos(angle - 3.1416/4)); 
      p.y = (int) (p2.y + spinSize * sin(angle - 3.1416/4)); 
      cvLine(resultDenseOpticalFlow, p, p2, CV_RGB(0,255,0), 1, CV_AA, 0); 

     } 
    } 
} 

这是本OpenCV的代码会是什么样子

enter image description here

我希望这种帮助别人谷歌搜索同一个问题的例子。

+1

感谢dan有帮助 – wolvorinePk 2012-06-27 07:40:27

+1

@wolvorinePk我很高兴它帮助了某人! – Dan 2012-06-27 08:30:06

+1

@Dan:我可以建议你编辑代码,并将其放在像“arrowedLine()”这样的函数中。它有一个类似cv :: line()的语法? – mkuse 2014-03-27 15:26:21

cvCalOpticalFlowLK不积速度矢量,它计算这些速度矢量。如果你没有这些矢量,你必须用两个图像调用这个函数。我想你已经有了这些载体,而你只是想绘制它们。

在这种情况下,你可以使用cv::line function,例如:

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

我希望这会帮助你!

+0

谢谢我试图用一堆不同的方式来创建一个使用一个单一的图像箭头,现在它的工作。 – wolvorinePk 2012-04-17 05:44:53

+0

为了我的其他帮助而添加了上面的代码 – wolvorinePk 2012-04-17 05:47:51

+0

没有符号(方向/箭头提示)的矢量绘图是不好的做法。我建议下面的答案。 – TimZaman 2014-02-24 09:38:00

基于从丹的代码和mkuse的建议,这里是相同的语法CV ::线()函数:

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); 
    p.x = cvRound(pt2.x + tipSize * cos(angle - CV_PI/4)); 
    p.y = cvRound(pt2.y + tipSize * sin(angle - CV_PI/4)); 
    line(img, p, pt2, color, thickness, line_type, shift); 
} 

我们将看到如果这些保持OpenCV的库会喜欢它:-)

+2

下一个OpenCV版本将有[cv :: arrowedLine](https://github.com/Itseez/opencv/blob/a7006ac21c2e41b98be5d6635d75b3962000986b/modules/core/doc/drawing_functions.rst#arrowedline)可用 – PhilLab 2014-07-24 07:58:39