OpenCV+Python 让你的朋友出现在《法制进行时》

本文介绍如何使用Python的OpenCV库实现图片的抠图功能,具体步骤包括导入前景和背景图片,选择顶点,计算单应性矩阵,进行透视变换并将结果融合到背景图片中。

项目说明

通过 Python 中的 OpenCV 库实现一个类似于抠图的功能,如下图所示:
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

实现步骤

  • 1、导入朋友的照片(前景图片);
  • 2、选中前景图片中的四个顶点;
  • 3、导入《法制进行时》栏目的照片(背景图片);
  • 4、选取背景图片中要嵌入前景图片区域的四个顶点;
  • 5、通过两组(八个)坐标计算单应性矩阵;
  • 6、进行透视变换得到结果。

Python 实现

1、导入需要的库

import cv2
import numpy as np

2、绘图函数

这里写一个绘图函数,方便绘图操作。

def cv_show(name,img):
    cv2.imshow(name, img)
    cv2.waitKey(0)
    cv2.destroyAllWindows()

3、前景图片

3.1 导入前景图片

fore = cv2.imread('fore.jpg')

3.2 选中前景图片中的四个顶点

size = fore.shape
H, W = size[:2]
pts_fore = np.array([[0, 0], [W-1, 0], [W-1, H-1],[0, H-1]])

这里点的顺序为左上角、右上角、左下角和右下角,在背景图片中选点的时候也要遵循这个顺序。

坐标说明如下图所示:
在这里插入图片描述

4、背景图片

4.1 导入背景图片

back = cv2.imread('back.jpg')

4.2 选取背景图片中要嵌入前景图片区域的四个顶点

这个要比选取前景图片中的顶点难一些,因为要嵌入前景图片的区域的四个顶点并非整张图片的四个顶点,于是,在这里我们使用鼠标事件来找顶点坐标:

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()

【注】这里选点的顺序必须和前景图片中选点的顺序一致。

4.3 将顶点坐标写成前景图片顶点坐标的形式

pts_back = np.zeros((4, 2))
for i in range(4):
    pts_back[i, :] = [a[i], b[i]]

5、透视变换

5.1 计算单应性矩阵

h, status = cv2.findHomography(pts_fore, pts_back)

5.2 对前景图片进行透视变换

out = cv2.warpPerspective(fore, h, (fore.shape[1], fore.shape[0]))

注意这里是 (fore.shape[1], fore.shape[0])。

透视变换的结果为:
在这里插入图片描述

6、将透视变换的结果放入背景图片中并保存

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)
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

cofisher

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值