幾何變換不改變圖像的像素值,只是在圖像平面上進行像素的從新安排。適當的幾何變換能夠最大程度地消除因爲成像角度、透視關係乃至鏡頭自身緣由所形成的幾何失真所產生的負面影響。幾何變換經常做爲圖像處理應用的預處理步驟, 是圖像歸一化的核心工做之一。python
一個幾何變換須要兩部分運算:首先是空間變換所需的運算,如平移、縮放、旋轉和正平行投影等,須要用它來表示輸出圖像與輸入圖像之間的(像素)映射關係;此外,還須要使用灰度插值算法, 由於按照這種變換關係進行計算, 輸出圖像的像素可能被映射到輸入圖像的非整數座標上。算法
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)
複製代碼
結果api
x,y是圖片最終的座標(x,y),x0,y0是圖片原始座標,∆x,∆y圖片平移的大小,公式以下:函數
變換成矩陣以下:ui
函數warpAffine使用指定的矩陣轉換源圖像:spa
𝚍𝚜𝚝(X,y )= 𝚜𝚛𝚌(𝙼11X+ 𝙼12y + 𝙼13,𝙼21X+ 𝙼22y + 𝙼23).net
cv2.warpAffine(src,M,dsize[,dst[,flags[,borderMode[,borderValue]]]])3d
參數:code
- 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)
複製代碼
結果:orm
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 下的圖像處理),即 高×寬×顏色通道。
warpAffine()實現縮放,矩陣公式以下。
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 - 基於4x4像素鄰域的3次插值法
- INTER_LANCZOS4 - 基於8x8像素鄰域的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)
複製代碼
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)
複製代碼
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)
複製代碼
如上圖,r是點到原點的固定距離,角θ是點的原始角度位置與水平線的夾角,θ是旋轉角。座標表示
在極座標系中,點的原始座標爲
變換方程爲:
變換成矩陣:
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)
複製代碼
先看一個動圖,直觀的瞭解一些什麼是仿射變換,
仿射變換:一個任意的仿射變換都能表示爲 乘以一個矩陣 (線性變換) 接着再 加上一個向量 (平移).
咱們可以用仿射變換來表示:
仿射變換是一種二維座標(x0, y0)到二維座標(x,y)的線性變換,其數學表達式形式以下:
對應的齊次座標矩陣表示形式爲:
圖像處理中,可應用仿射變換對二維圖像進行平移、縮放、旋轉等操做,具體參考上面幾節。
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)
複製代碼