【问题标题】:How do I remove the background from this kind of image?如何从这种图像中删除背景?
【发布时间】:2015-06-01 13:08:30
【问题描述】:

我想删除此图像的背景以仅获取此人。我有一千张这样的图片,基本上是一个人和一个有点发白的背景。

我所做的是使用像 canny 边缘检测器或 sobel 过滤器(来自 skimage 库)这样的边缘检测器。然后我认为可以做的是,将边缘内的像素变白,将边缘内的像素变黑。之后,可以对原始图像进行蒙版,只得到人的照片。

但是,使用 canny 边缘检测器很难获得封闭边界。使用 Sobel 过滤器的结果还不错,但我不知道如何从那里着手。

编辑:

是否也可以去除右手和裙子之间以及头发之间的背景?

【问题讨论】:

标签: python opencv image-processing scikit-image


【解决方案1】:

以下代码应该可以帮助您入门。您可能想要使用程序顶部的参数来微调您的提取:

import cv2
import numpy as np

#== Parameters =======================================================================
BLUR = 21
CANNY_THRESH_1 = 10
CANNY_THRESH_2 = 200
MASK_DILATE_ITER = 10
MASK_ERODE_ITER = 10
MASK_COLOR = (0.0,0.0,1.0) # In BGR format


#== Processing =======================================================================

#-- Read image -----------------------------------------------------------------------
img = cv2.imread('C:/Temp/person.jpg')
gray = cv2.cvtColor(img,cv2.COLOR_BGR2GRAY)

#-- Edge detection -------------------------------------------------------------------
edges = cv2.Canny(gray, CANNY_THRESH_1, CANNY_THRESH_2)
edges = cv2.dilate(edges, None)
edges = cv2.erode(edges, None)

#-- Find contours in edges, sort by area ---------------------------------------------
contour_info = []
_, contours, _ = cv2.findContours(edges, cv2.RETR_LIST, cv2.CHAIN_APPROX_NONE)
# Previously, for a previous version of cv2, this line was: 
#  contours, _ = cv2.findContours(edges, cv2.RETR_LIST, cv2.CHAIN_APPROX_NONE)
# Thanks to notes from commenters, I've updated the code but left this note
for c in contours:
    contour_info.append((
        c,
        cv2.isContourConvex(c),
        cv2.contourArea(c),
    ))
contour_info = sorted(contour_info, key=lambda c: c[2], reverse=True)
max_contour = contour_info[0]

#-- Create empty mask, draw filled polygon on it corresponding to largest contour ----
# Mask is black, polygon is white
mask = np.zeros(edges.shape)
cv2.fillConvexPoly(mask, max_contour[0], (255))

#-- Smooth mask, then blur it --------------------------------------------------------
mask = cv2.dilate(mask, None, iterations=MASK_DILATE_ITER)
mask = cv2.erode(mask, None, iterations=MASK_ERODE_ITER)
mask = cv2.GaussianBlur(mask, (BLUR, BLUR), 0)
mask_stack = np.dstack([mask]*3)    # Create 3-channel alpha mask

#-- Blend masked img into MASK_COLOR background --------------------------------------
mask_stack  = mask_stack.astype('float32') / 255.0          # Use float matrices, 
img         = img.astype('float32') / 255.0                 #  for easy blending

masked = (mask_stack * img) + ((1-mask_stack) * MASK_COLOR) # Blend
masked = (masked * 255).astype('uint8')                     # Convert back to 8-bit 

cv2.imshow('img', masked)                                   # Display
cv2.waitKey()

#cv2.imwrite('C:/Temp/person-masked.jpg', masked)           # Save

输出:

【讨论】:

  • 我不敢相信结果有多好。你愿意解释一下你做了什么吗?
  • @user74158 我为处理的每个主要“步骤”添加了一些简短的 cmets - 显示中间图像(例如 edgesmask)以查看发生了什么可能会有所帮助. opencv 文档很好地介绍了不同函数背后的理论——然而,就示例代码而言,它有点混乱,因为它支持许多不同的绑定。我不是图像处理专家,但如果您有任何问题,我可以尽力回答。
  • @user74158 在这里发表评论,我经常在这里(看!)
  • 如果您使用当前 OpenCV 的 master 分支,那么上面的 py 代码在第 25 行给出一个错误,指出“a ValueError : too many values to unpack” 将第 25 行更改为 _、contours、_= cv2。 findContours(edges, cv2.RETR_LIST, cv2.CHAIN_APPROX_NONE) 也可以。
  • 我在当前版本的 python2 中遇到了这个错误。 _, contours, _ = cv2.findContours(edges, cv2.RETR_LIST, cv2.CHAIN_APPROX_NONE) ValueError: need more than 2 values to unpack。如何解决问题?
【解决方案2】:

如果您希望不使用红色填充背景而是使其透明,您可以在解决方案中添加以下行:

# split image into channels
c_red, c_green, c_blue = cv2.split(img)

# merge with mask got on one of a previous steps
img_a = cv2.merge((c_red, c_green, c_blue, mask.astype('float32') / 255.0))

# show on screen (optional in jupiter)
%matplotlib inline
plt.imshow(img_a)
plt.show()

# save to disk
cv2.imwrite('girl_1.png', img_a*255)

# or the same using plt
plt.imsave('girl_2.png', img_a)

如果您愿意,可以调整一些 png 压缩参数以使文件更小。

下面的白色背景上的图像。或者黑色的 - http://imgur.com/a/4NwmH

【讨论】:

  • 你能否添加一个完整的例子,我似乎无法让它工作,只是把它放在脚本的底部。
  • 您能详细说明您遇到了什么问题/错误吗?
  • 我刚刚在上面答案中提到的代码末尾添加了代码,但结果我得到了带有背景的原始图像
【解决方案3】:

作为替代方案,您可以使用像这样的神经网络:CRFRNN。

结果如下:

【讨论】:

【解决方案4】:
  • 在获得不完整的边缘(如您所拥有的)后,您可以运行闭合形态(一系列扩张和侵蚀)(必须根据边缘的需要/状态设置大小和迭代)。

  • 1234563对象的内部。

【讨论】:

    【解决方案5】:

    vs2017 的工作示例。
    设置红色背景但保存蓝色..
    还添加了透明的例子。

    我怎样才能去除女孩的身体,只留下照片中的裙子? 有什么想法吗?

    # == https://stackoverflow.com/questions/29313667/how-do-i-remove-the-background-from-this-kind-of-image
    
    import cv2
    import numpy as np
    from matplotlib import pyplot as plt
    
    #== Parameters =======================================================================
    BLUR = 21
    CANNY_THRESH_1 = 10
    CANNY_THRESH_2 = 200
    MASK_DILATE_ITER = 10
    MASK_ERODE_ITER = 10
    MASK_COLOR = (0.0,0.0,1.0) # In BGR format
    
    
    #== Processing =======================================================================
    
    #-- Read image -----------------------------------------------------------------------
    img = cv2.imread('img/SYxmp.jpg')
    gray = cv2.cvtColor(img,cv2.COLOR_BGR2GRAY)
    
    #-- Edge detection -------------------------------------------------------------------
    edges = cv2.Canny(gray, CANNY_THRESH_1, CANNY_THRESH_2)
    edges = cv2.dilate(edges, None)
    edges = cv2.erode(edges, None)
    
    #-- Find contours in edges, sort by area ---------------------------------------------
    contour_info = []
    _, contours, _ = cv2.findContours(edges, cv2.RETR_LIST, cv2.CHAIN_APPROX_NONE)
    for c in contours:
        contour_info.append((
            c,
            cv2.isContourConvex(c),
            cv2.contourArea(c),
        ))
    contour_info = sorted(contour_info, key=lambda c: c[2], reverse=True)
    max_contour = contour_info[0]
    
    #-- Create empty mask, draw filled polygon on it corresponding to largest contour ----
    # Mask is black, polygon is white
    mask = np.zeros(edges.shape)
    cv2.fillConvexPoly(mask, max_contour[0], (255))
    
    
    
    #-- Smooth mask, then blur it --------------------------------------------------------
    mask = cv2.dilate(mask, None, iterations=MASK_DILATE_ITER)
    mask = cv2.erode(mask, None, iterations=MASK_ERODE_ITER)
    mask = cv2.GaussianBlur(mask, (BLUR, BLUR), 0)
    
    mask_stack = np.dstack([mask]*3)    # Create 3-channel alpha mask
    
    #-- Blend masked img into MASK_COLOR background --------------------------------------
    mask_stack  = mask_stack.astype('float32') / 255.0          # Use float matrices, 
    img         = img.astype('float32') / 255.0                 #  for easy blending
    
    masked = (mask_stack * img) + ((1-mask_stack) * MASK_COLOR) # Blend
    masked = (masked * 255).astype('uint8')                     # Convert back to 8-bit 
    
    plt.imsave('img/girl_blue.png', masked)
    # split image into channels
    c_red, c_green, c_blue = cv2.split(img)
    
    # merge with mask got on one of a previous steps
    img_a = cv2.merge((c_red, c_green, c_blue, mask.astype('float32') / 255.0))
    
    # show on screen (optional in jupiter)
    #%matplotlib inline
    plt.imshow(img_a)
    plt.show()
    
    # save to disk
    cv2.imwrite('img/girl_1.png', img_a*255)
    
    # or the same using plt
    plt.imsave('img/girl_2.png', img_a)
    
    cv2.imshow('img', masked)                                   # Displays red, saves blue
    
    cv2.waitKey()
    

    【讨论】:

    • 您是否能够实现“我怎样才能去除女孩的身体,只留下照片中的裙子?有什么想法吗?”我也在寻找这样的东西。谢谢。
    • @Tzvi,您的代码很好地删除了阴影。我正在从描绘沙发的图像中移除阴影。影子不见了,但乳白色的沙发变成了蓝灰色。这可以预防吗?
    【解决方案6】:

    根据@jedwards 的回答,与opencv4 一起使用时,会出现这个错误:

    Traceback (most recent call last):
      File "save.py", line 26, in <module>
        _, contours, _ = cv2.findContours(edges, cv2.RETR_LIST, cv2.CHAIN_APPROX_NONE)
    ValueError: not enough values to unpack (expected 3, got 2)
    

    函数cv2.findContours() 已更改为仅返回轮廓和层次结构

    你应该改成这样:

    contours, _ = cv2.findContours(edges, cv2.RETR_LIST, cv2.CHAIN_APPROX_NONE)
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2021-05-23
      • 2020-12-11
      • 1970-01-01
      • 2015-10-18
      相关资源
      最近更新 更多