opencv 圖像幾何變換基礎講解——含仿射和透射變換基礎

                         QQ:3020889729                                                                                 小蔡

實現原理

毫無疑問,一個個圖像——本質就是一個個多維數組,它包含像素點的排布,以及像素點的信息。
既然多維數組,我們將圖像中前兩維度——對應行列,當作一個矩陣進行處理。
第一維——也就是對應着行;第二維——也就是對應着列。
舉例:將一個多維數組當作矩陣
[[1, 2, 3]
[4, 5, 6]
[7, 8, 9]]
這裏應該能明白:第一維的每一個元素是一個list,且等大,每一個list作爲一個行,list裏邊的元素——就一一對應着屬於列。

實現函數

opencv提供的矩陣(圖像)轉換函數有兩個:
cv.warpAffine()——對應23的矩陣轉換——可以實現平移和翻轉(反轉還需要一個cv.getRotationMatrix2D來獲取旋轉後的移動座標),以及仿射變換——getAffineTransform
cv.warpPerspective()——對應3
3的矩陣轉換——可以應用透射變換
以及一個圖像大小按比例修改的函數:cv.resize()

warpAffine——參數

  • 參數一:輸入圖像
  • 參數二:平移矩陣——list類型
  • 參數三:輸出圖像大小(採用元組(寬值,高值))
  • 參數四:bordermode——邊界值處理——控制輸出圖像與原圖像異常值是否處理,如何處理的參數
  • 參數五:bordervalue邊界值——一般默認爲0不處理
  • 說明——參數四五,在簡單應用中不涉及,這裏就不細講了,後邊會慢慢整理進階的。
    在這裏插入圖片描述
    平移時——你應該知道移動的x,y值,並滿足以上矩陣:(也就是把x,y值放在這個位置——創建這樣的矩陣採用numpy實現)——採用numpy.float32創建

getRotationMatrix2D——參數

opencv使用該函數實現了任一點旋轉的方法——並且返回一個warpAffine的平移參數矩陣(2*3)

  • 參數一:旋轉中心位置座標(採用二元元組傳入)
  • 參數二:旋轉角度——正值爲逆時針旋轉角度
  • 參數三:縮放比例——一般不變傳入1即可

cv.getAffineTransform——參數

opencv使用該函數實現了通過取圖像三點以及變化後的對應位置,來實現變換的方法——並且返回一個warpAffine的平移參數矩陣(2*3)——實現仿射變換

  • 參數一:變化前的三個點的矩陣——list類型採用numpy.float32創建
  • 參數二:變化後的三個點的矩陣——list類型

warpPerspective——參數

cv.warpPerspective實現透射變換——所以需要對空間有一個座標——也就是對應着23到33矩陣變化的需要——當然實現透射變換還需要一個函數的幫助,來獲取這樣的移動參數矩陣

  • 參數一:輸入圖像
  • 參數二:移動(變換)參數
  • 參數三:輸出圖像大小
  • 參數四:插值方式
  • 參數五六與warpAffine一樣,都是對變換的邊界進行處理的參數設置

cv.getPerspectiveTransform——參數

該函數爲透色變換提供移動參數——一個3*3的移動參數矩陣。
而這樣的參數,來源於原圖像中的4個點座標,以及設置的改變後對應的座標

  • 參數一:原圖像四個座標——list類型採用numpy.float32創建
  • 參數二:變換後的座標——list類型

resize——參數

  • 參數一:輸入圖像
  • 參數二:輸出大小——設置輸出大小(二元元組)
  • 參數三:x伸展比例——參數二有具體大小,不爲None時,x,y伸展不用填寫,是無效的
  • 參數四:y伸展比例——也就是說,選擇一種伸縮方式即可
  • 參數五:插值
  • 常見插值爲:
  • cv.INTER_AREA——用於縮小
  • cv.INTER_LINEAR——用於縮放(放大/縮小都可以)
  • cv.INTER_CUBIC——用於低分辨率

代碼實例

縮放

這裏不要設置窗體可調——不然會顯示不出來伸縮變換的。

import cv2 as cv
import numpy as np


if __name__ == "__main__":
    img = cv.imread('../imag_in_save/open_class.png')
    # cv.namedWindow('imag', cv.WINDOW_NORMAL)

    img_size_h, img_size_w = img.shape[:2]  # 獲取形狀大小——即第一位爲行數,第二位爲列數
    res = cv.resize(img, (img_size_w*1, img_size_h*3), interpolation=cv.INTER_CUBIC)
    # 高度變爲3倍
    # 除了這樣的操作外,還可以如此
    # res = cv.resize(img, None, fx=1, fy=3, interpolation=cv.INTER_CUBIC)
    cv.imshow('imag', res)
    cv.waitKey(0)
    cv.destroyAllWindows()

效果:伸縮變換前
在這裏插入圖片描述
伸縮變換後
在這裏插入圖片描述

平移

import cv2 as cv
import numpy as np


if __name__ == "__main__":
    img = cv.imread('../imag_in_save/open_class.png')

    img_size_h, img_size_w = img.shape[:2]  # 獲取形狀大小——即第一位爲行數,第二位爲列數
    move_value = np.float32([[1, 0, 66], [0, 1, 66]])  # 前面的公式可知:這裏是移動x = 66, y = 66
    res = cv.warpAffine(img, move_value, (img_size_w, img_size_h))

    cv.imshow('imag', res)
    cv.waitKey(0)
    cv.destroyAllWindows()

效果:
在這裏插入圖片描述

翻轉(或者說叫做2D平移旋轉)

import cv2 as cv
import numpy as np


if __name__ == "__main__":
    img = cv.imread('../imag_in_save/open_class.png')
    # cv.namedWindow('imag', cv.WINDOW_NORMAL)

    img_size_h, img_size_w = img.shape[:2]  # 獲取形狀大小——即第一位爲行數,第二位爲列數
    move_value = cv.getRotationMatrix2D((img_size_w/2.0, img_size_h/2.0), 90, 1)  # 獲取旋轉後的移動座標矩陣
    res = cv.warpAffine(img, move_value, (img_size_w, img_size_h))  # 實現平移旋轉

    cv.imshow('imag', res)
    cv.waitKey(0)
    cv.destroyAllWindows()

效果:
在這裏插入圖片描述

仿射變換

import cv2 as cv
import numpy as np

if __name__ == "__main__":
    img = cv.imread('../imag_in_save/open_class.png')

    img_size_h, img_size_w = img.shape[:2]  # 獲取形狀大小——即第一位爲行數,第二位爲列數

    pst1 = np.float32([[20, 30], [50, 100], [100, 100]])  # 原圖像的點座標
    pst2 = np.float32([[40, 30], [50, 100], [80, 120]])  # 原點一一對應的變換點座標
    move_value = cv.getAffineTransform(pst1, pst2)  # 獲取仿射變換的平移座標
    res = cv.warpAffine(img, move_value, (img_size_w, img_size_h))  # 實現平移——得到仿射變換的圖形
    cv.imshow('res_imag', res)  # 顯示變化後的圖形
    cv.imshow('imag', img)  # 顯示原圖形
    cv.waitKey(0)
    cv.destroyAllWindows()

效果:
在這裏插入圖片描述

投射變換(可以用來解決拍攝的圖形不平整進行平整變化的轉換)

import cv2 as cv
import numpy as np

if __name__ == "__main__":
    img = cv.imread('../imag_in_save/open_class.png')

    img_size_h, img_size_w = img.shape[:2]  # 獲取形狀大小——即第一位爲行數,第二位爲列數
	pst1 = np.float32([[56, 65], [368, 52], [28, 387], [389, 390]])  # 需要四個點座標_要求三個點不共線,# 將四點間內容作爲顯示內容
    pst2 = np.float32([[0, 0], [300, 0], [0, 300], [300, 300]])  # 四點的座標變化
    move_value = cv.getPerspectiveTransform(pst1, pst2)  # 獲取投射變換的平移座標
    res = cv.warpPerspective(img, move_value, (300, 300))  # 獲取投射變換的圖形——大小盡量與變化後的四點座標等大寬度
    cv.imshow('res_imag', res)
    cv.imshow('imag', img)
    cv.waitKey(0)
    cv.destroyAllWindows()

效果:操作前後——如果圖形是2d平整的,可能就會編程內凹或者其它的一些畸變。
以下圖形實現通過透視變換,得到更平整的圖像
視角變淺
在這裏插入圖片描述
在這裏插入圖片描述
**我的效果:**確實有透視的視角變深等變化
在這裏插入圖片描述

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章