如何使用Python中的OpenCV将图像背景颜色设置为白色

7
我在Python中使用OpenCV库读取了一张图片。我想知道如何将背景颜色更改为白色。我只希望从图像中提取人物并拥有白色背景。
例如:

enter image description here

我想要更改为这个:

enter image description here

我该如何做这样的事情:
import numpy as np
import cv2

my_image = r'C:\Users\Pc\Desktop\preklapanje4.jpg'
my_image = cv2.imread(my_image, 1)

cv2.imshow('img',my_image)
cv2.waitKey(0)
2个回答

18

在这张图片中,由于所有的背景绿色都不是相连的,你需要对几个区域进行泛洪填充。

import cv2
import numpy as np

# load image and get dimensions
img = cv2.imread("soccer.jpg")
h, w, c = img.shape

# create zeros mask 2 pixels larger in each dimension
mask = np.zeros([h + 2, w + 2], np.uint8)

# do floodfill
result = img.copy()
cv2.floodFill(result, mask, (0,0), (255,255,255), (3,151,65), (3,151,65), flags=8)
cv2.floodFill(result, mask, (38,313), (255,255,255), (3,151,65), (3,151,65), flags=8)
cv2.floodFill(result, mask, (363,345), (255,255,255), (3,151,65), (3,151,65), flags=8)
cv2.floodFill(result, mask, (619,342), (255,255,255), (3,151,65), (3,151,65), flags=8)

# write result to disk
cv2.imwrite("soccer_floodfill.jpg", result)

# display it
cv2.imshow("result", result)
cv2.waitKey(0)
cv2.destroyAllWindows()


Input:

enter image description here

结果:

enter image description here

根据需要调整低和高的颜色范围,以消除更多的绿色。

请参阅floodfill

补充:

以下是使用HSV进行inRange阈值处理的代码,如我的评论所建议的。但请注意,全局阈值处理已经影响到了衬衫中附近的一些白色区域,使其变为纯白色。可以通过对较大的形态学区域进行某些操作或者用白色填充较小的轮廓来去除其中一部分。

import cv2
import numpy as np
import skimage.exposure

# load image and get dimensions
img = cv2.imread("soccer.jpg")

# convert to hsv
hsv = cv2.cvtColor(img,cv2.COLOR_BGR2HSV)

# threshold using inRange
range1 = (20,80,80)
range2 = (90,255,255)
mask = cv2.inRange(hsv,range1,range2)
mask = 255 - mask

# apply morphology opening to mask
kernel = np.ones((3,3), np.uint8)
mask = cv2.morphologyEx(mask, cv2.MORPH_ERODE, kernel)
mask = cv2.morphologyEx(mask, cv2.MORPH_CLOSE, kernel)

# antialias mask
mask = cv2.GaussianBlur(mask, (0,0), sigmaX=3, sigmaY=3, borderType = cv2.BORDER_DEFAULT)
mask = skimage.exposure.rescale_intensity(mask, in_range=(127.5,255), out_range=(0,255))

result = img.copy()
result[mask==0] = (255,255,255)

# write result to disk
cv2.imwrite("soccer_mask.png", mask)
cv2.imwrite("soccer_green2white.jpg", result)

# display it
cv2.imshow("mask", mask)
cv2.imshow("result", result)
cv2.waitKey(0)
cv2.destroyAllWindows()

掩码:

enter image description here

结果:

enter image description here

附加2:

这是另一种我发现有效的去除绿屏的方法。将图像转换为LAB颜色空间。然后取反A通道并将其乘以B通道。接下来,对其进行inRange()阈值处理以创建遮罩层。然后使用遮罩层将绿色转换为白色。它比先前的方法更好地保留了衬衫上近白色的部分,避免了强制将其变成纯白。但不幸的是会留下一些绿色残留。

import cv2
import numpy as np
import skimage.exposure

# load image and get dimensions
img = cv2.imread("soccer.jpg")

# convert to hsv
lab = cv2.cvtColor(img,cv2.COLOR_BGR2LAB)
L = lab[:,:,0]
A = lab[:,:,1]
B = lab[:,:,2]

# negate A
A = (255 - A)

# multiply negated A by B
nAB = 255 * (A/255) * (B/255)
nAB = np.clip((nAB), 0, 255)
nAB = np.uint8(nAB)


# threshold using inRange
range1 = 100
range2 = 160
mask = cv2.inRange(nAB,range1,range2)
mask = 255 - mask

# apply morphology opening to mask
kernel = np.ones((3,3), np.uint8)
mask = cv2.morphologyEx(mask, cv2.MORPH_ERODE, kernel)
mask = cv2.morphologyEx(mask, cv2.MORPH_CLOSE, kernel)

# antialias mask
mask = cv2.GaussianBlur(mask, (0,0), sigmaX=3, sigmaY=3, borderType = cv2.BORDER_DEFAULT)
mask = skimage.exposure.rescale_intensity(mask, in_range=(127.5,255), out_range=(0,255))

# put white where ever the mask is zero
result = img.copy()
result[mask==0] = (255,255,255)

# write result to disk
cv2.imwrite("soccer_green2white_inrange_lab.jpg", result)

# display it
cv2.imshow("nAB", nAB)
cv2.imshow("mask", mask)
cv2.imshow("result", result)
cv2.waitKey(0)
cv2.destroyAllWindows()


Result:

enter image description here


是否有可能移除所有“绿色”颜色? - taga
可能无法使用泛洪填充而不改变衬衫的白色部分。但是您可以尝试更改绿色颜色范围的值。更好的方法可能是在HSV颜色空间中使用floodfill或inRange()阈值处理来制作掩模,然后使用掩模来更改原始图像中绿色的颜色。但是,在衬衫周围可能仍会有一些绿色边缘需要进行抗锯齿处理以去除。 - fmw42
你能告诉我为什么在 [h + 2, w + 2] 中使用数字2,以及如何确定floodfill中的数字? - taga
1
掩码必须大出2个像素。请参阅文档。我通过在类似于GIMP或Photoshop的工具中交互式测量暗绿色区域来获取颜色。 - fmw42
可能的话,在Python/OpenCV中将图像转换为HSV格式。获取左上角的HSV值。对HSV图像执行inRange()阈值处理以生成遮罩。使用该遮罩将原始图像中遮罩为白色的部分修改为白色。这只在没有除背景以外的绿色时才有效。或者可以尝试 https://www.remove.bg 这个完全自动化在线工具。 - fmw42
显示剩余2条评论

0
你是如何选择种子点的?有没有计算方法,还是只能试错来找到种子点? 然后这些种子点只适用于特定的图像,不具备普适性。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接