我有以下 python 代码来使用 cv2.findContours 提取形状的轮廓:
import cv2
import numpy as np
img = cv2.imread(
r'inp.png', cv2.IMREAD_COLOR)
def parse_shape(img):
hsv = cv2.cvtColor(img, cv2.COLOR_BGR2HSV)
# Dilate the image
kernel = np.ones((3,3), np.uint8)
dilate = cv2.dilate(hsv, kernel, iterations = 2)
# Get all the white pixels
lower_white_hsv = np.array([0, 0, 200])
upper_white_hsv = np.array([255, 255, 255])
# Create a mask for the white pixels and find contours
mask_hsv = cv2.inRange(dilate, lower_white_hsv, upper_white_hsv)
contours, _ = cv2.findContours(mask_hsv, cv2.RETR_TREE , cv2.CHAIN_APPROX_SIMPLE)
if len(contours) == 0:
print("No contours found from mask")
return None
# Filter out contours that are too small
# This filters out some noise but not all
contour_area_threshold = 600
valid_contours = []
for cnt in contours:
if cv2.contourArea(cnt) > contour_area_threshold:
valid_contours.append(cnt)
if len(valid_contours) == 0:
print("No valid contours found from mask")
return None
# Draw the contours on the image and show the resulting image
draw_img = img.copy()
cv2.drawContours(draw_img, valid_contours, -1, (0, 255, 0), cv2.FILLED)
cv2.imshow("draw_img", draw_img)
cv2.imshow("mask_hsv", mask_hsv)
cv2.waitKey(0)
cv2.destroyAllWindows()
return valid_contours
# Do stuff
lines = parse_shape(img)
现在已经非常接近了,但是正如您所看到的,仍然存在一些较大的间隙,这些间隙不能通过仅增加图像的稀释度来修复。 有什么办法可以填补空白吗? 如果形状被正确检测到,检查一个点是否在形状内部是非常简单的,但我似乎无法找到间隙的解决方案。
这不是通用解决方案,而是解决方案。
我添加了一个配置“DILATE_PARAMETER”,它指定膨胀多少次,以创建一个消除间隙的封闭区域。然后会找到该区域的轮廓,给出闭合轮廓。
“CONTOUR_AREA_THRESHOLD”也需要根据您的用例进行微调。
问题之一是轮廓与实际所需的轮廓有点远。
import cv2
import numpy as np
DILATE_PARAMETER = 8
CONTOUR_AREA_THRESHOLD = 5000
img = cv2.imread('ring.png', cv2.IMREAD_COLOR)
def parse_shape(img):
# Dilate the image
img_gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
kernel = np.ones((3,3), np.uint8)
dilate = cv2.dilate(img_gray, kernel, iterations = 2)
for _ in range(DILATE_PARAMETER-1):
dilate = cv2.dilate(dilate, kernel, iterations = 2)
# Create a mask for the white pixels and find contours
mask = cv2.inRange(dilate, 200, 255)
contours, _ = cv2.findContours(mask, cv2.RETR_EXTERNAL , cv2.CHAIN_APPROX_SIMPLE)
if len(contours) == 0:
print("No contours found from mask")
return None
# Filter out contours that are too small
# This filters out some noise but not all
valid_contours = []
for cnt in contours:
if cv2.contourArea(cnt) > CONTOUR_AREA_THRESHOLD:
valid_contours.append(cnt)
if len(valid_contours) == 0:
print("No valid contours found from mask")
return None
# Draw the contours on the image and show the resulting image
draw_img = img.copy()
cv2.drawContours(draw_img, valid_contours, -1, (0, 255, 0), 5)
cv2.imwrite("result.png",draw_img)
cv2.imshow("draw_img", draw_img)
cv2.waitKey(0)
cv2.destroyAllWindows()
return valid_contours
# Do stuff
lines = parse_shape(img)
输出