今天在对图片进行预处理是遇到了cv2.bitwise_and函数,感觉还是挺有意思的,那就趁热记一下吧。
将下面这个柯南logo头像加到下面图像的左上角并且背景无遮挡(logo图片白的部分不遮挡星空图片的背景)。
import cv2
img1 = cv2.imread(r'D:\Python\pytorchLearn\ImagePreprocess\test.jpg')
img2 = cv2.imread(r'D:\Python\pytorchLearn\ImagePreprocess\kelan.jpg')
rows, cols, channels = img2.shape
roi = img1[0:rows, 0:cols]
img2gray = cv2.cvtColor(img2, cv2.COLOR_BGR2GRAY)
ret, mask = cv2.threshold(img2gray, 245, 255, cv2.THRESH_BINARY)
mask_inv = cv2.bitwise_not(mask)
img1_bg = cv2.bitwise_and(roi, roi, mask=mask)
img2_fg = cv2.bitwise_and(img2, img2, mask=mask_inv)
dst = cv2.add(img1_bg, img2_fg)
img1[0:rows, 0:cols] = dst
cv2.imshow('test', img1)
cv2.waitKey(0)
cv2.destroyAllWindows()
首先下面这两行的代码作用是将我们的星空图像中的对应logo图像的区域找出来记为roi
rows,cols,channels = img2.shape
roi = img1[0:rows, 0:cols]
我们将这个roi图像显示出来,与我们预想的一致,正是星空图像的左上角对应logo图像的区域:
下面三行代码是生成一个mask掩码矩阵和mask_inv逆掩码矩阵方便我们后面cv2.bitwise_and函数的使用,我们稍微讲一下参数和原理,后面再看效果。
img2gray = cv2.cvtColor(img2,cv2.COLOR_BGR2GRAY)
ret, mask = cv2.threshold(img2gray, 245, 255, cv2.THRESH_BINARY)
mask_inv = cv2.bitwise_not(mask)
第一行是将我们的logo图像变成灰度图像,第二行cv2.threshold函数的参数:第一个参数为原图像,第二个参数为进行分类的阈值,第三个参数为高于(低于)阈值时赋予的新值,第四个方法选择参数,常用的有:
• cv2.THRESH_BINARY(黑白二值)
• cv2.THRESH_BINARY_INV(黑白二值反转)
• cv2.THRESH_TRUNC (得到的图像为多像素值)
• cv2.THRESH_TOZERO
• cv2.THRESH_TOZERO_INV
返回值为:第一个retVal(得到的阈值值),第二个就是阈值化后的掩码图像
根据我们选择的模式为cv2.THRESH_BINARY,以及第二三个参数为245、255,表示:高于245的像素设置为255,否则像素值置零。其他模式见文章:(13条消息) 图像阈值处理cv2.threshold()函数(python)_肥宅_Sean的博客-CSDN博客_cv2threshold
于是我们的mask图像便是对于img2gray图像的高于200的像素值置255(白),否则置0(黑),我们来验证一下:
img2gray图像:
mask掩码矩阵图像:
mask_inv矩阵图像:
可以看见img2gray中黑的和灰的像素值较低被置为黑色,背景白色仍置为白色。
得到mask掩码矩阵图像后我们接着往下看:
img1_bg = cv2.bitwise_and(roi,roi,mask = mask)
img2_fg = cv2.bitwise_and(img2,img2,mask = mask_inv)
cv2.bitwise_and函数的作用取与运算,第一个参数为输入图像,第二个参数为输出图像,第三个参数mask:图像掩膜,可选参数,为8位单通道的灰度图像,用于指定要更改的输出图像数组的元素,即输出图像像素只有mask对应位置元素不为0的部分才输出,否则该位置像素的所有通道分量都设置为0。
roi图像和mask图像上面已给出,下面我们给出img1_bg的图像:
与声明的一致,同理img2_fg图像只是将参数mask换成了其反矩阵,并且作用对象变成了我们的logo图像。我们看看效果:
img2_fg图像:
也即在原来mask矩阵图像为白的时候输出原图logo图像,反之置黑。
最后,我们将上面两张图加起来就达到了我们想要的左上角部分,再把原图星空图像的左上角替换成我们加起来后的左上角部分即得到结果:
dst = cv2.add(img1_bg,img2_fg)
img1[0:rows, 0:cols ] = dst
可以看到对柯南的抠图还是存在一点瑕疵,出现了一些黑点,这里可以使用另一篇博客里面提到的开闭运算来解决:
数据预处理的一些常见方法
加入以下代码:
kernel = cv2.getStructuringElement(cv2.MORPH_ELLIPSE,(5,5))
mask_inv = cv2.morphologyEx(mask_inv,cv2.MORPH_CLOSE,kernel) # 闭运算