**非常詳細(xì)的視頻和文字教程,講解常見的openmv教程包括 巡線、物體識(shí)別、圓環(huán)識(shí)別、閾值自動(dòng)獲取等。非常適合學(xué)習(xí)openmv、K210、K230等項(xiàng)目
視頻合集鏈接在
openmv教程合集 openmv入門到項(xiàng)目開發(fā) openmv和STM32通信 openmv和opencv區(qū)別 openmv巡線 openmv數(shù)字識(shí)別教程LCD
專刊openmv視覺文章鏈接:
https://blog.csdn.net/qq_46187594/category_12900902.html
3.6.2-通過顏色區(qū)域+霍夫變換檢測(cè)圓形+一種顏色閾值
優(yōu)化 滿足顏色閾值再進(jìn)行圓形檢測(cè),這樣可以放置誤識(shí)別其他圓形,
import sensor, image, time
from ulab import numpy as np
# ******************** 參數(shù)配置 ********************
# 紅色色環(huán)的LAB顏色閾值
RED_THRESHOLD = (0, 100, 0, 127, 0, 127) # LAB顏色空間的紅色閾值范圍
# 霍夫變換參數(shù)
HOUGH_THRESHOLD = 2000 # 圓形檢測(cè)的靈敏度,值越高要求邊緣越明顯
MIN_RADIUS = 10 # 檢測(cè)的最小半徑
MAX_RADIUS = 50 # 檢測(cè)的最大半徑
# 卡爾曼濾波參數(shù)
TS = 1/60 # 幀時(shí)間(假設(shè)幀率為60fps)
# 初始化攝像頭
sensor.reset() # 重置攝像頭
sensor.set_pixformat(sensor.RGB565) # 設(shè)置像素格式為RGB565
sensor.set_framesize(sensor.QQVGA) # 設(shè)置分辨率為QQVGA(160x120)
sensor.set_vflip(True) # 垂直翻轉(zhuǎn)圖像
sensor.set_hmirror(True) # 水平翻轉(zhuǎn)圖像
sensor.set_auto_gain(False) # 關(guān)閉自動(dòng)增益
sensor.set_auto_whitebal(False) # 關(guān)閉自動(dòng)白平衡
clock = time.clock() # 創(chuàng)建時(shí)鐘對(duì)象用于計(jì)算幀率
# ******************** 卡爾曼濾波器類 ********************
class KalmanFilter:
def __init__(self, initial_state):
# 狀態(tài)轉(zhuǎn)移矩陣
self.A = np.array([
[1, 0, 0, 0, TS, 0], # 位置和速度的狀態(tài)轉(zhuǎn)移
[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]
])
# 觀測(cè)矩陣
self.C = np.eye(6) # 單位矩陣,表示狀態(tài)和觀測(cè)值直接對(duì)應(yīng)
# 過程噪聲協(xié)方差矩陣
self.Q = np.diag([1e-6]*6) # 過程噪聲較小
# 觀測(cè)噪聲協(xié)方差矩陣
self.R = np.diag([1e-6]*6) # 觀測(cè)噪聲較小
# 初始狀態(tài)
self.x_hat = initial_state # 初始狀態(tài)估計(jì)值
self.p = np.diag([10]*6) # 初始誤差協(xié)方差矩陣
def update(self, Z):
# 預(yù)測(cè)步驟
x_hat_minus = np.dot(self.A, self.x_hat) # 預(yù)測(cè)狀態(tài)
p_minus = np.dot(self.A, np.dot(self.p, self.A.T)) + self.Q # 預(yù)測(cè)誤差協(xié)方差
# 更新步驟
S = np.dot(self.C, np.dot(p_minus, self.C.T)) + self.R # 計(jì)算卡爾曼增益的分母
S_inv = np.linalg.inv(S + 1e-4*np.eye(6)) # 計(jì)算逆矩陣,加入正則化項(xiàng)避免奇異矩陣
K = np.dot(np.dot(p_minus, self.C.T), S_inv) # 計(jì)算卡爾曼增益
self.x_hat = x_hat_minus + np.dot(K, (Z - np.dot(self.C, x_hat_minus))) # 更新狀態(tài)估計(jì)
self.p = np.dot((np.eye(6) - np.dot(K, self.C)), p_minus) # 更新誤差協(xié)方差
return self.x_hat
# 初始化卡爾曼濾波器
kf = KalmanFilter(np.array([80, 60, 30, 30, 2, 2])) # 初始狀態(tài):[x, y, w, h, dx, dy]
# ******************** 主循環(huán) ********************
while True:
clock.tick() # 記錄當(dāng)前幀的時(shí)間
img = sensor.snapshot().lens_corr(1.8) # 獲取圖像并校正鏡頭畸變
# ===== 在畫幅中心繪制小圓環(huán)標(biāo)志 =====
img.draw_circle(80, 60, 5, color=(0, 0, 0), thickness=1) # 黑色小圓環(huán),半徑5像素
# 第一步:顏色閾值分割,找到紅色區(qū)域
blobs = img.find_blobs([RED_THRESHOLD], merge=True, margin=10) # 查找紅色區(qū)域
if blobs:
# 取最大的紅色色塊
largest_blob = max(blobs, key=lambda b: b.area()) # 找到面積最大的紅色區(qū)域
img.draw_rectangle(largest_blob.rect(), color=(255,0,0)) # 繪制紅色區(qū)域的矩形框
# 第二步:在紅色區(qū)域內(nèi)檢測(cè)圓形
roi = (largest_blob.x(), largest_blob.y(), largest_blob.w(), largest_blob.h()) # 定義檢測(cè)區(qū)域
circles = img.find_circles(
threshold=HOUGH_THRESHOLD, # 圓形檢測(cè)的靈敏度
x_margin=10, # 圓心x坐標(biāo)的誤差范圍
y_margin=10, # 圓心y坐標(biāo)的誤差范圍
r_margin=10, # 半徑的誤差范圍
r_min=MIN_RADIUS, # 最小半徑
r_max=MAX_RADIUS, # 最大半徑
roi=roi # 限制檢測(cè)區(qū)域?yàn)榧t色區(qū)域
)
if circles:
# 篩選同心圓:取半徑最大的圓(假設(shè)最外層是目標(biāo))
valid_circles = []
for c in circles:
# 檢查是否在紅色區(qū)域中心附近
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() # 獲取圓心坐標(biāo)和半徑
img.draw_circle(x, y, r, color=(0,255,0)) # 繪制檢測(cè)到的圓環(huán)
# 更新卡爾曼濾波器
Z = np.array([x, y, 2*r, 2*r, 0, 0]) # 構(gòu)造觀測(cè)值:[x, y, w, h, dx, dy]
state = kf.update(Z) # 更新卡爾曼濾波器狀態(tài)
# 輸出卡爾曼濾波預(yù)測(cè)的圓心坐標(biāo)
print("卡爾曼預(yù)測(cè)坐標(biāo): X={}, Y={}, R={}".format(int(state[0]), int(state[1]), int(state[2]/2)))
# 繪制預(yù)測(cè)結(jié)果
if 'state' in locals(): # 如果存在卡爾曼濾波器的狀態(tài)
pred_x = int(state[0]) # 預(yù)測(cè)的圓心x坐標(biāo)
pred_y = int(state[1]) # 預(yù)測(cè)的圓心y坐標(biāo)
pred_r = int(state[2]/2) # 預(yù)測(cè)的半徑
# 約束圓心在紅色區(qū)域內(nèi)
if blobs:
blob_x, blob_y, blob_w, blob_h = largest_blob.rect() # 獲取紅色區(qū)域的邊界
pred_x = max(blob_x, min(blob_x + blob_w, pred_x)) # 約束x坐標(biāo)在紅色區(qū)域內(nèi)
pred_y = max(blob_y, min(blob_y + blob_h, pred_y)) # 約束y坐標(biāo)在紅色區(qū)域內(nèi)
pred_r = min(pred_r, min(blob_w, blob_h) // 2) # 約束半徑不超過紅色區(qū)域大小
# 繪制預(yù)測(cè)的圓心和圓環(huán)
img.draw_cross(pred_x, pred_y, color=(255,0,0)) # 紅色十字標(biāo)記圓心
img.draw_circle(pred_x, pred_y, pred_r, color=(255,255,0)) # 黃色圓環(huán)
# 打印幀率
print("FPS:", clock.fps()) # 輸出當(dāng)前幀率
閱讀全文