• 方案介紹
  • 附件下載
  • 相關(guān)推薦
申請入駐 產(chǎn)業(yè)圖譜

3.4.7-卡爾曼濾波與運(yùn)動估計(jì)算法介紹和使用 openmv+STM32串口通信

03/20 09:51
758
加入交流群
掃碼加入
獲取工程師必備禮包
參與熱點(diǎn)資訊討論

聯(lián)系方式.txt

共1個文件

非常詳細(xì)的視頻和文字教程,講解常見的openmv教程包括 巡線、物體識別、圓環(huán)識別、閾值自動獲取等。非常適合學(xué)習(xí)openmv、K210、K230等項(xiàng)目
視頻合集鏈接在:


openmv教程合集 openmv入門到項(xiàng)目開發(fā) openmv和STM32通信 openmv和opencv區(qū)別 openmv巡線 openmv數(shù)字識別教程LCD

下面的代碼是自己寫幾個點(diǎn)的坐標(biāo),模擬后面識別到的物體,然后把前幾個點(diǎn)給卡爾曼算法,卡爾曼算法就會預(yù)測計(jì)算出后面的點(diǎn)軌跡

注意為了方便演示,這里給系統(tǒng)增加了500ms延時時間

    time. sleep_ms(500) #方便演示增加500ms延時時間

所以我們就想要大概調(diào)整下Ts時間

Ts = 1/2 #Ts = 1  幀率的倒數(shù)  這個要根據(jù)延時手動調(diào)節(jié)
import sensor, image, time
#*********[0]-增加卡爾曼計(jì)算需要數(shù)學(xué)計(jì)算的模塊導(dǎo)入*********************************************
import sensor, image, time, math
from ulab import numpy as np
#教程作者:好家伙VCC
#歡迎交流群QQ: 771027961 作者郵箱: 1930299709@qq.com
#更多教程B站主頁:[好家伙VCC的個人空間-好家伙VCC個人主頁-嗶哩嗶哩視頻](https://space.bilibili.com/434192043)
#淘寶主頁鏈接:[首頁-好家伙VCC-淘寶網(wǎng)](https://shop415231378.taobao.com)
#更多嵌入式手把手教程-盡在好家伙VCC
# 初始化攝像頭模塊
sensor.reset()  # 重置攝像頭,確保設(shè)備正常工作
sensor.set_pixformat(sensor.RGB565)  # 設(shè)置攝像頭的像素格式為RGB565,每個像素16位色深
sensor.set_framesize(sensor.QQVGA)  # 設(shè)置攝像頭的分辨率為QQVGA(160x120),適合快速處理

# *************************** 如果不需要鏡像就注釋掉以下代碼 **************************
# 攝像頭鏡像和翻轉(zhuǎn)設(shè)置,根據(jù)攝像頭的安裝方向調(diào)整
sensor.set_vflip(True)  # 設(shè)置垂直翻轉(zhuǎn),適用于攝像頭上下安裝的情況
sensor.set_hmirror(True)  # 設(shè)置水平翻轉(zhuǎn),適用于攝像頭左右安裝的情況
# *************************** 如果不需要鏡像就注釋掉以上代碼 **************************

sensor.skip_frames(time = 2000)  # 跳過前幾幀的圖像,確保圖像穩(wěn)定后再開始處理
sensor.set_auto_gain(False)  # 必須關(guān)閉自動增益,防止影響顏色追蹤
sensor.set_auto_whitebal(False)  # 必須關(guān)閉自動白平衡,防止影響顏色追蹤

# 創(chuàng)建一個時鐘對象,用于計(jì)算和控制幀率
clock = time.clock()
#****************演示預(yù)測定義的變量 用來表示要識別到的點(diǎn)************
ball_positions = [#*演示預(yù)測定義的變量 這個是80個點(diǎn)
    [20, 50, 5],
    [22, 50, 5],
    [24, 50, 5],
    [26, 50, 5],
    [28, 50, 5],
    [30, 50, 5],
    [32, 50, 5],
    [34, 50, 5],
    [36, 50, 5],
    [38, 50, 5],
    [40, 50, 5],
    [42, 50, 5],
    [44, 50, 5],
    [46, 50, 5],
    [48, 50, 5],
    [50, 50, 5],
    [52, 50, 5],
    [54, 50, 5],
    [56, 50, 5],
    [58, 50, 5],
    [60, 50, 5],
    [62, 50, 5],
    [64, 50, 5],
    [66, 50, 5],
    [68, 50, 5],
    [70, 50, 5],
    [72, 50, 5],
    [74, 50, 5],
    [76, 50, 5],
    [78, 50, 5],
    [80, 50, 5],
    [82, 50, 5],
    [84, 50, 5],
    [86, 50, 5],
    [88, 50, 5],
    [90, 50, 5],
    [92, 50, 5],
    [94, 50, 5],
    [96, 50, 5],
    [98, 50, 5],
    [100, 50, 5],
    [102, 50, 5],
    [104, 50, 5],
    [106, 50, 5],
    [108, 50, 5],
    [110, 50, 5],
    [112, 50, 5],
    [114, 50, 5],
    [116, 50, 5],
    [118, 50, 5],
    [120, 50, 5],
    [122, 50, 5],
    [124, 50, 5],
    [126, 50, 5],
    [128, 50, 5],
    [130, 50, 5],
    [132, 50, 5],
    [134, 50, 5],
    [136, 50, 5],
    [138, 50, 5],
    [140, 50, 5],
    [142, 50, 5],
    [144, 50, 5],
    [146, 50, 5],
    [148, 50, 5],
    [150, 50, 5],
    [152, 50, 5],
    [154, 50, 5],
    [156, 50, 5],
    [158, 50, 5],
    [160, 50, 5],
    [162, 50, 5],
    [164, 50, 5],
    [166, 50, 5],
    [168, 50, 5],
    [170, 50, 5],
    [172, 50, 5],
    [174, 50, 5],
    [176, 50, 5],
    [178, 50, 5],
    [180, 50, 5],
    [182, 50, 5],
    [184, 50, 5],
    [186, 50, 5],
    [188, 50, 5],
    [190, 50, 5],
    [192, 50, 5],
    [194, 50, 5],
    [196, 50, 5],
    [198, 50, 5],
    [200, 50, 5]
]

# 設(shè)置遍歷的起始索引和最大索引
start_index = 0  # 開始從哪個位置進(jìn)行識別

#*********************[1]-增加卡爾曼相關(guān)變量定義**有些參數(shù)需要根據(jù)情況調(diào)整 比如Ts*************************
Ts = 1/2 #Ts = 1  幀率的倒數(shù)  這個要根據(jù)延時手動調(diào)節(jié)
# 狀態(tài)空間矩陣定義
 # 狀態(tài)轉(zhuǎn)移矩陣 A,描述系統(tǒng)的狀態(tài)變化
#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]])
# 改進(jìn)狀態(tài)轉(zhuǎn)移矩陣A,將速度部分更明確地包含進(jìn)來A 是狀態(tài)轉(zhuǎn)移矩陣,描述了系統(tǒng)狀態(tài)(位置、速度等)的變化。該矩陣會把當(dāng)前的狀態(tài)轉(zhuǎn)換到下一時刻的狀態(tài)。
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]])

 # 觀測矩陣 C,描述從狀態(tài)到觀測值的映射關(guān)系  C 是觀測矩陣,它將狀態(tài)向量(位置、速度)與觀測量(圖像中的矩形框信息)聯(lián)系起來。這里假設(shè)觀測量是位置和速度。
C = np.array([[1,0,0,0,0,0],[0,1,0,0,0,0],[0,0,1,0,0,0],[0,0,0,1,0,0],[0,0,0,0,1,0],[0,0,0,0,0,1]])
# 過程噪聲協(xié)方差矩陣
# 過程噪聲協(xié)方差矩陣 Q,用于描述過程的隨機(jī)噪聲
#Q_value = [1e-8 for _ in range(6)]
#Q = np.diag(Q_value) #創(chuàng)建對角矩陣
# 增大過程噪聲矩陣Q_value,使得卡爾曼濾波更靈活地應(yīng)對物體快速運(yùn)動
#Q 是過程噪聲協(xié)方差矩陣,用于描述系統(tǒng)過程中的不確定性。矩陣的對角元素表示每個狀態(tài)變量的噪聲水平。
Q_value = [1e-6 for _ in range(6)]  # 調(diào)整過程噪聲值Q_value = [1e-6 for _ in range(6)]
Q = np.diag(Q_value)  # 更新過程噪聲協(xié)方差矩陣

# 觀測噪聲協(xié)方差矩陣  R 是觀測噪聲協(xié)方差矩陣,表示觀測過程中測量誤差的大小。
R_value = [1e-6 for _ in range(6)]
R = np.diag(R_value)
# 定義觀測量Z
x = 0 #左頂點(diǎn)x坐標(biāo)
y = 0 #左頂點(diǎn)y坐標(biāo)
last_frame_x = x #上一幀左頂點(diǎn)x坐標(biāo)
last_frame_y = y #上一幀左頂點(diǎn)y坐標(biāo)
w = 0 #矩形框?qū)挾葁
h = 0 #矩形框高度h
dx = 0 #左頂點(diǎn)x坐標(biāo)移動速度
dy = 0 #左頂點(diǎn)y坐標(biāo)移動速度
Z = np.array([x,y,w,h,dx,dy])
# 定義卡爾曼濾波函數(shù)變量
#x_hat = np.array([80,60,30,30,2,2]) # 初始估計(jì)的狀態(tài)值(位置、速度等)
# 初始狀態(tài)估計(jì):根據(jù)實(shí)際應(yīng)用情況調(diào)整位置和速度的初值
x_hat = np.array([80, 60, 30, 30, 2, 2])  # 根據(jù)你的應(yīng)用需要調(diào)整這些值

x_hat_minus = np.array([0,0,0,0,0,0]) # 初始預(yù)測的狀態(tài)值
p_value = [10 for _ in range(6)] # 狀態(tài)誤差的初始值 p 是狀態(tài)誤差的初始協(xié)方差矩陣。
p = np.diag(p_value)# 創(chuàng)建誤差協(xié)方差矩陣 p
#*********************[2]-增加卡爾曼濾波函數(shù)**這個不需要動基本復(fù)制過去就可以用***********************************************************************
# 卡爾曼濾波函數(shù)
#預(yù)測階段:利用狀態(tài)轉(zhuǎn)移矩陣和上一狀態(tài)估計(jì)預(yù)測當(dāng)前狀態(tài)。
#校正階段:通過卡爾曼增益對預(yù)測狀態(tài)進(jìn)行校正,使得估計(jì)值接近真實(shí)值。
#輸入 Z:觀測值(或測量值),通常是來自外部傳感器(例如相機(jī)、雷達(dá)等)的數(shù)據(jù)。在這個代碼中,Z 是一個包含目標(biāo)的位置信息(如矩形框的四個角坐標(biāo))的向量,格式為 [x, y, w, h, dx, dy],其中 x 和 y 是目標(biāo)的中心位置,w 和 h 是目標(biāo)的寬度和高度,dx 和 dy 是目標(biāo)的速度。
#輸出 x_hat:更新后的狀態(tài)估計(jì),包括位置(x, y)、寬度(w, h)、速度(dx, dy)。該值是通過卡爾曼濾波器的預(yù)測和校正步驟計(jì)算得到的最優(yōu)估計(jì)。
def Kalman_Filter(Z):
    global A,C,Q,R,x_hat,x_hat_minus,p
    # 預(yù)測部分
    x_hat_minus = np.dot(A,x_hat)
    p_minus = np.dot(A, np.dot(p, A.T)) + Q
    # 校正部分
    S = np.dot(np.dot(C, p_minus), C.T) + R
    # 選擇一個小的正則化項(xiàng)
    regularization_term = 1e-4
    # 正則化 S 矩陣
    S_regularized = S + regularization_term * np.eye(S.shape[0])
    # 計(jì)算正則化后的 S 矩陣的逆
    S_inv = np.linalg.inv(S_regularized)
    # 計(jì)算卡爾曼增益 K
    K = np.dot(np.dot(p_minus, C.T), S_inv)
    x_hat = x_hat_minus + np.dot(K,(Z - np.dot(C,x_hat_minus)))
    p = np.dot((np.eye(6) - np.dot(K,C)),p_minus)
    return x_hat
#*********************[3]-定義用于存儲給卡爾曼濾波使用的變量 用于保存一些歷史數(shù)據(jù)**這個也不需要動***********************************************************************
last_frame_location = [0 for _ in range(4)] #用于存儲上一幀的目標(biāo)位置,這通常用于目標(biāo)跟蹤和計(jì)算目標(biāo)移動等任務(wù)。一個長度為4的列表 last_frame_location,其中每個元素的初始值為 0
last_frame_rect = [0 for _ in range(4)]  #存儲上一幀檢測到的矩形框坐標(biāo) 成了一個長度為4的列表 last_frame_rect,并且每個元素的初始值為 0。
box = [0 for _ in range(4)] #生成一個包含四個子列表的列表,存儲x1,y1,x2,y2

# 主循環(huán),不斷獲取攝像頭圖像并進(jìn)行處理
while(True):
    clock.tick()  # 計(jì)時當(dāng)前幀的處理時間,計(jì)算幀率
    # 獲取當(dāng)前圖像并進(jìn)行鏡頭畸變校正,糾正因鏡頭產(chǎn)生的畸變
    img = sensor.snapshot().lens_corr(1.8)  # 1.8是畸變系數(shù),適當(dāng)調(diào)整可以改善圖像質(zhì)量

    start_index += 1  # 遍歷下一個位置
    if start_index >= 80: #如果值過大,就清零
        start_index = 0  # 將 start_index 重置為 0

    # 確定當(dāng)前需要使用哪個位置的數(shù)據(jù)
    if start_index < 25 or start_index > 40:   #設(shè)置多少個點(diǎn)設(shè)置為可以被檢測到
        #*********************[4]-賦值要輸入卡爾曼的數(shù)據(jù)*************
        circle_center_x, circle_center_y, circle_radius = ball_positions[start_index]  # 從ball_positions獲取當(dāng)前球的中心坐標(biāo)和半徑
        #*********************[4]-賦值要輸入卡爾曼的數(shù)據(jù)*************


        img.draw_circle(circle_center_x, circle_center_y, circle_radius, color=(192, 255, 0)) #繪制圓為綠色
        print("識別到的坐標(biāo)          recognition : center_x = {}, center_y = {}, radius = {}".format(circle_center_x, circle_center_y, circle_radius))

        #*********************[4]-檢測出要識別物體后通過物體位置坐標(biāo)等信息輸入卡爾曼**根據(jù)自己的實(shí)際情況賦值rect_x、rect_y、rect_w、rect_h*********
        #需要給賦值的是下面四個參數(shù) rect_x、rect_y、rect_w、rect_h 這些參數(shù)是圈住識別物體的矩形框
        # 計(jì)算矩形框的左上角坐標(biāo)和寬高 給要賦值的四個變量賦值
        rect_x = int(circle_center_x - circle_radius)  # 矩形框左上角的 x 坐標(biāo)
        rect_y = int(circle_center_y - circle_radius)  # 矩形框左上角的 y 坐標(biāo)
        rect_w = int(2 * circle_radius)  # 矩形框的寬度,等于圓的直徑
        rect_h = int(2 * circle_radius)  # 矩形框的高度,等于圓的直徑

        # 將矩形框的四個參數(shù)存儲到 rect 數(shù)組中
        rect = [rect_x, rect_y, rect_w, rect_h]
        box = [rect[0], rect[1], rect[0] + rect[2], rect[1] + rect[3]] # 計(jì)算標(biāo)記框的四個角坐標(biāo)(左上角和右下角)
        x, y, w, h = rect[0], rect[1], rect[2], rect[3]# 獲取新的矩形框的坐標(biāo) 識別成功的時候這個值是識別值的數(shù)據(jù)賦值
        dx = (x - last_frame_x) / Ts# 計(jì)算x方向的速度,假設(shè) Ts 為時間步長
        dy = (y - last_frame_y) / Ts# 計(jì)算y方向的速度
        Z = np.array([x, y, w, h, dx, dy]) # 構(gòu)造測量向量 Z,包括位置和速度
        x_hat = Kalman_Filter(Z)# 使用卡爾曼濾波器進(jìn)行狀態(tài)估計(jì)
        last_frame_x, last_frame_y = x, y # 更新上一幀的x, y坐標(biāo)
        last_frame_rect = rect# 更新上一幀的矩形框 識別成功的時候
        last_frame_location = box# 更新上一幀的位置 識別成功的時候
    else:
        #*********************[5]-檢測檢測不出物體時候 使用之前物體數(shù)據(jù)預(yù)測物體下面的位置等**不需要改動**********
        #解釋:根據(jù)卡爾曼濾波的預(yù)測值和目標(biāo)的速度來更新目標(biāo)的位置:
        #x_hat[0] 和 x_hat[1] 是預(yù)測的位置,x_hat[4] 和 x_hat[5] 是目標(biāo)的速度(速度分別對應(yīng) dx 和 dy)。
        #Ts 是時間步長。更新后的 x, y 位置是通過加入速度(dx 和 dy)的影響來計(jì)算的。
        #w 和 h 是目標(biāo)的寬度和高度,這些信息沒有改變,仍然使用 x_hat[2] 和 x_hat[3]。
        x,y,w,h = (x_hat[0] + (x_hat[4] * Ts)),(x_hat[1] + (x_hat[5] * Ts)),x_hat[2],x_hat[3]
        #解釋:計(jì)算目標(biāo)在 X 方向的速度(dx),通過當(dāng)前幀的 x 位置與上一幀的 last_frame_x 位置之差來計(jì)算,除以時間步長 Ts
        dx = (x - last_frame_x) / Ts
        #解釋:計(jì)算目標(biāo)在 Y 方向的速度(dy),通過當(dāng)前幀的 y 位置與上一幀的 last_frame_y 位置之差來計(jì)算,除以時間步長 Ts
        dy = (y - last_frame_y) / Ts
        #解釋:將目標(biāo)的位置、寬高、速度(dx 和 dy)組合成一個狀態(tài)向量 Z,這個向量將作為卡爾曼濾波器的輸入
        Z = np.array([x, y, w, h, dx, dy])
        #解釋:將狀態(tài)向量 Z 傳遞給卡爾曼濾波器 Kalman_Filter,以獲得更新后的預(yù)測狀態(tài) x_hat
        x_hat = Kalman_Filter(Z)
        #更新上一幀的目標(biāo)位置 last_frame_x 和 last_frame_y 為當(dāng)前幀的目標(biāo)位置 x 和 y,以便在下一幀計(jì)算速度時使用
        last_frame_x, last_frame_y = x, y
        #更新上一幀的目標(biāo)矩形框 last_frame_rect 為當(dāng)前幀的矩形框 x, y, w, h。
        last_frame_rect = [x,y,w,h]
        #更新上一幀的目標(biāo)位置 last_frame_location 為當(dāng)前幀的目標(biāo)位置。這是一個矩形框的坐標(biāo),包括左上角 (x, y) 和右下角 (x + w, y + h)
        last_frame_location = [x,y,(x + w),(y + h)]

    #*********************[6]-無論是否可以檢測到物體都 根據(jù)卡爾曼預(yù)測值繪制矩形框**這個不需要改動*********
    predicted_rect = [ # 使用卡爾曼濾波的預(yù)測值繪制預(yù)測的矩形框
        int(x_hat[0]),# 預(yù)測的矩形框左上角x坐標(biāo)
        int(x_hat[1]),# 預(yù)測的矩形框左上角y坐標(biāo)
        int(x_hat[2]), # 預(yù)測的矩形框?qū)挾?
        int(x_hat[3]) # 預(yù)測的矩形框高度
    ]
    # 繪制矩形框 這個就是一直繪制的卡爾曼預(yù)測的位置
    img.draw_rectangle(predicted_rect, color=(100, 100, 100))  # 使用灰色繪制矩形框
    #下面是把矩形轉(zhuǎn)化會園繪制的,我們不需要
    # 計(jì)算圓心坐標(biāo)和半徑
    center_x = int(x_hat[0] + x_hat[2] / 2)  # 圓心x坐標(biāo)(矩形框左上角x + 寬度的一半)
    center_y = int(x_hat[1] + x_hat[3] / 2)  # 圓心y坐標(biāo)(矩形框左上角y + 高度的一半)
    radius = int(min(x_hat[2], x_hat[3]) / 2)  # 半徑取矩形框?qū)挾群透叨鹊淖钚≈档囊话?
    # 輸出圓心坐標(biāo)和半徑信息
    print("卡爾曼預(yù)測       Predicted Circle: center_x = {}, center_y = {}, radius = {}".format(center_x, center_y, radius))


    # 打印當(dāng)前幀率(每秒幀數(shù)),便于調(diào)試性能
    print("FPS %f" % clock.fps())  # 輸出當(dāng)前的幀率
    time. sleep_ms(500) #方便演示增加500ms延時時間

  • 聯(lián)系方式.txt
    下載

相關(guān)推薦

方案定制

去合作
方案開發(fā)定制化,2000+方案商即時響應(yīng)!