【发布时间】:2021-02-06 00:26:51
【问题描述】:
因为我是计算机视觉的新手。我还想问我如何删除这张图片的整个背景,只保留药片。我尝试了不同的方法,例如更改背景颜色,但仍然存在一些小边缘和噪点。
或者,如果所有白色背景都可以是中性色,圆圈之间没有线条。
【问题讨论】:
标签: python-3.x image opencv computer-vision
因为我是计算机视觉的新手。我还想问我如何删除这张图片的整个背景,只保留药片。我尝试了不同的方法,例如更改背景颜色,但仍然存在一些小边缘和噪点。
或者,如果所有白色背景都可以是中性色,圆圈之间没有线条。
【问题讨论】:
标签: python-3.x image opencv computer-vision
这是在 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()
阈值图像:
形态图像:
填充轮廓图像:
输入凸包:
圆形图片:
最终蒙版图片:
结果:
【讨论】:
这是 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()
阈值图像:
形态清洁图像:
面具图片:
结果:
【讨论】:
@nathancy。谢谢。但这与我在下面发布的内容不同。我对使用凸包的方法做了更多的介绍。你的 minEnclosureCircle 是个好主意。我已经忘记了。我希望 OpenCV 除了 fitEllipse 之外还有一个 fitCircle。有没有办法使用 fitEllipse 强制它找到一个半径的圆?
cv.inRange 来确定一个范围之间的阈值,但这就是我正在使用的全部内容。 -1 因为形态很复杂,我不知道它是如何工作的,而且它确实不起作用,至少对于我试图捕捉背景的通用图像(例如一个人站在任何颜色或色调的墙壁前)。在大多数这些一般情况下,形态学完全无法检测前景/背景。注意:事后证明,我没有对这个答案投票。