原文連結:
4 Point OpenCV getPerspective Transform Example - PyImageSearchwww.pyimagesearch.com
本篇文章介紹使用OpenCV的
cv2.getPerspectiveTransform
函數實作四點透視變換。
在文章中我提到可以使用透視變換來得到自上而下的“鳥瞰”圖,前提是要能找到參考點。
這篇文章繼續讨論自上而下的“鳥瞰”圖,但是這次我将要我分享在我每次需要做四點透視變換時都要用到的代碼。
# transform.py
import numpy as np
import cv2
def order_points(pts):
# initialzie a list of coordinates that will be ordered
# such that the first entry in the list is the top-left,
# the second entry is the top-right, the third is the
# bottom-right, and the fourth is the bottom-left
rect = np.zeros((4, 2), dtype = "float32")
# the top-left point will have the smallest sum, whereas
# the bottom-right point will have the largest sum
s = pts.sum(axis = 1)
rect[0] = pts[np.argmin(s)]
rect[2] = pts[np.argmax(s)]
# now, compute the difference between the points, the
# top-right point will have the smallest difference,
# whereas the bottom-left will have the largest difference
diff = np.diff(pts, axis = 1)
rect[1] = pts[np.argmin(diff)]
rect[3] = pts[np.argmax(diff)]
# return the ordered coordinates
return rect
定義一個
order_points
函數,需要傳入參數
pts
,是一個包含矩形四個點的(x, y)坐标的清單。
對矩形中的四個點進行 一緻的排序 是非常重要的,實際的排序可以是任意的,隻要它在整個實作過程中是一緻的。
對于我來說,我習慣将點按照 “左上,右上,右下,左下” 進行排序。
代碼裡使用
np.zeros
為四個點配置設定記憶體。根據 x 與 y 之和最小找到左上角的點,x 與 y 之和最大找到右下角的點。
然後使用
np.diff
函數,根據 x 與 y 之差(y-x)最小找到右上角的點,x 與 y 之差最大找到左下角的點。
最後将排好序的點傳回給調用函數。
def four_point_transform(image, pts):
# obtain a consistent order of the points and unpack them
# individually
rect = order_points(pts)
(tl, tr, br, bl) = rect
# compute the width of the new image, which will be the
# maximum distance between bottom-right and bottom-left
# x-coordiates or the top-right and top-left x-coordinates
widthA = np.sqrt(((br[0] - bl[0]) ** 2) + ((br[1] - bl[1]) ** 2))
widthB = np.sqrt(((tr[0] - tl[0]) ** 2) + ((tr[1] - tl[1]) ** 2))
maxWidth = max(int(widthA), int(widthB))
# compute the height of the new image, which will be the
# maximum distance between the top-right and bottom-right
# y-coordinates or the top-left and bottom-left y-coordinates
heightA = np.sqrt(((tr[0] - br[0]) ** 2) + ((tr[1] - br[1]) ** 2))
heightB = np.sqrt(((tl[0] - bl[0]) ** 2) + ((tl[1] - bl[1]) ** 2))
maxHeight = max(int(heightA), int(heightB))
# now that we have the dimensions of the new image, construct
# the set of destination points to obtain a "birds eye view",
# (i.e. top-down view) of the image, again specifying points
# in the top-left, top-right, bottom-right, and bottom-left
# order
dst = np.array([
[0, 0],
[maxWidth - 1, 0],
[maxWidth - 1, maxHeight - 1],
[0, maxHeight - 1]], dtype = "float32")
# compute the perspective transform matrix and then apply it
M = cv2.getPerspectiveTransform(rect, dst)
warped = cv2.warpPerspective(image, M, (maxWidth, maxHeight))
# return the warped image
return warped
接下來定義
four_point_transform
函數,需要傳入兩個參數
image
和
pts
。
image
是我們想應用透視變換的圖檔,
pts
表示圖檔中要做變換的區域(ROI)的四個點坐标的清單。
先調用
order_points
函數,按順序獲得點的坐标。然後我們需要确定新圖檔的次元。
新圖檔的寬度就是右下角和左下角的點的x坐标之差。同理新圖檔的高度就是右上角和右下角的點的y坐标之差。
接下來就是重點:
dst = np.array([
[0, 0],
[maxWidth - 1, 0],
[maxWidth - 1, maxHeight - 1],
[0, maxHeight - 1]], dtype = "float32")
這裡定義了代表圖像 “鳥瞰” 視圖的四個點,清單第一個元素
(0, 0)
表示左上角的點,第二個元素
(maxWidth - 1, 0)
表示右上角的點,第三個元素
(maxWidth - 1, maxHeight - 1)
表示右下角的點,最後第四個元素
(0, maxHeight - 1)
表示左下角的點。如上面所說,這裡還是按照這個順序對點進行排列。
先使用
cv2.getPerspectiveTransform
函數。要傳入兩個參數,
rect
是原始圖像中代表感興趣區域的點組成的清單,
dst
是我們轉換後的點組成的清單。傳回值
M
是實際的變換矩陣(transformation matrix)。
最後使用
cv2.warpPerspective
來得到自上而下的“鳥瞰”圖,傳入的三個參數分别是原始圖檔,轉換矩陣,輸出圖像的長和寬。其傳回值就是透視變換後的圖像。
four_point_transform
函數已經實作好了,現在來調用它并應用到圖檔中,
# transform_example.py
from pyimagesearch.transform import four_point_transform
import numpy as np
import argparse
import cv2
# construct the argument parse and parse the arguments
ap = argparse.ArgumentParser()
ap.add_argument("-i", "--image", help = "path to the image file")
ap.add_argument("-c", "--coords",
help = "comma seperated list of source points")
args = vars(ap.parse_args())
# load the image and grab the source coordinates (i.e. the list of
# of (x, y) points)
# NOTE: using the 'eval' function is bad form, but for this example
# let's just roll with it -- in future posts I'll show you how to
# automatically determine the coordinates without pre-supplying them
image = cv2.imread(args["image"])
pts = np.array(eval(args["coords"]), dtype = "float32")
# apply the four point tranform to obtain a "birds eye view" of
# the image
warped = four_point_transform(image, pts)
# show the original and warped images
cv2.imshow("Original", image)
cv2.imshow("Warped", warped)
cv2.waitKey(0)
先進行參數解析,可以傳入兩個參數,
--image
是想應用變換的圖檔,
--coords
是一個由4個點組成的清單,代表圖檔中要進行透視變換的區域。
然後加載圖檔,并将點坐标轉換為 NumPy 數組格式。最後應用
four_point_transform
就可以得到我們想要的結果了。
這裡是需要手動輸入需要進行透視變換的區域的點坐标,這個很麻煩,下篇将介紹如何自動确定透視變換所需的四個點。
執行這個函數:
python transform_example.py --image images/example_01.png --coords "[(73, 239), (356, 117), (475, 265), (187, 443)]"
得到如下結果:
換一張圖檔試試,
python transform_example.py --image images/example_03.png --coords "[(63, 242), (291, 110), (361, 252), (78, 386)]
到此我們就成功地擷取了圖檔中的一個區域的“鳥瞰”圖。
在這裡可以檢視源碼:
zxdefying/OpenCV_projectgithub.com
參考資料:https://blog.csdn.net/rrrfff/article/details/77340641?locationNum=1&fps=1
https://blog.csdn.net/u013063099/article/details/81937848?utm_medium=distribute.pc_relevant.none-task-blog-searchFromBaidu-1.not_use_machine_learn_pai&depth_1-utm_source=distribute.pc_relevant.none-task-blog-searchFromBaidu-1.not_use_machine_learn_pai