通过 Python 中的 OpenCV 库实现一个类似于抠图的功能,如下图所示:
import cv2
import numpy as np
这里写一个绘图函数,方便绘图操作。
def cv_show(name,img):
cv2.imshow(name, img)
cv2.waitKey(0)
cv2.destroyAllWindows()
fore = cv2.imread('fore.jpg')
size = fore.shape
H, W = size[:2]
pts_fore = np.array([[0, 0], [W-1, 0], [W-1, H-1],[0, H-1]])
这里点的顺序为左上角、右上角、左下角和右下角,在背景图片中选点的时候也要遵循这个顺序。
back = cv2.imread('back.jpg')
这个要比选取前景图片中的顶点难一些,因为要嵌入前景图片的区域的四个顶点并非整张图片的四个顶点,于是,在这里我们使用鼠标事件来找顶点坐标:
back_copy = back.copy() # 复制一个背景图片用于找顶点坐标,否则找出来的坐标会留在背景上
a =[] # 空列表用于存放顶点横坐标
b = [] # 空列表用于存放顶点纵坐标
def on_EVENT_LBUTTONDOWN(event, x, y, flags, param):
if event == cv2.EVENT_LBUTTONDOWN: # 鼠标事件:点击鼠标
xy = "%d,%d" % (x, y) # x 是这个点的横坐标;y 是这个点的纵坐标
a.append(x)
b.append(y)
cv2.circle(back_copy, (x, y), 1, (255, 0, 0), thickness=-1) # 在这个点上标红
cv2.putText(back_copy, xy, (x, y), cv2.FONT_HERSHEY_PLAIN,
1.0, (0, 0, 255), thickness=2) # 将这个点的坐标写在旁边
cv2.imshow("image", back_copy)
cv2.namedWindow("image")
cv2.setMouseCallback("image", on_EVENT_LBUTTONDOWN)
cv2.imshow("image", back_copy)
cv2.waitKey(0)
cv2.destroyAllWindows()
【注】这里选点的顺序必须和前景图片中选点的顺序一致。
pts_back = np.zeros((4, 2))
for i in range(4):
pts_back[i, :] = [a[i], b[i]]
h, status = cv2.findHomography(pts_fore, pts_back)
out = cv2.warpPerspective(fore, h, (fore.shape[1], fore.shape[0]))
注意这里是 (fore.shape[1], fore.shape[0])。
for i in range(H):
for j in range(W):
if out[i, j, :].all() != 0:
back[i, j, :] = out[i, j, :]
cv2.imwrite('out.jpg', back)
import cv2
import numpy as np
def cv_show(name,img):
cv2.imshow(name, img)
cv2.waitKey(0)
cv2.destroyAllWindows()
fore = cv2.imread('fore.jpg')
size = fore.shape
H, W = size[:2]
pts_fore = np.array([[0, 0], [W-1, 0], [W-1, H-1],[0, H-1]])
back = cv2.imread('back.jpg')
back_copy = back.copy()
a =[]
b = []
def on_EVENT_LBUTTONDOWN(event, x, y, flags, param):
if event == cv2.EVENT_LBUTTONDOWN:
xy = "%d,%d" % (x, y)
a.append(x)
b.append(y)
cv2.circle(back_copy, (x, y), 1, (255, 0, 0), thickness=-1)
cv2.putText(back_copy, xy, (x, y), cv2.FONT_HERSHEY_PLAIN,
1.0, (0, 0, 255), thickness=2)
cv2.imshow("image", back_copy)
cv2.namedWindow("image")
cv2.setMouseCallback("image", on_EVENT_LBUTTONDOWN)
cv2.imshow("image", back_copy)
cv2.waitKey(0)
cv2.destroyAllWindows()
pts_back = np.zeros((4, 2))
for i in range(4):
pts_back[i, :] = [a[i], b[i]]
h, status = cv2.findHomography(pts_fore, pts_back)
out = cv2.warpPerspective(fore, h, (fore.shape[1], fore.shape[0]))
for i in range(H):
for j in range(W):
if out[i, j, :].all() != 0:
back[i, j, :] = out[i, j, :]
cv2.imwrite('out.jpg', back)