Opencv中幾何變換

幾何變換

OpenCV 提供了兩個變換函數(shù),cv2.warpA?ne 和 cv2.warpPerspective,使用這兩個函數(shù)你可以實現(xiàn)所有類型的變換。cv2.warpA?ne 接收的參數(shù)是2 x 3 的變換矩陣,而 cv2.warpPerspective 接收的參數(shù)是 3 x 3 的變換矩陣。

1.尺度變換

尺度變換(縮放,拉伸)是調(diào)整圖像大小,使其變大或變小。但實際操作時要比想象的復(fù)雜一些,因為調(diào)整大小帶來了像素如何插值(放大)或合并(減少)的問題。

cv2.resize(src,dsize,fx=0,fy=0,interpolation=cv2.INTER_LINEAR)

作用:根據(jù)設(shè)置調(diào)整圖像為指定大小,其中有兩種指定方式:① 絕對尺寸:通過dsize直接設(shè)置;② 相對尺寸:dsize設(shè)置為None,然后將fx和fy設(shè)置為我們想要的比例因子即可。

插值方法

插值 含義
cv2.INTER_LINEAR 雙線性插值法
cv2.INTER_NEAREST 最近鄰插值
cv2.INTER_AREA 像素區(qū)域重采樣(默認(rèn))
cv2.INTER_CUBIC 雙三次插值
cv2.INTER_LANCZ0S4 插值(超過8×8個鄰域)

例子

img1 = cv2.imread("beautiful-beauty-brunette-2147192.jpg")

# 絕對尺寸
height,width = img1.shape[:2]
res = cv2.resize(img1,(2*width,2*height),interpolation=cv2.INTER_CUBIC)

# 相對尺寸
res1 = cv2.resize(img1,None,fx=0.5,fy=0.5)

# 圖像顯示
plt.figure(figsize=(10,8),dpi=100)
plt.subplot(231)
img_show('原圖',img1)
plt.subplot(232)
img_show('絕對尺度(放大)',res)
plt.subplot(233)
img_show('相對尺度(縮小)',res1)
尺度變換.png

2.平移變換

平移就是將對象換一個位置。如果你要沿(x,y)方向移動,移動的距離是(t_{x}, t_{y}),你可以以下面的方式構(gòu)建移動矩陣:
M=\left[\begin{array}{lll}{1} & {0} & {t_{x}} \\ {0} & {1} & {t_{y}}\end{array}\right]

cv2.warpAffine(src, M, dsize)
  • src:輸入圖像
  • M:移動矩陣
  • dsize:輸出圖像大小

注意:第三個參數(shù)的是輸出圖像的大小,它的格式應(yīng)該是圖像的(寬,高)。應(yīng)該記住的是圖像的寬對應(yīng)的是列數(shù),高對應(yīng)的是行數(shù)。

img1 = cv2.imread("beautiful-beauty-brunette-2147192.jpg")
tx = 500
ty = 1000

M = np.float32([[1,0,tx],[0,1,ty]])
dst = cv2.warpAffine(img1,M,(img1.shape[1]+tx,img1.shape[0]+ty))

tx = 500
ty = 200
M = np.float32([[1,0,tx],[0,1,ty]])
dst1 = cv2.warpAffine(img1,M,(3000,4000))

plt.figure(figsize=(10,8),dpi=100)
plt.subplot(231)
img_show('原圖',img1)
plt.subplot(232)
img_show('平移(右移500,下移1000)',dst)
plt.subplot(233)
img_show('平移(右移500,下移200)',dst1)
平移變換.png

例子

import cv2
import matplotlib.pyplot as plt
import numpy as np


def cv_show(name,img):
    """圖像顯示函數(shù)
    name:字符串,窗口名稱
    img:numpy.ndarray,圖像
    """
    cv2.namedWindow(name,cv2.WINDOW_NORMAL)
    cv2.imshow(name,img)
    cv2.waitKey(0)
    cv2.destroyAllWindows()

    
if __name__=="__main__":

    #img1 = cv2.imread("lenaNoise.png")
    img1 = cv2.imread("attractive-beautiful-beauty-2267088.jpg")
    
    
    tx = 100
    ty = 150
     
    M = np.float32([[1,0,tx],[0,1,ty]])
     
    dst = cv2.warpAffine(img1,M,(img1.shape[0],img1.shape[1]))
       
    cv_show('translation',dst)
平移.jpg

3.旋轉(zhuǎn)變換

對一個圖像旋轉(zhuǎn)角度 θ, 需要使用到下面形式的旋轉(zhuǎn)矩陣。
M=\left[\begin{array}{cc}{\cos \theta} & {-\sin \theta} \\ {\sin \theta} & {\cos \theta}\end{array}\right]
但是 OpenCV 允許你在任意地方進(jìn)行旋轉(zhuǎn),但是旋轉(zhuǎn)矩陣的形式應(yīng)該修改為
M=\left[\begin{array}{ccc}{\alpha} & {\beta} & {(1-\alpha) \cdot \text { center } x-\beta \cdot \text { centery }} \\ {-\beta} & {\alpha} & {\beta \cdot \text { centerx }+(1-\alpha) \cdot \text { centerx }}\end{array}\right]
其中:
\begin{aligned} \alpha &=s c a l e \cdot \cos \theta \\ \beta &=s c a l e \cdot \sin \theta \end{aligned}
為了構(gòu)建這個旋轉(zhuǎn)矩陣,OpenCV 提供了一個函數(shù):cv2.getRotationMatrix2D。

cv2.getRotationMatrix2D(center, angle, scale)
cv2.warpAffine(src, M, dsize[, dst[, flags[, borderMode[, borderValue]]]]) → dst

參數(shù)說明:

  • getRotationMatrix2D:
  • center–表示旋轉(zhuǎn)的中心點
  • angle–表示旋轉(zhuǎn)的角度degrees
  • scale–圖像縮放因子

warpAffine:

  • src – 輸入的圖像
  • M – 2 X 3 的變換矩陣.
  • dsize – 輸出的圖像的size大小
  • dst – 輸出的圖像
  • flags – 輸出圖像的插值方法(參考尺度變換)
  • borderMode – 圖像邊界的處理方式

旋轉(zhuǎn)任意角度的步驟
1.讀取圖像

2.使用getRotationMatrix2D函數(shù)求取旋轉(zhuǎn)矩陣M,使用warpAffine函數(shù)對圖像進(jìn)行旋轉(zhuǎn)

3.顯示圖像

例子:在不縮放的情況下將圖像旋轉(zhuǎn) 90 度。

import cv2
import matplotlib.pyplot as plt
import numpy as np


def cv_show(name,img):
    """圖像顯示函數(shù)
    name:字符串,窗口名稱
    img:numpy.ndarray,圖像
    """
    cv2.namedWindow(name,cv2.WINDOW_NORMAL)
    cv2.imshow(name,img)
    cv2.waitKey(0)
    cv2.destroyAllWindows()


if __name__=="__main__":

    #img1 = cv2.imread("lenaNoise.png")
    img1 = cv2.imread("cute-dog.jpg")
    
    rows,cols = img1.shape[:2]
    
    # 這里的第一個參數(shù)為旋轉(zhuǎn)中心,第二個為旋轉(zhuǎn)角度,第三個為旋轉(zhuǎn)后的縮放因子
    # 可以通過設(shè)置旋轉(zhuǎn)中心,縮放因子,以及窗口大小來防止旋轉(zhuǎn)后超出邊界的問題
    M = cv2.getRotationMatrix2D((cols/2,rows/2),90,1)
   
    dst = cv2.warpAffine(img1,M,(cols,rows))
       
    cv_show('translation',dst)
旋轉(zhuǎn)90度.jpg

例子

import cv2
import matplotlib.pyplot as plt
import numpy as np


def img_show(name,img):
    """matplotlib圖像顯示函數(shù)
    name:字符串,圖像標(biāo)題
    img:numpy.ndarray,圖像
    """
    if len(img.shape) == 3:
        img = cv2.cvtColor(img,cv2.COLOR_BGR2RGB)
    plt.imshow(img,'gray')
    #plt.xticks([])
    #plt.yticks([])
    plt.xlabel(name,fontproperties='FangSong',fontsize=12)
    

if __name__=="__main__":

    #img1 = cv2.imread("lenaNoise.png")
    img1 = cv2.imread("cute-dog.jpg")
    
    rows,cols = img1.shape[:2]
    
    #將圖像放到圖像大小的兩倍畫布中,將圖像移動的畫布中心
    maxBorder =int(max(cols*2, rows*2))
    tx = (maxBorder-cols)/2
    ty = (maxBorder-rows)/2 
    M = np.float32([[1,0,tx],[0,1,ty]])
    img2 = cv2.warpAffine(img1,M,(maxBorder,maxBorder))
    
    # 這里的第一個參數(shù)為旋轉(zhuǎn)中心,第二個為旋轉(zhuǎn)角度,第三個為旋轉(zhuǎn)后的縮放因子
    # 可以通過設(shè)置旋轉(zhuǎn)中心,縮放因子,以及窗口大小來防止旋轉(zhuǎn)后超出邊界的問題
    M = cv2.getRotationMatrix2D((maxBorder/2,maxBorder/2),45,1)
    dst = cv2.warpAffine(img2,M,(maxBorder,maxBorder))
    
    
    plt.figure(figsize=(10,8),dpi=80)
    plt.subplot(231)
    img_show('原圖',img1)
    plt.subplot(232)
    img_show('平移到畫布中心',img2)
    plt.subplot(233)
    img_show('旋轉(zhuǎn)45度',dst)
x.png

4.翻轉(zhuǎn)

翻轉(zhuǎn)通過函數(shù)flip實現(xiàn):

函數(shù)說明:

cv2.flip(src, flipCode[, dst]) → dst1

參數(shù)說明:

  • src – 輸入的圖像

  • dst – 輸出的圖像

  • flipCode – 翻轉(zhuǎn)模式:

    flipCode==0垂直翻轉(zhuǎn)(沿X軸翻轉(zhuǎn))

    flipCode>0水平翻轉(zhuǎn)(沿Y軸翻轉(zhuǎn))

    flipCode<0水平垂直翻轉(zhuǎn)(先沿X軸翻轉(zhuǎn),再沿Y軸翻轉(zhuǎn),等價于旋轉(zhuǎn)180°)

例子

import cv2
import matplotlib.pyplot as plt
import numpy as np

def img_show(name,img):
    """matplotlib圖像顯示函數(shù)
    name:字符串,圖像標(biāo)題
    img:numpy.ndarray,圖像
    """
    if len(img.shape) == 3:
        img = cv2.cvtColor(img,cv2.COLOR_BGR2RGB)
    plt.imshow(img,'gray')
    plt.xticks([])
    plt.yticks([])
    plt.xlabel(name,fontproperties='FangSong',fontsize=12)
    

if __name__=="__main__":

    #img1 = cv2.imread("lenaNoise.png")
    img1 = cv2.imread("cute-dog.jpg")
    
    # 水平翻轉(zhuǎn)
    flip_horiz_img = cv2.flip(img1, 1)
    # 垂直翻轉(zhuǎn)
    flip_verti_img = cv2.flip(img1, 0)
    # 水平垂直翻轉(zhuǎn)
    flip_horandver_img = cv2.flip(img1, -1)

    plt.figure(figsize=(8,12),dpi=80)
    plt.subplot(221)
    img_show('原圖',img1)
    plt.subplot(222)
    img_show('水平翻轉(zhuǎn)',flip_horiz_img)
    plt.subplot(223)
    img_show('垂直翻轉(zhuǎn)',flip_verti_img)
    plt.subplot(224)
    img_show('水平垂直翻轉(zhuǎn)',flip_horandver_img)
翻轉(zhuǎn).png

5.仿射變換

圖像的仿射變換涉及到圖像的形狀位置角度的變化,是深度學(xué)習(xí)預(yù)處理中常到的功能,在此簡單回顧一下。仿射變換具體到圖像中的應(yīng)用,主要是對圖像的縮放scale,旋轉(zhuǎn)rotate,剪切shear,翻轉(zhuǎn)flip和平移translate的組合。在OpenCV中,仿射變換的矩陣是一個2×3的矩陣,其中左邊的2×2子矩陣是線性變換矩陣,右邊的2×1的兩項是平移項:
\begin{array}{l}{A=\left[\begin{array}{ll}{a_{00}} & {a_{01}} \\ {a_{10}} & {a_{11}}\end{array}\right], B=\left[\begin{array}{l}{b_{0}} \\ {b_{1}}\end{array}\right]} \\ {M=\left[\begin{array}{ll}{A} & {B}\end{array}\right]=\left[\begin{array}{lll}{a_{00}} & {a_{01}} & {b_{0}} \\ {a_{10}} & {a_{11}} & {b_{1}}\end{array}\right]}\end{array}
對于圖像上的任一位置(x,y),仿射變換執(zhí)行的是如下的操作:
T_{a f f i n e}=A\left[\begin{array}{l}{x} \\ {y}\end{array}\right]+B=M\left[\begin{array}{l}{x} \\ {y} \\ {1}\end{array}\right]
需要注意的是,對于圖像而言,寬度方向是x,高度方向是y,坐標(biāo)的順序和圖像像素對應(yīng)下標(biāo)一致。所以原點的位置不是左下角而是右上角,y的方向也不是向上,而是向下。

在仿射變換中,原圖中所有的平行線在結(jié)果圖像中同樣平行。為了創(chuàng)建這個矩陣我們需要從原圖像中找到三個點以及他們在輸出圖像中的位置。然后cv2.getA?neTransform 會創(chuàng)建一個 2x3 的矩陣,最后這個矩陣會被傳給函數(shù) cv2.warpA?ne。

例子

import cv2
import matplotlib.pyplot as plt
import numpy as np

def img_show(name,img):
    """matplotlib圖像顯示函數(shù)
    name:字符串,圖像標(biāo)題
    img:numpy.ndarray,圖像
    """
    if len(img.shape) == 3:
        img = cv2.cvtColor(img,cv2.COLOR_BGR2RGB)
    plt.imshow(img,'gray')
    plt.xticks([])
    plt.yticks([])
    plt.xlabel(name,fontproperties='FangSong',fontsize=12)
    

if __name__=="__main__":

    #img1 = cv2.imread("lenaNoise.png")
    img1 = cv2.imread("cute-dog.jpg")
    rows,cols = img1.shape[:2]
    
    pts1 = np.float32([[500,500],[2000,500],[500,2000]])
    pts2 = np.float32([[100,1000],[2000,500],[1000,2500]])
    M = cv2.getAffineTransform(pts1,pts2)
    img2 = cv2.warpAffine(img1,M,(rows,cols))
    
    plt.figure(figsize=(10,8),dpi=80)
    plt.subplot(221)
    img_show('原圖',img1)
    plt.subplot(222)
    img_show('仿射變換',img2)
仿射變換.png

6.透視變換

對于視角變換,我們需要一個 3x3 變換矩陣。在變換前后直線還是直線。要構(gòu)建這個變換矩陣,你需要在輸入圖像上找 4 個點,以及他們在輸出圖像上對應(yīng)的位置。這四個點中的任意三個都不能共線。這個變換矩陣可以有
函數(shù) cv2.getPerspectiveTransform() 構(gòu)建。然后把這個矩陣傳給函數(shù)cv2.warpPerspective。

例子

import cv2
import matplotlib.pyplot as plt
import numpy as np

def img_show(name,img):
    """matplotlib圖像顯示函數(shù)
    name:字符串,圖像標(biāo)題
    img:numpy.ndarray,圖像
    """
    if len(img.shape) == 3:
        img = cv2.cvtColor(img,cv2.COLOR_BGR2RGB)
    plt.imshow(img,'gray')
    plt.xticks([])
    plt.yticks([])
    plt.xlabel(name,fontproperties='FangSong',fontsize=12)
    

if __name__=="__main__":

    #img1 = cv2.imread("lenaNoise.png")
    img1 = cv2.imread("cute-dog.jpg")
    


    rows,cols = img1.shape[:2]
    
    pts1 = np.float32([[200,200],[200,3000],[4800,200],[4800,3000]])
    pts2 = np.float32([[200,200],[200,3000],[4800,600],[4800,2000]])
    M = cv2.getPerspectiveTransform(pts1,pts2)
    dst=cv2.warpPerspective(img1,M,(cols,rows),0.6)
        
    plt.figure(figsize=(10,8),dpi=80)
    plt.subplot(121)
    img_show('原圖',img1)
    plt.subplot(122)
    img_show('透視變換',dst)
透視變換.png

參考資料
網(wǎng)址:https://blog.csdn.net/zh_jessica/article/details/77946346
書籍:《數(shù)字圖像處理》《OpenCV-Python-Toturial-中文版》

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容