OpenCV Как использовать векторы скорости в виде стрелок при использовании одного статического изображения

17

Я пытаюсь построить векторы скорости, как в Matlab, мы используем функцию «колчана» Ссылка

Мне нужно перенести ту же методологию на C ++, используя библиотеку OpenCV.

Я слышал. Существует несколько методов оптического потока, то есть 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
    }

}
    
задан wolvorinePk 15.04.2012 в 12:52
источник

3 ответа

29

Я как бы завершаю текущий ответ здесь, который не дает правильного размера каждого из подсказок стрелок. 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 );

        }
   }
}

И это пример того, как этот код OpenCV будет выглядеть как

Надеюсь, что эта помощь поможет другим людям Googling по той же проблеме.

    
ответ дан Dan 06.06.2012 в 21:26
источник
  • спасибо, что он полезен –  wolvorinePk 27.06.2012 в 09:40
  • @wolvorinePk Я рад, что это помогло кому-то! –  Dan 27.06.2012 в 10:30
  • @ Dan: Могу ли я предложить вам отредактировать код и использовать его в функции типа «arrowedLine ()». У кого есть аналогичный синтаксис cv :: line ()? –  mkuse 27.03.2014 в 16:26
9

На основе кода от Dan и предложения mkuse, вот функция с тем же синтаксисом, что и 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);
    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: -)

    
ответ дан PhilLab 28.06.2014 в 14:05
источник
  • Следующая версия OpenCV будет иметь cv :: arrowedLine –  PhilLab 24.07.2014 в 09:58
4

cvCalOpticalFlowLK не отображает векторы скорости, он вычисляет эти векторы скорости. Если у вас нет этих векторов, вы должны вызвать эту функцию двумя изображениями. Я думаю, у вас уже есть эти векторы, и вы просто хотите их застроить.

В этом случае вы можете использовать функцию cv :: line , для пример:

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

Надеюсь, это поможет!     

ответ дан Samuel Gosselin 15.04.2012 в 18:00
источник
  • спасибо, я попробовал линию с пучком разных способов создания стрелки с использованием одного единственного изображения, и теперь он работает. –  wolvorinePk 17.04.2012 в 07:44
  • ради другой помощи, я добавил код выше –  wolvorinePk 17.04.2012 в 07:47
  • Нанесение векторов без знака (направление / стрелка) - это плохая практика. Я рекомендую ответить ниже. –  TimZaman 24.02.2014 в 10:38