01
引言
初學(xué)圖像處理,很多人遇到的第一關(guān)就是圖像旋轉(zhuǎn),圖像旋轉(zhuǎn)是圖像幾何變換中最具代表性的操作,包含了插值、背景處理、三角函數(shù)等相關(guān)知識(shí),一個(gè)變換矩陣跟計(jì)算圖像旋轉(zhuǎn)之后的大小公式就讓很多開(kāi)發(fā)者最后直接調(diào)用函數(shù)了事,但是其實(shí)這個(gè)東西并沒(méi)有這么難懂,可以說(shuō)主要是之前別人寫(xiě)的公式太嚇人,小編很久以前第一次接觸的也是被嚇暈了!所以決定從程序員可以接受的角度從新介紹一下圖像旋轉(zhuǎn)基本原理與OpenCV中圖像旋轉(zhuǎn)函數(shù)操作的基本技巧。
圖像旋轉(zhuǎn)基本原理
旋轉(zhuǎn)涉及到兩個(gè)問(wèn)題,一個(gè)是圖像旋轉(zhuǎn)之后的大小會(huì)發(fā)生改變,會(huì)產(chǎn)生背景,通過(guò)背景填充方式都是填充黑色,此外旋轉(zhuǎn)還是產(chǎn)生像素的位置遷移,新的位置像素需要通過(guò)插值計(jì)算獲得,常見(jiàn)的插值方式有最近鄰、線性插值、立方插值等。
首先看旋轉(zhuǎn)之后的圖像寬高變化,如下圖所示:
這個(gè)是正常的平面坐標(biāo)系中的旋轉(zhuǎn)矩陣,可以簡(jiǎn)寫(xiě)為:
是一個(gè)2x3的矩陣,但是在圖像中左上角是原點(diǎn),要實(shí)現(xiàn)圍繞圖像的中心位置旋轉(zhuǎn),M就要重新計(jì)算,所以O(shè)penCV中的圖像旋轉(zhuǎn)矩陣為:
其中scale是表示矩陣支持旋轉(zhuǎn)+放縮,這里可以把Scale=1。第三列是圖像旋轉(zhuǎn)之后中心位置平移量。
函數(shù)支持
OpenCV中支持圖像旋轉(zhuǎn)的函數(shù)有兩個(gè),一個(gè)是直接支持旋轉(zhuǎn)的函數(shù),但是它支持的是90,180,270這樣的特殊角度旋轉(zhuǎn)。
void cv::rotate ( InputArray src, OutputArray dst, int rotateCode )
其中rotateCode參數(shù)必須為:
ROTATE_180, ROTATE_90_CLOCKWISE ROTATE_90_COUNTERCLOCKWISE
函數(shù)warpAffine支持任意角度的旋轉(zhuǎn),通過(guò)定義M矩陣實(shí)現(xiàn)
void cv::warpAffine( InputArray src, // 輸入圖像 OutputArray dst, // 輸出圖像 InputArray M, // 旋轉(zhuǎn)矩陣 Size dsize, // 輸出圖像大小 int flags = INTER_LINEAR, // 像素插值方式 int borderMode = BORDER_CONSTANT, // 背景填充默認(rèn)為常量 const Scalar & borderValue = Scalar() // 填充顏色默認(rèn)為黑色 )
但是M如何生成與獲取,OpenCV中提供了一個(gè)函數(shù)根據(jù)輸入的參數(shù)自動(dòng)生成旋轉(zhuǎn)矩陣M,該函數(shù)為
Mat cv::getRotationMatrix2D( Point2f center, double angle, double scale )
代碼演示
使用自定義的M矩陣實(shí)現(xiàn)圖像旋轉(zhuǎn)
h,w,c=src.shape #定義矩陣 M=np.zeros((2,3),dtype=np.float32) #定義角度 alpha=np.cos(np.pi/4.0) beta=np.sin(np.pi/4.0) print("alpha:",alpha) #初始化矩陣 M[0,0]=alpha M[1,1]=alpha M[0,1]=beta M[1,0]=-beta cx=w/2 cy=h/2 tx=(1-alpha)*cx-beta*cy ty=beta*cx+(1-alpha)*cy M[0,2]=tx M[1,2]=ty #執(zhí)行旋轉(zhuǎn) dst=cv.warpAffine(src,M,(w,h)) cv.imshow("rotate-center-demo",dst)
重新計(jì)算旋轉(zhuǎn)之后的圖像大小,實(shí)現(xiàn)無(wú)Crop版本的圖像旋轉(zhuǎn)
h,w,c=src.shape M=np.zeros((2,3),dtype=np.float32) alpha=np.cos(np.pi/4.0) beta=np.sin(np.pi/4.0) print("alpha:",alpha) #初始旋轉(zhuǎn)矩陣 M[0,0]=alpha M[1,1]=alpha M[0,1]=beta M[1,0]=-beta cx=w/2 cy=h/2 tx=(1-alpha)*cx-beta*cy ty=beta*cx+(1-alpha)*cy M[0,2]=tx M[1,2]=ty #changewithfullsize bound_w=int(h*np.abs(beta)+w*np.abs(alpha)) bound_h=int(h*np.abs(alpha)+w*np.abs(beta)) #添加中心位置遷移 M[0,2]+=bound_w/2-cx M[1,2]+=bound_h/2-cy dst=cv.warpAffine(src,M,(bound_w,bound_h)) cv.imshow("rotatewithoutcropping",dst)
背景隨便變化+無(wú)Crop版本的圖像旋轉(zhuǎn)動(dòng)態(tài)演示
degree=1.0 d1=np.pi/180.0 whileTrue: alpha=np.cos(d1*degree) beta=np.sin(d1*degree) M[0,0]=alpha M[1,1]=alpha M[0,1]=beta M[1,0]=-beta cx=w/2 cy=h/2 tx=(1-alpha)*cx-beta*cy ty=beta*cx+(1-alpha)*cy M[0,2]=tx M[1,2]=ty #changewithfullsize bound_w=int(h*np.abs(beta)+w*np.abs(alpha)) bound_h=int(h*np.abs(alpha)+w*np.abs(beta)) M[0,2]+=bound_w/2-cx M[1,2]+=bound_h/2-cy red=np.random.randint(0,255) green=np.random.randint(0,255) blue=np.random.randint(0,255) dst=cv.warpAffine(src,M,(bound_w,bound_h),borderMode=cv.BORDER_CONSTANT,borderValue=(blue,green,red)) cv.imshow("rotate+background",dst) c=cv.waitKey(1000) ifc==27: break degree+=1 print("degree",degree) ifdegree>360: degree=degree%360
編輯:黃飛
-
函數(shù)
+關(guān)注
關(guān)注
3文章
4369瀏覽量
64187 -
OpenCV
+關(guān)注
關(guān)注
32文章
642瀏覽量
42431
原文標(biāo)題:經(jīng)驗(yàn) | OpenCV圖像旋轉(zhuǎn)的原理與技巧
文章出處:【微信號(hào):CVSCHOOL,微信公眾號(hào):OpenCV學(xué)堂】歡迎添加關(guān)注!文章轉(zhuǎn)載請(qǐng)注明出處。
發(fā)布評(píng)論請(qǐng)先 登錄
Vivado HLS實(shí)現(xiàn)OpenCV圖像處理的設(shè)計(jì)流程與分析
如何使用Python中的OpenCV模塊檢測(cè)顏色
OpenCV圖像處理編程研究
基于OpenCV的圖像特征智能識(shí)別系統(tǒng)設(shè)計(jì)
opencv如何實(shí)現(xiàn)圖像旋轉(zhuǎn)_原理是什么

OpenCV函數(shù)圖像處理目錄說(shuō)明

如何使用OpenCV訪問(wèn)Mat圖像中每個(gè)像素的值
OpenCV的基本操作

OpenCV中色彩空間的轉(zhuǎn)換函數(shù)
OpenCV中的圖像的計(jì)算
OpenCV中實(shí)現(xiàn)了圖像形態(tài)學(xué)什么常見(jiàn)操作?

評(píng)論