【问题标题】:How to remove the background from a picture in OpenCV python如何从OpenCV python中的图片中删除背景
【发布时间】:2021-02-06 00:26:51
【问题描述】:

因为我是计算机视觉的新手。我还想问我如何删除这张图片的整个背景,只保留药片。我尝试了不同的方法,例如更改背景颜色,但仍然存在一些小边缘和噪点。

或者,如果所有白色背景都可以是中性色,圆圈之间没有线条。

【问题讨论】:

    标签: python-3.x image opencv computer-vision


    【解决方案1】:

    这是在 Python/OpenCV 中移除环的另一种方法。但它会去除与环重叠的部分药丸。

    • 读取输入
    • 白色阈值
    • 应用形态接近去除中心条
    • 获取轮廓
    • 在黑色背景上绘制白色填充轮廓
    • 获取白色填充轮廓的凸包
    • 将椭圆拟合到凸包
    • 打印椭圆以确保它接近圆形
    • 在输入上用红色绘制凸包轮廓以检查是否适合白色区域
    • 使用椭圆的平均半径绘制一个圆,中心为黑色背景上的白色填充
    • 稍微腐蚀圆圈以避免留下部分白圈
    • 将倒置的变形图像和圆形图像组合起来制作最终蒙版
    • 将最终掩码应用于输入
    • 保存结果

    import cv2
    import numpy as np
    
    # Read image
    img = cv2.imread('pills.jpg')
    hh, ww = img.shape[:2]
    
    # threshold on white
    # Define lower and uppper limits
    lower = np.array([200, 200, 200])
    upper = np.array([255, 255, 255])
    
    # Create mask to only select black
    thresh = cv2.inRange(img, lower, upper)
    
    # apply morphology
    kernel = cv2.getStructuringElement(cv2.MORPH_ELLIPSE, (20,20))
    morph = cv2.morphologyEx(thresh, cv2.MORPH_CLOSE, kernel)
    
    # get contours
    contours = cv2.findContours(morph, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE)
    contours = contours[0] if len(contours) == 2 else contours[1]
    
    # draw white contours on black background as mask
    mask = np.zeros((hh,ww), dtype=np.uint8)
    for cntr in contours:
        cv2.drawContours(mask, [cntr], 0, (255,255,255), -1)
    
    # get convex hull
    points = np.column_stack(np.where(thresh.transpose() > 0))
    hullpts = cv2.convexHull(points)
    ((centx,centy), (width,height), angle) = cv2.fitEllipse(hullpts)
    print("center x,y:",centx,centy)
    print("diameters:",width,height)
    print("orientation angle:",angle)
    
    # draw convex hull on image
    hull = img.copy()
    cv2.polylines(hull, [hullpts], True, (0,0,255), 1)
    
    # create new circle mask from ellipse 
    circle = np.zeros((hh,ww), dtype=np.uint8)
    cx = int(centx)
    cy = int(centy)
    radius = (width+height)/4
    cv2.circle(circle, (cx,cy), int(radius), 255, -1)
    
    # erode circle a bit to avoid a white ring
    kernel = cv2.getStructuringElement(cv2.MORPH_ELLIPSE, (6,6))
    circle = cv2.morphologyEx(circle, cv2.MORPH_ERODE, kernel)
    
    # combine inverted morph and circle
    mask2 = cv2.bitwise_and(255-morph, 255-morph, mask=circle)
    
    # apply mask to image
    result = cv2.bitwise_and(img, img, mask=mask2)
    
    # save results
    cv2.imwrite('pills_thresh2.jpg', thresh)
    cv2.imwrite('pills_morph2.jpg', morph)
    cv2.imwrite('pills_mask2.jpg', mask)
    cv2.imwrite('pills_hull2.jpg', hull)
    cv2.imwrite('pills_circle.jpg', circle)
    cv2.imwrite('pills_result2.jpg', result)
    
    cv2.imshow('thresh', thresh)
    cv2.imshow('morph', morph)
    cv2.imshow('mask', mask)
    cv2.imshow('hull', hull)
    cv2.imshow('circle', circle)
    cv2.imshow('mask2', mask2)
    cv2.imshow('result', result)
    cv2.waitKey(0)
    cv2.destroyAllWindows()
    

    阈值图像:

    形态图像:

    填充轮廓图像:

    输入凸包:

    圆形图片:

    最终蒙版图片:

    结果:

    【讨论】:

    • 我添加了另一张图片,我尝试将您的代码应用于第二张图片但效果不佳。
    • 我修复了另一张图片的问题。只需要调整上下数组
    【解决方案2】:

    这是 Python/OpenCV 中的一种方法。将图像设置为白色阈值。然后应用一些形态来清理它。然后将其反转以制作蒙版。然后将掩码应用于输入。我注意到你的药片与戒指重叠。所以这个方法不会去掉环。

    输入:

    import cv2
    import numpy as np
    
    # Read image
    img = cv2.imread('pills.jpg')
    hh, ww = img.shape[:2]
    
    # threshold on white
    # Define lower and uppper limits
    lower = np.array([200, 200, 200])
    upper = np.array([255, 255, 255])
    
    # Create mask to only select black
    thresh = cv2.inRange(img, lower, upper)
    
    # apply morphology
    kernel = cv2.getStructuringElement(cv2.MORPH_ELLIPSE, (20,20))
    morph = cv2.morphologyEx(thresh, cv2.MORPH_CLOSE, kernel)
    
    # invert morp image
    mask = 255 - morph
    
    # apply mask to image
    result = cv2.bitwise_and(img, img, mask=mask)
    
    
    # save results
    cv2.imwrite('pills_thresh.jpg', thresh)
    cv2.imwrite('pills_morph.jpg', morph)
    cv2.imwrite('pills_mask.jpg', mask)
    cv2.imwrite('pills_result.jpg', result)
    
    cv2.imshow('thresh', thresh)
    cv2.imshow('morph', morph)
    cv2.imshow('mask', mask)
    cv2.imshow('result', result)
    cv2.waitKey(0)
    cv2.destroyAllWindows()
    

    阈值图像:

    形态清洁图像:

    面具图片:

    结果:

    【讨论】:

    • 是的,确实很有帮助,而且解释得很好。但是,我尝试应用到另一张图片上,图片并没有那么好。
    • 发布另一张图片。它有一个白色的中心圆吗?白色是纯白色吗?您可能需要调整 inRange 值。
    • @fmw42 要取下戒指并隔离药丸,请执行此继续过程。从您的形态清洁图像开始,找到最小的封闭圆,然后将其完全填充到新的蒙版上。从那里扩展这个新掩码,然后按位或仅隔离添加的边框部分。接下来我们逐位 - 并使用形态清洁图像。这应该将药丸与环“分离”,所以最后我们只需找到轮廓来隔离所有药丸:)
    • @nathancy。谢谢。但这与我在下面发布的内容不同。我对使用凸包的方法做了更多的介绍。你的 minEnclosureCircle 是个好主意。我已经忘记了。我希望 OpenCV 除了 fitEllipse 之外还有一个 fitCircle。有没有办法使用 fitEllipse 强制它找到一个半径的圆?
    • +0。 +1 一开始的想法是使用cv.inRange 来确定一个范围之间的阈值,但这就是我正在使用的全部内容。 -1 因为形态很复杂,我不知道它是如何工作的,而且它确实不起作用,至少对于我试图捕捉背景的通用图像(例如一个人站在任何颜色或色调的墙壁前)。在大多数这些一般情况下,形态学完全无法检测前景/背景。注意:事后证明,我没有对这个答案投票。
    猜你喜欢
    • 2020-06-03
    • 2021-11-29
    • 1970-01-01
    • 2020-12-05
    • 1970-01-01
    • 1970-01-01
    • 2017-07-06
    • 2020-12-11
    • 1970-01-01
    相关资源
    最近更新 更多