opencv實現坐標旋轉(教你框住小姐姐)


 一、項目背景

最近在做一個人臉檢測項目,需要接入百度AI的系統進行識別和檢測。主要流程就是往指定的URLpost圖片上去,之后接收檢測結果就好了。

百度的檢測結果包含這樣的信息:

  left - 人臉區域離左邊界的距離

  top - 人臉區域離上邊界的距離

  width - 人臉區域的寬度

  height - 人臉區域的高度

  ratation 人臉框相對於豎直方向的順時針旋轉角[-180, 180].

 如果我想把人臉框出來,很容易想到的是以(left, top)為左上頂點,以width 為寬,height為高,畫一個矩形就好了。但其實這樣是不合理的,如果人頭是倒着的,這樣畫出來是不合理的。就像下面這樣:

 

所以必須考慮把旋轉角加上去。於是我想的策略是先把框畫出來,再逆時針旋轉ratation 就可以了。

 

二、如何旋轉

大致策略就是:先算出四個點的左標,再以左上角的點為原點,逆時針旋轉ratation ok了。四個點的左標比較容易確定,利用起點左標加寬高就能算出來。

這里主要講解如何算旋轉后的左標,如下圖:

 

 

已知x1x2y1y2和∠a,求x,和y’。這時候就需要用到高中的三角函數的知識了。

假設,(x1, y1) (x2, y2)的長度為r,再畫一個∠b

x’ = x1 + r * cos(a + b);

x’ = x1 + r * cos(a) * cos(b) - r * sin(a) * sin(b);

又因為:

r * cos(b) = x2 - x1;

r * sin(b) = (y2 - y1);

最終可以求出:

x’ = x1 + cos(a) * (x2 - x1) - sin(a) * (y2 - y1);

同理求出:

y’ = y1 + sin(a) * (x2 - x1) - cos(a) * (y2 - y1);

啊,這真是用了我畢生所學的數學知識,真沒想到工作后還會用到三角函數的知識。還是要多學點數學知識才好啊。

 

三、源碼

下面就是真正畫圖的東西了,為了測試這個公式是否可行,我用opencv畫了一個四根線(其實就是一個方形),然后以左上角為頂點旋轉。

下面的具體的代碼,比較簡單,主要是那個公式,所以也沒什么注釋。需要包含opencv頭文件,以及鏈接opencv的庫。

/*
 * @author:xcywt
 * @date:2018-08-10
 * @contact me: https://www.cnblogs.com/xcywt/
 */
#include<iostream>
#include "opencv2/highgui/highgui.hpp"

using namespace cv;
#define PI 3.14159265

#define ROTATE_COUNT 180
int RotateTest2()
{
    if (ROTATE_COUNT > 360)
    {
        return -1;
    }
    int x1 = 200, y1 = 200;
    int x2 = 300, y2 = 200;
    int x3 = 300, y3 = 300;
    int x4 = 200, y4 = 300;

    int arrX1[ROTATE_COUNT], arrY1[ROTATE_COUNT];
    int arrX2[ROTATE_COUNT], arrY2[ROTATE_COUNT];
    int arrX3[ROTATE_COUNT], arrY3[ROTATE_COUNT];
    int arrX4[ROTATE_COUNT], arrY4[ROTATE_COUNT];

    int nAgree = 0;
    for (int i = 0; i < ROTATE_COUNT; i++)
    {
        nAgree = i * (360 / ROTATE_COUNT);
        double dRot = nAgree * PI / 180;
        double dSinRot = sin(dRot), dCosRot = cos(dRot);

        arrX1[i] = x1;
        arrY1[i] = y1;

        arrX2[i] = x1 + dCosRot * (x2 - x1) - dSinRot * (y2 - y1); 
        arrY2[i] = y1 + dSinRot * (x2 - x1) + dCosRot * (y2 - y1);

        arrX3[i] = x1 + dCosRot * (x3 - x1) - dSinRot * (y3 - y1); 
        arrY3[i] = y1 + dSinRot * (x3 - x1) + dCosRot * (y3 - y1);

        arrX4[i] = x1 + dCosRot * (x4 - x1) - dSinRot * (y4 - y1); 
        arrY4[i] = y1 + dSinRot * (x4 - x1) + dCosRot * (y4 - y1);
    }

    Mat im(800, 480, CV_8UC3);
    line(im, Point(x1, y1), Point(x2, y2), Scalar(89, 90, 90), 3);
    line(im, Point(x1, y1), Point(x4, y4), Scalar(89, 90, 90), 3);
    line(im, Point(x3, y3), Point(x2, y2), Scalar(89, 90, 90), 3);
    line(im, Point(x4, y4), Point(x3, y3), Scalar(89, 90, 90), 3);

    for (int i = 1; i < ROTATE_COUNT; i++)
    {
        line(im, Point(arrX1[i], arrY1[i]), Point(arrX2[i], arrY2[i]), Scalar(189, 255, 0), 1);
        line(im, Point(arrX1[i], arrY1[i]), Point(arrX4[i], arrY4[i]), Scalar(189, 255, 0), 1);
        line(im, Point(arrX3[i], arrY3[i]), Point(arrX2[i], arrY2[i]), Scalar(189, 255, 0), 1);
        line(im, Point(arrX4[i], arrY4[i]), Point(arrX3[i], arrY3[i]), Scalar(189, 255, 0), 1);
    }
    imshow("Is ok", im);
    cvWaitKey(0);

    return 0;
}

int RotateTest()
{
    int nAgree = 170; 
    double dRot = nAgree * PI / 180;
    double dSinRot = sin(dRot), dCosRot = cos(dRot);

    int x1 = 200, y1 = 200;
    int x2 = 300, y2 = 200;
    int x3 = 300, y3 = 300;
    int x4 = 200, y4 = 300;

    int x1_1 = x1, y1_1 = y1;
    int x2_1 = x1 + dCosRot * (x2 - x1) - dSinRot * (y2 - y1), y2_1 = y1 + dSinRot * (x2 - x1) + dCosRot * (y2 - y1);
    int x3_1 = x1 + dCosRot * (x3 - x1) - dSinRot * (y3 - y1), y3_1 = y1 + dSinRot * (x3 - x1) + dCosRot * (y3 - y1);
    int x4_1 = x1 + dCosRot * (x4 - x1) - dSinRot * (y4 - y1), y4_1 = y1 + dSinRot * (x4 - x1) + dCosRot * (y4 - y1);

    std::cout << "P1:(" << x1 << " , " << y1 << ") --> (" << x1_1 << ", " << y1_1 << ")" << std::endl;
    std::cout << "P2:(" << x2 << " , " << y2 << ") --> (" << x2_1 << ", " << y2_1 << ")" << std::endl;
    std::cout << "P3:(" << x3 << " , " << y3 << ") --> (" << x3_1 << ", " << y3_1 << ")" << std::endl;
    std::cout << "P4:(" << x4 << " , " << y4 << ") --> (" << x4_1 << ", " << y4_1 << ")" << std::endl;

    Mat im(800, 480, CV_8UC3);
    line(im, Point(x1, y1), Point(x2, y2), Scalar(89, 90, 90), 2);
    line(im, Point(x1, y1), Point(x4, y4), Scalar(89, 90, 90), 2);
    line(im, Point(x3, y3), Point(x2, y2), Scalar(89, 90, 90), 2);
    line(im, Point(x4, y4), Point(x3, y3), Scalar(89, 90, 90), 2);

    line(im, Point(x1_1, y1_1), Point(x2_1, y2_1), Scalar(189, 0, 0), 2);
    line(im, Point(x1_1, y1_1), Point(x4_1, y4_1), Scalar(189, 0, 0), 2);
    line(im, Point(x3_1, y3_1), Point(x2_1, y2_1), Scalar(189, 0, 0), 2);
    line(im, Point(x4_1, y4_1), Point(x3_1, y3_1), Scalar(189, 0, 0), 2);

    imshow("Is ok", im);
    cvWaitKey(0);
    return 0;

}

int main()
{
    //RotateTest();
    RotateTest2();
    return 0;
}

其中RotateTest2()實現了在一個Mat上,畫出了旋轉各個角度的樣子,具體把360分成 ROTATE_COUNT這么多份。可以看到效果還是很好看的。

ROTATE_COUNT10時:

 

ROTATE_COUNT60時:

 

ROTATE_COUNT180時:

 

ROTATE_COUNT360時:

 

旋轉之后的神仙姐姐就框的比較准確了。這樣就能正確的框住小姐姐了。

 

 

四、總結

數學還是很有用的。人工智能、深度學習還是需要具備數學知識的。

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM