**非常详细的视频和文字教程,讲解常见的openmv教程包括 巡线、物体识别、圆环识别、阈值自动获取等。非常适合学习openmv、K210、K230等项目
视频合集链接在
openmv教程合集 openmv入门到项目开发 openmv和STM32通信 openmv和opencv区别 openmv巡线 openmv数字识别教程LCD
专刊openmv视觉文章链接:
https://blog.csdn.net/qq_46187594/category_12900902.html
3.6.2-通过颜色区域+霍夫变换检测圆形+一种颜色阈值
优化 满足颜色阈值再进行圆形检测,这样可以放置误识别其他圆形,
import sensor, image, time
from ulab import numpy as np
# ******************** 参数配置 ********************
# 红色色环的LAB颜色阈值
RED_THRESHOLD = (0, 100, 0, 127, 0, 127) # LAB颜色空间的红色阈值范围
# 霍夫变换参数
HOUGH_THRESHOLD = 2000 # 圆形检测的灵敏度,值越高要求边缘越明显
MIN_RADIUS = 10 # 检测的最小半径
MAX_RADIUS = 50 # 检测的最大半径
# 卡尔曼滤波参数
TS = 1/60 # 帧时间(假设帧率为60fps)
# 初始化摄像头
sensor.reset() # 重置摄像头
sensor.set_pixformat(sensor.RGB565) # 设置像素格式为RGB565
sensor.set_framesize(sensor.QQVGA) # 设置分辨率为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):
# 状态转移矩阵
self.A = np.array([
[1, 0, 0, 0, TS, 0], # 位置和速度的状态转移
[0, 1, 0, 0, 0, TS],
[0, 0, 1, 0, 0, 0],
[0, 0, 0, 1, 0, 0],
[0, 0, 0, 0, 1, 0],
[0, 0, 0, 0, 0, 1]
])
# 观测矩阵
self.C = np.eye(6) # 单位矩阵,表示状态和观测值直接对应
# 过程噪声协方差矩阵
self.Q = np.diag([1e-6]*6) # 过程噪声较小
# 观测噪声协方差矩阵
self.R = np.diag([1e-6]*6) # 观测噪声较小
# 初始状态
self.x_hat = initial_state # 初始状态估计值
self.p = np.diag([10]*6) # 初始误差协方差矩阵
def update(self, Z):
# 预测步骤
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) # 计算卡尔曼增益
self.x_hat = x_hat_minus + np.dot(K, (Z - np.dot(self.C, x_hat_minus))) # 更新状态估计
self.p = np.dot((np.eye(6) - np.dot(K, self.C)), p_minus) # 更新误差协方差
return self.x_hat
# 初始化卡尔曼滤波器
kf = KalmanFilter(np.array([80, 60, 30, 30, 2, 2])) # 初始状态:[x, y, w, h, dx, dy]
# ******************** 主循环 ********************
while True:
clock.tick() # 记录当前帧的时间
img = sensor.snapshot().lens_corr(1.8) # 获取图像并校正镜头畸变
# ===== 在画幅中心绘制小圆环标志 =====
img.draw_circle(80, 60, 5, color=(0, 0, 0), thickness=1) # 黑色小圆环,半径5像素
# 第一步:颜色阈值分割,找到红色区域
blobs = img.find_blobs([RED_THRESHOLD], merge=True, margin=10) # 查找红色区域
if blobs:
# 取最大的红色色块
largest_blob = max(blobs, key=lambda b: b.area()) # 找到面积最大的红色区域
img.draw_rectangle(largest_blob.rect(), color=(255,0,0)) # 绘制红色区域的矩形框
# 第二步:在红色区域内检测圆形
roi = (largest_blob.x(), largest_blob.y(), largest_blob.w(), largest_blob.h()) # 定义检测区域
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, # 最大半径
roi=roi # 限制检测区域为红色区域
)
if circles:
# 筛选同心圆:取半径最大的圆(假设最外层是目标)
valid_circles = []
for c in circles:
# 检查是否在红色区域中心附近
if abs(c.x() - largest_blob.cx()) < 15 and abs(c.y() - largest_blob.cy()) < 15:
valid_circles.append(c)
if valid_circles:
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)) # 绘制检测到的圆环
# 更新卡尔曼滤波器
Z = np.array([x, y, 2*r, 2*r, 0, 0]) # 构造观测值:[x, y, w, h, dx, dy]
state = kf.update(Z) # 更新卡尔曼滤波器状态
# 输出卡尔曼滤波预测的圆心坐标
print("卡尔曼预测坐标: X={}, Y={}, R={}".format(int(state[0]), int(state[1]), int(state[2]/2)))
# 绘制预测结果
if 'state' in locals(): # 如果存在卡尔曼滤波器的状态
pred_x = int(state[0]) # 预测的圆心x坐标
pred_y = int(state[1]) # 预测的圆心y坐标
pred_r = int(state[2]/2) # 预测的半径
# 约束圆心在红色区域内
if blobs:
blob_x, blob_y, blob_w, blob_h = largest_blob.rect() # 获取红色区域的边界
pred_x = max(blob_x, min(blob_x + blob_w, pred_x)) # 约束x坐标在红色区域内
pred_y = max(blob_y, min(blob_y + blob_h, pred_y)) # 约束y坐标在红色区域内
pred_r = min(pred_r, min(blob_w, blob_h) // 2) # 约束半径不超过红色区域大小
# 绘制预测的圆心和圆环
img.draw_cross(pred_x, pred_y, color=(255,0,0)) # 红色十字标记圆心
img.draw_circle(pred_x, pred_y, pred_r, color=(255,255,0)) # 黄色圆环
# 打印帧率
print("FPS:", clock.fps()) # 输出当前帧率