一.作用
透視變換是將圖像從一個視平面投影到另外一個視平面的過程,所以透視變換也被稱為投影映射(Projection Mapping)。我們知道在圖像的仿射變換中需要變換矩陣是一個2x3的兩維平面變換矩陣,而透視變換本質上空間立體三維變換,根據其次坐標方差,要把三維坐標投影到另外一個視平面,就需要一個完全不同的變換矩陣M,所以這個是透視變換跟OpenCV中幾何仿射變換最大的不同。
常用的應用場景如將放在桌面的文檔用OCR得到其文字,需要進行透視變換把這張紙“放正”
二.原理
參考博客:https://blog.csdn.net/zhangjunp3/article/details/80036310
u,v是原始圖片左邊,對應得到變換后的圖片坐標x,y,其中。
變換矩陣可以分作四部分來理解,
表示線性變換,
表示平移,
產生透視,
所以可以理解成仿射等是透視變換的特殊形式。經過透視變換之后的圖片通常不是平行四邊形(除非映射視平面和原來平面平行的情況)。
重寫之前的變換公式可以得到:
所以,已知變換對應的幾個點就可以求取變換公式。反之,特定的變換公式也能新的變換后的圖片。簡單的看一個正方形到四邊形的變換:
根據變換公式得到:
定義幾個輔助變量:
都為0時變換平面與原來是平行的,可以得到:
不為0時,得到
求解出的變換矩陣就可以將一個正方形變換到四邊形。反之,四邊形變換到正方形也是一樣的。於是,我們通過兩次變換:四邊形變換到正方形+正方形變換到四邊形就可以將任意一個四邊形變換到另一個四邊形。
三.示例
原圖,要把發票放正:
代碼:
1 import cv2 2 import matplotlib.pyplot as plt 3 import numpy as np 4 5 if __name__ == '__main__': 6 img = cv2.imread('../pics/10.png', 0) 7 img = cv2.GaussianBlur(img, (5, 5), 0) 8 9 edge = cv2.Canny(img, 40, 180) 10 contours, hierarchy = cv2.findContours(edge, cv2.RETR_TREE, cv2.CHAIN_APPROX_NONE) 11 12 tmp = np.zeros(img.shape, np.uint8) 13 draw_cnt = [] 14 arcs = [] 15 for c in contours: 16 arc = cv2.arcLength(c, False) 17 arcs.append(arc) 18 19 draw_cnt.append(contours[arcs.index(max(arcs))]) 20 cv2.drawContours(tmp, draw_cnt, -1, (250, 255, 255), 2) 21 22 approx = cv2.approxPolyDP(draw_cnt[0], 10, True) # 近似多邊形,10為精度,調這個參數使邊數為4 23 24 approx_point1 = approx.reshape(4, 2).astype(np.float32) 25 26 plane = np.array([[0, 0], [0, 600], [400, 600], [400, 0]], dtype="float32") # 投影到400*600的面上 27 28 M = cv2.getPerspectiveTransform(approx_point1, plane) 29 out_img = cv2.warpPerspective(img, M, (400, 600)) 30 dst = cv2.perspectiveTransform(plane.reshape(1, 4, 2), M) 31 32 transformed = cv2.resize(out_img, (400, 600)) 33 34 cv2.imshow('edge', transformed) 35 36 cv2.waitKey()
效果: