OpenCV實(shí)現(xiàn)繞圖片中任意角度旋轉(zhuǎn)任意角度
最近在做項(xiàng)目需要把把圖片繞圖片中任意點(diǎn)旋轉(zhuǎn)任意角度,考慮到自己旋轉(zhuǎn)需要編寫(xiě)插值算法,所以想到了用opencv,但是網(wǎng)上都是圍繞圖片中點(diǎn)旋轉(zhuǎn)任意角度的,都是向下面這樣寫(xiě)的:
繞圖片中心旋轉(zhuǎn)圖片不裁剪
#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;旋轉(zhuǎn)之后的效果:

但是遇到繞任意點(diǎn)旋轉(zhuǎn)時(shí),會(huì)產(chǎn)生問(wèn)題,用這種方式還是會(huì)存在裁剪,如果要理解繞任意點(diǎn)旋轉(zhuǎn),需要先理解函數(shù)getRotationMatrix2D,這個(gè)函數(shù)處理過(guò)程如下面矩陣表示所示:

具體實(shí)現(xiàn)代碼如下:
Mat src = imread("/home/sss/1111.jpg", IMREAD_GRAYSCALE);
Mat des, m;
//旋轉(zhuǎn)的任意角度
double angle = 45;
int w = src.cols, h = src.rows;
Point2f rorate_center;
//旋轉(zhuǎn)的任意中心
rorate_center.x = w;
rorate_center.y = h;
//重新計(jì)算旋轉(zhuǎn)后的寬和高
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);
//通過(guò)eigen計(jì)算旋轉(zhuǎn)矩陣
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;
//計(jì)算原來(lái)矩陣的四個(gè)頂點(diǎn)經(jīng)過(guò)變換后的頂點(diǎn)
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;
//找到經(jīng)過(guò)變換過(guò)定位的最大最小值
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;
//變換,最后不會(huì)存在裁剪
warpAffine(src, des , m , Size2i(bound_w , bound_h),
INTER_LINEAR, 0, Scalar(100, 100, 100));
imwrite("/home/sss/222.jpg", des);
return 0;經(jīng)過(guò)變換過(guò)的圖片不會(huì)存在裁剪:

到此這篇關(guān)于OpenCV實(shí)現(xiàn)繞圖片中任意角度旋轉(zhuǎn)任意角度的文章就介紹到這了,更多相關(guān)OpenCV圖片旋轉(zhuǎn)內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
C++實(shí)現(xiàn)特殊矩陣的壓縮存儲(chǔ)算法
在實(shí)際存儲(chǔ)時(shí),會(huì)發(fā)現(xiàn)矩陣中有許多值相同的數(shù)據(jù)或有許多零數(shù)據(jù),且分布呈現(xiàn)出一定的規(guī)律,稱這類型的矩陣為特殊矩陣。本文將利用C++實(shí)現(xiàn)特殊矩陣的壓縮存儲(chǔ),感興趣的可以了解一下2022-08-08
如何基于 Blueprint 在游戲中創(chuàng)建實(shí)時(shí)音視頻功能
我們?cè)诒疚南葋?lái)講講如何在 Unreal 中用 Blueprint 快速實(shí)現(xiàn)。稍后會(huì)分享基于 C++的實(shí)現(xiàn)步驟。感興趣的朋友跟隨小編一起看看吧2020-05-05
vscode工程中c_cpp_properties.json文件作用詳細(xì)說(shuō)明
c_cpp_properties.json是Visual Studio Code的一個(gè)配置文件,用于定義C/C++編譯器的路徑、默認(rèn)包含路徑和預(yù)處理器定義,這篇文章主要給大家介紹了關(guān)于vscode工程中c_cpp_properties.json文件作用詳細(xì)說(shuō)明的相關(guān)資料,需要的朋友可以參考下2024-08-08
C++使用遞歸和非遞歸算法實(shí)現(xiàn)的二叉樹(shù)葉子節(jié)點(diǎn)個(gè)數(shù)計(jì)算方法
這篇文章主要介紹了C++使用遞歸和非遞歸算法實(shí)現(xiàn)的二叉樹(shù)葉子節(jié)點(diǎn)個(gè)數(shù)計(jì)算方法,涉及C++二叉樹(shù)的定義、遍歷、統(tǒng)計(jì)相關(guān)操作技巧,需要的朋友可以參考下2017-05-05
C++函數(shù)指針與指針函數(shù)有哪些關(guān)系和區(qū)別
函數(shù)指針是一個(gè)指針變量,它可以存儲(chǔ)函數(shù)的地址,然后使用函數(shù)指針,這篇文章主要介紹了C++中函數(shù)指針與指針函數(shù)有哪些關(guān)系和區(qū)別,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值2022-08-08

