【OpenCV】高精度识别圆(支持复杂场景下的圆)

使用 OpenCV 霍夫变换-圆检测,对周围背景比较敏感,容易误识别,不受控。若你也有此困惑,建议试试本文中的方法,识别效果佳,能够很好地排除类圆矩形的干扰,话不多说直接上代码。

代码

一、实现类

import math

import cv2


class CircleDetector(object):

    '''
	Parameters
	----------
	img: ndarray
		A color image.
	threshold: int or float
        Image binary threshold.
	minRadius: int or float
		Minimum value of circle radius.
	maxRadius: int or flaot
		Maximum value of circle radius.

	Returns
	-------
	A tuple of (center(x, y), size(w, h), angle)
	'''
    def detectCircles(self, image, threshold, minRadius, maxRadius):
        circles = list()
        gray_image = cv2.cvtColor(image, cv2.COLOR_BGR2GRAY)
        blur_image = cv2.GaussianBlur(gray_image, (5, 5), 0)
        ret, thresh = cv2.threshold(gray_image, threshold, 255, cv2.THRESH_BINARY)
        kernel = cv2.getStructuringElement(cv2.MORPH_RECT, (5, 5), (-1, -1))
        thresh = cv2.morphologyEx(thresh, cv2.MORPH_CLOSE, kernel, (-1, -1))
        thresh = cv2.morphologyEx(thresh, cv2.MORPH_OPEN, kernel, (-1, -1))

        contours, hierarchy = cv2.findContours(thresh, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE)

        for cnt in contours:
            if len(cnt) < 5:
                continue

            area = cv2.contourArea(cnt)
            if area < (minRadius**2) * math.pi or area > (maxRadius**2) * math.pi:
                continue

            arc_length = cv2.arcLength(cnt, True)
            radius = arc_length / (2 * math.pi)

            if not (minRadius < radius and radius < maxRadius):
                continue

            ellipse = cv2.fitEllipse(cnt)
            ratio = float(ellipse[1][0]) / float(ellipse[1][1])

            if ratio > 0.9 and ratio < 1.1:
                corner = cv2.approxPolyDP(cnt, 0.02 * arc_length, True)
                cornerNum = len(corner)
                if cornerNum > 4: # 当cornerNum=4时,识别矩形;而cornerNum>4时,识别圆
                    circles.append(ellipse)

        return circles

二、使用

import cv2

from detector.circle_detector import CircleDetector

if __name__ == '__main__':
    src = 0
    cap = cv2.VideoCapture(src)

    detector = CircleDetector()
    
    while True:
        if not cap.isOpened():
            print('相机未打开')
            break

        ret, frame = cap.read()

        if not ret:
            continue

        circles = detector.detectCircles(frame, 158, 50, 200)
        img = frame.copy()

        for circle in circles:
            cv2.circle(img, (int(circle[0][0]), int(circle[0][1])), int(20), (0, 255, 0), thickness=5)

        cv2.imshow('image', img)
        key = cv2.waitKey(int(1000/30)) & 0xFF
        if key == ord(' '):
            break

三、注意事项

如果遇到无法识别,或者误识别,注意调整参数。

  1. 确保你图中所绘圆的半径在[minRadius, maxRadius]之间。
  2. 建议使用白背景黑圆作为识别目标,否之请自行调整Threshold,直到识别效果达到最佳状态(可以查看二值化图片进行分析)。

效果图

在这里插入图片描述

猜你喜欢

转载自blog.csdn.net/m0_53129012/article/details/127477838