【问题标题】:How do I crop an image using a binary mask image of the same picture to remove the background in python?如何使用同一图片的二进制蒙版图像裁剪图像以去除python中的背景?
【发布时间】:2020-04-06 00:09:00
【问题描述】:

我尝试使用以下代码获取蒙版图像的边缘:

import numpy as np
from matplotlib import pyplot as plt

img = cv2.imread('ISIC_0000000_segmentation.png',0)
edges = cv2.Canny(img,0,255)

plt.subplot(121), plt.imshow(img, cmap='gray')
plt.title('Original Image'), plt.xticks([]), plt.yticks([])
plt.subplot(122), plt.imshow(edges, cmap='gray')
plt.title('Edge Image'), plt.xticks([]), plt.yticks([])

plt.show

我得到的是这样的:

但由于某种原因,边缘并不光滑。

我的计划是使用边缘图像裁剪以下图片:

有谁知道如何使边缘图像更好,以及如何使用它来裁剪正常图像?

编辑:@Mark Setchell 提出了一个很好的观点:如果我可以直接使用蒙版图像来裁剪图像,那就太好了。

另外:可以将正常图像精确地放置在蒙版图像上,以便蒙版上的黑色区域覆盖正常图片上的蓝色区域。

编辑:@Mark Setchell 引入了将法线图像与蒙版图像相乘的想法,因此背景将导致 0(黑色),其余部分将保持其颜色。当我的蒙版图片是.png,而我的正常图片是.jpg时,会不会有问题?

编辑: 我编写了以下代码来尝试将两张图片相乘:

# Importing Image and ImageChops module from PIL package  
from PIL import Image, ImageChops 

# creating a image1 object 
im1 = Image.open("ISIC_0000000.jpg") 

# creating a image2 object 
im2 = Image.open("ISIC_0000000_segmentation.png") 

# applying multiply method 
im3 = ImageChops.multiply(im1, im2) 

im3.show()

但我得到了错误: ValueError: images do not match

有谁知道我该如何解决这个问题?

【问题讨论】:

  • 我完全不明白你为什么想要边缘图像。为什么不用遮罩遮住图像?
  • 我最初的想法是勾勒出边框,这样我仍然可以使用背景,但我真的不再需要背景了,所以如果可以直接使用蒙版图像会很棒的。问题是我不知道怎么做。
  • 你的面具是黑色的,它是零。因此,如果您将图像乘以蒙版,它将变为零(黑色)。考虑一下白色部分。
  • 白色会给出“1”,它可以与每种颜色相乘,而黑色“0”会主导每种颜色,因为一切都乘以 0,结果为 0。这就是你要告诉我的,因为这个会解决我的问题!
  • 这就是我要去的地方。你的面具可能有 white=1 或 white=255,但是是的。

标签: python image opencv image-processing computer-vision


【解决方案1】:

您可以通过形态学操作来获得优势。

抱歉使用 MATLAB:

I = imbinarize(rgb2gray(imread('I.png'))); %Load input image, and convert to binary image.

%Erode the image with mask 3x3
J = imerode(I, ones(3));

%Pefrom XOR operation (1 xor 1 = 0, 0 xor 0 = 0, 0 xor 1 = 1, 1 xor 0 = 1)
J = xor(I, J);

%Use "skeleton" operation to make sure eage thikness is 1 pixel.
K = bwskel(J); 

结果:

正如马克所提到的,您不需要边缘进行裁剪(除非您使用我不知道的特殊裁剪方法)。

【讨论】:

    【解决方案2】:

    检测到的边缘不平滑,因为图像中的实际边缘不平滑。您可以尝试先用low-pass filters过滤原始图像。

    如果你可以使用轮廓,以下将起作用:

    import numpy as np
    import cv2
    from matplotlib import pyplot as plt
    
    # Read in image
    imgRaw = cv2.imread('./Misc/edgesImg.jpg',0)
    
    # Blur image
    blurSize = 25
    blurredImg = cv2.blur(imgRaw,(blurSize,blurSize))
    
    # Convert to Binary
    thrImgRaw, binImgRaw = cv2.threshold(imgRaw, 0, 255, cv2.THRESH_OTSU)
    thrImgBlur, binImgBlur = cv2.threshold(blurredImg, 0, 255, cv2.THRESH_OTSU)
    
    # Detect the contours in the image
    contoursRaw = cv2.findContours(binImgRaw,cv2.RETR_TREE,cv2.CHAIN_APPROX_NONE)
    contoursBlur = cv2.findContours(binImgBlur,cv2.RETR_TREE,cv2.CHAIN_APPROX_NONE)
    
    # Draw all the contours
    contourImgOverRaw = cv2.drawContours(imgRaw, contoursRaw[0], -1, (0,255,0),5)
    contourImgOverBlur = cv2.drawContours(blurredImg, contoursBlur[0], -1, (0,255,0),5)
    
    # Plotting
    plt.figure()
    plt.subplot(121)
    plt.imshow(contourImgOverRaw)
    plt.title('Raw Edges'), plt.xticks([]), plt.yticks([])
    plt.subplot(122)
    plt.imshow(contourImgOverBlur)
    plt.title('Edges with {}px Blur'.format(blurSize)), plt.xticks([]), plt.yticks([])
    plt.show()
    

    编辑:这里是关于来自轮廓的图像的getting a mask 的更多信息。

    【讨论】:

      【解决方案3】:

      如果我理解正确,您想提取对象并移除背景。为此,您只需使用掩码和原始输入图像执行简单的cv2.bitwise_and()

      有谁知道如何使边缘图像更好,以及如何使用它来裁剪正常图像?

      要从图像中提取背景,您不需要边缘图像,阈值图像可用于仅删除图像的所需部分。您可以使用蒙版图像直接删除图像并去除背景。获得二进制掩码的其他方法包括使用固定阈值、自适应阈值或 Canny 边缘检测。这是一个简单的例子,使用 Otsu 的阈值来获得二进制掩码,然后进行按位与运算。

      这是移除背景的结果

      如果您希望移除的背景为白色,您也可以将遮罩上的所有像素变为白色

      注意:根据您希望结果的“平滑”程度,您可以在阈值处理之前将任何blur 应用于图像以平滑边缘。这可以包括平均、高斯、中值或双边滤波。


      代码

      import cv2
      
      # Load image, grayscale, Otsu's threshold
      image = cv2.imread('1.jpg')
      gray = cv2.cvtColor(image, cv2.COLOR_BGR2GRAY)
      thresh = cv2.threshold(gray, 0, 255, cv2.THRESH_BINARY_INV + cv2.THRESH_OTSU)[1]
      
      # Remove background using bitwise-and operation
      result = cv2.bitwise_and(image, image, mask=thresh)
      result[thresh==0] = [255,255,255] # Turn background white
      
      cv2.imshow('thresh', thresh)
      cv2.imshow('result', result)
      cv2.waitKey()
      

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2013-06-10
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2019-11-01
        • 2019-03-10
        • 1970-01-01
        相关资源
        最近更新 更多