目标检测

opencv C++ 图片旋转任意角度

2021-07-28  本文已影响0人  1037号森林里一段干木头

摘要:opencv里面似乎没有直接的旋转图片的接口,这里实现一个旋转任意角度的方法,在旋转的时候调用opencv里面的仿射变换函数实现。有两种旋转模式:一种按图片中心旋转,尺寸与原图一致;另外一种模式是扩充图片尺寸以包含所有像素点。
@[toc]

1. 示例:

aa.gif

2. 原理

旋转平移的坐标变换

设有任意一点p,在平面直角坐标中其坐标为(x,y), 在平面极坐标系中其坐标为(\rho,\theta),则根据坐标系转换公式有
\begin{cases} x = \rho * cos\theta\\ y = \rho * sin\theta \end{cases}
在这里x,y \in [-\infty,\infty], \rho \in[0,\infty], \theta \in [0,2\pi). 假设对p点对应的极径\overline{op} 逆时针旋转\alpha弧度得到\overline{op'},则p'点的坐标为
\begin{cases} x' &= \rho * cos(\theta + \alpha)\\ &=\rho * cos\theta *cos\alpha - \rho*sin\theta*\sin\alpha\\ &= x*cos\alpha - y*sin\alpha\\ \\ y' &= \rho * sin(\theta + \alpha)\\ &=\rho * sin\theta *cos\alpha + \rho*cos\theta*\sin\alpha\\ &= y*cos\alpha + x*sin\alpha\\ \end{cases}
再在直角坐标系中按向量(Tx,Ty)平移p'p'',则p''的坐标为
\begin{cases} x''&=x'+Tx\\ &=x*cos\alpha - y*sin\alpha+Tx \\\\ y''&=y'+Ty\\ &=y*cos\alpha + x*sin\alpha+Ty \end{cases}
转为矩阵形式为
\begin{bmatrix} x'' \\ y'' \end{bmatrix} = \begin{bmatrix} \cos\alpha & -sin\alpha &Tx\\ sin\alpha &\cos\alpha &Ty \end{bmatrix} \cdot \begin{bmatrix} x \\ y \\ 1 \end{bmatrix}
也就是说只要知道仿射变换矩阵,那么每一个像素点(x,y)都可以用上面的公式直接计算了。

3. 两种方式

4. 源码

#include <iostream>
#include<algorithm>
#include "opencv.hpp"

int rotateImage(const cv::Mat &src, cv::Mat &dst, const double angle, const int mode)
{
    //mode = 0 ,Keep the original image size unchanged
    //mode = 1, Change the original image size to fit the rotated scale, padding with zero

    if (src.empty())
    {
        std::cout << "Damn, the input image is empty!\n";
        return -1;
    }

    if (mode == 0)
    {
        cv::Point2f center((src.cols - 1) / 2.0, (src.rows - 1) / 2.0);
        cv::Mat rot = cv::getRotationMatrix2D(center, angle, 1.0);
        cv::warpAffine(src, dst, rot, src.size());//the original size
    }
    else {

        double alpha = -angle * CV_PI / 180.0;//convert angle to radian format 

        cv::Point2f srcP[3];
        cv::Point2f dstP[3];
        srcP[0] = cv::Point2f(0, src.rows);
        srcP[1] = cv::Point2f(src.cols, 0);
        srcP[2] = cv::Point2f(src.cols, src.rows);
        
        //rotate the pixels
        for (int i=0;i<3;i++)
                    dstP[i] = cv::Point2f(srcP[i].x*cos(alpha) - srcP[i].y*sin(alpha), srcP[i].y*cos(alpha) + srcP[i].x*sin(alpha));
        double minx, miny, maxx, maxy;
        minx = std::min(std::min(std::min(dstP[0].x, dstP[1].x), dstP[2].x),float(0.0));
        miny  = std::min(std::min(std::min(dstP[0].y, dstP[1].y), dstP[2].y),float(0.0));
        maxx = std::max(std::max(std::max(dstP[0].x, dstP[1].x), dstP[2].x),float(0.0));
        maxy = std::max(std::max(std::max(dstP[0].y, dstP[1].y), dstP[2].y),float(0.0));

        int w = maxx - minx;
        int h = maxy - miny;

        //translation
        for (int i = 0; i < 3; i++)
        {
            if (minx < 0)
                dstP[i].x -= minx;
            if (miny < 0)
                dstP[i].y -= miny;
        }

        cv::Mat warpMat = cv::getAffineTransform(srcP, dstP);
        cv::warpAffine(src, dst, warpMat, cv::Size(w, h));//extend size

    }//end else

    return 0;
}

int rotateImage2(const cv::Mat &src, cv::Mat &dst, const double angle, const int mode)
{
    //mode = 0 ,Keep the original image size unchanged
    //mode = 1, Change the original image size to fit the rotated scale, padding with zero

    if (src.empty())
    {
        std::cout << "Damn, the input image is empty!\n";
        return -1;
    }

    if (mode == 0)
    {
        cv::Point2f center((src.cols - 1) / 2.0, (src.rows - 1) / 2.0);
        cv::Mat rot = cv::getRotationMatrix2D(center, angle, 1.0);
        cv::warpAffine(src, dst, rot, src.size());//the original size
    }
    else {

        double alpha = -angle * CV_PI / 180.0;//convert angle to radian format 

        cv::Point2f srcP[3];
        cv::Point2f dstP[3];
        srcP[0] = cv::Point2f(0, src.rows);
        srcP[1] = cv::Point2f(src.cols, 0);
        srcP[2] = cv::Point2f(src.cols, src.rows);

        //rotate the pixels
        for (int i = 0; i < 3; i++)
            dstP[i] = cv::Point2f(srcP[i].x*cos(alpha) - srcP[i].y*sin(alpha), srcP[i].y*cos(alpha) + srcP[i].x*sin(alpha));
        double minx, miny, maxx, maxy;
        minx = std::min(std::min(std::min(dstP[0].x, dstP[1].x), dstP[2].x), float(0.0));
        miny = std::min(std::min(std::min(dstP[0].y, dstP[1].y), dstP[2].y), float(0.0));
        maxx = std::max(std::max(std::max(dstP[0].x, dstP[1].x), dstP[2].x), float(0.0));
        maxy = std::max(std::max(std::max(dstP[0].y, dstP[1].y), dstP[2].y), float(0.0));

        int w = maxx - minx;
        int h = maxy - miny;

        cv::Mat warpMat =cv::Mat::zeros(cv::Size(3,2),CV_64F);//rows=2,cols=3
        
        std::cout << warpMat.type() << std::endl;
        std::cout << warpMat.size()<<std::endl;
        warpMat.at<double>(0, 0) = cos(alpha);
        warpMat.at<double>(0, 1) = 0- sin(alpha);
        warpMat.at<double>(1, 0) = sin(alpha);
        warpMat.at<double>(1, 1) = cos(alpha);
        warpMat.at<double>(0, 2) =0- minx;
        warpMat.at<double>(1, 2) =0-miny;
        //std::cout << warpMat;
        cv::warpAffine(src, dst, warpMat, cv::Size(w, h));//extend size

    }//end else

    return 0;
}

int main()
{
    std::cout << "Hello World!\n";
    std::string filePath = "K:\\imageData\\lena\\images.png";
    cv::Mat src = cv::imread(filePath);
    cv::Mat dst1,dst2;
    for (double i = -360; i <= 360; i++)
    {
        int flg1 = rotateImage(src, dst1, i, 0);
        int flg2 = rotateImage(src, dst2, i, 1);
        if (flg1 == -1 || flg2 == -1) continue;
        cv::imshow("src", src);
        cv::imshow("dst1", dst1);
        cv::imshow("dst2", dst2);
        cv::waitKey(5);
    }
    cv::waitKey(0);
    cv::destroyAllWindows();

}
上一篇 下一篇

猜你喜欢

热点阅读