youcans 的 OpenCV 学习课—5.图像的几何变换
youcans 的 OpenCV 學(xué)習(xí)課—5.圖像的幾何變換
本系列面向 Python 小白,從零開(kāi)始實(shí)戰(zhàn)解說(shuō) OpenCV 項(xiàng)目實(shí)戰(zhàn)。
幾何變換是指對(duì)圖像的位置、大小、形狀、投影進(jìn)行變換,是將圖像從原始平面投影到新的視平面。OpenCV 中的圖像以多維數(shù)組描述,幾何變換本質(zhì)上是將一個(gè)多維數(shù)組通過(guò)映射關(guān)系求得另一個(gè)多維數(shù)組。
本節(jié)介紹圖像的幾何變換,提供完整例程和運(yùn)行結(jié)果:位置變換:平移,旋轉(zhuǎn),鏡像;形狀變換:縮放,扭變;投影變換:透視投影,平行投影;極坐標(biāo)變換。
歡迎關(guān)注 『youcans 的 OpenCV 學(xué)習(xí)課』 系列,持續(xù)更新
youcans 的 OpenCV 學(xué)習(xí)課—1.安裝與環(huán)境配置
youcans 的 OpenCV 學(xué)習(xí)課—2.圖像讀取與顯示
youcans 的 OpenCV 學(xué)習(xí)課—3.圖像的創(chuàng)建與修改
youcans 的 OpenCV 學(xué)習(xí)課—4.圖像的疊加與混合
youcans 的 OpenCV 學(xué)習(xí)課—5.圖像的幾何變換
youcans 的 OpenCV 學(xué)習(xí)課—6.灰度變換與直方圖處理
youcans 的 OpenCV 學(xué)習(xí)課—7.空間域圖像濾波
youcans 的 OpenCV 學(xué)習(xí)課—8.頻率域圖像濾波(上)
youcans 的 OpenCV 學(xué)習(xí)課—9.頻率域圖像濾波(下)
1. 幾何變換簡(jiǎn)介
幾何變換是指對(duì)對(duì)圖像的位置、大小、形狀、投影進(jìn)行變換,是將圖像從原始平面投影到新的視平面。OpenCV 中的圖像以多維數(shù)組描述,幾何變換本質(zhì)上是將一個(gè)多維數(shù)組通過(guò)映射關(guān)系求得另一個(gè)多維數(shù)組。
幾何變換可以分為等距變換、相似變換、仿射變換和投影變換。在很多書(shū)籍中把等距變換、相似變換都稱(chēng)為仿射變換,常見(jiàn)的仿射變換包括平移、旋轉(zhuǎn)、縮放、翻轉(zhuǎn)、斜切等方法。
- 等距變換:圖像中的長(zhǎng)度、面積不變,典型的等距變換是 平移、旋轉(zhuǎn)。
- 相似變換:圖像中的長(zhǎng)度比、夾角、虛圓點(diǎn)不變,相似變換是在等距變換的基礎(chǔ)上進(jìn)行了縮放,典型的相似變換是 縮放。
- 仿射變換:圖像中的平行關(guān)系、面積比、共線(xiàn)線(xiàn)段或平行線(xiàn)段的長(zhǎng)度比、矢量的線(xiàn)性組合不變,仿射變換是旋轉(zhuǎn)和非均勻縮放的復(fù)合,典型的仿射變換是 斜切。
- 投影變換:圖像中的共點(diǎn)、共線(xiàn)、相交、相切、拐點(diǎn)的關(guān)系不變,,投影變換是在仿射變換基礎(chǔ)上進(jìn)行的非線(xiàn)性縮放,典型的投影變換是 透視。
1.1 仿射變換
仿射變換(affine)的特點(diǎn)是原始圖像中的平行關(guān)系和線(xiàn)段長(zhǎng)度比例關(guān)系保持不變。
OpenCV 中的圖像以多維數(shù)組描述,通過(guò)仿射變換變換為另一個(gè)多維數(shù)組(轉(zhuǎn)換圖像)。
仿射變換中的校正圖像在二維空間中完成,在幾何上定義為一個(gè)線(xiàn)性變換接一個(gè)平移變換。
仿射變換由以下公式描述:
[x~y~1]=MA[xy1],MA=[a11a12a13a21a22a23001]\begin{bmatrix} \tilde{x}\\ \tilde{y}\\ 1 \end{bmatrix} = M_A \begin{bmatrix} x\\ y\\ 1 \end{bmatrix} ,\hspace{1em} M_A= \begin{bmatrix} a_{11} &a_{12} &a_{13}\\ a_{21} &a_{22} &a_{23}\\ 0 &0 &1 \end{bmatrix} ???x~y~?1????=MA????xy1????,MA?=???a11?a21?0?a12?a22?0?a13?a23?1????
OpenCV 提供了 cv2.warpAffine 函數(shù)實(shí)現(xiàn)仿射變換的操作。
仿射變換矩陣 MA 中有 6 個(gè)未知參數(shù),cv2.getAffineTransform 根據(jù)圖像中不共線(xiàn)的 3 個(gè)點(diǎn)在變換前后的對(duì)應(yīng)位置坐標(biāo),構(gòu)造 6元一次方程組即可求出仿射變換矩陣 MA。cv2.warpAffine 再用變換矩陣 MA 計(jì)算得到變換后的圖像。
基本例程:1.33 圖像的仿射變換
# 1.33 仿射變換: 平移、鏡像、旋轉(zhuǎn) (cv2.warpAffine)img = cv2.imread("../images/imgB2.jpg") # 讀取彩色圖像(BGR)rows, cols, ch = img.shapepts1 = np.float32([[50, 50], [200, 50], [50, 200]]) # 初始位置pts2 = np.float32([[50, 100], [200, 50], [100, 250]]) # 終止位置MA = cv2.getAffineTransform(pts1, pts2) # 計(jì)算 2x3 變換矩陣 MAdst = cv2.warpAffine(img, MA, (cols, rows)) # 實(shí)現(xiàn)仿射變換plt.figure(figsize=(9,6))plt.subplot(121), plt.imshow(cv2.cvtColor(img, cv2.COLOR_BGR2RGB)), plt.title("Original")plt.subplot(122), plt.imshow(cv2.cvtColor(dst, cv2.COLOR_BGR2RGB)), plt.title("warpAffine")plt.show()1.2 投影變換
投影變換(Projective mapping)也稱(chēng)透視變換(Perspective transformation),其特點(diǎn)是:原始圖像中的平行關(guān)系、比例關(guān)系在轉(zhuǎn)換后可以改變,但直線(xiàn)在轉(zhuǎn)換后仍然保持直線(xiàn)。
投影變換將圖片投影到一個(gè)新的視平面(Viewing plane),可以對(duì)三維空間中的物體旋轉(zhuǎn)進(jìn)行校正,主要用于圖像拼接和校正透視投影導(dǎo)致的圖像失真 。
投影變換由以下公式描述:
[x~y~z~]=M[xyz],M=[a11a12a13a21a22a23a31a32a33]\begin{bmatrix} \tilde{x}\\ \tilde{y}\\ \tilde{z} \end{bmatrix} = M \begin{bmatrix} x\\ y\\ z \end{bmatrix} ,\hspace{1em} M= \begin{bmatrix} a_{11} &a_{12} &a_{13}\\ a_{21} &a_{22} &a_{23}\\ a_{31} &a_{32} &a_{33} \end{bmatrix} ???x~y~?z~????=M???xyz????,M=???a11?a21?a31??a12?a22?a32??a13?a23?a33?????
OpenCV 提供了 cv2.warpPerspective 函數(shù)實(shí)現(xiàn)投影變換的操作。cv2.getPerspectiveTransform 根據(jù)圖像中不共線(xiàn)的 4 個(gè)點(diǎn)在變換前后的對(duì)應(yīng)位置求得 (3x3) 變換矩陣,cv2.warpPerspective 使用該 (3x3) 變換矩陣即可求出變換后的圖像。
1.3 極坐標(biāo)變換
極坐標(biāo)變換可以校正圖像中的圓形物體和圓環(huán)中所包含的物體。
極坐標(biāo)變換由以下公式描述:
KaTeX parse error: No such environment: align* at position 8: \begin{?a?l?i?g?n?*?}? r &= \sqrt{(x-…
OpenCV 提供了 cv2.cartToPolar 函數(shù)和 cv2.ploarToCart 函數(shù)實(shí)現(xiàn)笛卡爾坐標(biāo)與極坐標(biāo)的相互轉(zhuǎn)換。
2. 圖像的平移
平移是物體位置在水平和垂直方向的移動(dòng)。
像素點(diǎn) (x,y) 沿 x 軸平移 dx、沿 y 軸平移 dy,可以由以下公式描述:
[x~y~1]=MAT[xy1],MAT=[10dx01dy001]\begin{bmatrix} \tilde{x}\\ \tilde{y}\\ 1 \end{bmatrix} = M_{AT} \begin{bmatrix} x\\ y\\ 1 \end{bmatrix} ,\hspace{1em} M_{AT} = \begin{bmatrix} 1 &0 &d_x\\ 0 &1 &d_y\\ 0 &0 &1 \end{bmatrix} ???x~y~?1????=MAT????xy1????,MAT?=???100?010?dx?dy?1????
由偏移量 (Tx, Ty) 按上式構(gòu)造平移變換矩陣 MAT,由函數(shù) cv2.warpAffine 可以計(jì)算變換后的平移圖像。
函數(shù)說(shuō)明:
cv2.warpAffine(src, M, dsize[, dst[, flags[, borderMode[, borderValue]]]]) → dst函數(shù) cv2.warpAffine() 通過(guò)變換矩陣 M 對(duì)圖像 src 進(jìn)行仿射變換。
參數(shù)說(shuō)明:
- scr:變換操作的輸入圖像
- M:仿射變換矩陣,2行3列
- dsize: 輸出圖像的大小,二元元組 (width, height)
- dst:變換操作的輸出圖像,可選項(xiàng)
- flags:插值方法,整型(int),可選項(xiàng)
- cv2.INTER_LINEAR:線(xiàn)性插值,默認(rèn)選項(xiàng)
- cv2.INTER_NEAREST:最近鄰插值
- cv2.INTER_AREA:區(qū)域插值
- cv2.INTER_CUBIC:三次樣條插值
- cv2.INTER_LANCZOS4:Lanczos 插值
- borderMode:邊界像素方法,整型(int),可選項(xiàng),默認(rèn)值為 cv2.BORDER_REFLECT
- borderValue:邊界填充值,可選項(xiàng),默認(rèn)值為 0(黑色填充)
- 返回值:dst,變換操作的輸出圖像,ndarray 多維數(shù)組
注意事項(xiàng):
基本例程:1.34 圖像的平移
# 1.34 圖像平移 (Translation transform)img = cv2.imread("../images/imgLena.tif") # 讀取彩色圖像(BGR)rows, cols, ch = img.shapedx, dy = 100, 50 # dx=100 向右偏移量, dy=50 向下偏移量MAT = np.float32([[1, 0, dx], [0, 1, dy]]) # 構(gòu)造平移變換矩陣 # dst = cv2.warpAffine(img, MAT, (cols, rows)) # 默認(rèn)為黑色填充dst = cv2.warpAffine(img, MAT, (cols, rows), borderValue=(255,255,255)) # 設(shè)置白色填充plt.figure(figsize=(9,6))plt.subplot(121), plt.imshow(cv2.cvtColor(img, cv2.COLOR_BGR2RGB)), plt.title("Original")plt.subplot(122), plt.imshow(cv2.cvtColor(dst, cv2.COLOR_BGR2RGB)), plt.title("Translational")plt.show()3. 圖像的旋轉(zhuǎn)
- 圖像以原點(diǎn) (0, 0) 為中心、順時(shí)針旋轉(zhuǎn)角度 θ 進(jìn)行旋轉(zhuǎn)操作,可以由以下公式描述:
[x~y~1]=MAR[xy1],MAR=[cosθ?sinθ0sinθcosθ0001]\begin{bmatrix} \tilde{x}\\ \tilde{y}\\ 1 \end{bmatrix} = M_{AR} \begin{bmatrix} x\\ y\\ 1 \end{bmatrix} , M_{AR} = \begin{bmatrix} cos \theta &-sin \theta &0\\ sin \theta &cos \theta &0\\ 0 &0 &1 \end{bmatrix} ???x~y~?1????=MAR????xy1????,MAR?=???cosθsinθ0??sinθcosθ0?001????
按上式構(gòu)造旋轉(zhuǎn)變換矩陣 MAR,由函數(shù) cv2.warpAffine 可以計(jì)算變換后的繞原點(diǎn)旋轉(zhuǎn)圖像。
- 圖像以任意點(diǎn) (x0, y0) 為旋轉(zhuǎn)中心、順時(shí)針旋轉(zhuǎn)角度 θ 的旋轉(zhuǎn)操作,可以先將原點(diǎn)平移到旋轉(zhuǎn)中心 (x0, y0) ,然后按照原點(diǎn)旋轉(zhuǎn),最后再平移回坐標(biāo)原點(diǎn),可以由以下公式描述:
[x~y~1]=[10x001y0001][cosθ?sinθ0sinθcosθ0001][10?x001?y0001][xy1]\begin{bmatrix} \tilde{x}\\ \tilde{y}\\ 1 \end{bmatrix}= \begin{bmatrix} 1 &0 &x_0\\ 0 &1 &y_0\\ 0 &0 &1 \end{bmatrix} \begin{bmatrix} cos \theta &-sin \theta &0\\ sin \theta &cos \theta &0\\ 0 &0 &1 \end{bmatrix} \begin{bmatrix} 1 &0 &-x_0\\ 0 &1 &-y_0\\ 0 &0 &1 \end{bmatrix} \begin{bmatrix} x\\ y\\ 1 \end{bmatrix} ???x~y~?1????=???100?010?x0?y0?1???????cosθsinθ0??sinθcosθ0?001???????100?010??x0??y0?1???????xy1????
- 簡(jiǎn)便地,OpenCV 提供了 cv2.getRotationMatrix2D 函數(shù), 根據(jù)旋轉(zhuǎn)角度和位移計(jì)算旋轉(zhuǎn)變換矩陣 MAR。
函數(shù)說(shuō)明:
cv2.getRotationMatrix2D(center, angle, scale) → M函數(shù) getRotationMatrix2D 根據(jù)旋轉(zhuǎn)參數(shù)計(jì)算旋轉(zhuǎn)變換矩陣 MAR。
參數(shù)說(shuō)明:
- center:旋轉(zhuǎn)中心坐標(biāo),二元元組 (x0, y0)
- angle:旋轉(zhuǎn)角度,單位為角度,逆時(shí)針為正數(shù),順時(shí)針為負(fù)數(shù)
- scale: 縮放因子
- 返回值:M, 旋轉(zhuǎn)變換矩陣,2行3列
注意事項(xiàng):
基本例程:1.35 圖像的旋轉(zhuǎn)(以原點(diǎn)為中心旋轉(zhuǎn))
# 1.35 圖像旋轉(zhuǎn) (以原點(diǎn) (0,0) 為中心旋轉(zhuǎn))img = cv2.imread("../images/imgLena.tif") # 讀取彩色圖像(BGR)rows, cols, ch = img.shapetheta = np.pi / 8.0 # 順時(shí)針旋轉(zhuǎn)角度cosTheta = np.cos(theta)sinTheta = np.sin(theta)MAT = np.float32([[cosTheta, -sinTheta, 0], [sinTheta, cosTheta, 0]]) # 構(gòu)造旋轉(zhuǎn)變換矩陣# dst = cv2.warpAffine(img, MAT, (cols, rows)) # 默認(rèn)為黑色填充dst = cv2.warpAffine(img, MAT, (cols, rows), borderValue=(255,255,255)) # 設(shè)置白色填充plt.figure(figsize=(9,6))plt.subplot(121), plt.imshow(cv2.cvtColor(img, cv2.COLOR_BGR2RGB)), plt.title("Origin")plt.subplot(122), plt.imshow(cv2.cvtColor(dst, cv2.COLOR_BGR2RGB)), plt.title("Rotation")plt.show()
基本例程:1.36 圖像的旋轉(zhuǎn)(任意旋轉(zhuǎn)中心)
# 1.36 圖像旋轉(zhuǎn) (以任意點(diǎn) (x0,y0) 為中心旋轉(zhuǎn))img = cv2.imread("../images/imgGaia.tif") # 讀取彩色圖像(BGR)height, width = img.shape[:2] # 圖片的高度和寬度theta1, theta2 = 30, 45 # 順時(shí)針旋轉(zhuǎn)角度,單位為角度x0, y0 = width//2, height//2 # 以圖像中心作為旋轉(zhuǎn)中心MAR1 = cv2.getRotationMatrix2D((x0,y0), theta1, 1.0)MAR2 = cv2.getRotationMatrix2D((x0,y0), theta2, 1.0)imgR1 = cv2.warpAffine(img, MAR1, (width, height)) # 旋轉(zhuǎn)變換,默認(rèn)為黑色填充imgR2 = cv2.warpAffine(img, MAR2, (width, height), borderValue=(255,255,255)) # 設(shè)置白色填充plt.figure(figsize=(10,6))plt.subplot(131), plt.axis('off'), plt.title(r"$Origin$")plt.imshow(cv2.cvtColor(img, cv2.COLOR_BGR2RGB))plt.subplot(132), plt.axis('off'), plt.title(r"$Rotation {}^o$".format(theta1))plt.imshow(cv2.cvtColor(imgR1, cv2.COLOR_BGR2RGB))plt.subplot(133), plt.axis('off'), plt.title(r"$Rotation {}^o$".format(theta2))plt.imshow(cv2.cvtColor(imgR2, cv2.COLOR_BGR2RGB))plt.show()
擴(kuò)展例程:1.37 圖像的直角旋轉(zhuǎn)
當(dāng)旋轉(zhuǎn)角度為 90,180,270 度時(shí),可以用圖像旋轉(zhuǎn)函數(shù) cv2.rotate(src, rotateCode) 實(shí)現(xiàn),該方法通過(guò)矩陣轉(zhuǎn)置實(shí)現(xiàn),速度很快。此外,numpy 中也提供了旋轉(zhuǎn)矩陣的方法 np.rot90 可以按 90 度的整數(shù)倍進(jìn)行旋轉(zhuǎn)。
# 1.37 圖像的直角旋轉(zhuǎn) (90, 180, 270)# cv2.rotate(src, rotateCode)# rotateCode: cv2.ROTATE_90_CLOCKWISE, 順時(shí)針旋轉(zhuǎn)90度# cv2.ROTATE_180, 順時(shí)針旋轉(zhuǎn)180度# cv2.ROTATE_90_COUNTERCLOCKWISE, 順時(shí)針旋轉(zhuǎn)270度img = cv2.imread("../images/imgLena.tif") # 讀取彩色圖像(BGR)imgR90 = cv2.rotate(img, cv2.ROTATE_90_CLOCKWISE)imgR180 = cv2.rotate(img, cv2.ROTATE_180)imgR270 = cv2.rotate(img, cv2.ROTATE_90_COUNTERCLOCKWISE)# imgR90 = np.rot90(img, 1) # numpy 矩陣旋轉(zhuǎn) 90*1=90 度# imgR180 = np.rot90(img, 2) # numpy 矩陣旋轉(zhuǎn) 90*2=180 度# imgR270 = np.rot90(img, 3) # numpy 矩陣旋轉(zhuǎn) 90*3=270 度plt.figure(figsize=(9,7))plt.subplot(221), plt.imshow(cv2.cvtColor(img, cv2.COLOR_BGR2RGB)), plt.title(r"$Origin$")plt.subplot(222), plt.imshow(cv2.cvtColor(imgR90, cv2.COLOR_BGR2RGB)), plt.title(r"$Rotation 90^{o}$")plt.subplot(223), plt.imshow(cv2.cvtColor(imgR180, cv2.COLOR_BGR2RGB)), plt.title(r"$Rotation 180^{o}$")plt.subplot(224), plt.imshow(cv2.cvtColor(imgR270, cv2.COLOR_BGR2RGB)), plt.title(r"$Rotation 270^{o}$")plt.show()4. 圖像的翻轉(zhuǎn)(鏡像)
翻轉(zhuǎn)也稱(chēng)鏡像,是指將圖像沿軸線(xiàn)進(jìn)行軸對(duì)稱(chēng)變換。水平鏡像是將圖像沿垂直中軸線(xiàn)進(jìn)行左右翻轉(zhuǎn),垂直鏡像是將圖像沿水平中軸線(xiàn)進(jìn)行上下翻轉(zhuǎn),水平垂直鏡像是水平鏡像和垂直鏡像的疊加。
以水平鏡像為例,圖像寬度為 fw,像素點(diǎn) (x,y) 以垂直中軸線(xiàn)為中心進(jìn)行左右對(duì)換,可以由以下公式描述:
[x~y~1]=MAF[xy1],MAF=[?10fw010001]\begin{bmatrix} \tilde{x}\\ \tilde{y}\\ 1 \end{bmatrix} = M_{AF} \begin{bmatrix} x\\ y\\ 1 \end{bmatrix} ,\hspace{1em} M_{AF} = \begin{bmatrix} -1 &0 &f_w\\ 0 &1 &0\\ 0 &0 &1 \end{bmatrix} ???x~y~?1????=MAF????xy1????,MAF?=????100?010?fw?01????
由上式構(gòu)造鏡像變換矩陣 MAF,由函數(shù) cv2.warpAffine 可以計(jì)算變換后的鏡像圖像。
簡(jiǎn)便地,OpenCV 提供了 cv2.flip 函數(shù),可以將圖像沿水平方向、垂直方向、或水平/垂直方向同時(shí)進(jìn)行翻轉(zhuǎn)。
函數(shù)說(shuō)明:
cv2.flip(src, flipCode[, dst]) -> dst參數(shù)說(shuō)明:
- scr:變換操作的輸入圖像
- flipCode:控制參數(shù),整型(int),flipCode>0 水平翻轉(zhuǎn),flipCode=0 垂直翻轉(zhuǎn),flipCode<0 水平和垂直翻轉(zhuǎn)
- dst:變換操作的輸出圖像,可選項(xiàng)
基本例程:1.38 圖像的翻轉(zhuǎn)(鏡像)
# 1.38 圖像的翻轉(zhuǎn) (鏡像)img = cv2.imread("../images/Fractal03.png") # 讀取彩色圖像(BGR)imgFlip1 = cv2.flip(img, 0) # 垂直翻轉(zhuǎn)imgFlip2 = cv2.flip(img, 1) # 水平翻轉(zhuǎn)imgFlip3 = cv2.flip(img, -1) # 水平和垂直翻轉(zhuǎn)plt.figure(figsize=(9, 6))plt.subplot(221), plt.axis('off'), plt.title("Original")plt.imshow(cv2.cvtColor(img, cv2.COLOR_BGR2RGB)) # 原始圖像plt.subplot(222), plt.axis('off'), plt.title("Flipped Horizontally")plt.imshow(cv2.cvtColor(imgFlip2, cv2.COLOR_BGR2RGB)) # 水平翻轉(zhuǎn)plt.subplot(223), plt.axis('off'), plt.title("Flipped Vertically")plt.imshow(cv2.cvtColor(imgFlip1, cv2.COLOR_BGR2RGB)) # 垂直翻轉(zhuǎn)plt.subplot(224), plt.axis('off'), plt.title("Flipped Horizontally & Vertically")plt.imshow(cv2.cvtColor(imgFlip3, cv2.COLOR_BGR2RGB)) # 水平垂直翻轉(zhuǎn)plt.show()5. 圖像的縮放
縮放只是調(diào)整圖像的大小。
OpenCV 提供了 cv2.resize 函數(shù),實(shí)現(xiàn)圖像的縮放和大小變換 。
函數(shù)說(shuō)明:
cv2.resize(src, dsize[, dst[, fx[, fy[, interpolation]]]]) → dst參數(shù)說(shuō)明:
- scr:變換操作的輸入圖像
- dsize: 輸出圖像的大小,二元元組 (width, height)
- dst:變換操作的輸出圖像,可選項(xiàng)
- fx, fy:x 軸、y 軸上的縮放比例,實(shí)型,可選項(xiàng)
- interpolation:插值方法,整型,可選項(xiàng)
- cv2.INTER_LINEAR:雙線(xiàn)性插值(默認(rèn)方法)
- cv2.INTER_AREA:使用像素區(qū)域關(guān)系重采樣,縮小圖像時(shí)可以避免波紋出現(xiàn)
- cv2.INTER_NEAREST:最近鄰插值
- cv2.INTER_CUBIC:4x4 像素鄰域的雙三次插值
- cv2.INTER_LANCZOS4:8x8 像素鄰域的Lanczos插值
- 返回值:dst,變換操作的輸出圖像,ndarray 多維數(shù)組
注意事項(xiàng):
圖像縮放可以通過(guò) dsize 直接設(shè)定輸出圖像的大小,也可以通過(guò) dx, dy 設(shè)置圖像縮放的比例(dsize 設(shè)為 None)。
也可以通過(guò)構(gòu)造縮放變換矩陣 MAZ,由函數(shù) cv2.warpAffine 計(jì)算變換后的縮放平移圖像。縮放變換矩陣 MAZ 由以下公式描述:
[x~y~1]=MAZ[xy1],MAZ=[fx000fy0001]\begin{bmatrix} \tilde{x}\\ \tilde{y}\\ 1 \end{bmatrix} = M_{AZ} \begin{bmatrix} x\\ y\\ 1 \end{bmatrix} ,\hspace{1em} M_{AZ} = \begin{bmatrix} f_x &0 &0\\ 0 &f_y &0\\ 0 &0 &1 \end{bmatrix} ???x~y~?1????=MAZ????xy1????,MAZ?=???fx?00?0fy?0?001????
由偏移量 (Tx, Ty) 按上式構(gòu)造平移變換矩陣 MAT,由函數(shù) cv2.warpAffine 可以計(jì)算變換后的平移圖像。
基本例程:1.39 圖像的縮放變換
# 1.39 圖像的縮放img = cv2.imread("../images/Fractal08.png") # 讀取彩色圖像(BGR)height, width = img.shape[:2] # 圖片的高度和寬度imgZoom1 = cv2.resize(img, (int(0.75*width), int(height)))imgZoom2 = cv2.resize(img, None, fx=0.75, fy=1.0, interpolation=cv2.INTER_AREA)plt.figure(figsize=(8,6))plt.subplot(121), plt.axis('off'), plt.title("Zoom: 0.75*W,1.0*H")plt.imshow(cv2.cvtColor(imgZoom1, cv2.COLOR_BGR2RGB))plt.subplot(122), plt.axis('off'), plt.title("Zoom: fx=0.75,fy=1.0")plt.imshow(cv2.cvtColor(imgZoom2, cv2.COLOR_BGR2RGB))plt.show()擴(kuò)展例程:1.40 圖像金字塔
圖像金字塔是一種以多分辨率來(lái)解釋圖像的結(jié)構(gòu),常用于圖像分割、圖像壓縮和機(jī)器視覺(jué)。
在需要處理同一圖像的不同分辨率的子圖時(shí),需要?jiǎng)?chuàng)建一組具有不同分辨率的原始圖像。把最大的圖像放在底部,最小的放在頂部,看起來(lái)就像一座金字塔,稱(chēng)為圖像金字塔。
圖像金字塔是一系列來(lái)源于同一張?jiān)紙D像、以金字塔形狀排列的分辨率逐步降低的圖像集合。
金字塔的底部是原始圖像的高分辨率的表示,頂部是低分辨率的近似。
OpenCV 為向下采樣和向上采樣提供了兩個(gè)函數(shù):cv2.pyrDown 和 cv2.pyrUp。
函數(shù)說(shuō)明:
cv2.pyrDown(src, dst=None, dstsize=None, borderType=None) → dst # 向下采樣 cv2.pyrUp(src, dst=None, dstsize=None, borderType=None) → dst # 向上采樣函數(shù) cv2.pyrDown 是從高分辨率的大尺寸圖像逐次向下采樣得到一系列圖像,構(gòu)建一個(gè)金字塔,稱(chēng)為高斯金字塔(Gaussian pyramid),實(shí)際上是一個(gè)重復(fù)高斯平滑并重新對(duì)圖像采樣的過(guò)程。拉普拉斯金字塔每次向下采樣后將再次向上采樣,并記錄殘差信息,可以對(duì)圖像進(jìn)行最大程度的還原。
# 1.40 圖像金字塔def GussianPyramid(image): # 高斯金字塔level = 2 # 金字塔的層數(shù)imgCopy = image.copy()pyramidImages = [] # 創(chuàng)建圖像 Listfor i in range(level):dst = cv2.pyrDown(imgCopy) # 下采樣pyramidImages.append(dst) # 添加到圖像 Listcv2.imshow("pyramid down "+str(i), dst)imgCopy = dst.copy()return pyramidImagesimg = cv2.imread("../images/imgLena.tif") # 讀取彩色圖像(BGR) cv2.namedWindow("input image", cv2.WINDOW_AUTOSIZE) cv2.imshow("input image", img) GussianPyramid(img) # 高斯圖像金字塔 # LapalianPyramid(img) # 拉普拉斯圖像金字塔 cv2.waitKey(0)6. 圖像的扭變(錯(cuò)切)
圖像的錯(cuò)切變換也稱(chēng)斜切,是指平面景物在投影平面上的非垂直投影,使圖像中的圖形在水平方向或垂直方向產(chǎn)生扭變。
以水平扭變?yōu)槔?#xff0c;像素點(diǎn) (x,y) 在水平方向發(fā)生扭變變成斜邊,而在垂直方向的邊不變,可以由以下公式描述:
[x~y~1]=MAS[xy1],MAS=[1tanθ0010001]\begin{bmatrix} \tilde{x}\\ \tilde{y}\\ 1 \end{bmatrix} = M_{AS} \begin{bmatrix} x\\ y\\ 1 \end{bmatrix} ,\hspace{1em} M_{AS} = \begin{bmatrix} 1 &tan \theta &0\\ 0 &1 &0\\ 0 &0 &1 \end{bmatrix} ???x~y~?1????=MAS????xy1????,MAS?=???100?tanθ10?001????
由扭變角度 θ上式構(gòu)造錯(cuò)切變換矩陣 MAS,由函數(shù) cv2.warpAffine 可以計(jì)算變換后的扭變圖像。
基本例程:1.41 圖像的錯(cuò)切
# 1.41 圖像的錯(cuò)切img = cv2.imread("../images/imgB2.jpg") # 讀取彩色圖像(BGR)height, width = img.shape[:2] # 圖片的高度和寬度MAS = np.float32([[1, 0.2, 0], [0, 1, 0]]) # 構(gòu)造錯(cuò)切變換矩陣imgShear = cv2.warpAffine(img, MAS, (width, height))plt.figure(figsize=(9,6))plt.subplot(121), plt.imshow(cv2.cvtColor(img, cv2.COLOR_BGR2RGB)), plt.title("imgOrigin")plt.subplot(122), plt.imshow(cv2.cvtColor(imgShear, cv2.COLOR_BGR2RGB)), plt.title("imgShear")plt.show()7. 圖像的復(fù)合變換
圖像的復(fù)合變換是指對(duì)給定的圖像連續(xù)進(jìn)行多次上述的平移、旋轉(zhuǎn)、翻轉(zhuǎn)、縮放、錯(cuò)切等基本變換,也稱(chēng)為級(jí)聯(lián)變換。
對(duì)給定圖像按一定順序執(zhí)行若干次基本變換,其變換矩陣仍然可以用 3x3 階變換矩陣表示。進(jìn)一步地,對(duì)圖像依次執(zhí)行基本變換 F1、F2、…Fn 的變換矩陣分別為 M1、M2、…Mn,可以證明,以圖像中心點(diǎn)為中心進(jìn)行比例、旋轉(zhuǎn)進(jìn)行變換,則復(fù)合變換的變換矩陣 M 等于各基本變換矩陣依次相乘所得到的組合矩陣:
M=M1×M2×?×MnM = M_1 \times M_2 \times \dots \times M_n M=M1?×M2?×?×Mn?
縮放:
MAZ=[fx000fy0001]M_{AZ} = \begin{bmatrix} fx &0 &0\\ 0 &f_y &0\\ 0 &0 &1 \end{bmatrix} MAZ?=???fx00?0fy?0?001????
旋轉(zhuǎn):
MAR=[cosθ?sinθ0sinθcosθ0001]M_{AR} = \begin{bmatrix} cos \theta &-sin \theta &0\\ sin \theta &cos \theta &0\\ 0 &0 &1 \end{bmatrix} MAR?=???cosθsinθ0??sinθcosθ0?001????
平移:
MAT=[10dx01dy001]M_{AT} = \begin{bmatrix} 1 &0 &d_x\\ 0 &1 &d_y\\ 0 &0 &1 \end{bmatrix} MAT?=???100?010?dx?dy?1????
扭變:
MAS=[1tanθ0010001]M_{AS} = \begin{bmatrix} 1 &tan \theta &0\\ 0 &1 &0\\ 0 &0 &1 \end{bmatrix} MAS?=???100?tanθ10?001????
鏡像:
MAF=[?10fw010001]M_{AF} = \begin{bmatrix} -1 &0 &f_w\\ 0 &1 &0\\ 0 &0 &1 \end{bmatrix} MAF?=????100?010?fw?01????
基本例程:1.42 圖像的復(fù)合變換
# 1.42 圖像的復(fù)合變換img = cv2.imread("../images/imgLena.tif") # 讀取彩色圖像(BGR)height, width = img.shape[:2] # 圖片的高度和寬度# (1) 縮放fx, fy = 0.6, 0.6MAZ = np.float32([[fx, 0, 0], [0, fy, 0]]) # 構(gòu)造縮放變換矩陣imgT1 = cv2.warpAffine(img, MAZ, (width, height)) # 仿射變換, 黑色填充# (2) 平移dx, dy = 50, 200 # dx=100 向右偏移量, dy=50 向下偏移量MAT = np.float32([[1, 0, dx], [0, 1, dy]]) # 構(gòu)造平移變換矩陣imgT2 = cv2.warpAffine(imgT1, MAT, (width, height), borderValue=(0,255,255)) # 實(shí)現(xiàn)仿射變換# (3) 旋轉(zhuǎn)theta = -30 * np.pi / 180 # 逆時(shí)針旋轉(zhuǎn) 30°cosTheta = np.cos(theta)sinTheta = np.sin(theta)MAR = np.float32([[cosTheta, -sinTheta, 0], [sinTheta, cosTheta, 0]]) # 構(gòu)造旋轉(zhuǎn)變換矩陣imgT3 = cv2.warpAffine(imgT2, MAR, (width, height), borderValue=(255,255,0)) # 實(shí)現(xiàn)仿射變換# (4) 扭曲theta = -30 * np.pi / 180 # 逆時(shí)針扭變 30°MAS = np.float32([[1, np.tan(theta), 0], [0, 1, 0]]) # 構(gòu)造扭變變換矩陣imgT4 = cv2.warpAffine(imgT3, MAS, (width, height), borderValue=(255,0,255)) # 實(shí)現(xiàn)仿射變換plt.figure(figsize=(9,6))plt.subplot(221), plt.axis('off'), plt.title("T1:Zoom")plt.imshow(cv2.cvtColor(imgT1, cv2.COLOR_BGR2RGB)),plt.subplot(222), plt.axis('off'), plt.title("T2:Translation")plt.imshow(cv2.cvtColor(imgT2, cv2.COLOR_BGR2RGB))plt.subplot(223), plt.axis('off'), plt.title("T3:Rotation")plt.imshow(cv2.cvtColor(imgT3, cv2.COLOR_BGR2RGB))plt.subplot(224), plt.axis('off'), plt.title("T4:Shear")plt.imshow(cv2.cvtColor(imgT4, cv2.COLOR_BGR2RGB))plt.show()8. 投影變換
投影變換(Projective mapping)也稱(chēng)透視變換(Perspective transformation)是建立兩平面場(chǎng)之間的對(duì)應(yīng)關(guān)系, 將圖片投影到一個(gè)新的視平面(Viewing plane)。
OpenCV 提供了 cv2.warpPerspective 函數(shù)實(shí)現(xiàn)投影變換的操作。
函數(shù)說(shuō)明:
cv2.getPerspectiveTransform(src, dst[,solveMethod]) → MP cv2.warpPerspective(src, M, dsize[, dst[, flags[, borderMode[, borderValue]]]]) → dst函數(shù)cv2.getPerspectiveTransform 根據(jù)圖像中不共線(xiàn)的 4 個(gè)點(diǎn)在變換前后的對(duì)應(yīng)位置求得 (3x3) 變換矩陣,cv2.warpPerspective 使用該 (3x3) 變換矩陣即可求出變換后的圖像。標(biāo)量進(jìn)行加法運(yùn)算。
參數(shù)說(shuō)明:
- src:變換前圖像四邊形頂點(diǎn)坐標(biāo)
- dst:變換后圖像四邊形頂點(diǎn)坐標(biāo)
- solveMethod:矩陣分解方法,傳遞給 cv2.solve 求解變換矩陣 MP
- cv2.DECOMP_LU:選擇最優(yōu)軸的高斯消去法,默認(rèn)方法
- cv2.DECOMP_SVD:奇異值分解(SVD)方法
- cv2.DECOMP_EIG:特征值分解方法,src 必須對(duì)稱(chēng)
- cv2.DECOMP_QR:QR(正交三角)分解
- cv2.DECOMP_CHOLESKY:Cholesky LLT 分解
- MP:透視變換矩陣,3行3列
- dsize: 輸出圖像的大小,二元元組 (width, height)
- dst:變換操作的輸出圖像,可選項(xiàng)
- flags:插值方法,整型(int),可選項(xiàng)
- cv2.INTER_LINEAR:線(xiàn)性插值,默認(rèn)選項(xiàng)
- cv2.INTER_NEAREST:最近鄰插值
- cv2.INTER_AREA:區(qū)域插值
- cv2.INTER_CUBIC:三次樣條插值
- cv2.INTER_LANCZOS4:Lanczos 插值
- borderMode:邊界像素方法,整型(int),可選項(xiàng),默認(rèn)值為 cv2.BORDER_REFLECT
- borderValue:邊界填充模式,可選項(xiàng),默認(rèn)值為 0(黑色填充)
- 返回值:dst,透視變換操作的輸出圖像,ndarray 多維數(shù)組
基本例程:1.43 圖像的投影變換
# 1.43 投影變換 (Projective mapping)img = cv2.imread("../images/imgB2.jpg") # 讀取彩色圖像(BGR)h, w = img.shape[:2] # 圖片的高度和寬度pointSrc = np.float32([[0,0], [w-1,0], [0,h-100], [w-1, h-100]]) # 原始圖像中 4點(diǎn)坐標(biāo)pointDst = np.float32([[180,50], [w-180,50], [0,h-100], [w-1, h-100]]) # 變換圖像中 4點(diǎn)坐標(biāo)MP = cv2.getPerspectiveTransform(pointSrc, pointDst) # 計(jì)算投影變換矩陣 MimgP = cv2.warpPerspective(img, MP, (512, 512)) # 用變換矩陣 M 進(jìn)行投影變換plt.figure(figsize=(9,6))plt.subplot(121), plt.imshow(cv2.cvtColor(img, cv2.COLOR_BGR2RGB)), plt.title("Original")plt.subplot(122), plt.imshow(cv2.cvtColor(imgP, cv2.COLOR_BGR2RGB)), plt.title("Projective")plt.show()基本例程:1.44 圖像的投影變換
# 1.44 圖像的投影變換img = cv2.imread("../images/imgC2.jpg") # 讀取彩色圖像(BGR)h, w = img.shape[:2] # 圖片的高度和寬度pointSrc = np.float32([[0,0], [w,0], [0,h], [w,h]]) # 原始圖像中 4點(diǎn)坐標(biāo)pointDst = np.float32([[int(w/3), int(h/3)], [int(w*2/3), int(h/3)], [0,h], [w,h]]) # 變換圖像中 4點(diǎn)坐標(biāo)MP = cv2.getPerspectiveTransform(pointSrc, pointDst) # 計(jì)算投影變換矩陣 MimgP = cv2.warpPerspective(img, MP, (w,h), flags=cv2.INTER_AREA, borderMode=cv2.BORDER_WRAP)plt.figure(figsize=(9,6))plt.subplot(121), plt.imshow(cv2.cvtColor(img, cv2.COLOR_BGR2RGB)), plt.title("Original"), plt.axis('off')plt.subplot(122), plt.imshow(cv2.cvtColor(imgP, cv2.COLOR_BGR2RGB)), plt.title("Projective"), plt.axis('off')plt.show()9. 直角坐標(biāo)與極坐標(biāo)的轉(zhuǎn)換
函數(shù) cv2.cartToPolar 用于將直角坐標(biāo)(笛卡爾坐標(biāo))轉(zhuǎn)換為極坐標(biāo),函數(shù) cv2.polarToCart 用于將極坐標(biāo)轉(zhuǎn)換為直角坐標(biāo)(笛卡爾坐標(biāo))。
圓形圖案邊緣上的文字經(jīng)過(guò)及坐標(biāo)變換后可以垂直的排列在新圖像的邊緣,便于對(duì)文字的識(shí)別和檢測(cè)。
函數(shù)說(shuō)明:
cv2.cartToPolar(x, y[, magnitude[, angle[, angleInDegrees]]]) → magnitude, angle cv2.polarToCart(magnitude, angle[, x[, y[, angleInDegrees]]]) → x, y函數(shù) cv2.cartToPolar 實(shí)現(xiàn)將原點(diǎn)移動(dòng)到變換中心后的直角坐標(biāo)向極坐標(biāo)的轉(zhuǎn)換,輸入?yún)?shù)為直角坐標(biāo)系的橫坐標(biāo)、縱坐標(biāo),輸出為極坐標(biāo)系的向量值、角度值。
函數(shù) cv2.polarToCart 實(shí)現(xiàn)將原點(diǎn)移動(dòng)到變換中心后的極坐標(biāo)向直角坐標(biāo)的轉(zhuǎn)換,輸入?yún)?shù)為極坐標(biāo)系的向量值、角度值,輸出為直角坐標(biāo)系的橫坐標(biāo)、縱坐標(biāo)。
參數(shù)說(shuō)明:
- x, y:直角坐標(biāo)系的橫坐標(biāo)、縱坐標(biāo),ndarray 多維數(shù)組,浮點(diǎn)型
- magnitude, angle:極坐標(biāo)系的向量值、角度值,ndarray 多維數(shù)組
- angleInDegrees:弧度制/角度值選項(xiàng),默認(rèn)值 0 選擇弧度制,1 選擇角度制([0,360] )
- 返回值 magnitude, angle:極坐標(biāo)系的向量值、角度值,ndarray 多維數(shù)組,與輸入的 x, y 具有相同的尺寸和數(shù)據(jù)類(lèi)型
- 返回值 x, y:直角坐標(biāo)系的橫坐標(biāo)、縱坐標(biāo),ndarray 多維數(shù)組,與輸入的 magnitude, angle 具有相同的尺寸和數(shù)據(jù)類(lèi)型
注意事項(xiàng):
基本例程:1.45 直角坐標(biāo)轉(zhuǎn)換為極坐標(biāo)
# 1.45 直角坐標(biāo)轉(zhuǎn)換為極坐標(biāo)x = np.float32([0,1,2, 0,1,2, 0,1,2]) -1y = np.float32([0,0,0, 1,1,1, 2,2,2]) -1n = np.arange(9)r, theta = cv2.cartToPolar(x, y, angleInDegrees=True)xr,yr = cv2.polarToCart(r, theta, angleInDegrees=1)print(xr,yr)plt.figure(figsize=(9,5))plt.subplot(121), plt.title("Cartesian coordinate"), plt.plot(x, y, 'o')for i, txt in enumerate(n):plt.annotate(txt, (x[i], y[i]))plt.subplot(122), plt.title("Polar coordinate"), plt.plot(r, theta, 'o')for i, txt in enumerate(n):plt.annotate(txt, (r[i], theta[i]))plt.show()擴(kuò)展例程:1.46 極坐標(biāo)系中的圓形圖像修正
# 1.46 極坐標(biāo)系中的圓形圖像修正img = cv2.imread("../images/imgC3.jpg") # 讀取彩色圖像(BGR)h, w = img.shape[:2] # 圖片的高度和寬度cx, cy = int(w/2), int(h/2) # 以圖像中心點(diǎn)作為變換中心maxR = max(cx, cy) # 最大變換半徑imgPolar = cv2.linearPolar(img, (cx,cy), maxR, cv2.INTER_LINEAR)imgPR = cv2.rotate(imgPolar, cv2.ROTATE_90_COUNTERCLOCKWISE)plt.figure(figsize=(10,6))plt.subplot(121), plt.imshow(cv2.cvtColor(img, cv2.COLOR_BGR2RGB)), plt.title("Original"), plt.axis('off')plt.subplot(122), plt.imshow(cv2.cvtColor(imgPR, cv2.COLOR_BGR2RGB)), plt.title("PolarTrans"), plt.axis('off')plt.show()通過(guò)極坐標(biāo)和直角坐標(biāo)的對(duì)應(yīng)關(guān)系,將圓環(huán)圖像轉(zhuǎn)換為矩形圖像,可以對(duì)圓形圖像進(jìn)行修正。
【本節(jié)完】
版權(quán)聲明:
youcans 的 OpenCV 學(xué)習(xí)課 @ youcans 原創(chuàng)作品
轉(zhuǎn)載必須標(biāo)注原文鏈接:https://blog.csdn.net/youcans/article/details/121288020
Copyright 2021 youcans, XUPT
Crated:2021-11-15
歡迎關(guān)注 『youcans 的 OpenCV 學(xué)習(xí)課』 系列,持續(xù)更新
youcans 的 OpenCV 學(xué)習(xí)課—1.安裝與環(huán)境配置
youcans 的 OpenCV 學(xué)習(xí)課—2.圖像讀取與顯示
youcans 的 OpenCV 學(xué)習(xí)課—3.圖像的創(chuàng)建與修改
youcans 的 OpenCV 學(xué)習(xí)課—4.圖像的疊加與混合
youcans 的 OpenCV 學(xué)習(xí)課—5.圖像的幾何變換
youcans 的 OpenCV 學(xué)習(xí)課—6.灰度變換與直方圖處理
youcans 的 OpenCV 學(xué)習(xí)課—7.空間域圖像濾波
youcans 的 OpenCV 學(xué)習(xí)課—8.頻率域圖像濾波(上)
youcans 的 OpenCV 學(xué)習(xí)課—9.頻率域圖像濾波(下)
總結(jié)
以上是生活随笔為你收集整理的youcans 的 OpenCV 学习课—5.图像的几何变换的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問(wèn)題。
- 上一篇: lingo入门(数据部分)
- 下一篇: python学习socket的客户端实现