zoukankan      html  css  js  c++  java
  • 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时:

     

    旋转之后的神仙姐姐就框的比较准确了。这样就能正确的框住小姐姐了。

     

    四、总结

    数学还是很有用的。人工智能、深度学习还是需要具备数学知识的。

  • 相关阅读:
    高格-远程支持中的奇怪问题【15】
    关于er图的几个工具
    如何解决win10明明是管理员还要权限的问题
    判断日期天数
    谈一谈在公司两次压测我总结的思路
    vue学习之-----v-model数据双向绑定,自定义组件父子传参
    Js各种小技巧总结
    openlayers学习之-----核心类
    openlayers学习之-----把坐标点改为WKT格式的数据
    新书介绍 -- 《Redis核心原理与实践》
  • 原文地址:https://www.cnblogs.com/xcywt/p/9456526.html
Copyright © 2011-2022 走看看