opencv - 从外部轮廓创建蒙版以移除图像背景

标签 opencv image-processing

我有一个无法控制的背景颜色的对象(样本)的图像。此问题已通过 post 的建议得到解决.如果图像是从垂直角度拍摄的,则该代码可以很好地工作。

但是,我还有另一个问题。一些图像是从无法控制的角度拍摄的。我上面提到的帖子中的现有代码返回了意外的结果。例如,给定原始图像

original

结果是result .

我修改该代码的想法是从外部轮廓制作一个蒙版,然后在原始和蒙版之间按位应用。但我不知道如何从外轮廓制作面具。我可以有你的建议吗?

最佳答案

您可以使用以下解决方案(尽管它不能很好地分离样本):

  • 使用cv2.floodFill用黑色背景替换彩色背景。
  • 使用“关闭”形态学操作来移除在 floodFill 之后留下的一些不需要的伪影。 .
  • 阈值结果,并找到最大的轮廓。
  • 使用 following post 中的代码平滑轮廓
  • 从“平滑”轮廓构建面膜,然后涂抹面膜。

  • 这是代码:

    import numpy as np
    import cv2
    from scipy.interpolate import splprep, splev
    
    orig_im = cv2.imread("specimen1.jpg")
    
    im = orig_im.copy()
    
    h, w = im.shape[0], im.shape[1]
    
    # Seed points for floodFill (use two points at each corner for improving robustness)
    seedPoints = ((0, 0), (10, 10), (w-1, 0), (w-1, 10), (0, h-1), (10, h-1), (w-1, h-1), (w-10, h-10))
    
    # Fill background with black color
    for seed in seedPoints:
        cv2.floodFill(im, None, seedPoint=seed, newVal=(0, 0, 0), loDiff=(5, 5, 5), upDiff=(5, 5, 5))
    
    # Use "close" morphological operation
    im = cv2.morphologyEx(im, cv2.MORPH_OPEN, cv2.getStructuringElement(cv2.MORPH_ELLIPSE, (10,10)));
    
    #Convert to Grayscale, and then to binary image.
    gray = cv2.cvtColor(im, cv2.COLOR_RGB2GRAY)
    ret, thresh_gray = cv2.threshold(gray, 5, 255, cv2.THRESH_BINARY)
    
    #Find contours
    _, contours, _ = cv2.findContours(thresh_gray, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_NONE)
    c = max(contours, key=cv2.contourArea) # Get the largest contour
    
    # Smooth contour
    # https://agniva.me/scipy/2016/10/25/contour-smoothing.html
    x,y = c.T
    x = x.tolist()[0]
    y = y.tolist()[0]
    tck, u = splprep([x,y], u=None, s=1.0, per=1)
    u_new = np.linspace(u.min(), u.max(), 20)
    x_new, y_new = splev(u_new, tck, der=0)
    res_array = [[[int(i[0]), int(i[1])]] for i in zip(x_new,y_new)]
    smoothened = np.asarray(res_array, dtype=np.int32)
    
    # For testing
    test_im = orig_im.copy()
    cv2.drawContours(test_im, [smoothened], 0, (0, 255, 0), 1)
    
    # Build a mask
    mask = np.zeros_like(thresh_gray)
    cv2.drawContours(mask, [smoothened], -1, 255, -1)
    
    # Apply mask
    res = np.zeros_like(orig_im)
    res[(mask > 0)] = orig_im[(mask > 0)]
    
    # Show images for testing
    cv2.imshow('test_im', test_im)
    cv2.imshow('res', res)
    cv2.imshow('mask', mask)
    cv2.waitKey(0)
    cv2.destroyAllWindows()
    

    评论:
    我不认为该解决方案非常强大。
    您可能需要使用迭代方法(例如逐渐增加 loDiffhiDiff 参数以匹配给定图像的最佳参数)。

    结果:

    第一个样本:

    test_im:
    enter image description here

    面具:
    enter image description here

    资源:
    enter image description here

    第二个样本:

    test_im:
    enter image description here

    面具:
    enter image description here

    资源:
    enter image description here

    第三个样本:

    资源:
    enter image description here

    关于opencv - 从外部轮廓创建蒙版以移除图像背景,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/60319634/

    相关文章:

    python - 如何从 PIL 图像创建 OpenCV 图像?

    opencv - 为什么直接线性变换 (DLT) 不能给出最佳的相机外部参数?

    c++ - 从文件夹加载文件并保存到另一个文件夹

    python pytesseract.image_to_string 无法读取图像中的文本

    java - 如何区分图像中的两条线

    c++ - 我的 findContours() 函数在具有不同 dpi 的图像上表现异常

    python - OpenCV 错误 : bitwise_and throws error that mask and image are not same size

    c# - .NET 中的透明度和 GIF——不一致的行为

    matlab - MATLAB 中的四叉树分解 : qtdecomp function input

    node.js - 当尝试写入图像文件时,它会向前移动并延迟写入工作