opencv圖片的任意角度旋轉(zhuǎn)實(shí)現(xiàn)示例
一 旋轉(zhuǎn)角度坐標(biāo)的計(jì)算
1.如果O點(diǎn)為圓心,則點(diǎn)P繞點(diǎn)O旋轉(zhuǎn)redian弧度之后,點(diǎn)P的坐標(biāo)變換為點(diǎn)Q的計(jì)算公式為:
Q.x=P.x*cos(redian)-P.y*sin(redian)
Q.y=P.x*sin(redian)+P.y*cos(redian)
redian表示的為弧度
弧度與角度的變換公式為:
redian=pi*180/angle
2. 如果O點(diǎn)不是圓心,則點(diǎn)P繞點(diǎn)O旋轉(zhuǎn)redian弧度之后,點(diǎn)P的坐標(biāo)變換為Q的計(jì)算公式如下:
Q.x=(P.x-O.x)*cos(redian)-(P.y-O.y)*sin(redian)+O.x
Q.y=(P.x-O.x)*sin(redian)+(P.y-O.y)*cos(redian)+O.y
二 旋轉(zhuǎn)任意角度的步驟
1.首先默認(rèn)旋轉(zhuǎn)45度時(shí),所擴(kuò)展的圖像最大,即為根號(hào)2倍的長(zhǎng)或?qū)挼淖畲笾?將圖像填充到可能達(dá)到的最大
2 使用getRotationMatrix2D函數(shù)求取旋轉(zhuǎn)矩陣,使用warpAffine函數(shù)旋轉(zhuǎn)矩陣
3 求旋轉(zhuǎn)之后包括圖像的最大的矩形
4 刪除多余的黑色邊框
三 實(shí)現(xiàn)
#include <iostream> #include<opencv2/opencv.hpp> using namespace cv; void rotate_arbitrarily_angle(Mat &src,Mat &dst,float angle) { float radian = (float) (angle /180.0 * CV_PI); //填充圖像 int maxBorder =(int) (max(src.cols, src.rows)* 1.414 ); //即為sqrt(2)*max int dx = (maxBorder - src.cols)/2; int dy = (maxBorder - src.rows)/2; copyMakeBorder(src, dst, dy, dy, dx, dx, BORDER_CONSTANT); //旋轉(zhuǎn) Point2f center( (float)(dst.cols/2) , (float) (dst.rows/2)); Mat affine_matrix = getRotationMatrix2D( center, angle, 1.0 );//求得旋轉(zhuǎn)矩陣 warpAffine(dst, dst, affine_matrix, dst.size()); //計(jì)算圖像旋轉(zhuǎn)之后包含圖像的最大的矩形 float sinVal = abs(sin(radian)); float cosVal = abs(cos(radian)); Size targetSize( (int)(src.cols * cosVal +src.rows * sinVal), (int)(src.cols * sinVal + src.rows * cosVal) ); //剪掉多余邊框 int x = (dst.cols - targetSize.width) / 2; int y = (dst.rows - targetSize.height) / 2; Rect rect(x, y, targetSize.width, targetSize.height); dst = Mat(dst,rect); } int main() { cv::Mat src=cv::imread("../3.png"); cv::Mat dst; rotate_arbitrarily_angle(src,dst,30); cv::imshow("src",src); cv::imshow("dst",dst); cv::waitKey(0); return 0; }
原圖
繞中心點(diǎn)旋轉(zhuǎn)30度的結(jié)果
需要注意的是該方法僅適用于水平圖像旋轉(zhuǎn)到有角度的圖像,至于可以隨意旋轉(zhuǎn)角度的方法我現(xiàn)在還不知道如何完成,以后有機(jī)會(huì)再做.
以上做法還有個(gè)最大的缺點(diǎn)是在旋轉(zhuǎn)之后像素大小發(fā)生了變化,如果你要對(duì)像素操作就會(huì)產(chǎn)生很多問(wèn)題,接下來(lái)的代碼會(huì)將像素固定下來(lái),不過(guò)也是針對(duì)旋轉(zhuǎn)到一定角度之后再返回到水平位置的代碼,具有很大的局限性,研究明白之后再更新其他情況
cv::Mat rotate_arbitrarily_angle1(cv::Mat matSrc, float angle, bool direction,int height,int width) { float theta = angle * CV_PI / 180.0; int nRowsSrc = matSrc.rows; int nColsSrc = matSrc.cols; // 如果是順時(shí)針旋轉(zhuǎn) if (!direction) theta = 2 * CV_PI - theta; // 全部以逆時(shí)針旋轉(zhuǎn)來(lái)計(jì)算 // 逆時(shí)針旋轉(zhuǎn)矩陣 float matRotate[3][3]{ { std::cos(theta), -std::sin(theta), 0}, {std::sin(theta), std::cos(theta), 0 }, {0, 0, 1} }; float pt[3][2]{ { 0, nRowsSrc }, {nColsSrc, nRowsSrc}, {nColsSrc, 0} }; for (int i = 0; i < 3; i++) { float x = pt[i][0] * matRotate[0][0] + pt[i][1] * matRotate[1][0]; float y = pt[i][0] * matRotate[0][1] + pt[i][1] * matRotate[1][1]; pt[i][0] = x; pt[i][1] = y; } // 計(jì)算出旋轉(zhuǎn)后圖像的極值點(diǎn)和尺寸 float fMin_x = std::min(std::min(std::min(pt[0][0], pt[1][0]), pt[2][0]), (float)0.0); float fMin_y = std::min(std::min(std::min(pt[0][1], pt[1][1]), pt[2][1]), (float)0.0); float fMax_x = std::max(std::max(std::max(pt[0][0], pt[1][0]), pt[2][0]), (float)0.0); float fMax_y = std::max(std::max(std::max(pt[0][1], pt[1][1]), pt[2][1]), (float)0.0); int nRows = cvRound(fMax_y - fMin_y + 0.5) + 1; int nCols = cvRound(fMax_x - fMin_x + 0.5) + 1; int nMin_x = cvRound(fMin_x + 0.5); int nMin_y = cvRound(fMin_y + 0.5); // 拷貝輸出圖像 cv::Mat matRet(nRows, nCols, matSrc.type(), cv::Scalar(0)); for (int j = 0; j < nRows; j++) { for (int i = 0; i < nCols; i++) { // 計(jì)算出輸出圖像在原圖像中的對(duì)應(yīng)點(diǎn)的坐標(biāo),然后復(fù)制該坐標(biāo)的灰度值 // 因?yàn)槭悄鏁r(shí)針轉(zhuǎn)換,所以這里映射到原圖像的時(shí)候可以看成是,輸出圖像 // 到順時(shí)針旋轉(zhuǎn)到原圖像的,而順時(shí)針旋轉(zhuǎn)矩陣剛好是逆時(shí)針旋轉(zhuǎn)矩陣的轉(zhuǎn)置 // 同時(shí)還要考慮到要把旋轉(zhuǎn)后的圖像的左上角移動(dòng)到坐標(biāo)原點(diǎn)。 int x = (i + nMin_x) * matRotate[0][0] + (j + nMin_y) * matRotate[0][1]; int y = (i + nMin_x) * matRotate[1][0] + (j + nMin_y) * matRotate[1][1]; if (x >= 0 && x < nColsSrc && y >= 0 && y < nRowsSrc) { matRet.at<uchar>(j, i) = matSrc.at<uchar>(y, x); } } } if(direction== false){//當(dāng)需要順時(shí)針旋轉(zhuǎn)回水平位置時(shí) int x = (matRet.cols -width) / 2; int y = (matRet.rows -height) / 2; //width和height是水平條件下圖像的寬高 cv::Rect rect(x, y, width, height); matRet = cv::Mat(matRet,rect); } return matRet; }
到此這篇關(guān)于opencv圖片的任意角度旋轉(zhuǎn)實(shí)現(xiàn)示例的文章就介紹到這了,更多相關(guān)opencv圖片任意角度旋轉(zhuǎn)內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
一起來(lái)看看C++STL容器之string類(lèi)
這篇文章主要為大家詳細(xì)介紹了C++STL容器之string類(lèi),文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下,希望能夠給你帶來(lái)幫助2022-03-03C++基于EasyX庫(kù)實(shí)現(xiàn)拼圖小游戲
這篇文章主要為大家詳細(xì)介紹了C++基于EasyX庫(kù)實(shí)現(xiàn)拼圖小游戲,文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2021-07-07C++ STL入門(mén)教程(1) vector向量容器使用方法
這篇文章主要為大家詳細(xì)介紹了C++ STL入門(mén)教程第一篇,vector向量容器使用方法,具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2017-08-08C++?vector的簡(jiǎn)單實(shí)現(xiàn)
這篇文章主要為大家詳細(xì)介紹了C++?vector的簡(jiǎn)單實(shí)現(xiàn),使用數(shù)據(jù)庫(kù),文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下,希望能夠給你帶來(lái)幫助2022-03-03C++?system()函數(shù)的常用用法(全網(wǎng)最新)
system()用于從C?/C++程序調(diào)用操作系統(tǒng)命令,這里給大家講解下C++?system()函數(shù)的常用用法,感興趣的朋友跟隨小編一起看看吧2023-01-01