OpenCV能夠這樣實現圖像變換(python)

通常對圖像的變化操做有放大、縮小、旋轉等,統稱爲幾何變換,對一個圖像的圖像變換主要有兩大步驟,一是實現空間座標的轉換,就是使圖像從初始位置到終止位置的移動。二是使用一個插值的算法完成輸出圖像的每一個像素的灰度值。其中主要的圖像變換有:仿射變換、投影變換、極座標變換。python

仿射變換

二維空間座標的仿射變換公式:git

(x¯¯¯y¯¯¯)=(a11a21a12a22)(xy)+(a13a23)(x¯y¯)=(a11a12a21a22)(xy)+(a13a23)算法

在如下矩陣中: 函數

⎛⎝⎜x¯¯¯y¯¯¯1⎞⎠⎟=A⎛⎝⎜xy1⎞⎠⎟(x¯y¯1)=A(xy1)spa

矩陣A就是仿射矩陣,由於它最後一行爲(0,0,1) code

A=⎛⎝⎜a11a210a12a220a13a2311⎞⎠⎟A=(a11a12a13a21a22a230011)orm

平移
平移是最簡單的仿射變換如將空間座標(x,y)沿着x軸移動100,沿着y軸移動200。平移後的座標爲(x+100,y+200)。將這個過程通常化後,假設任意的空間座標(x,y)先沿着x軸平移Px再沿着y軸平移Py。獲得的座標爲(x+Px,y+Py)。用矩陣表示這個平移過程爲: blog

⎛⎝⎜x¯¯¯y¯¯¯1⎞⎠⎟=⎛⎝⎜100010PxPy1⎞⎠⎟⎛⎝⎜xy1⎞⎠⎟(x¯y¯1)=(10Px01Py001)(xy1)ip

對於Px和Py若大於0則表示沿着軸正向移動,若小於0則表示沿着軸負向移動。
放大縮小
在座標軸中以原點爲中心的放大與縮小S倍是指對其x軸方向的橫座標放縮成原座標的橫座標距離中心點(0,0)的距離的S倍並對其y軸方向的橫座標放縮成原座標的縱座標距離原點的距離的S倍。其中若S大於1則表示增大,若小於1則表示縮小。放縮在矩陣中的表示爲: rem

⎛⎝⎜x¯¯¯y¯¯¯1⎞⎠⎟=⎛⎝⎜sx000sy0001⎞⎠⎟⎛⎝⎜xy1⎞⎠⎟(x¯y¯1)=(sx000sy0001)(xy1)

座標(x,y)在座標軸中以任意一點的座標(x0,y0)爲中心在水平和垂直方向上放縮S倍,放縮後的座標爲

((x0+Sx(x−x0),y0+Sy(y−y0))((x0+Sx(x−x0),y0+Sy(y−y0))

用矩陣能夠表示爲:

⎛⎝⎜x¯¯¯y¯¯¯1⎞⎠⎟=⎛⎝⎜100010X0Y01⎞⎠⎟⎛⎝⎜sx000sy0001⎞⎠⎟⎛⎝⎜100010−X0−Y01⎞⎠⎟⎛⎝⎜xy1⎞⎠⎟(x¯y¯1)=(10X001Y0001)(sx000sy0001)(10−X001−Y0001)(xy1)

座標(x,y)繞原點順時針旋轉α(α>0),cosΘ=x/p sinΘ=y/p.其中p表明(x,y)到中心點(0,0)的距離。則
cos(Θ+α)=cosΘcosα-sinΘsinα=(x/p)cosα -(y/p)sinα=Ex/p
sin(Θ+α)=sinΘcosα+cosΘsinα=(y/p)cosα -(y/p)sinα=Ey/p
化解以上公式,使用矩陣表示爲:

⎛⎝⎜x¯¯¯y¯¯¯1⎞⎠⎟=⎛⎝⎜cosαsinα0−sinαcosα0001⎞⎠⎟⎛⎝⎜xy1⎞⎠⎟(x¯y¯1)=(cosα−sinα0sinαcosα0001)(xy1)

放射矩陣的計算
若是已知座標以及其放射變換後的矩陣,從而計算出變換後的座標,就須要放射矩陣的計算,主要的實現方法有:方程法,矩陣法,插值算法。在OpenCV中有對應的實現函數,如使用方程法:cv2.getAffineTransform(src,dst) 該方法就是經過計算參數src到dst的對應仿射變換的矩陣,其中參數src和dst分別表明原座標和變換後的座標,而且均爲3行2列的二維ndarray,數據必須爲浮點型。實現代碼:

import numpy as np

src=np.array([[0,0],[200,0],[0,200]],np.float32)
dst=np.array([[0,0],[100,0],[0,100]],np.float32)
A=cv2.getAffineTransform(src,dst)

print(A)

運行結果:

在矩陣法中,須要預先知道具體的變化步驟,好比先放大再平移仍是先移動再放大

⎛⎝⎜x¯¯¯y¯¯¯1⎞⎠⎟=⎛⎝⎜100010X0Y01⎞⎠⎟⎛⎝⎜sx000sy0001⎞⎠⎟⎛⎝⎜xy1⎞⎠⎟(x¯y¯1)=(10X001Y0001)(sx000sy0001)(xy1)

以上的矩陣變換就是平移仿射矩陣乘以縮放仿射矩陣獲得的而不是縮放仿射矩陣乘以平移仿射矩陣獲得的,因爲等式是由右向左運行,因此必需要知道變化順序。矩陣的乘法並非矩陣的點乘,再Numpy中乘法是經過dot函數實現的,關於Numpy語法能夠參考我以前寫的博文。咱們經過一個實例來了解矩陣的乘法計算。
假設先對一矩陣等比例放大二倍,而後水平與垂直方向上分別平移100,計算該矩陣的算法以下:

import numpy as np

#先對矩陣進行放大
s=np.array([[2,0,0],[0,2,0],[0,0,1]])
#再對矩陣進行平移
t=np.array([[1,0,100],[0,1,100],[0,0,1]])
#矩陣相乘
A=np.dot(t,s)
print(A)

運行結果:

必定要注意傳入dot參數的順序。
下面介紹插值算法,咱們能夠將圖像理解爲一個二維的函數,行數爲H,列數爲W的圖像矩陣I:Z=F(x,y), 0<=x<W,0<=y<H,x⊆N,y⊆N
矩陣的列號對應x座標,垂直方向爲y軸,行號對應y座標,稱該函數爲圖像函數。
利用已知的整數座標處的函數值估算非整數座標處的函數值的方法主要有:最近鄰插值(就是從四個相鄰整數座標中找到一個最近的)輸出的圖像通過放大後會有鋸齒狀的外觀。雙線性插值法有兩個變量的插值函數的線性插值擴展,其核心是在兩個方向分別進行一次線性插值。待插點像素值取原圖像中與其相鄰的4個點像素值的水平、垂直兩個方向上的線性內插,即根據待採樣點與周圍4個鄰點的距離肯定相應的權重,從而計算出待採樣點的像素值。有的時候須要更高階的插值函數,如三次樣條插值、Lengendre中心函數和sin(axs)函數,高階插值經常使用二維離散卷積運算來實現。後續博客會對二維離散卷積運算作詳細的描述。
對於雙線性插值法在這表一次形象化的描述:


如圖:先估計f1在(x,[y])處的函數值,再估計f1在(x,[y]+1)處的函數值,最後估計f1在(x,y)處的函數值

對於空間座標變換和插值方法在已知的仿射變換矩陣上OpenV提供了warpAffine(src,M,dsize[,flags[,borderMode[,borderValue ]]])函數

參數

釋義

src

圖像矩陣

M

2行3列的仿射變換矩陣

dsize

一個二元元組,輸出圖像的大小

flags

插值法:INTE_NEAREST、INTE_LINEAR(默認)等

borderMode

填充模式,如:BORDER_CONSTANT等

borderValue

當borderMode=BORDER_CONSTANT時的填充值

下面使用python實現圖像的幾何變換:

import numpy as np
import cv2
import sys
import math

img=cv2.imread('yun.jpg',cv2.IMREAD_GRAYSCALE)
cv2.imwrite('yun.jpg',img)
#原圖的寬高
h,w=img.shape[:2]
#仿射變換矩陣 縮小2倍
A1=np.array([[0.5,0,0],[0,0.5,0]],np.float32)
A2=cv2.warpAffine(img,A1,(w,h),borderValue=126)
#縮小後平移
B1=np.array([[0.5,0,w/4],[0,0.5,h/4]],np.float32)
B2=cv2.warpAffine(img,B1,(w,h),borderValue=126)
#使圖像旋轉
C1=cv2.getRotationMatrix2D((w/2.0,h/2.0),30,1)
C2=cv2.warpAffine(img,C1,(w,h),borderValue=126)

cv2.imshow('img',img)
cv2.imshow('A2',A2)
cv2.imshow('B2',B2)
cv2.imshow('C2',C2)
cv2.waitKey(0)
cv2.destroyAllWindows()

運行效果

參考文獻:
【1】ROBERT G.KEYS.Cubic Convolution Interpolation for Digital Image Processing.IEEE TRANSACTIONS ON ACOUSTICS.SPEECH,AND SIGNAL PROCESSING,1981
【2】R. Hartley and A. Zisserman, 「Multiple View Geometry in Computer Vision,」 2-nd edition, Cambridge University Press, 2004.

今天就先寫到這吧!投影變換和極座標變換後續再寫

相關文章
相關標籤/搜索