龙空技术网

不可错过!一文让你学会OpenCV轮廓筛选与识别,全程干货

人工智能-泰罗 197

前言:

现时各位老铁们对“opencv 采集卡”大致比较珍视,大家都需要知道一些“opencv 采集卡”的相关知识。那么小编也在网上网罗了一些有关“opencv 采集卡””的相关文章,希望小伙伴们能喜欢,兄弟们一起来了解一下吧!

轮廓筛选

《OpenCV轮廓绘制详解》中我们已经学习了如何绘制轮廓。接下来,如果想要计算检测到的轮廓的大小,可以使用基于图像矩的方法或使用 OpenCV 函数 cv2.contourArea() 来计算检测到的轮廓的大小,本节中,我们将首先根据每个检测到的轮廓大小对其进行排序,在实践中,某些小的轮廓可能是噪声导致的,可能需要对轮廓进行筛选。

我们首先在画布上绘制不同半径的圆,用于后续检测:

# 画布image = np.ones((300,700,3), dtype='uint8')# 绘制不同半径的圆cv2.circle(image, (20, 20), 8, (64, 128, 0), -1)cv2.circle(image, (60, 80), 25, (128, 255, 64), -1)cv2.circle(image, (100, 180), 50, (64, 255, 64), -1)cv2.circle(image, (200, 250), 45, (255, 128, 64), -1)cv2.circle(image, (300, 250), 30, (35, 128, 35), -1)cv2.circle(image, (380, 100), 15, (125, 255, 125), -1)cv2.circle(image, (600, 210), 55, (125, 125, 255), -1)cv2.circle(image, (450, 150), 60, (0, 255, 125), -1)cv2.circle(image, (330, 180), 20, (255, 125, 0), -1)cv2.circle(image, (500, 60), 35, (125, 255, 0), -1)cv2.circle(image, (200, 80), 65, (125, 64, 125), -1)cv2.circle(image, (620, 80), 48, (255, 200, 128), -1)cv2.circle(image, (400, 260), 28, (255, 255, 0), -1)

接下来,检测图中的轮廓:

gray_image = cv2.cvtColor(image, cv2.COLOR_BGR2GRAY)# 阈值处理ret, thresh = cv2.threshold(gray_image, 50, 255, cv2.THRESH_BINARY)# 检测轮廓contours, hierarchy = cv2.findContours(thresh, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_NONE)# 打印检测到的轮廓数print("detected contours: '{}' ".format(len(contours)))

根据每个检测到的轮廓大小进行排序:

def sort_contours_size(cnts):    """根据大小对轮廓进行排序"""    cnts_sizes = [cv2.contourArea(contour) for contour in cnts]    (cnts_sizes, cnts) = zip(*sorted(zip(cnts_sizes, cnts)))    return cnts_sizes, cnts    (contour_sizes, contours) = sort_contours_size(contours)

最后进行可视化:

for i, (size, contour) in enumerate(zip(contour_sizes, contours)):    # 计算轮廓的矩    M = cv2.moments(contour)    # 质心    cX = int(M['m10'] / M['m00'])    cY = int(M['m01'] / M['m00'])    # get_position_to_draw() 函数与上例相同    (x, y) = get_position_to_draw(str(i + 1), (cX, cY), cv2.FONT_HERSHEY_SIMPLEX, 2, 5)    # 将排序结果置于形状的质心    cv2.putText(image, str(i + 1), (x, y), cv2.FONT_HERSHEY_SIMPLEX, 2, (255, 255, 255), 5)# show_img_with_matplotlib() 函数与上例相同show_img_with_matplotlib(image, 'image', 1)show_img_with_matplotlib(image, "result", 2)plt.show()

程序运行结果如下所示:

轮廓识别

我们之前已经介绍过了 cv2.approxPolyDP(),它可以使用 Douglas Peucker 算法用较少的点来使一个轮廓逼近检测的轮廓。此函数中的一个关键参数是 epsilon,其用于设置近似精度。我们使用 cv2.approxPolyDP(),以便根据被抽取的轮廓中的检测到顶点的数量识别轮廓(例如,三角形,方形,矩形,五角形或六角形)。为了减少点数,给定某个轮廓,我们首先计算轮廓的边( perimeter )。基于边,建立 epsilon 参数, epsilon 参数计算如下:

epsilon = 0.03 * perimeter

如果该常数变大(例如,从 0.03 变为 0.1 ),则 epsilon 参数也会更大,近似精度将减小,这导致具有较少点的轮廓,并且导致顶点的缺失,对轮廓的识别也将不正确,因为它基于检测到的顶点的数量;另一方面,如果该常数较小(例如,从0.03 变为 0.001),则 epsilon 参数也将变小,因此,近似精度将增加,将产生具有更多点的近似轮廓,对轮廓的识别同样会出现错误,因为获得了虚假顶点。

# 构建测试图像image = np.ones((300,700,3), dtype='uint8')cv2.circle(image, (100, 80), 65, (64, 128, 0), -1)pts = np.array([[300, 10], [400, 150], [200, 150]], np.int32)pts = pts.reshape((-1, 1, 2))cv2.fillPoly(image, [pts], (64, 255, 64))cv2.rectangle(image, (450, 20),(650, 150),(125, 125, 255),-1)cv2.rectangle(image, (50, 180),(150, 280),(255, 125, 0),-1)pts = np.array([[365, 220], [320, 282], [247, 258], [247, 182], [320, 158]], np.int32)pts = pts.reshape((-1, 1, 2))cv2.fillPoly(image, [pts], (125, 64, 125))pts = np.array([[645, 220], [613, 276], [548, 276], [515, 220], [547, 164],[612, 164]], np.int32)pts = pts.reshape((-1, 1, 2))cv2.fillPoly(image, [pts], (255, 255, 0))gray_image = cv2.cvtColor(image, cv2.COLOR_BGR2GRAY)ret, thresh = cv2.threshold(gray_image, 50, 255, cv2.THRESH_BINARY)# 轮廓检测contours, hierarchy = cv2.findContours(thresh, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_NONE)image_contours = image.copy()image_recognition_shapes = image.copy()# 绘制所有检测的轮廓draw_contour_outline(image_contours, contours, (255, 255, 255), 4)def get_position_to_draw(text, point, font_face, font_scale, thickness):    """获取图形坐标中心点"""    text_size = cv2.getTextSize(text, font_face, font_scale, thickness)[0]    text_x = point[0] - text_size[0] / 2    text_y = point[1] + text_size[1] / 2    return round(text_x), round(text_y)def detect_shape(contour):    """形状识别"""    # 计算轮廓的周长    perimeter = cv2.arcLength(contour, True)    contour_approx = cv2.approxPolyDP(contour, 0.03 * perimeter, True)    if len(contour_approx) == 3:        detected_shape = 'triangle'    elif len(contour_approx) == 4:        x, y, width, height = cv2.boundingRect(contour_approx)        aspect_ratio = float(width) / height        if 0.90 < aspect_ratio < 1.10:            detected_shape = "square"        else:            detected_shape = "rectangle"    elif len(contour_approx) == 5:        detected_shape = "pentagon"    elif len(contour_approx) == 6:        detected_shape = "hexagon"    else:        detected_shape = "circle"    return detected_shape, contour_approxfor contour in contours:    # 计算轮廓的矩    M = cv2.moments(contour)    # 计算轮廓的质心    cX = int(M['m10'] / M['m00'])    cY = int(M['m01'] / M['m00'])    # 识别轮廓形状    shape, vertices = detect_shape(contour)    # 绘制轮廓    draw_contour_points(image_contours, [vertices], (255, 255, 255))    # 将形状的名称置于形状的质心    (x, y) = get_position_to_draw(shape, (cX, cY), cv2.FONT_HERSHEY_SIMPLEX, 1.6, 3)    cv2.putText(image_recognition_shapes, shape, (x+35, y), cv2.FONT_HERSHEY_SIMPLEX, 1, (255, 255, 255), 3)# 可视化show_img_with_matplotlib(image, "image", 1)show_img_with_matplotlib(cv2.cvtColor(thresh, cv2.COLOR_GRAY2BGR), "threshold = 100", 2)show_img_with_matplotlib(image_contours, "contours outline (after approximation)", 3)show_img_with_matplotlib(image_recognition_shapes, "contours recognition", 4)plt.show()
相关链接:

OpenCV轮廓检测详解 - 掘金:

OpenCV图像矩详解 - 掘金:

OpenCV Hu不变矩详解 - 掘金:

OpenCV轮廓绘制详解 - 掘金:

作者:盼小辉丶

链接:

来源:稀土掘金

标签: #opencv 采集卡