幾何變換不改變影像的畫素值,只是在影像平面上進行畫素的重新安排。適當的幾何變換可以最大程度地消除由於成像角度、透視關係乃至鏡頭自身原因所造成的幾何失真所產生的負面影響。幾何變換常常作為影像處理應用的預處理步驟, 是影像歸一化的核心工作之一。
一個幾何變換需要兩部分運算:首先是空間變換所需的運算,如平移、縮放、旋轉和正平行投影等,需要用它來表示輸出影像與輸入影像之間的(畫素)對映關係;此外,還需要使用灰度插值演算法, 因為按照這種變換關係進行計算, 輸出影像的畫素可能被對映到輸入影像的非整數座標上。
一、圖片剪下
import cv2
img = cv2.imread(`image0.jpg`,1)
imgInfo = img.shape
dst = img[100:200,100:300]
# 從X軸的100px到200px,y軸的100px到300px
cv2.imshow(`image`,img)
# 剪下前
cv2.imshow(`image`,dst)
# 剪下後
cv2.waitKey(0)
複製程式碼
結果
二、圖片移位
1、圖片移位的數學原理
x,y是圖片最終的座標(x,y),x0,y0是圖片原始座標,∆x,∆y圖片平移的大小,公式如下:
變換成矩陣如下:
2、opencv的實現方法
函式warpAffine使用指定的矩陣轉換源影像:
???(X,y )= ???(?11X+ ?12y + ?13,?21X+ ?22y + ?23)
cv2.warpAffine(src,M,dsize[,dst[,flags[,borderMode[,borderValue]]]])
引數:
- SRC 輸入影像。
- DST 輸出具有dsize大小和src相同型別的影像。
中號 2 × 3 變換矩陣。- DSIZE 輸出影像的大小。
- flags 插值方法的組合和可選標誌WARP_INVERSE_MAP,這意味著M是逆變換(??? → ??? )。
- borderMode 畫素外插法; 當borderMode = BORDER_TRANSPARENT時,這意味著目標影像中與源影像中的“離群值”相對應的畫素不會被該函式修改。
- borderValue 在邊界不變的情況下使用的值; 預設情況下,它是0。
import cv2
import numpy as np
img = cv2.imread(`image0.jpg`,1)
cv2.imshow(`src`,img)
imgInfo = img.shape
height = imgInfo[0]
width = imgInfo[1]
matShift = np.float32([[1,0,100],[0,1,200]])
dst = cv2.warpAffine(img,matShift,(height,width))
cv2.imshow(`dst`,dst)
# 平移圖片
cv2.waitKey(0)
複製程式碼
結果:
3、python的實現方法
import cv2
import numpy as np
img = cv2.imread(`image0.jpg`,1)
cv2.imshow(`src`,img)
imgInfo = img.shape
dst = np.zeros(img.shape,np.uint8)
height = imgInfo[0]
width = imgInfo[1]
for i in range(0,height):
for j in range(0,width-100):
dst[i,j+100]=img[i,j]
cv2.imshow(`image`,dst)
cv2.waitKey(0)
複製程式碼
三、圖片縮放
在計算機中,影像是以矩陣的形式儲存的,先行後列。 所以,一張寬×高×顏色通道=480×256×3 的圖片會儲存在一個 256×480×3 的三維張量中。影像處理時也是按照這種思想進行計算的(其中就包括 OpenCV 下的影像處理),即 高×寬×顏色通道。
1、圖片縮放的數學原理
warpAffine()實現縮放,矩陣公式如下。
2、opencv的實現方法
cv2.resize()可以實現圖片的縮放,但是cv2.resize這個api卻是個小例外。因為它的引數輸入卻是 寬×高×顏色通道
cv2.resize(src, dsize[, dst[, fx[, fy[, interpolation]]]])
引數:
- src – 原圖
- dst – 目標影像。當引數dsize不為0時,dst的大小為size;否則,它的大小需要根據src的大小,引數fx和fy決定。dst的型別(type)和src影像相同
- dsize – 目標影像大小。
當dsize為0時,它可以通過以下公式計算得出:
dsize = Size(round(fxsrc.cols) round(fysrc.rows))
所以,引數dsize和引數(fx, fy)不能夠同時為0- fx – 水平軸上的比例因子。當它為0時,計算公式如下:
(double) dsize.width/src.cols- fy – 垂直軸上的比例因子。當它為0時,計算公式如下:
(double) dsize.width/src.cols- interpolation – 插值方法。共有5種:
- INTER_NEAREST – 最近鄰插值法
- INTER_LINEAR – 雙線性插值法(預設)
- INTER_AREA – 基於區域性畫素的重取樣(resampling using pixel area relation)。對於影像抽取(image decimation)來說,這可能是一個更好的方法。但如果是放大影像時,它和最近鄰法的效果類似。
- INTER_CUBIC – 基於4×4畫素鄰域的3次插值法
- INTER_LANCZOS4 – 基於8×8畫素鄰域的Lanczos插值
差值方法原理介紹:https://blog.csdn.net/chaipp0607/article/details/65658736
# 1 load 2 info 3 resize 4 check
import cv2
img = cv2.imread(`image0.jpg`,1)
imgInfo = img.shape
print(imgInfo)
height = imgInfo[0]
width = imgInfo[1]
mode = imgInfo[2]
# 1 放大 縮小 2 等比例 非 2:3
dstHeight = int(height*0.5)
dstWidth = int(width*0.5)
#最近臨域插值 雙線性插值 畫素關係重取樣 立方插值
dst = cv2.resize(img,(dstWidth,dstHeight))
cv2.imshow(`image`,dst)
matScale = np.float32([[0.5,0,0],[0,0.7,0]])
dst = cv2.warpAffine(img,matScale,(int(width*0.5),int(height*0.7)))
cv2.imshow(`dst2`,dst2)
# 圖片寬*0.5,高*0.7
cv2.waitKey(0)
複製程式碼
結果:
(547, 730, 3)
複製程式碼
3、python的實現方法
import cv2
import numpy as np
img = cv2.imread(`image0.jpg`,1)
imgInfo = img.shape
height = imgInfo[0]
width = imgInfo[1]
dstHeight = int(height/2)
dstWidth = int(width/2)
dstImage = np.zeros((dstHeight,dstWidth,3),np.uint8)#0-255
for i in range(0,dstHeight):#行
for j in range(0,dstWidth):#列
iNew = int(i*(height*1.0/dstHeight))
jNew = int(j*(width*1.0/dstWidth))
dstImage[i,j] = img[iNew,jNew]
cv2.imshow(`dst`,dstImage)
cv2.waitKey(0)
複製程式碼
四、圖片映象
1、圖片映象的數學原理
(1)垂直翻轉原理
(2)水平翻轉原理
(3)180度翻轉原理
2、opencv的實現方法
import cv2
import numpy as np
img = cv2.imread(`canton02.jpg`,1)
cv2.imshow(`src`,img)
imgInfo = img.shape
height = imgInfo[0]
width = imgInfo[1]
deep = imgInfo[2]
newImgInfo = (height*2,width,deep)
newImgInfo2 = (height,width*2,deep)
newImgInfo3 = (height*2,width*2,deep)
dst = np.zeros(newImgInfo,np.uint8)
# 垂直翻轉
cv2.imshow(`dst`,dst)
for i in range(0,height):
for j in range(0,width):
dst[i,j] = img[i,j]
# x , y=2*h-y-1
dst[height*2-i-1,j] = img[i,j]
cv2.imshow(`dst`,dst)
# 水平翻轉
dst2 = np.zeros(newImgInfo2,np.uint8)
for i in range(0,height):
for j in range(0,width):
dst2[i,j] = img[i,j]
# x=2*w-x-1 , y
dst2[i,width*2-j-1] = img[i,j]
cv2.imshow(`dst2`,dst2)
# 水平垂直都翻轉
dst3 = np.zeros(newImgInfo3,np.uint8)
for i in range(0,height):
for j in range(0,width):
dst3[i,j] = img[i,j]
# x=2*w-x-1 , y=2*h-y-1
dst3[height*2-i-1,width*2-j-1] = img[i,j]
cv2.imshow(`dst3`,dst3)
cv2.waitKey(0)
複製程式碼
四、圖片轉換
1、圖片旋轉的數學原理
如上圖,r是點到原點的固定距離,角θ是點的原始角度位置與水平線的夾角,θ是旋轉角。座標表示
在極座標系中,點的原始座標為
變換方程為:
變換成矩陣:
2、opencv的實現方法
cv2.getRotationMatrix2D函式
影像先繞座標原點旋轉,旋轉之後影像的中心點到了另一個位置。
旋轉前後影像的中心點就不在一個位置了,為了讓它們在一個位置上,需要再平移影像。
影像中心點旋轉後的座標減去旋轉前的座標就是轉換矩陣中的平移向量了。
getRotationMatrix2D (Point2f center,double angle,double scale)
引數:
- center 源影像中的旋轉中心
- angle 旋轉角度(度)。正值表示逆時針旋轉(座標原點被認為是左上角)
- scale 各向同性的比例因子。
import cv2
import numpy as np
img = cv2.imread(`canton02.jpg`,1)
cv2.imshow(`src`,img)
imgInfo = img.shape
height = imgInfo[0]
width = imgInfo[1]
# 2*3
matRotate = cv2.getRotationMatrix2D((height*0.5,width*0.5),45,1)# mat rotate 1 center 2 angle 3 scale
#100*100 25
dst = cv2.warpAffine(img,matRotate,(height,width))
cv2.imshow(`dst`,dst)
cv2.waitKey(0)
複製程式碼
五、圖片仿射變換
1、圖片仿射變換的數學原理
先看一個動圖,直觀的瞭解一些什麼是仿射變換,
仿射變換:一個任意的仿射變換都能表示為 乘以一個矩陣 (線性變換) 接著再 加上一個向量 (平移).
我們能夠用仿射變換來表示:
- 旋轉 (線性變換)
- 平移 (向量加)
- 縮放操作 (線性變換)
仿射變換是一種二維座標(x0, y0)到二維座標(x,y)的線性變換,其數學表示式形式如下:
對應的齊次座標矩陣表示形式為:
影像處理中,可應用仿射變換對二維影像進行平移、縮放、旋轉等操作,具體參考上面幾節。
2、opencv的實現方法
getAffineTransform(InputArray src,InputArray DST)
引數:
- InputArray src: 表示輸入的三個點
- InputArray dstL: 表示輸出的三個點
import cv2
import numpy as np
img = cv2.imread(`image0.jpg`,1)
cv2.imshow(`src`,img)
imgInfo = img.shape
height = imgInfo[0]
width = imgInfo[1]
#src 3->dst 3 (左上角 左下角 右上角)
matSrc = np.float32([[0,0],[0,height-1],[width-1,0]])
matDst = np.float32([[50,50],[300,height-200],[width-300,100]])
#組合
matAffine = cv2.getAffineTransform(matSrc,matDst)# mat 1 src 2 dst
dst = cv2.warpAffine(img,matAffine,(width,height))
cv2.imshow(`dst`,dst)
cv2.waitKey(0)
複製程式碼