You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何使用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()

核心修改点说明

  1. 坐标提取:直接通过blob.pt获取Blob的中心坐标,这是KeyPoint对象的原生属性,非常方便。
  2. 惯性率计算:
    • 封装了calculate_inertia_ratio函数,使用图像矩计算惯性率,公式和OpenCV内置的SimpleBlobDetector逻辑完全一致,保证结果准确。
    • 针对每个Blob截取ROI区域,二值化后提取轮廓,再计算惯性率,确保只针对检测到的目标区域计算。
  3. 性能优化:把SimpleBlobDetector的初始化移到循环外,避免每次循环重复创建检测器,提升视频处理的效率。

如果觉得ROI提取轮廓的方式有点繁琐,你也可以考虑用cv.HoughCircles做圆形检测,再对检测到的圆形区域计算惯性率,两种方案都能满足你的需求。

内容的提问来源于stack exchange,提问作者OnlyM

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.04.27 16:52:33