01
引言
初學(xué)圖像處理,很多人遇到的第一關(guān)就是圖像旋轉(zhuǎn),圖像旋轉(zhuǎn)是圖像幾何變換中最具代表性的操作,包含了插值、背景處理、三角函數(shù)等相關(guān)知識,一個變換矩陣跟計算圖像旋轉(zhuǎn)之后的大小公式就讓很多開發(fā)者最后直接調(diào)用函數(shù)了事,但是其實(shí)這個東西并沒有這么難懂,可以說主要是之前別人寫的公式太嚇人,小編很久以前第一次接觸的也是被嚇暈了!所以決定從程序員可以接受的角度從新介紹一下圖像旋轉(zhuǎn)基本原理與OpenCV中圖像旋轉(zhuǎn)函數(shù)操作的基本技巧。
圖像旋轉(zhuǎn)基本原理
旋轉(zhuǎn)涉及到兩個問題,一個是圖像旋轉(zhuǎn)之后的大小會發(fā)生改變,會產(chǎn)生背景,通過背景填充方式都是填充黑色,此外旋轉(zhuǎn)還是產(chǎn)生像素的位置遷移,新的位置像素需要通過插值計算獲得,常見的插值方式有最近鄰、線性插值、立方插值等。
首先看旋轉(zhuǎn)之后的圖像寬高變化,如下圖所示:
這個是正常的平面坐標(biāo)系中的旋轉(zhuǎn)矩陣,可以簡寫為:
是一個2x3的矩陣,但是在圖像中左上角是原點(diǎn),要實(shí)現(xiàn)圍繞圖像的中心位置旋轉(zhuǎn),M就要重新計算,所以O(shè)penCV中的圖像旋轉(zhuǎn)矩陣為:
其中scale是表示矩陣支持旋轉(zhuǎn)+放縮,這里可以把Scale=1。第三列是圖像旋轉(zhuǎn)之后中心位置平移量。
函數(shù)支持
OpenCV中支持圖像旋轉(zhuǎn)的函數(shù)有兩個,一個是直接支持旋轉(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),通過定義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中提供了一個函數(shù)根據(jù)輸入的參數(shù)自動生成旋轉(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)
重新計算旋轉(zhuǎn)之后的圖像大小,實(shí)現(xiàn)無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)
背景隨便變化+無Crop版本的圖像旋轉(zhuǎn)動態(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文章
4331瀏覽量
62622 -
OpenCV
+關(guān)注
關(guān)注
31文章
635瀏覽量
41352
原文標(biāo)題:經(jīng)驗(yàn) | OpenCV圖像旋轉(zhuǎn)的原理與技巧
文章出處:【微信號:CVSCHOOL,微信公眾號:OpenCV學(xué)堂】歡迎添加關(guān)注!文章轉(zhuǎn)載請注明出處。
發(fā)布評論請先 登錄
相關(guān)推薦
評論