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

C++ OpenCV如何使用单个静态图像将速度矢量绘制为箭头,c++,opencv,vector,C++,Opencv,Vector,我正在尝试绘制速度向量,就像在matlab中我们使用“quiver”函数一样 我需要使用OpenCV库在C++中移植相同的方法。p> 我听说有几种光流方法,即Lucas和Kanade(cvCalOpticalFlowLK)或Horn和Schunck(cvCalOpticalFlowHS)或块匹配方法(cvCalOpticalFlowBM) 但是所有这些函数都需要两张图像,而我需要使用一张图像,因为我正在处理指纹 请帮助我 [编辑] 解决方案 void cvQuiver(IplImage*Imag

我正在尝试绘制速度向量,就像在matlab中我们使用“quiver”函数一样

我需要使用OpenCV库在C++中移植相同的方法。p> 我听说有几种光流方法,即Lucas和Kanade(cvCalOpticalFlowLK)或Horn和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
    }

}
cvCalOpticalFlowLK不绘制速度向量,它计算这些速度向量。如果没有这些向量,则必须使用两个图像调用此函数。我想你已经有了这些向量,你只想画出来

在这种情况下,您可以使用,例如:

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

我希望这对你有帮助

我在这里完成了当前的回答,但没有给出每个箭头尖端的正确大小。MATLAB的做法是,当箭头接近一个点时,它没有任何尖端,而对于长箭头,它显示一个大尖端,如下图所示

为了获得这种效果,我们需要在箭头长度范围内对每个箭头的“尖端大小”进行归一化。下面的代码实现了这一点

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

        }
   }
}
double l_max=-10;
对于(int y=0;yl_max)l_max=l;
}
}
对于(int y=0;y0)
{
double spinSize=5.0*l/l_max;//根据箭头的长度使旋转大小正常化的因子
CvPoint p2=CvPoint(p.x+(int)(dx),p.y+(int)(dy));
cvLine(结果光流,p,p2,CV_RGB(0255,0),1,CV_AA);
双角度;//绘制箭头的旋转
角度=atan2((双)p.y-p2.y,(双)p.x-p2.x);
p、 x=(int)(p2.x+spinSize*cos(角度+3.1416/4));
p、 y=(int)(p2.y+spinSize*sin(角度+3.1416/4));
cvLine(结果光流,p,p2,CV_RGB(0255,0),1,CV_AA,0);
p、 x=(int)(p2.x+spinSize*cos(角度-3.1416/4));
p、 y=(int)(p2.y+spinSize*sin(角度-3.1416/4));
cvLine(结果光流,p,p2,CV_RGB(0255,0),1,CV_AA,0);
}
}
}
这是一个OpenCV代码的示例


我希望这能帮助其他人搜索相同的问题。

基于Dan的代码和mkuse的建议,这里有一个与cv::line()语法相同的函数:


我们将看看那些维护OpenCV存储库的人是否会喜欢它:-)

谢谢,我尝试了一系列不同的方法,用一个图像创建箭头,现在它成功了。绘制没有符号(方向/箭头尖)的向量是一种糟糕的做法。我推荐下面的答案。@wolvorinePk我很高兴它帮助了某人@丹:我可以建议您编辑代码,并将其放入“arrowedLine()”之类的函数中吗。它的语法与cv::line()类似?下一个OpenCV版本将提供
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);
}