1. 程式人生 > >Python 影象處理 OpenCV (5):影象的幾何變換

Python 影象處理 OpenCV (5):影象的幾何變換

![](https://cdn.geekdigging.com/opencv/opencv_header.png) 前文傳送門: [「Python 影象處理 OpenCV (1):入門」](https://www.geekdigging.com/2020/05/17/5513454552/) [「Python 影象處理 OpenCV (2):畫素處理與 Numpy 操作以及 Matplotlib 顯示影象」](https://www.geekdigging.com/2020/05/18/4936041986/) [「Python 影象處理 OpenCV (3):影象屬性、影象感興趣 ROI 區域及通道處理」](https://www.geekdigging.com/2020/05/19/1227329671/) [「Python 影象處理 OpenCV (4):影象算數運算以及修改顏色空間」](https://www.geekdigging.com/2020/05/21/1757913240/) ## 影象縮放 影象縮放只是調整影象的大小,為此, OpenCV 為我們提供了一個函式 `cv.resize()` ,原函式如下: ```python resize(src, dsize, dst=None, fx=None, fy=None, interpolation=None) ``` src 表示的是輸入影象,而 dsize 代表的是輸出影象的大小,如果為 0 ,則: $$\texttt{dsize = Size(round(fx*src.cols), round(fy*src.rows))}$$ dsize 和 fx 、 fy 不能同時為 0 。 fx 、 fy 是沿 x 軸和 y 軸的縮放係數,預設取 0 時,演算法如下: $$\texttt{fx=(double)dsize.width/src.cols}$$ $$\texttt{fy=(double)dsize.height/src.rows}$$ 最後一個引數 interpolation 表示插值方式: * INTER_NEAREST - 最近鄰插值 * INTER_LINEAR - 線性插值(預設) * INTER_AREA - 區域插值 * INTER_CUBIC - 三次樣條插值 * INTER_LANCZOS4 - Lanczos插值 看一個簡單的示例: ```python import cv2 as cv #讀取圖片 src = cv.imread('maliao.jpg') print(src.shape) #影象縮放 result = cv.resize(src, (300, 150)) print(result.shape) #顯示影象 cv.imshow("src", src) cv.imshow("result", result) #等待顯示 cv.waitKey() cv.destroyAllWindows() ``` 結果如下: ![](https://cdn.geekdigging.com/opencv/05/resize_1.png) 需要注意的是,這裡的 `(300, 150)` 設定的是 dsize 的列數為 300 ,行數為 150 。 同理,我們可以通過設定一個比例進行縮放,可以是等比例縮放,也可以是不等比例縮放,下面是等比例縮放的示例: ```python import cv2 as cv # 設定比例 scale = 0.5 #讀取圖片 src = cv.imread('maliao.jpg') rows, cols = src.shape[:2] #影象縮放 result = cv.resize(src, ((int(cols * scale), int(rows * scale)))) print(result.shape) #顯示影象 cv.imshow("src", src) cv.imshow("result", result) #等待顯示 cv.waitKey() cv.destroyAllWindows() ``` 結果如下: ![](https://cdn.geekdigging.com/opencv/05/resize_2.png) 除了可通過設定 dszie 對影象進行縮放,我們還可以通過設定 fx 和 fy 對影象進行縮放: ```python import cv2 as cv #讀取圖片 src = cv.imread('maliao.jpg') print(src.shape) #影象縮放 result = cv.resize(src, None, fx=0.5, fy=0.5) print(result.shape) #顯示影象 cv.imshow("src", src) cv.imshow("result", result) #等待顯示 cv.waitKey() cv.destroyAllWindows() ``` 結果如下: ![](https://cdn.geekdigging.com/opencv/05/resize_3.png) ## 影象平移 影象平移是通過仿射函式 `warpAffine()` 來實現的,原函式如下: ```python warpAffine(src, M, dsize, dst=None, flags=None, borderMode=None, borderValue=None) ``` 在影象平移中我們會用到前三個引數: 1. 需要變換的原始影象 2. 移動矩陣M 3. 變換的影象大小(如果這個大小不和原始影象大小相同,那麼函式會自動通過插值來調整畫素間的關係)。 影象的平移是沿著 x 方向移動 tx 距離, y 方向移動 ty 距離,那麼需要構造移動矩陣: $$ M = [\begin{matrix} 1 & 0 & tx \\ 0 & 1 & ty \end{matrix}] $$ 我們通過 Numpy 來產生這個矩陣(必須是float型別的),並將其賦值給仿射函式 `warpAffine()` ,下面來看個示例: ```python import cv2 as cv import numpy as np #讀取圖片 src = cv.imread('maliao.jpg') rows, cols = src.shape[:2] # 定義移動距離 tx = 50 ty = 100 # 生成 M 矩陣 affine = np.float32([[1, 0, tx], [0, 1, ty]]) dst = cv.warpAffine(src, affine, (cols, rows)) # 顯示影象 cv.imshow('src', src) cv.imshow("dst", dst) # 等待顯示 cv.waitKey(0) cv.destroyAllWindows() ``` 結果如下: ![](https://cdn.geekdigging.com/opencv/05/warpAffine_1.png) > 注意: `warpAffine` 函式的第三個引數是輸出影象的大小,我這裡設定的大小是原圖片的大小,所以結果會有部分遮擋。 ## 影象旋轉 影象旋轉主要呼叫 `getRotationMatrix2D()` 函式和 `warpAffine()` 函式實現,繞影象的某一箇中心點旋轉,具體如下: * M = cv2.getRotationMatrix2D((cols/2, rows/2), 30, 1) 引數分別為:旋轉中心、旋轉度數、scale * rotated = cv2.warpAffine(src, M, (cols, rows)) 引數分別為:原始影象、旋轉引數、原始影象寬高 影象旋轉:設( x0 , y0 )是旋轉後的座標,( x , y )是旋轉前的座標,( m , n )是旋轉中心, a 是旋轉的角度(順時針),( left , top )是旋轉後圖像的左上角座標,則公式如下: $$ \begin{bmatrix}x0 & y0 & 1\end{bmatrix} = \begin{bmatrix}x & y & 1\end{bmatrix} \begin{bmatrix}1 & 0 & 0 \\ 0 & -1 & 0 \\ -m & n & 1\end{bmatrix} \begin{bmatrix}\cos a & -\sin a & 0 \\ \sin a & \cos a & 0 \\ 0 & 0 & 1 \end{bmatrix} \begin{bmatrix} 1 & 0 & 0 \\ 0 & -1 & 0 \\ left & top & 1 \end{bmatrix}$$ 上面這個公式具體的推導過程可以參考這篇文章:https://www.cnblogs.com/xuanyuyt/p/7112876.html 。 示例如下: ```python import cv2 as cv #讀取圖片 src = cv.imread('maliao.jpg') # 原圖的高、寬 rows, cols = src.shape[:2] # 繞影象的中心旋轉 # 引數:旋轉中心 旋轉度數 scale M = cv.getRotationMatrix2D((cols/2, rows/2), 90, 1) # dst = cv.warpAffine(src, M, (cols, rows)) # 顯示影象 cv.imshow("src", src) cv.imshow("dst", dst) # 等待顯示 cv.waitKey() cv.destroyAllWindows() ``` 結果如下: ![](https://cdn.geekdigging.com/opencv/05/matrix2d_1.png) ## 影象翻轉 第一個影象翻轉,這個可是製作表情包的利器。 影象翻轉在 OpenCV 中呼叫函式 `flip()` 實現,原函式如下: ```python flip(src, flipCode, dst=None) ``` * src:原始影象。 * flipCode:翻轉方向,如果 flipCode 為 0 ,則以 X 軸為對稱軸翻轉,如果 fliipCode > 0 則以 Y 軸為對稱軸翻轉,如果 flipCode < 0 則在 X 軸、 Y 軸方向同時翻轉。 示例如下: ```python import cv2 as cv import matplotlib.pyplot as plt # 讀取圖片 由 GBR 轉 RGB img = cv.imread('maliao.jpg') src = cv.cvtColor(img, cv.COLOR_BGR2RGB) # 影象翻轉 # flipCode 為 0 ,則以 X 軸為對稱軸翻轉,如果 fliipCode > 0 則以 Y 軸為對稱軸翻轉,如果 flipCode < 0 則在 X 軸、 Y 軸方向同時翻轉。 img1 = cv.flip(src, 0) img2 = cv.flip(src, 1) img3 = cv.flip(src, -1) # plt 顯示圖形 titles = ['Source', 'Ima1', 'Ima2', 'Ima3'] images = [src, img1, img2, img3] for i in range(4): plt.subplot(2, 2, i + 1) plt.imshow(images[i]) plt.title(titles[i]) plt.xticks([]) plt.yticks([]) plt.show() ``` 結果如下: ![](https://cdn.geekdigging.com/opencv/05/flip_1.png) ## 示例程式碼 如果有需要獲取原始碼的同學可以在公眾號回覆「OpenCV」進行獲取。 ## 參考 https://blog.csdn.net/Eastmount/article/details/82454335 https://www.cnblogs.com/korbin/p/5612427.html http://www.woshic