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

0lvr5msh  于 2023-04-21  发布在  Python
关注(0)|答案(4)|浏览(301)

所以我有下面这张图片:

正如你所看到的,图像中有一些嘈杂的绿色轮廓。这是到目前为止,我用OpenCV和Python的最新输出。我还是一个初学者,所以我需要你的帮助。
假设我要创建一个全新的脚本,并提供此图像和“清洁”的形象,我将如何做到这一点?
编辑:这是原始图像:

zkure5ic

zkure5ic1#

这里有一个相当简单的方法。

背景:

LAB color space中分析时,可以很容易地分割红、绿色、蓝和黄等主色。LAB空间有3个通道,其中只有2个是颜色通道,而1个是亮度通道:

  • L通道:表示亮度
  • A通道:表示红/绿色颜色的量
  • B通道:表示蓝色/黄色的量

观察上面的图:

  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

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)

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

threshold_value = 100
dst_th = cv2.threshold(dst, threshold_value, 255, cv2.THRESH_BINARY_INV)[1]

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

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

mlab2 = mlab.copy()
mlab[:,:,1][dst_th == 255] = 127

现在在上面的图像中,我们看不到人周围的黑色边界。
将图像转换为BGR,并将阈值图像中的暗(0)像素设置为彩色图像中的白色(255、255、255

img2 = cv2.cvtColor(mlab, cv2.COLOR_LAB2BGR)
img2[th==0]=(255,255,255)

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

第二步前:

第二步后:

总结:

边框周围的***嘈杂的绿色轮廓***有一定程度的改善。您可以尝试改变threshold_value并进行实验。
这个人脸上的绿色阴影仍然存在。需要复杂的方法来消除这些阴影。希望这种方法能有所帮助。

eiee3dmh

eiee3dmh2#

这里是@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()

阈值图像:

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

结果:

g0czyy6m

g0czyy6m3#

在图像上使用Canny Edge Detection。然后根据它的外观使用Morphological Dilationcv.dilate())使边缘变厚。然后从图像的绿色通道中删除边缘或降低绿色通道的亮度。或者使像素透明。
This post说明了以下方法:
1.)将绿色像素转换为透明。基本上使用HSV颜色空间中的过滤规则。
2.)在头发和一些边界像素上颜色与绿色混合。为了减少这个问题,这些像素被过滤和平衡以减少它们的绿色比例。
3.)对所有边界像素应用渐变透明度。

6mzjoqzu

6mzjoqzu4#

尝试创建自定义阈值,例如:

def color_filter(img, r, g, b):
    colors = [b, g, r]
    result = np.zeros(img.shape, dtype=np.uint8)
    for i in range(3):
        result[:, :, i] = np.where(img[:, :, i] < colors[i], 0, 255)
    return result.astype(np.uint8)

UPDATE:这里是另一个解决方案https://codereview.stackexchange.com/a/184059/15056

以不同的值对每个颜色通道进行阈值化。
您可以使用找到最适合您的配置

def test_colors(img):
    cv.imshow("test_colors", img)
    r = 100
    g = 100
    b = 100
    while True:
        k = chr(cv.waitKey(0))
        if k == 'a':
            r += 1
        elif k == 'q':
            r -= 1
        elif k == 's':
            g += 1
        elif k == 'w':
            g -= 1
        elif k == 'd':
            b += 1
        elif k == 'e':
            b -= 1
        elif k == 't':
            r += 1
            g += 1
            b += 1
        elif k == 'g':
            r -= 1
            g -= 1
            b -= 1
        elif k == 'r':
            r = 100
            g = 100
            b = 100
            cv.imshow("test_colors", img)
            continue
        elif k == 'x':
            cv.destroyAllWindows()   
            print("The RGB is ", (r, g, b))
            break
        else:
            continue
        cv.imshow("test_colors", color_filter(img, r, g, b))

相关问题