如何使用OpenCV Python的SimpleBlobDetector()获取已检测圆形的惯性率及坐标
获取检测圆形的惯性率与坐标
我来帮你调整代码,顺利实现获取检测圆形的惯性率(你的核心需求)与坐标的功能。下面是具体的修改方案:
关键说明
你当前用SimpleBlobDetector已经能检测到符合条件的圆形Blob,但KeyPoint对象只直接提供坐标信息,惯性率需要通过计算Blob的图像矩得到——惯性率的定义是「最小惯性矩/最大惯性矩」,完美圆形的惯性率会接近1,和你设置的minInertiaRatio过滤条件逻辑一致。
修改后的完整代码
import numpy as np import cv2 as cv def calculate_inertia_ratio(contour): """计算轮廓的惯性率,和OpenCV SimpleBlobDetector的定义一致""" moments = cv.moments(contour) # 避免除以0的情况 if moments['mu20'] + moments['mu02'] == 0: return 0.0 # 惯性率计算公式 inv_ratio = (moments['mu20'] + moments['mu02'] - np.sqrt((moments['mu20'] - moments['mu02'])**2 + 4*moments['mu11']**2)) / \ (moments['mu20'] + moments['mu02'] + np.sqrt((moments['mu20'] - moments['mu02'])**2 + 4*moments['mu11']**2)) return inv_ratio video = "1.avi" cam = cv.VideoCapture(video) # 把检测器初始化移到循环外,避免重复创建浪费资源 detector_params = cv.SimpleBlobDetector_Params() detector_params.filterByCircularity = True detector_params.minCircularity = 0.1 detector_params.filterByConvexity = True detector_params.minConvexity = 0.1 detector_params.filterByInertia = True detector_params.minInertiaRatio = 0.01 detector_params.filterByArea = True detector_params.maxArea = 1000000 detector_params.minArea = 300 blob_detector = cv.SimpleBlobDetector_create(detector_params) while cam.isOpened(): ret, frame = cam.read() if not ret: break # 视频读取完毕,退出循环 gray_frame = cv.cvtColor(frame, cv.COLOR_BGR2GRAY) detected_blobs = blob_detector.detect(gray_frame) # 遍历每个检测到的Blob,提取坐标和计算惯性率 for idx, blob in enumerate(detected_blobs): # 1. 获取Blob中心坐标 center_x, center_y = blob.pt print(f"Blob {idx+1} 中心坐标: ({center_x:.2f}, {center_y:.2f})") # 2. 计算Blob的惯性率 # 根据Blob的尺寸截取ROI区域 radius = int(blob.size / 2) # 确保ROI不超出图像边界 x_start = max(0, int(center_x - radius)) y_start = max(0, int(center_y - radius)) x_end = min(gray_frame.shape[1], int(center_x + radius)) y_end = min(gray_frame.shape[0], int(center_y + radius)) blob_roi = gray_frame[y_start:y_end, x_start:x_end] # 二值化提取Blob轮廓 _, thresh = cv.threshold(blob_roi, 0, 255, cv.THRESH_BINARY_INV + cv.THRESH_OTSU) contours, _ = cv.findContours(thresh, cv.RETR_EXTERNAL, cv.CHAIN_APPROX_SIMPLE) if contours: # 取面积最大的轮廓(对应检测到的目标Blob) main_contour = max(contours, key=cv.contourArea) inertia_ratio = calculate_inertia_ratio(main_contour) print(f"Blob {idx+1} 惯性率: {inertia_ratio:.4f}\n") # 可选:在图像上标注惯性率信息 cv.putText(frame, f"IR: {inertia_ratio:.2f}", (int(center_x)+10, int(center_y)), cv.FONT_HERSHEY_SIMPLEX, 0.5, (0,255,0), 2) # 绘制检测结果 blank_canvas = np.zeros((1,1)) result_frame = cv.drawKeypoints(frame, detected_blobs, blank_canvas, (0,0,255), cv.DRAW_MATCHES_FLAGS_DRAW_RICH_KEYPOINTS) cv.imshow("door", result_frame) if cv.waitKey(1) == ord('q'): break # 释放资源 cam.release() cv.destroyAllWindows()
核心修改点说明
- 坐标提取:直接通过
blob.pt获取Blob的中心坐标,这是KeyPoint对象的原生属性,非常方便。 - 惯性率计算:
- 封装了
calculate_inertia_ratio函数,使用图像矩计算惯性率,公式和OpenCV内置的SimpleBlobDetector逻辑完全一致,保证结果准确。 - 针对每个Blob截取ROI区域,二值化后提取轮廓,再计算惯性率,确保只针对检测到的目标区域计算。
- 封装了
- 性能优化:把
SimpleBlobDetector的初始化移到循环外,避免每次循环重复创建检测器,提升视频处理的效率。
如果觉得ROI提取轮廓的方式有点繁琐,你也可以考虑用cv.HoughCircles做圆形检测,再对检测到的圆形区域计算惯性率,两种方案都能满足你的需求。
内容的提问来源于stack exchange,提问作者OnlyM
相关产品推荐
相关产品推荐

