Python OpenCV背景减去法抠图实现详解
本文详细介绍利用Python和OpenCV通过背景减去法进行图像抠图的完整流程。涵盖图像预处理、灰度转换、背景减法计算差异、自适应阈值二值化、形态学操作去噪、轮廓查找与筛选、以及最终Alpha通道合成保存。通过具体代码示例,展示如何处理不同尺寸背景图并生成透明背景图像。
首先导入必要的Python库,包括OpenCV用于图像处理、Matplotlib用于图像显示以及NumPy用于数组运算。
import cv2
from matplotlib import pyplot as plt
import numpy as np
读取目标图像target.png,并使用Matplotlib将其从BGR格式转换为RGB格式进行显示。同时获取图像尺寸信息,示例中图像尺寸为2436x1125像素,包含3个颜色通道。
imA=cv2.imread("target.png")
plt.imshow(cv2.cvtColor(imA,cv2.COLOR_BGR2RGB))
imA.shape #(2436, 1125, 3)

imBG=cv2.imread("bg_30061.jpg")
plt.imshow(cv2.cvtColor(imBG,cv2.COLOR_BGR2RGB))

读取背景图像bg_30061.jpg并显示。接着进行预处理步骤:将背景图像缩放到与目标图像相同的尺寸(1125x2436),使用双三次插值算法确保缩放质量。随后将目标图像和背景图像均转换为灰度图像,以便后续进行像素级运算。
# Step 1 预处理
# 日常缩放图像,背景图要缩放到和图A意一样大
imBG=cv2.resize(imBG,(1125,2436),interpolation=cv2.INTER_CUBIC)
# 后续代码都是基于灰度图像操作的
imA_gray=cv2.cvtColor(imA,cv2.COLOR_BGR2GRAY)
imBG_gray=cv2.cvtColor(imBG,cv2.COLOR_BGR2GRAY)
# 背景减去
sub=imBG_gray.astype("int32")-imA_gray.astype("int32")
sub=np.absolute(sub).astype("uint8")
plt.imshow(cv2.cvtColor(sub,cv2.COLOR_BGR2RGB))

执行背景减法操作:将背景灰度图像转换int32类型后减去目标灰度图像,取绝对值并转换回uint8类型得到差异图像。该差异图像反映了前景与背景的不同之处,用于后续的二值化处理。
# Step 2 二值化图像
thresh=cv2.adaptiveThreshold(sub,255,cv2.ADAPTIVE_THRESH_GAUSSIAN_C,cv2.THRESH_BINARY,19,5)
## 图像二值化有很多种方法, adaptiveThreshold 是基于局部的,最后两个参数,19,5 决定了边缘检测的清晰度
thresh=cv2.erode(thresh,None,iterations=2)
thresh=cv2.dilate(thresh,None,iterations=2)
# 膨胀腐蚀,主要是消去噪声点,同时边缘封闭(边缘不封闭,无法完全填充)
plt.figure(num="thresh")
plt.imshow(cv2.cvtColor(thresh,cv2.COLOR_BGR2RGB))
plt.close

对差异图像进行二值化处理,采用自适应高斯阈值法(adaptiveThreshold),参数19和5控制局部窗口大小和常数C,以增强边缘检测的清晰度。随后进行形态学操作:先腐蚀(erode)再膨胀(dilate)两次,以消除噪声点并封闭边缘,确保后续轮廓填充的完整性。
# Step 3 边缘检测
cnts,hierarchy=cv2.findContours(thresh.copy(),cv2.RETR_TREE,cv2.CHAIN_APPROX_NONE)
len(cnts)
area=[]
for i in cnts:
cnt_area = cv2.contourArea(i)
area.append(cnt_area)
# 通过面积大小,找到需要的边缘的 index,这里为 866
mask=np.zeros([2436,1125],dtype=np.uint8)
mask[:,:]=255
res=cv2.drawContours(mask,cnts,866,(0,0,225),2)
plt.imshow(cv2.cvtColor(res,cv2.COLOR_BGR2RGB))
# 画出边缘

查找二值化图像中的所有轮廓,并计算每个轮廓的面积。通过面积筛选找到目标对象的轮廓索引(示例中为866)。初始化一个与图像尺寸相同的黑色掩模,并将所有像素设为255(白色),然后绘制选定的轮廓,线条颜色为蓝色,粗细为2像素,用于可视化边缘检测结果。
# 填充轮廓并制作掩模
mask2=np.zeros([2436,1125],dtype=np.uint8)
mask2[:,:]=0
res2=cv2.drawContours(mask2,cnts,866,255,cv2.FILLED)
plt.imshow(cv2.cvtColor(res2,cv2.COLOR_BGR2RGB))

基于筛选出的轮廓创建填充掩模:初始化全黑掩模,使用drawContours函数以FILLED模式填充指定索引的轮廓,生成白色填充区域。该掩模将用于提取前景图像。最后,将目标图像的B、G、R通道分离,并与生成的Alpha通道(掩模)合并,创建包含4个通道的图像数组,其中Alpha通道控制透明度。最终保存为PNG格式文件imA_new.png,实现透明背景抠图效果。
# 保存为 png
h,w,c=imA.shape
b,g,r=cv2.split(imA)
imA_2=np.zeros((4,h,w),dtype=imA.dtype)
imA_2[0][0:h,0:w]=b
imA_2[1][0:h,0:w]=g
imA_2[2][0:h,0:w]=r
imA_2[3][0:h,0:w]=mask2
imA_new=cv2.merge(imA_2)
cv2.imwrite("imA_new.png",imA_new)

以上就是Python OpenCV背景减去法抠图实现示例的详细内容,更多关于Python OpenCV背景减去法抠图的资料请关注本站其它相关文章!
本站声明
本文内容仅供参考,不代表本站观点。转载或引用请注明出处。如发现内容问题,请通过联系我们页面反馈。













