使用opencv Python删除图像的背景
image
image-processing
numpy
opencv
7
0

我有两张图像,一个只有背景,另一个带有背景+可检测物体(在我的情况下是汽车)。以下是图片

在此处输入图片说明

我正在尝试删除背景,以便在生成的图像中只有汽车。以下是我试图获得所需结果的代码

import numpy as np
import cv2


original_image = cv2.imread('IMG1.jpg', cv2.IMREAD_COLOR)
gray_original = cv2.cvtColor(original_image, cv2.COLOR_BGR2GRAY)
background_image = cv2.imread('IMG2.jpg', cv2.IMREAD_COLOR)
gray_background = cv2.cvtColor(background_image, cv2.COLOR_BGR2GRAY)

foreground = np.absolute(gray_original - gray_background)
foreground[foreground > 0] = 255

cv2.imshow('Original Image', foreground)
cv2.waitKey(0)

通过减去两个图像得到的图像是

在此处输入图片说明

这是问题所在。预期的最终图像应仅为汽车。另外,如果您仔细查看这两个图像,您会发现它们并不完全相同,也就是说,相机稍微移动了一点,因此背景受到了一点干扰。我的问题是,对于这两张图片,我该如何减去背景。我现在不希望使用grabCut或backgroundSubtractorMOG算法,因为我现在不知道这些算法内部发生了什么。

我正在尝试做的是获得以下结果图像在此处输入图片说明

另外,如果可能的话,请不仅以这种特殊情况为我提供一般的操作方法,即在一个图像中有背景,在第二个图像中有背景+对象。这样做可能是最好的方式。很抱歉这么长的问题。

参考资料:
Stack Overflow
收藏
评论
共 2 个回答
高赞 时间 活跃

我使用OpenCV的分水岭算法解决了您的问题。您可以在此处找到分水岭的理论和示例。

首先,我选择了几个点(标记)来指示要保留的对象在哪里,背景在哪里。此步骤是手动操作,每个图像可能会有很大差异。此外,它需要重复一些操作,直到获得所需的结果。我建议使用工具获取像素坐标。然后,我创建了一个空的零整数数组,其大小与汽车图像的大小相同。然后,我为标记位置的像素分配了一些值(1:background,[255,192,128,64]:car_parts)。

注意:下载您的图片时,我必须对其进行裁剪才能将其与汽车一起使用。裁剪后,图像的大小为400x601。这可能不是您所拥有图像的大小,因此标记将关闭。

之后,我使用了分水岭算法。第一个输入是您的图像,第二个输入是标记图像(除标记位置外,其他所有位置均为零)。结果如下图所示。 分水岭之后

我将所有值大于1到255(汽车)的像素设置为零,其余的(背景)像素设置为零。然后,我使用3x3内核对获得的图像进行了扩展,以避免丢失有关汽车轮廓的信息。最后,我使用cv2.bitwise_and()函数将膨胀后的图像用作原始图像的遮罩,结果位于以下图像中: 最终裁剪的图像

这是我的代码:

import cv2
import numpy as np
import matplotlib.pyplot as plt

# Load the image
img = cv2.imread("/path/to/image.png", 3)

# Create a blank image of zeros (same dimension as img)
# It should be grayscale (1 color channel)
marker = np.zeros_like(img[:,:,0]).astype(np.int32)

# This step is manual. The goal is to find the points
# which create the result we want. I suggest using a
# tool to get the pixel coordinates.

# Dictate the background and set the markers to 1
marker[204][95] = 1
marker[240][137] = 1
marker[245][444] = 1
marker[260][427] = 1
marker[257][378] = 1
marker[217][466] = 1

# Dictate the area of interest
# I used different values for each part of the car (for visibility)
marker[235][370] = 255    # car body
marker[135][294] = 64     # rooftop
marker[190][454] = 64     # rear light
marker[167][458] = 64     # rear wing
marker[205][103] = 128    # front bumper

# rear bumper
marker[225][456] = 128
marker[224][461] = 128
marker[216][461] = 128

# front wheel
marker[225][189] = 192
marker[240][147] = 192

# rear wheel
marker[258][409] = 192
marker[257][391] = 192
marker[254][421] = 192

# Now we have set the markers, we use the watershed
# algorithm to generate a marked image
marked = cv2.watershed(img, marker)

# Plot this one. If it does what we want, proceed;
# otherwise edit your markers and repeat
plt.imshow(marked, cmap='gray')
plt.show()

# Make the background black, and what we want to keep white
marked[marked == 1] = 0
marked[marked > 1] = 255

# Use a kernel to dilate the image, to not lose any detail on the outline
# I used a kernel of 3x3 pixels
kernel = np.ones((3,3),np.uint8)
dilation = cv2.dilate(marked.astype(np.float32), kernel, iterations = 1)

# Plot again to check whether the dilation is according to our needs
# If not, repeat by using a smaller/bigger kernel, or more/less iterations
plt.imshow(dilation, cmap='gray')
plt.show()

# Now apply the mask we created on the initial image
final_img = cv2.bitwise_and(img, img, mask=dilation.astype(np.uint8))

# cv2.imread reads the image as BGR, but matplotlib uses RGB
# BGR to RGB so we can plot the image with accurate colors
b, g, r = cv2.split(final_img)
final_img = cv2.merge([r, g, b])

# Plot the final result
plt.imshow(final_img)
plt.show()

如果您有很多图像,则可能需要创建一个工具以图形方式注释标记,或者甚至需要一个算法来自动查找标记。

收藏
评论

问题在于您要减去无符号的 8位整数数组。此操作可能溢出。

展示

>>> import numpy as np
>>> a = np.array([[10,10]],dtype=np.uint8)
>>> b = np.array([[11,11]],dtype=np.uint8)
>>> a - b
array([[255, 255]], dtype=uint8)

由于您使用的是OpenCV,因此实现目标的最简单方法是使用cv2.absdiff()

>>> cv2.absdiff(a,b)
array([[1, 1]], dtype=uint8)
收藏
评论
新手导航
  • 社区规范
  • 提出问题
  • 进行投票
  • 个人资料
  • 优化问题
  • 回答问题

关于我们

常见问题

内容许可

联系我们

@2020 AskGo
京ICP备20001863号