在用python进行图像处理的时候经常需要把一个图片的指定目标复制到另一个图像上,而图像的其他区域保持不变,有点类似给图像打上水印,但是这个水印区域是完全覆盖图像的。最近找到了一个比较好的实现方法,主要使用opencv的按位运算章节的内容,分享给大家。
参考资料:OpenCV-Python 中文教程 10 图像上的算术运算 10.3 按位运算
代码实现:
1 import cv2
2 import matplotlib.pyplot as plt
3
4
5 # 加载原始图片
6 img1 = cv2.imread('original.jpg')
7 # 加载logo图片
8 img_logo = cv2.imread('opencv_logo.jpg')
9
10 plt.figure(), plt.subplot(1, 2, 1), plt.title("original"), plt.imshow(img1, "gray")
11 plt.subplot(1, 2, 2), plt.title("logo_img"), plt.imshow(img_logo, "gray")
12
13 # 获取logo图片的宽,高
14 height, width = img_logo.shape[:2]
15 # 设置你要替换的原始图片中左上角坐标位置(x, y)
16 roi_coord_top_lef = [200, 300]
17 # 获取原始图片中要和roi融合的区域,截取的长度大小默认就是logo图片的长宽大小
18 roi = img1[roi_coord_top_lef[1]:roi_coord_top_lef[1]+height, roi_coord_top_lef[0]:roi_coord_top_lef[0]+width]
19
20 # Now create a mask of logo and create its inverse mask also
21 # 把logo图片转成灰度图片
22 img2gray = cv2.cvtColor(img_logo,cv2.COLOR_BGR2GRAY)
23 plt.figure(), plt.subplot(1, 3, 1), plt.title("gray image"), plt.imshow(img2gray, "gray")
24 # 把logo灰度图片转换成二值图片,现在是背景白色,前景黑色
25 ret, mask = cv2.threshold(img2gray, 175, 255, cv2.THRESH_BINARY)
26 plt.subplot(1, 3, 2), plt.title("binary image - mask"), plt.imshow(mask, "gray")
27 # logo图片的前景和背景交换,现在是背景黑色,前景是白色
28 mask_inv = cv2.bitwise_not(mask)
29 plt.subplot(1, 3, 3), plt.title("binary image - mask inv"), plt.imshow(mask_inv, "gray")
30
31 # 让原始图片与背景白色,前景黑色的mask相与从而保留原始图片的区域
32 img1_bg = cv2.bitwise_and(roi, roi, mask=mask)
33 plt.figure(), plt.subplot(1, 3, 1), plt.title("img1_bg"), plt.imshow(img1_bg)
34 # 让logo图片与背景黑色,前景白色的mask_inv相与从而保留logo图片的区域
35 img2_fg = cv2.bitwise_and(img_logo, img_logo, mask = mask_inv)
36 plt.subplot(1, 3, 2), plt.title("img2_fg"), plt.imshow(img2_fg)
37 # 对应相加两张图片,填充黑色0像素区域
38 dst = cv2.add(img1_bg,img2_fg)
39 plt.subplot(1, 3, 3), plt.title("dst"), plt.imshow(dst)
40
41 img1[roi_coord_top_lef[1]:roi_coord_top_lef[1]+height, roi_coord_top_lef[0]:roi_coord_top_lef[0]+width] = dst
42 plt.figure(), plt.imshow(img1, "gray")
43 plt.show()
结果图片:
这个方法也可以实现精确的复制一张图片的轮廓内部区域到另一张图片上。这里,重点就是要把要复制的轮廓区域的那张图除了前景(轮廓以及它的内部区域)以外的区域都设置为全白像素或者全黑的像素,即生成类似以上 opencv_logo.jpg 这张图片。具体实现方法可以这样
1. 生成一个和轮廓图一样大小的纯白色或者纯黑色的画布: canva = np.zeros((height, image, 3), dtype=np.uint8) (这里生成的是纯黑色)
2. 在画布上画出轮廓区域: canva = cv2.fillPoly(canva, pts=cnt, color=0) (注意,这里的轮廓需要是 (x, y) 类型,所以需要把从用 cv2.findContours() 得到的轮廓 cnt 进行 cnt = cnt[:, ::-1] 进行这个处理)
3. 把想要复制的图片区域和 canva 进行相与: cv2.bitwise(cavna, img2)
大致思路就是以上三点,通过以上3点就可以生成类似 opencv_logo.png 这样的图片,之后再实现图像印章的功能。