01
引言
初學圖像處理,很多人遇到的第一關就是圖像旋轉,圖像旋轉是圖像幾何變換中最具代表性的操作,包含了插值、背景處理、三角函數等相關知識,一個變換矩陣跟計算圖像旋轉之后的大小公式就讓很多開發者最后直接調用函數了事,但是其實這個東西并沒有這么難懂,可以說主要是之前別人寫的公式太嚇人,小編很久以前第一次接觸的也是被嚇暈了!所以決定從程序員可以接受的角度從新介紹一下圖像旋轉基本原理與OpenCV中圖像旋轉函數操作的基本技巧。
圖像旋轉基本原理
旋轉涉及到兩個問題,一個是圖像旋轉之后的大小會發生改變,會產生背景,通過背景填充方式都是填充黑色,此外旋轉還是產生像素的位置遷移,新的位置像素需要通過插值計算獲得,常見的插值方式有最近鄰、線性插值、立方插值等。
首先看旋轉之后的圖像寬高變化,如下圖所示:
這個是正常的平面坐標系中的旋轉矩陣,可以簡寫為:
是一個2x3的矩陣,但是在圖像中左上角是原點,要實現圍繞圖像的中心位置旋轉,M就要重新計算,所以OpenCV中的圖像旋轉矩陣為:
其中scale是表示矩陣支持旋轉+放縮,這里可以把Scale=1。第三列是圖像旋轉之后中心位置平移量。
函數支持
OpenCV中支持圖像旋轉的函數有兩個,一個是直接支持旋轉的函數,但是它支持的是90,180,270這樣的特殊角度旋轉。
void cv::rotate ( InputArray src, OutputArray dst, int rotateCode )
其中rotateCode參數必須為:
ROTATE_180, ROTATE_90_CLOCKWISE ROTATE_90_COUNTERCLOCKWISE
函數warpAffine支持任意角度的旋轉,通過定義M矩陣實現
void cv::warpAffine( InputArray src, // 輸入圖像 OutputArray dst, // 輸出圖像 InputArray M, // 旋轉矩陣 Size dsize, // 輸出圖像大小 int flags = INTER_LINEAR, // 像素插值方式 int borderMode = BORDER_CONSTANT, // 背景填充默認為常量 const Scalar & borderValue = Scalar() // 填充顏色默認為黑色 )
但是M如何生成與獲取,OpenCV中提供了一個函數根據輸入的參數自動生成旋轉矩陣M,該函數為
Mat cv::getRotationMatrix2D( Point2f center, double angle, double scale )
代碼演示
使用自定義的M矩陣實現圖像旋轉
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 #執行旋轉 dst=cv.warpAffine(src,M,(w,h)) cv.imshow("rotate-center-demo",dst)
重新計算旋轉之后的圖像大小,實現無Crop版本的圖像旋轉
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 #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版本的圖像旋轉動態演示
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
編輯:黃飛
-
函數
+關注
關注
3文章
4327瀏覽量
62573 -
OpenCV
+關注
關注
31文章
634瀏覽量
41338
原文標題:經驗 | OpenCV圖像旋轉的原理與技巧
文章出處:【微信號:CVSCHOOL,微信公眾號:OpenCV學堂】歡迎添加關注!文章轉載請注明出處。
發布評論請先 登錄
相關推薦
評論