計算機視覺現在很流行,世界各地的人們都在從事某種形式的基于深度學習的計算機視覺項目。但在深度學習出現之前,圖像處理技術已被用來處理和轉換圖像,以獲得有助于我們完成任務的見解。今天,讓我們看看如何實作一種簡單而有用的技術,即透視投影來扭曲圖像。
那麼扭曲圖像是什麼意思?我可以用很多花哨的詞和技術術語來解釋它。但是,展示最終結果很容易,這樣我們就可以通過觀察來學習。
基礎圖像——主題圖像——扭曲的輸出
是以基本上,我們需要拍攝一個圖像并剪切它以使其适合任何所需形狀的畫布。請注意,反過來也是可能的。現在,這已經不成問題了,讓我們就來看看如何使用 OpenCV 和 Python 來實作這一點。
在進入代碼的主要部分之前,我們必須首先導入必要的庫。
import cv2
import numpy as np
複制
現在,讓我們按如下方式讀取基本圖像和主題圖像。
base_image = cv2.imread('base_img.jpg')
base_image_copy = base_image.copy()
subject_image = cv2.imread('subject.jpg')
複制
基本圖像(左)——主體圖像(右)
初始化一個數組來存儲我們想要覆寫主題圖像的 4 個角的坐标,我們可以使用setMouseCallback()函數手動選擇這 4 個點,如下所示。
def click_event(event, x, y, flags, params):
if event == cv2.EVENT_LBUTTONDOWN:
cv2.circle(base_image_copy, (x, y), 4, (0, 0, 255), -1)
points.append([x, y])
if len(points) <= 4:
cv2.imshow('image', base_image_copy)
points = []
base_image = cv2.imread('base_img.jpg')
base_image_copy = base_image.copy()
subject_image = cv2.imread('subject.jpg')
cv2.imshow('image', base_image_copy)
cv2.setMouseCallback('image', click_event)
cv2.waitKey(0)
cv2.destroyAllWindows()
複制
在上面給出的代碼片段中,我們定義了一個名為click_event()的函數,并将其作為參數傳遞給setMouseCallback()函數。使用這種方法,我們将首先顯示基礎圖像,然後我們可以手動選擇圖像中的四個點作為目标。我們的主題圖像會扭曲到這個目标上,按下滑鼠左鍵時記錄坐标,這些存儲在我們之前初始化的點數組中。標明的點以紅點突出顯示,如下所示。
選擇角點
衆所周知,我們每個人都可以按任意順序選擇 4 個點。是以需要在所選點之間保持恒定的排序。我選擇以順時針方式對點進行排序,即從左上到右上,再到右下然後到左下,這是通過如下所示的sort_pts()方法實作的。我們使用以下事實:x 和 y 坐标的總和在左上角最小,在右下角最大。同樣,它們之間的差異在右上角最小,在左下角最大。請記住,對于圖像,原點位于圖像的左上角。
def sort_pts(points):
sorted_pts = np.zeros((4, 2), dtype="float32")
s = np.sum(points, axis=1)
sorted_pts[0] = points[np.argmin(s)]
sorted_pts[2] = points[np.argmax(s)]
diff = np.diff(points, axis=1)
sorted_pts[1] = points[np.argmin(diff)]
sorted_pts[3] = points[np.argmax(diff)]
return sorted_pts
sorted_pts = sort_pts(points)
複制
對點進行排序後,讓我們用它們來計算變換矩陣。我們建立一個名為“pts1”的 numpy 數組,它儲存了主題圖像的四個角的坐标。同樣,我們建立一個名為“pts2”的清單,其中包含已排序的點。“pts1”的坐标順序應該與“pts2”坐标的順序相比對。
h_base, w_base, c_base = base_image.shape
h_subject, w_subject = subject_image.shape[:2]
pts1 = np.float32([[0, 0], [w_subject, 0], [w_subject, h_subject], [0, h_subject]])
pts2 = np.float32(sorted_pts)
複制
現在我們獲得了扭曲對象圖像所需的變換矩陣。這是使用函數cv2.getPerspectiveTransform() 獲得的。由于我們希望以适合我們在基礎圖像中選擇的框的方式變化主題圖像,是以“ src ”應為“ pts1 ”,“ dst ”應為“ pts2 ”。生成的圖像的大小可以指定為元組。我們確定生成的圖像具有基本圖像的尺寸。使用生成的矩陣,我們可以使用cv2.warpPerspective()方法扭曲圖像,如給定的代碼片段所示。
transformation_matrix = cv2.getPerspectiveTransform(pts1, pts2)
warped_img = cv2.warpPerspective(subject_image, transformation_matrix, (w_base, h_base))
cv2.imshow('Warped Image', warped_img)
複制
變形的圖像看起來像這樣:
變形的圖像
下一步是建立一個蒙版,我們為其建立一個具有基本圖像形狀的空白圖像。
mask = np.zeros(base_image.shape, dtype=np.uint8)
複制
初始蒙版
在這個空白蒙版上,我們繪制一個具有由“ sorted_pts ”指定的角的多邊形,并使用cv2.fillConvexPoly()方法将其填充為白色,生成的蒙版将如下所示。
roi_corners = np.int32(sorted_pts)
cv2.fillConvexPoly(mask, roi_corners, (255, 255, 255))
複制
填充蒙版
現在我們使用cv2.bitwise_not()方法反轉蒙版顔色。
mask = cv2.bitwise_not(mask)
複制
倒置蒙版
現在我們使用cv2.bitwise_and()方法擷取蒙版和基礎圖像并執行按位與運算。
masked_image = cv2.bitwise_and(base_image, mask)
複制
這将為我們提供如下所示的圖像。我們可以看到單獨放置對象圖像的區域是黑色的。
蒙面基礎圖像
最後一步是使用cv2.bitwise_or()方法擷取變形圖像和蒙版圖像并執行按位或運算,這将生成我們想要完成的融合圖像。
output = cv2.bitwise_or(warped_img, masked_image)
cv2.imshow('Fused Image', output)
cv2.imwrite('Final_Output.png', output)
cv2.waitKey(0)
cv2.destroyAllWindows()
複制
我們做到了!我們已經成功地将一張圖檔疊加到另一張圖檔上。
融合圖像
這是透視變換的一個非常簡單的用例。當我們跟蹤架構中物體/人物的運動時,可以使用它來生成區域的鳥瞰圖。
Github代碼連接配接:
https://github.com/GSNCodes/Image_Overlaying_Using_Perspective_Transform