假设我有一个灰度的,阈值图像,如下所示:
我需要圆圈的轮廓。我该怎么做呢?
我尝试了findContours
有多种选择:
RETR_EXTERNAL
:这仅返回外部矩形的轮廓
RETR_TREE
:这会返回太多轮廓(外圆和内圆的轮廓)
每个圆只需要1个轮廓。我想在原始圆上绘制另一个色环(绿色或红色)。我预先指定了多少个圆(在本例中为120个圆),但是因为它生成120 * 2 = 240个轮廓(每个圆2个轮廓),所以程序失败。
那么,有没有办法只获得矩形内的圆的轮廓,而每个圆仅获得1个轮廓?
答案 0 :(得分:1)
假设输入图像名为“ circles.jpg”。
首先,导入所需的库并以灰色格式加载图像。使用Numpy.where()函数可净化图像的前景和背景。然后在该图像上找到所有轮廓:
import cv2
import numpy as np
image_gray = cv2.imread("circles.jpg", 0)
image_gray = np.where(image_gray > 30, 255, image_gray)
image_gray = np.where(image_gray <= 30, 0, image_gray)
image_gray = cv2.adaptiveThreshold(image_gray, 255,
cv2.ADAPTIVE_THRESH_GAUSSIAN_C,
cv2.THRESH_BINARY, 115, 1)
_, contours, _ = cv2.findContours(image_gray, cv2.RETR_TREE, cv2.CHAIN_APPROX_SIMPLE)
第二,创建一个具有相同宽度和高度的空图像。然后,使用过滤条件在新创建的图像上绘制轮廓-轮廓必须具有圆形形状:
image_copy = np.zeros_like(image_gray) # create a new emtpy image
for cnt in contours:
peri = cv2.arcLength(cnt, True)
approx = cv2.approxPolyDP(cnt, 0.04 * peri, True)
(x, y, w, h) = cv2.boundingRect(cnt)
ar = w / float(h)
if len(approx) > 5 and 0.9 < ar < 1.1: # filtering condition
cv2.drawContours(image_copy, [cnt], 0, 255, -1)
第三,您需要将每个轮廓的区域存储到列表中,并删除所有过小的轮廓:
cnt_areas = []
cnt_circles = []
for cnt in contours:
(x, y, w, h) = cv2.boundingRect(cnt)
cnt_areas.append(w*h)
cnt_circles.append(cnt)
import statistics
median_size_limit = statistics.median(cnt_areas) * 0.3
cnt_circles = [cnt for i, cnt in enumerate(cnt_circles)
if cnt_areas[i] > median_size_limit]
最后,显示并检查结果:
# Draw the result and display
image = cv2.cvtColor(image_gray, cv2.COLOR_GRAY2RGB)
cv2.drawContours(image, cnt_circles, -1, (0, 0,255), 2)
cv2.imshow("Result Preview", image)
cv2.waitKey()
最终结果预览可以在这里查看: