OpenCV实现绕图片中任意角度旋转任意角度

 更新时间:2022年09月29日 08:30:38   作者:万丈高楼平地起  
这篇文章主要为大家详细介绍了在图片不被裁剪时,opencv如何实现绕图片中任意点旋转任意角度,文中的示例代码讲解详细,需要的可以参考一下

最近在做项目需要把把图片绕图片中任意点旋转任意角度,考虑到自己旋转需要编写插值算法,所以想到了用opencv,但是网上都是围绕图片中点旋转任意角度的,都是向下面这样写的:

绕图片中心旋转图片不裁剪

#include"opencv.hpp"
#include<iostream>
using namespace std;
using namespace cv;
int main() {
	Mat src = imread("timg.jpg");
	Mat des,m;
	Point2f center = Point(src.cols / 2, src.rows / 2);
	double angle = 50,scale=0.5;
	int w = src.cols, h = src.rows;
	int bound_w = (h * fabs(sin(angle * CV_PI / 180)) + w * fabs(cos(angle * CV_PI / 180))) * scale;
	int bound_h = (h * fabs(cos(angle * CV_PI / 180)) + w * fabs(sin(angle * CV_PI / 180))) * scale;
	m = getRotationMatrix2D(center, angle, scale);
	m.at<double>(0, 2) += (bound_w - src.cols) / 2;
	m.at<double>(1, 2) += (bound_h - src.rows) / 2;
	
	warpAffine(src,des,m,Size2i(bound_h,bound_w));
	imshow("image",des);
	waitKey();
	return 0;

旋转之后的效果: 

但是遇到绕任意点旋转时,会产生问题,用这种方式还是会存在裁剪,如果要理解绕任意点旋转,需要先理解函数getRotationMatrix2D,这个函数处理过程如下面矩阵表示所示:

具体实现代码如下:

    Mat src = imread("/home/sss/1111.jpg", IMREAD_GRAYSCALE);
    Mat des, m;
//旋转的任意角度
    double angle = 45;
    int w = src.cols, h = src.rows;
    Point2f rorate_center;
//旋转的任意中心
    rorate_center.x = w;
    rorate_center.y = h;
//重新计算旋转后的宽和高
    int bound_w = ceil(h * fabs(sin(angle * CV_PI / 180.0)) + w * fabs(cos(angle * CV_PI / 180.0)));
    int bound_h = ceil(h * fabs(cos(angle * CV_PI / 180.0)) + w * fabs(sin(angle * CV_PI / 180.0)));
    m = getRotationMatrix2D(rorate_center, angle, 1.0);

//通过eigen计算旋转矩阵
    Eigen::Matrix3d T1;
    T1 << 1, 0, -rorate_center.x,
            0, 1, -rorate_center.y,
            0, 0, 1;
    Eigen::Matrix3d T2;
    T2 <<   1, 0, rorate_center.x,
            0, 1, rorate_center.y,
            0, 0, 1;
    Eigen::Matrix3d rorate;
    rorate << cos(angle * CV_PI / 180.0), sin(angle * CV_PI / 180.0), 0,
            -sin(angle * CV_PI / 180.0), cos(angle * CV_PI / 180.0), 0,
            0, 0, 1;
    Eigen::Matrix3d T = T2 * rorate * T1;
//计算原来矩阵的四个顶点经过变换后的顶点
    Eigen::Matrix<double,3, 1> left_top_p, right_top_p, right_bottom_p, left_botoom_p;
    left_top_p << 0, 0, 1;
    right_top_p << w, 0, 1;
    right_bottom_p << w, h, 1;
    left_botoom_p << 0, h , 1;
    left_top_p = T * left_top_p;
    right_top_p = T * right_top_p;
    right_bottom_p = T * right_bottom_p;
    left_botoom_p = T * left_botoom_p;

//找到经过变换过定位的最大最小值
    double min_x = 10000, min_y = 10000;
    //min_x
    if(left_top_p[0] < min_x){
        min_x = left_top_p[0];
    }
    if(right_top_p[0] < min_x){
        min_x = right_top_p[0];
    }
    if(right_bottom_p[0] < min_x)
    {
        min_x = right_bottom_p[0];
    }
    if(left_botoom_p[0] < min_x){
        min_x = left_botoom_p[0];
    }

    //min_y
    if(left_top_p[1] < min_y){
        min_y = left_top_p[1];
    }
    if(right_top_p[1] < min_y){
        min_y = right_top_p[1];
    }
    if(right_bottom_p[1] < min_y)
    {
        min_y = right_bottom_p[1];
    }
    if(left_botoom_p[1] < min_y){
        min_y = left_botoom_p[1];
    }

    double max_x = -1000, max_y = -1000;
    //max_x
    if(left_top_p[0] > max_x){
        max_x = left_top_p[0];
    }
    if(right_top_p[0] > max_x){
        max_x = right_top_p[0];
    }
    if(right_bottom_p[0] > max_x)
    {
        max_x = right_bottom_p[0];
    }
    if(left_botoom_p[0] > max_x){
        max_x = left_botoom_p[0];
    }

    //max_y
    if(left_top_p[1] > max_y){
        max_y = left_top_p[1];
    }
    if(right_top_p[1] > max_y){
        max_y = right_top_p[1];
    }
    if(right_bottom_p[1] > max_y)
    {
        max_y = right_bottom_p[1];
    }
    if(left_botoom_p[1] > max_y){
        max_y = left_botoom_p[1];
    }

    //将偏置添加到矩阵中
    m.at<double>(0, 2) += -min_x;
    m.at<double>(1, 2) += -min_y;

//变换,最后不会存在裁剪
    warpAffine(src, des , m , Size2i(bound_w , bound_h),
               INTER_LINEAR, 0, Scalar(100, 100, 100));
    imwrite("/home/sss/222.jpg", des);
    return 0;

经过变换过的图片不会存在裁剪:

到此这篇关于OpenCV实现绕图片中任意角度旋转任意角度的文章就介绍到这了,更多相关OpenCV图片旋转内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家!

相关文章

  • C++实现特殊矩阵的压缩存储算法

    C++实现特殊矩阵的压缩存储算法

    在实际存储时,会发现矩阵中有许多值相同的数据或有许多零数据,且分布呈现出一定的规律,称这类型的矩阵为特殊矩阵。本文将利用C++实现特殊矩阵的压缩存储,感兴趣的可以了解一下
    2022-08-08
  • c++ 实现文件逐行读取与字符匹配

    c++ 实现文件逐行读取与字符匹配

    这里尝试通过C++来实现一个文件IO的功能,看看是否能够比python的表现更好一些,感兴趣的朋友可以参考下
    2021-05-05
  • 利用Matlab制作一款狗头翻牌子小游戏

    利用Matlab制作一款狗头翻牌子小游戏

    本文将用Matlab制作一个狗头翻牌子的小游戏,就是点击一个牌子时,该牌子和周围四个牌子也会相应发生变化,想办法让所有牌子都在同一面即为游戏胜利。感兴趣的可以跟随小编学习一下
    2022-03-03
  • 使用C语言打印月历

    使用C语言打印月历

    这篇文章主要为大家详细介绍了使用C语言打印月历,文中示例代码介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们可以参考一下
    2021-06-06
  • 如何基于 Blueprint 在游戏中创建实时音视频功能

    如何基于 Blueprint 在游戏中创建实时音视频功能

    我们在本文先来讲讲如何在 Unreal 中用 Blueprint 快速实现。稍后会分享基于 C++的实现步骤。感兴趣的朋友跟随小编一起看看吧
    2020-05-05
  • Qt实现Flappy Bird游戏

    Qt实现Flappy Bird游戏

    这篇文章主要为大家详细介绍了Qt实现Flappy Bird游戏,具有一定的参考价值,感兴趣的小伙伴们可以参考一下
    2018-12-12
  • vscode工程中c_cpp_properties.json文件作用详细说明

    vscode工程中c_cpp_properties.json文件作用详细说明

    c_cpp_properties.json是Visual Studio Code的一个配置文件,用于定义C/C++编译器的路径、默认包含路径和预处理器定义,这篇文章主要给大家介绍了关于vscode工程中c_cpp_properties.json文件作用详细说明的相关资料,需要的朋友可以参考下
    2024-08-08
  • C++使用递归和非递归算法实现的二叉树叶子节点个数计算方法

    C++使用递归和非递归算法实现的二叉树叶子节点个数计算方法

    这篇文章主要介绍了C++使用递归和非递归算法实现的二叉树叶子节点个数计算方法,涉及C++二叉树的定义、遍历、统计相关操作技巧,需要的朋友可以参考下
    2017-05-05
  • 深入ORACLE变量的定义与使用的详解

    深入ORACLE变量的定义与使用的详解

    本篇文章是对ORACLE变量的定义与使用进行了详细的分析与介绍,需要的朋友参考下
    2013-05-05
  • C++函数指针与指针函数有哪些关系和区别

    C++函数指针与指针函数有哪些关系和区别

    函数指针是一个指针变量,它可以存储函数的地址,然后使用函数指针,这篇文章主要介绍了C++中函数指针与指针函数有哪些关系和区别,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值
    2022-08-08

最新评论