使用 OpenCV/Python 从图像中删除绿色背景屏幕

Jud*_*nga 7 python opencv image-processing

所以我有下面这张图片: 在此输入图像描述

正如您所看到的,图像中有一些嘈杂的绿色轮廓。这是迄今为止我使用 OpenCV 和 Python 的最新输出。我还是个初学者,所以我需要你的帮助。

假设我要创建一个全新的脚本并提供该图像并“清理”图像,我将如何做?

编辑:这是原始图像: 在此输入图像描述

Jer*_*uke 8

Here is a rather simple approach.

Background:

Dominant colors like red, green, blue and yellow can be segmented pretty easily when analyzed in LAB color space. LAB space has 3 channels, out of which only 2 are color channels while 1 is a brightness channel:

  • L-channel: represents the brightness
  • A-channel: represents the amount of red/green color
  • B-channel: represents the amount of blue/yellow color

在此输入图像描述

Observing the plot above:

  1. a 轴在其极值处清晰地显示出红色/绿色
  2. b 轴在其极值处显示蓝色/黄色

在相应的通道中应用合适的阈值可以使我们轻松分割这些颜色。

方法:

我们将使用上述信息作为解决当前问题的基础:

1. 执行基本屏蔽:

->将图像转换为 LAB 空间 ->阈值 a 通道​​以隔离绿色背景 ->使用二进制掩码掩蔽原始图像

img = cv2.imread('green_background.jpg')
lab = cv2.cvtColor(img, cv2.COLOR_BGR2LAB)
a_channel = lab[:,:,1]
th = cv2.threshold(a_channel,127,255,cv2.THRESH_BINARY+cv2.THRESH_OTSU)[1]
masked = cv2.bitwise_and(img, img, mask = th)    # contains dark background
m1 = masked.copy()
m1[th==0]=(255,255,255)                          # contains white background
Run Code Online (Sandbox Code Playgroud)

在此输入图像描述

2. 去除边框上的绿色阴影:

->转换蒙版图像 LAB 空间 ->标准化 a 通道mlab[:,:,1]​​以使用 [0-255] 逆二进制阈值之间的整个强度范围 ->来选择带有绿色边框的区域

mlab = cv2.cvtColor(masked, cv2.COLOR_BGR2LAB)
dst = cv2.normalize(mlab[:,:,1], dst=None, alpha=0, beta=255,norm_type=cv2.NORM_MINMAX, dtype=cv2.CV_8U)
Run Code Online (Sandbox Code Playgroud)

在此输入图像描述

上图是边界周围有暗像素的 a 通道​​。

threshold_value = 100
dst_th = cv2.threshold(dst, threshold_value, 255, cv2.THRESH_BINARY_INV)[1]
Run Code Online (Sandbox Code Playgroud)

上面是分割绿色阴影区域的阈值图像。

在此输入图像描述

在 a 通道​​中,绿色代表范围 [0-255] 的下限,而红色代表上限。我们将所选像素的 a 通道​​中的强度值设置为 127:

mlab2 = mlab.copy()
mlab[:,:,1][dst_th == 255] = 127
Run Code Online (Sandbox Code Playgroud)

在此输入图像描述

现在,在上图中,我们看不到人物周围的黑色边框。

将图像转换为 BGR,并将阈值图像中较暗 (0) 的像素设置为彩色图像中的白色 (255, 255, 255)

img2 = cv2.cvtColor(mlab, cv2.COLOR_LAB2BGR)
img2[th==0]=(255,255,255)
Run Code Online (Sandbox Code Playgroud)

在此输入图像描述

生成的图像看起来没有太大变化,所以这里是放大的比较:

步骤 2 之前:

在此输入图像描述

第 2 步之后:

在此输入图像描述

结论:

边界周围嘈杂的绿色轮廓得到了一定程度的改善。您可以尝试改变threshold_value并进行实验。

人脸上的绿色阴影仍然存在。需要复杂的方法来消除这些。希望这种方法有所帮助。


fmw*_*w42 5

这是 @Jeru Luke 使用 Python/OpenCV 的答案的变体。它在 LAB 色彩空间中执行相同的阈值处理,但我只是使用模糊和 A 通道上灰度值输入范围一半的拉伸来进行抗锯齿。它的优点是减少一些绿色并使结果平滑,以便它可以平滑地融入任何背景图像。

调整 rescale_intensity 中的模糊西格玛值和/或输入剪辑值,以调整平滑度和绿色显示量。

输入:

在此输入图像描述

import cv2
import numpy as np
import skimage.exposure

# load image
img = cv2.imread('greenscreen.jpg')

# convert to LAB
lab = cv2.cvtColor(img,cv2.COLOR_BGR2LAB)

# extract A channel
A = lab[:,:,1]

# threshold A channel
thresh = cv2.threshold(A, 0, 255, cv2.THRESH_BINARY+cv2.THRESH_OTSU)[1]

# blur threshold image
blur = cv2.GaussianBlur(thresh, (0,0), sigmaX=5, sigmaY=5, borderType = cv2.BORDER_DEFAULT)

# stretch so that 255 -> 255 and 127.5 -> 0
mask = skimage.exposure.rescale_intensity(blur, in_range=(127.5,255), out_range=(0,255)).astype(np.uint8)

# add mask to image as alpha channel
result = img.copy()
result = cv2.cvtColor(img,cv2.COLOR_BGR2BGRA)
result[:,:,3] = mask

# save output
cv2.imwrite('greenscreen_thresh.png', thresh)
cv2.imwrite('greenscreen_mask.png', mask)
cv2.imwrite('greenscreen_antialiased.png', result)

# Display various images to see the steps
cv2.imshow('A',A)
cv2.imshow('thresh', thresh)
cv2.imshow('blur', blur)
cv2.imshow('mask', mask)
cv2.imshow('result', result)

cv2.waitKey(0)
cv2.destroyAllWindows()
Run Code Online (Sandbox Code Playgroud)

阈值图像:

在此输入图像描述

遮罩图像(用于 Alpha 通道):

在此输入图像描述

结果:

在此输入图像描述


Joe*_*Joe 1

在图像上使用Canny 边缘检测。然后根据它的外观使用形态扩张( cv.dilate()) 使边缘变厚一点。然后去除图像绿色通道的边缘或降低绿色通道的亮度。或者使像素透明。

这篇文章阐述了以下方法:

1.) 将绿色像素转换为透明度。基本上使用 HSV 颜色空间中的过滤规则。

2.) 在头发和一些边界像素上,颜色与绿色混合。为了减少这个问题,这些像素被过滤和平衡以减少它们的绿色比例。

3.) 对所有边界像素应用渐变透明度。