• 方案介绍
  • 附件下载
  • 相关推荐
申请入驻 产业图谱

3.6.1-霍夫变换检测圆形 STM32串口通信 openmv+STM32串口通信

03/21 08:32
354
加入交流群
扫码加入
获取工程师必备礼包
参与热点资讯讨论

联系方式.txt

共1个文件

**非常详细的视频和文字教程,讲解常见的openmv教程包括 巡线、物体识别、圆环识别、阈值自动获取等。非常适合学习openmv、K210、K230等项目
视频合集链接在


openmv教程合集 openmv入门到项目开发 openmv和STM32通信 openmv和opencv区别 openmv巡线 openmv数字识别教程LCD

3.6.1-霍夫变换检测圆形

圆形检测和卡尔曼滤波
在这里插入图片描述

# 导入硬件操作库和数学计算库
import sensor, image, time   # OpenMV摄像头操作库
from ulab import numpy as np  # 嵌入式版numpy库

"""
====================== 全局参数配置 ======================
"""
# 霍夫圆检测参数
HOUGH_THRESHOLD = 2000   # 边缘检测敏感度(2000-4000典型值,值越大需要更明显的边缘)
MIN_RADIUS = 10          # 目标最小识别半径(根据实际目标尺寸调整)
MAX_RADIUS = 50          # 目标最大识别半径(建议设为画面宽度的1/4)

# 卡尔曼滤波参数
TS = 1/60                # 时间步长(基于60FPS帧率计算)

"""
====================== 摄像头初始化 ======================
"""
sensor.reset()                      # 复位摄像头硬件
sensor.set_pixformat(sensor.RGB565) # 设置像素格式为RGB565(每个像素16位)
sensor.set_framesize(sensor.QQVGA)  # 设置分辨率160x120(平衡处理速度与精度)
sensor.set_vflip(True)              # 垂直镜像(根据摄像头安装方向调整)
sensor.set_hmirror(True)            # 水平镜像
sensor.set_auto_gain(False)         # 关闭自动增益(防止亮度突变影响检测)
sensor.set_auto_whitebal(False)     # 关闭自动白平衡(保持色彩一致性)
clock = time.clock()                # 创建帧率计时器

"""
====================== 卡尔曼滤波器实现 ======================
"""
class KalmanFilter:
    def __init__(self, initial_state):
        """
        卡尔曼滤波器初始化
        :param initial_state: 初始状态向量 [x, y, w, h, dx, dy]
        """
        # 状态转移矩阵(描述物理运动模型)
        self.A = np.array([
            [1, 0, 0, 0, TS, 0],  # x位置 = 前次x + 速度x*Δt
            [0, 1, 0, 0, 0, TS],  # y位置 = 前次y + 速度y*Δt 
            [0, 0, 1, 0, 0, 0],   # 宽度保持不变(假设目标尺寸稳定)
            [0, 0, 0, 1, 0, 0],   # 高度保持不变
            [0, 0, 0, 0, 1, 0],   # x方向速度保持不变(匀速模型)
            [0, 0, 0, 0, 0, 1]    # y方向速度保持不变
        ])
        
        self.C = np.eye(6)         # 观测矩阵(直接观测位置和尺寸)
        self.Q = np.diag([1e-6]*6) # 过程噪声(系统不确定性,值越小滤波越敏感)
        self.R = np.diag([1e-6]*6) # 观测噪声(测量误差,值越小越信任传感器数据)
        
        # 初始化状态
        self.x_hat = initial_state  # 状态估计向量 [x, y, w, h, dx, dy]
        self.p = np.diag([10]*6)    # 误差协方差矩阵(初始不确定性较大)

    def update(self, Z):
        """ 
        卡尔曼滤波更新步骤
        :param Z: 观测值向量 [x, y, w, h, dx, dy]
        :return: 更新后的状态估计
        """
        # ---------- 预测阶段 ----------
        x_hat_minus = np.dot(self.A, self.x_hat)            # 状态预测
        p_minus = np.dot(self.A, np.dot(self.p, self.A.T)) + self.Q  # 协方差预测

        # ---------- 更新阶段 ----------
        S = np.dot(self.C, np.dot(p_minus, self.C.T)) + self.R  # 新息协方差
        S_inv = np.linalg.inv(S + 1e-4*np.eye(6))          # 正则化逆矩阵(防止奇异)
        K = np.dot(np.dot(p_minus, self.C.T), S_inv)       # 卡尔曼增益计算
        innovation = Z - np.dot(self.C, x_hat_minus)       # 测量残差
        self.x_hat = x_hat_minus + np.dot(K, innovation)   # 状态修正
        self.p = np.dot((np.eye(6) - np.dot(K, self.C)), p_minus)  # 协方差更新
        return self.x_hat

# 初始化卡尔曼滤波器(初始状态:[中心x, 中心y, 宽度, 高度, x速度, y速度])
kf = KalmanFilter(np.array([80, 60, 30, 30, 2, 2]))  # 初始位置设为画面中心

"""
====================== 主处理循环 ======================
"""
while True:
    clock.tick()  # 开始帧计时
    img = sensor.snapshot().lens_corr(1.8)  # 捕获图像并进行镜头畸变校正(1.8为校正强度)
    # ===== 在画幅中心绘制小圆环标志 =====
    img.draw_circle(80, 60, 5, color=(0, 0, 0), thickness=1)  # 黑色小圆环,半径5像素
    
    # ===== 阶段1:全局圆形检测 =====
    circles = img.find_circles(
        threshold=HOUGH_THRESHOLD,  # 边缘检测阈值
        x_margin=10,    # 圆心x坐标允许误差(像素)
        y_margin=10,    # 圆心y坐标允许误差
        r_margin=10,    # 半径允许误差
        r_min=MIN_RADIUS,  # 物理约束最小半径
        r_max=MAX_RADIUS   # 物理约束最大半径
    )

    if circles:
        # ===== 阶段2:有效圆筛选 =====
        valid_circles = []
        img_center_x = img.width() // 2   # 图像中心x坐标(QQVGA为80)
        img_center_y = img.height() // 2  # 图像中心y坐标(QQVGA为60)
        
        # 筛选位于画面中心区域(±30像素)的圆
        for c in circles:
            dx = abs(c.x() - img_center_x)
            dy = abs(c.y() - img_center_y)
            if dx < 30 and dy < 30:  # 排除边缘误检
                valid_circles.append(c)
        
        if valid_circles:
            # ===== 阶段3:选择最优目标 =====
            target = max(valid_circles, key=lambda c: c.r())  # 优先大尺寸目标
            x, y, r = target.x(), target.y(), target.r()
            
            # 绘制检测结果(绿色实线圆)
            img.draw_circle(x, y, r, color=(0,255,0), thickness=2)
            
            # ===== 阶段4:卡尔曼滤波更新 =====
            # 构造观测向量(假设瞬时速度为零)
            Z = np.array([x, y, 2*r, 2*r, 0, 0])  
            state = kf.update(Z)  # 执行卡尔曼滤波
            
            # ===== 阶段5:预测结果处理 =====
            pred_x = int(state[0])      # 预测x坐标(像素)
            pred_y = int(state[1])      # 预测y坐标
            pred_r = int(state[2]/2)    # 预测半径(宽度/2)
            
            # 打印坐标信息(新增输出)
            print("卡尔曼预测坐标: X={}, Y={}, R={}".format(pred_x, pred_y, pred_r))
            
            # 可视化预测结果
            img.draw_cross(pred_x, pred_y, color=(255,0,0), size=10)  # 红色十字标记
            img.draw_circle(pred_x, pred_y, pred_r, color=(255,255,0))  # 黄色虚线预测圆

    # 输出性能指标
    print("帧率: {:.1f}FPS".format(clock.fps()))  # 保留一位小数


  • 联系方式.txt
    下载
点赞
收藏
评论
分享
加入交流群
举报

相关推荐

方案定制

去合作
方案开发定制化,2000+方案商即时响应!