點(diǎn)設(shè)計(jì):從HSV目標(biāo)提取到穩(wěn)定脫靶量輸出)
簡介這份資源是2023年全國大學(xué)生電子設(shè)計(jì)競賽E題視覺部分的完整代碼包面向備戰(zhàn)電賽視覺賽題的高校參賽隊(duì)與指導(dǎo)教師也適合想入門嵌入式視覺的開發(fā)者參考。方案基于Sipeed Maix BitK210開發(fā)板實(shí)現(xiàn)圖像采集、預(yù)處理、特征提取與目標(biāo)檢測跟蹤等視覺功能并配套主從云臺控制代碼主控采用STC32G12K128形成視覺與運(yùn)動控制協(xié)同的完整框架。壓縮包共352個文件、約19.47MB以C與H源碼、Keil工程文件uvproj、uvopt、編譯中間文件obj、lst、crf、map及hex燒錄文件為主另有少量Python腳本、lib庫、asm匯編、PDF與md說明文檔可直接在Keil環(huán)境下打開編譯。目前已有619人學(xué)習(xí)下載。讀者可從中獲得賽題視覺部分的工程組織方式、K210與STC32G的通信與控制分工、云臺步進(jìn)電機(jī)與MPU6050姿態(tài)模塊的驅(qū)動代碼以及可復(fù)用的圖像處理函數(shù)便于快速搭建穩(wěn)定的視覺系統(tǒng)并在其基礎(chǔ)上做二次開發(fā)與賽前調(diào)試。1. 需求先立住視覺部分要交付的是穩(wěn)定脫靶量不是一張識別截圖拿到某屆電子設(shè)計(jì)競賽 E 題視覺部分代碼這個題目很多人第一反應(yīng)是先把攝像頭點(diǎn)亮、把目標(biāo)框出來截一張識別成功的圖就算交差。真正上云臺一跑問題立刻暴露光斑在畫面里跳、云臺來回?cái)[、串口數(shù)據(jù)斷斷續(xù)續(xù)。E 題視覺部分要交付的不是一張識別截圖而是一串穩(wěn)定、有坐標(biāo)系、有時序約束的脫靶量。適合誰正在做電子設(shè)計(jì)競賽視覺題、課程設(shè)計(jì)里要做目標(biāo)跟蹤、畢設(shè)需要搭一套攝像頭到云臺執(zhí)行鏈路的人。關(guān)鍵詞里寫的是軟件/插件實(shí)際這套代碼更像獨(dú)立視覺節(jié)點(diǎn)它不替主控做控制決策只負(fù)責(zé)把目標(biāo)位置、置信狀態(tài)和幀序號講清楚。先把需求立住后面的方案才不會變成調(diào)參玄學(xué)。2. 總體方案設(shè)計(jì)采集、識別、解算、通信四層鏈路怎么拆視覺部分最容易寫成一坨取圖、閾值、找輪廓、算中心、發(fā)串口全塞在一個while True里。調(diào)參時看著能跑換一個光照或者換一個云臺就翻車。我一般把電賽視覺題拆成四層每層只回答一個問題采集層回答“畫面是否穩(wěn)定且低延遲”識別層回答“目標(biāo)在哪里、可不可信”解算層回答“像素偏差對應(yīng)云臺要轉(zhuǎn)多少”通信層回答“主控什么時候拿到、拿到的數(shù)據(jù)是否完整”。四層拆開之后參數(shù)有歸屬問題有邊界答辯時也能把鏈路講清楚。2.1 視覺鏈路拆分四個層各自只做一件事采集層不參與識別只負(fù)責(zé)相機(jī)索引、分辨率、幀率、曝光和增益。競賽現(xiàn)場常見的問題是自動曝光把光斑壓暗或者自動白平衡讓顏色漂移所以相機(jī)參數(shù)通常要手動鎖定。分辨率不是越高越好640×480 在 60 幀下往往比 1280×720 在 30 幀下更適合跟蹤因?yàn)榭刂骗h(huán)需要的是低延遲而不是一張好看的圖。采集層還要記錄幀時間戳后面做丟幀判斷和延遲統(tǒng)計(jì)都靠它。識別層只輸出候選目標(biāo)列表不直接決定最終目標(biāo)。候選列表里包含中心點(diǎn)、面積、外接圓半徑、圓形度、置信分?jǐn)?shù)。最終目標(biāo)選擇放在解算層因?yàn)檫x擇邏輯會用到上一幀位置和跟蹤狀態(tài)。這樣拆的好處是識別層可以單獨(dú)拿靜態(tài)圖片回放測試不用接云臺解算層可以拿錄好的像素坐標(biāo)離線跑不用反復(fù)上電。解算層負(fù)責(zé)坐標(biāo)映射、死區(qū)、限幅和丟幀保持。它不直接驅(qū)動舵機(jī)只輸出角度增量或者歸一化偏差。通信層負(fù)責(zé)幀頭、長度、校驗(yàn)、序號和發(fā)送頻率。視覺節(jié)點(diǎn)只發(fā)“偏差狀態(tài)”不背控制鍋主控愿意用 PID 還是比例控制是主控的事。職責(zé)一混出現(xiàn)振蕩時就會互相甩鍋視覺說主控參數(shù)太猛主控說視覺數(shù)據(jù)太跳。把接口定死排查才有黑匣子。目錄上我習(xí)慣分成camera/、detect/、solve/、comm/、config/五塊配置文件單獨(dú)放現(xiàn)場改閾值不用翻代碼。下面這份參數(shù)表是視覺節(jié)點(diǎn)的起點(diǎn)不同場地要改的是 HSV 和曝光不是整個結(jié)構(gòu)。camera: index: 0 width: 640 height: 480 fps: 60 exposure: -6 # 手動曝光現(xiàn)場按光斑亮度微調(diào) gain: 8 # 增益過高會放大噪聲 target: hsv_lower: [0, 120, 80] hsv_upper: [10, 255, 255] min_area: 80 max_area: 8000 min_circularity: 0.55 blur_ksize: 5 track: kp_x: 0.08 kp_y: 0.08 deadband_px: 3 lost_hold_frames: 5 serial: port: /dev/ttyUSB0 baud: 115200 frame_head: 0xAA55這段配置把相機(jī)、目標(biāo)、跟蹤、串口分開。exposure和gain需要現(xiàn)場鎖定自動模式在光斑移動時會反復(fù)調(diào)整導(dǎo)致閾值跟著漂。min_area和max_area不是拍腦袋寫的先用靜態(tài)靶在目標(biāo)距離上量出光斑像素面積再取 0.5 倍到 3 倍作為范圍。deadband_px用來抑制中心點(diǎn)抖動太小會讓云臺追著噪聲走太大又會出現(xiàn)明顯滯后。lost_hold_frames是丟幀保持幀數(shù)目標(biāo)短暫被遮擋時不要立刻發(fā)丟失否則主控會急停再啟動機(jī)械結(jié)構(gòu)容易抖。2.2 坐標(biāo)系對齊圖像中心、光軸中心和云臺零位不能混視覺題翻車最多的地方不是識別而是坐標(biāo)系。圖像中心是(width/2, height/2)光軸中心是相機(jī)鏡頭實(shí)際瞄準(zhǔn)的點(diǎn)云臺零位是舵機(jī)或電機(jī)安裝后的機(jī)械零位。這三個點(diǎn)不重合時畫面里目標(biāo)在中心云臺卻偏一邊。我的做法是先做靜態(tài)對中把靶點(diǎn)固定在遠(yuǎn)處手動把云臺零位對準(zhǔn)再讀圖像中心偏差把這個偏差記成offset_x、offset_y后面所有脫靶量都先減掉它。像素到角度的映射有兩種常用做法。小孔模型適合快速起步已知水平視場角HFOV焦距像素近似為f (width/2) / tan(HFOV/2)像素偏差dx對應(yīng)角度theta atan(dx / f)。但鏡頭畸變和安裝誤差會讓邊緣不準(zhǔn)所以正式驗(yàn)收前通常要做一張標(biāo)定表在畫面橫向和縱向各取 5 個點(diǎn)記錄像素偏差和云臺實(shí)際角度用分段線性或者二次擬合修正。標(biāo)定表不用很復(fù)雜但一定要有否則中心準(zhǔn)、邊緣飄追蹤快速目標(biāo)時就會畫圈。提示先把云臺零位、相機(jī)光軸、圖像中心三件事在同一張靜態(tài)圖上對齊再談跟蹤算法。順序反了后面調(diào)參全是玄學(xué)。2.3 通信幀設(shè)計(jì)視覺節(jié)點(diǎn)輸出偏差、狀態(tài)和序號視覺節(jié)點(diǎn)和主控之間最常見的問題是“數(shù)據(jù)看起來發(fā)了主控解析出來是亂碼”。原因通常不是串口壞了而是幀邊界不清楚只發(fā)浮點(diǎn)數(shù)沒有幀頭沒有長度沒有校驗(yàn)主控一上電從中間開始讀就把半個浮點(diǎn)當(dāng)成幀頭。我一般用固定幀結(jié)構(gòu)幀頭兩字節(jié)、長度一字節(jié)、兩個浮點(diǎn)偏差、一個狀態(tài)字節(jié)、一個序號字節(jié)、一個校驗(yàn)字節(jié)。浮點(diǎn)用小端打包主控和視覺端約定死。import struct def pack_frame(dx, dy, state, seq): # 幀頭固定 0xAA55長度表示 payload 字節(jié)數(shù) head b\xAA\x55 # ffBB 表示小端兩個 float、兩個 unsigned char payload struct.pack(ffBB, dx, dy, state, seq) length len(payload) checksum sum(payload) 0xFF return head bytes([length]) payload bytes([checksum])這段代碼只做打包不負(fù)責(zé)發(fā)送。dx、dy是解算后的像素偏差或歸一化偏差單位要在協(xié)議里寫清楚state用位標(biāo)志表示“目標(biāo)有效、目標(biāo)丟失、幀超時、飽和”seq每幀加一主控可以用它判斷有沒有丟幀。checksum用簡單累加和就夠競賽現(xiàn)場干擾沒有大到必須上 CRC但幀頭和長度必須有。發(fā)送頻率通常跟圖像幀率一致50 到 60 幀足夠主控控制環(huán)再快也不能拿舊幀硬補(bǔ)。3. 目標(biāo)提取實(shí)現(xiàn)HSV 閾值、輪廓篩選與中心點(diǎn)穩(wěn)定的三組參數(shù)目標(biāo)提取是視覺部分最直觀的一層也是最容易被“能識別”騙過去的一層。靜態(tài)圖上閾值一拉光斑清清楚楚現(xiàn)場燈光一打白墻反光、地面高光、隊(duì)友衣服上的顏色全跑進(jìn)來。HSV 比 RGB 穩(wěn)是因?yàn)樯{(diào) H 和亮度 V 分開光照變化主要影響 V顏色類別主要看 H 和 S。但 HSV 不是萬能藥閾值范圍給太寬會把背景吃進(jìn)來給太窄目標(biāo)稍微暗一點(diǎn)就丟。我的習(xí)慣是先用固定曝光拍幾張現(xiàn)場圖再用滑動條調(diào) H、S、V 上下限最后把范圍收窄到剛好包住目標(biāo)而不是包住所有可能。3.1 顏色空間選擇HSV 閾值要按現(xiàn)場光而不是屏幕光調(diào)調(diào)閾值時不要只看攝像頭預(yù)覽窗口那個窗口經(jīng)過顯示器和環(huán)境光和實(shí)際保存下來的幀不是一回事。我一般先抓一幀原圖存成 PNG用離線腳本讀圖調(diào)參調(diào)完再把參數(shù)寫回配置文件。H 通道在 OpenCV 里是 0 到 179紅色通???0 和 179 兩端所以紅色目標(biāo)往往要做兩段掩膜再合并綠色和藍(lán)色一般一段就夠。S 下限用來壓掉白色和灰色背景V 下限用來壓掉暗部噪聲。若現(xiàn)場有強(qiáng)反光V 上限也可以適當(dāng)限制避免高光區(qū)域被當(dāng)成目標(biāo)。閾值不是一勞永逸的。比賽現(xiàn)場從上午到下午窗邊自然光會變LED 補(bǔ)光燈角度也會變。我的做法是準(zhǔn)備兩套閾值一套“保守閾值”用于正式跟蹤寧可丟幾幀也不要亂框一套“寬松閾值”只用于調(diào)試和找目標(biāo)。運(yùn)行中如果連續(xù)多幀丟失再短暫切到寬松閾值搜目標(biāo)搜到后切回保守閾值。這樣比全程寬松穩(wěn)也比全程保守不容易丟。3.2 輪廓篩選面積、長寬比、圓形度三板斧二值化之后直接取最大輪廓是另一個常見翻車點(diǎn)。現(xiàn)場最大的白色區(qū)域可能是反光板不是目標(biāo)。輪廓篩選我一般看三個量面積、外接矩形長寬比、圓形度。面積用來排除噪點(diǎn)和過大背景長寬比用來排除長條形反光圓形度4πA/P2用來排除不規(guī)則亮斑。光斑通常是近似圓形圓形度在 0.5 以上比較合理。三個條件不必同時卡死可以做成評分面積越接近期望值、圓形度越高、離上一幀位置越近分?jǐn)?shù)越高。import cv2 import numpy as np def extract_target(frame, cfg): hsv cv2.cvtColor(frame, cv2.COLOR_BGR2HSV) lower np.array(cfg[hsv_lower], dtypenp.uint8) upper np.array(cfg[hsv_upper], dtypenp.uint8) mask cv2.inRange(hsv, lower, upper) # 先開后閉去掉孤立噪點(diǎn)再把斷裂的光斑連起來 kernel cv2.getStructuringElement(cv2.MORPH_ELLIPSE, (5, 5)) mask cv2.morphologyEx(mask, cv2.MORPH_OPEN, kernel, iterations1) mask cv2.morphologyEx(mask, cv2.MORPH_CLOSE, kernel, iterations2) cnts, _ cv2.findContours(mask, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE) best None for c in cnts: area cv2.contourArea(c) if area cfg[min_area] or area cfg[max_area]: continue perimeter cv2.arcLength(c, True) if perimeter 1e-6: continue circularity 4 * np.pi * area / (perimeter * perimeter) if circularity cfg[min_circularity]: continue (cx, cy), radius cv2.minEnclosingCircle(c) if radius 3: continue score area * circularity if best is None or score best[score]: best { x: float(cx), y: float(cy), r: float(radius), area: float(area), score: float(score), } return best, mask這段函數(shù)只返回一個最佳候選和掩膜方便調(diào)試時把掩膜顯示出來看。min_area和max_area決定哪些輪廓進(jìn)入評分min_circularity卡掉不規(guī)則亮斑score area * circularity是簡單評分實(shí)際項(xiàng)目里還可以加上“離上一幀距離”的權(quán)重避免兩個相似光斑之間來回跳。注意minEnclosingCircle給的是外接圓中心不是質(zhì)心光斑被部分遮擋時外接圓中心更穩(wěn)但形狀被拉長時會偏所以后面還要濾波。3.3 中心點(diǎn)解算與濾波滑動平均不能替代丟幀保護(hù)中心點(diǎn)解算常用質(zhì)心、外接圓中心、最小二乘擬合圓心。質(zhì)心對形狀敏感外接圓對遮擋敏感擬合圓心計(jì)算量大一些。競賽場景里目標(biāo)通常是圓形光斑我一般用外接圓中心加滑動平均起步夠用且計(jì)算量小。濾波窗口不要太大5 幀左右窗口越大越平滑但相位滯后越明顯云臺追快速目標(biāo)時會畫弧。更好的做法是自適應(yīng)濾波目標(biāo)靜止時窗口大一點(diǎn)目標(biāo)快速移動時窗口小一點(diǎn)用中心點(diǎn)位移速度判斷。丟幀保護(hù)比濾波更重要。目標(biāo)短暫被遮擋時如果立刻發(fā)“丟失”主控會急停再出現(xiàn)時又猛追機(jī)械結(jié)構(gòu)容易抖。我一般設(shè)lost_hold_frames 5丟失后的前 5 幀繼續(xù)發(fā)上一幀偏差但狀態(tài)位標(biāo)記“預(yù)測/保持”主控可以選擇降速跟蹤。超過 5 幀再發(fā)丟失主控進(jìn)入搜索模式。這個數(shù)字不是固定的云臺慣量大就設(shè)大一點(diǎn)慣量小就設(shè)小一點(diǎn)。濾波和保持都要在解算層做不要塞進(jìn)識別函數(shù)否則離線回放時很難復(fù)現(xiàn)。4. 坐標(biāo)映射與云臺接口像素偏差到角度指令的閉環(huán)設(shè)計(jì)識別到目標(biāo)只是半成品真正決定追蹤效果的是映射和控制接口。像素偏差 100 在畫面中心可能對應(yīng) 5 度在邊緣可能對應(yīng) 7 度鏡頭畸變越大差異越明顯。云臺控制環(huán)的輸入如果是“像素偏差”主控就要自己猜比例如果視覺節(jié)點(diǎn)直接發(fā)“角度增量”主控的 PID 更容易調(diào)。我一般讓視覺節(jié)點(diǎn)輸出歸一化偏差或者角度增量單位在協(xié)議里寫死主控只做閉環(huán)。這樣視覺部分可以單獨(dú)用錄制的像素序列回放不用每次都接云臺。4.1 相機(jī)標(biāo)定與像素-角度映射小孔模型起步分段標(biāo)定收尾小孔模型適合快速搭鏈路。已知相機(jī)水平視場角焦距像素f (width / 2) / tan(HFOV / 2)像素偏差dx對應(yīng)的角度近似atan(dx / f)。這個公式在畫面中心附近準(zhǔn)邊緣會受畸變影響。如果鏡頭是廣角邊緣誤差可能大到讓云臺追偏。我的做法是先用小孔模型跑通再在畫面橫向取 -240、-120、0、120、240 五個像素點(diǎn)記錄云臺實(shí)際角度做分段線性修正??v向同理。標(biāo)定表不用很密五點(diǎn)足夠覆蓋競賽場地。標(biāo)定時要注意云臺角度讀數(shù)和圖像采集的時間同步。如果云臺還在動就讀數(shù)標(biāo)定表會帶滯后。正確做法是云臺轉(zhuǎn)到位置后停 200 毫秒等畫面穩(wěn)定再采圖記錄當(dāng)前角度和光斑中心。標(biāo)定完成后把offset_x、offset_y和分段斜率寫進(jìn)配置運(yùn)行時先減偏移再查表。若現(xiàn)場換了鏡頭或者相機(jī)安裝角度標(biāo)定表必須重做不能沿用舊參數(shù)。4.2 串口協(xié)議實(shí)現(xiàn)幀頭、長度、校驗(yàn)、浮點(diǎn)打包串口協(xié)議在第 2 章已經(jīng)給了打包函數(shù)這里補(bǔ)接收端和狀態(tài)位。主控解析時先找0xAA55再讀長度再按長度收 payload最后校驗(yàn)。校驗(yàn)不過直接丟幀不要嘗試修復(fù)。浮點(diǎn)數(shù)用struct.unpack(ffBB, payload)解析字節(jié)序必須和發(fā)送端一致。狀態(tài)位建議定義清楚bit0 目標(biāo)有效bit1 目標(biāo)丟失bit2 幀超時bit3 輸出飽和。主控看到 bit3 時應(yīng)該限幅而不是繼續(xù)加大控制量。import struct def pack_frame(dx, dy, state, seq): # dx/dy 單位為角度增量保留浮點(diǎn)state 為位標(biāo)志 head b\xAA\x55 payload struct.pack(ffBB, dx, dy, state, seq) checksum sum(payload) 0xFF return head bytes([len(payload)]) payload bytes([checksum]) def unpack_frame(buf): # buf 至少包含幀頭長度payload校驗(yàn) if len(buf) 4 or buf[0] ! 0xAA or buf[1] ! 0x55: return None length buf[2] if len(buf) 3 length 1: return None payload buf[3:3 length] checksum buf[3 length] if (sum(payload) 0xFF) ! checksum: return None if length ! 10: return None dx, dy, state, seq struct.unpack(ffBB, payload) return {dx: dx, dy: dy, state: state, seq: seq}發(fā)送端每幀調(diào)用pack_frame接收端把串口緩沖喂給unpack_frame。length ! 10是防御性判斷防止協(xié)議版本不一致時解析錯位。實(shí)際項(xiàng)目里還可以加時間戳但競賽現(xiàn)場主控和視覺端通常共用一個電源時間戳同步要求不高序號足夠判斷丟幀。若串口出現(xiàn)連續(xù)校驗(yàn)失敗先查波特率和地線再查發(fā)送頻率是否超過主控解析能力。4.3 跟蹤策略比例控制、死區(qū)和丟幀保護(hù)視覺節(jié)點(diǎn)不直接做 PID但可以給主控一個建議控制量。比例控制u kp * error簡單有效kp太大云臺會來回?cái)[太小追不上快速目標(biāo)。死區(qū)deadband_px用來忽略中心附近的小抖動通常 2 到 5 像素。輸出限幅必須有否則目標(biāo)突然出現(xiàn)在畫面邊緣時云臺會猛沖機(jī)械結(jié)構(gòu)容易撞限位。丟幀保護(hù)前面說過保持幀數(shù)內(nèi)繼續(xù)發(fā)上一幀偏差并標(biāo)記預(yù)測狀態(tài)超過后發(fā)丟失。調(diào)參順序我一般這樣走先把云臺斷開只看視覺輸出的偏差曲線確認(rèn)目標(biāo)靜止時偏差不跳再接云臺給很小的kp讓云臺慢慢追確認(rèn)方向?qū)υ僦鸩郊哟髃p直到出現(xiàn)輕微過沖然后回調(diào) 20%。不要一上來就上大kp云臺撞限位一次齒輪間隙可能就變了后面調(diào)參全是血淚經(jīng)驗(yàn)。死區(qū)也不要設(shè)太大否則目標(biāo)在中心附近移動時云臺不動看起來像“識別丟了”其實(shí)是控制沒響應(yīng)。5. 避坑與排查視覺部分最容易翻車的五個現(xiàn)場問題視覺代碼在實(shí)驗(yàn)室跑通到現(xiàn)場翻車通常不是算法不夠先進(jìn)而是幾個工程細(xì)節(jié)沒兜住。下面五條是電賽視覺題里最常見的現(xiàn)場問題每條按“現(xiàn)象、原因、解決”寫照著排查能省很多時間。5.1 光照一變閾值全廢現(xiàn)象是上午能跟下午丟目標(biāo)現(xiàn)象同一套 HSV 閾值上午在窗邊能穩(wěn)定跟蹤下午太陽角度變了目標(biāo)要么丟要么背景反光被當(dāng)成目標(biāo)。原因自動曝光和自動白平衡沒有鎖定環(huán)境光變化讓 H、S、V 整體漂移閾值范圍又給得太寬背景一亮就進(jìn)入掩膜。解決相機(jī)曝光、增益、白平衡全部手動鎖定現(xiàn)場先用靜態(tài)靶抓圖按實(shí)際幀調(diào)閾值準(zhǔn)備保守和寬松兩套閾值丟失時短暫切寬松搜索搜到后切回保守跟蹤。閾值范圍收窄到剛好包住目標(biāo)不要追求“所有光照都能識別”。5.2 反光與同色背景導(dǎo)致輪廓亂跳現(xiàn)象是目標(biāo)框在兩個亮斑之間跳現(xiàn)象畫面里目標(biāo)明明只有一個識別框卻在兩個位置之間來回跳云臺跟著左右擺。原因現(xiàn)場有同色反光或者高光區(qū)域面積和圓形度都接近目標(biāo)評分函數(shù)只按面積選最大誰大選誰。解決在評分里加入“離上一幀中心距離”的權(quán)重近距離候選優(yōu)先用跟蹤門限限制候選范圍超過上一幀一定像素半徑的候選直接排除實(shí)在分不開時用形狀和亮度分布做二次篩選。不要只靠面積面積最大的不一定是目標(biāo)。5.3 坐標(biāo)沒對齊導(dǎo)致越追越偏現(xiàn)象是目標(biāo)在畫面中心云臺卻往一邊跑現(xiàn)象靜態(tài)看目標(biāo)已經(jīng)在畫面中心云臺零位也調(diào)過但一追動態(tài)目標(biāo)就慢慢偏出畫面。原因圖像中心、光軸中心、云臺零位沒有完全對齊或者像素角度映射只用了中心點(diǎn)比例邊緣誤差被放大。解決先做靜態(tài)對中記錄offset_x、offset_y再用五點(diǎn)標(biāo)定做分段修正運(yùn)行時先減偏移再映射。若換了相機(jī)安裝角度標(biāo)定表必須重做。這個坑很隱蔽因?yàn)殪o態(tài)圖看起來一切正常。5.4 分辨率太高幀率掉現(xiàn)象是識別準(zhǔn)但云臺反應(yīng)慢半拍現(xiàn)象高分辨率下識別很準(zhǔn)但云臺總是慢半拍快速移動目標(biāo)追不上。原因圖像分辨率和幀率、處理耗時是矛盾的大圖找輪廓耗時增加控制環(huán)拿到的是舊幀。解決跟蹤階段降到 640×480 或 320×240先保證 50 到 60 幀識別只在 ROI 里做ROI 根據(jù)上一幀中心外擴(kuò)關(guān)閉不必要的顯示窗口和調(diào)試輸出。幀率比單幀精度更重要控制環(huán)吃的是延遲。5.5 串口丟包與浮點(diǎn)解析錯現(xiàn)象是數(shù)據(jù)偶爾飛點(diǎn)云臺猛抖一下現(xiàn)象大部分時間正常偶爾云臺猛抖日志里出現(xiàn)一個非常大的偏差值。原因串口幀沒有幀頭或者校驗(yàn)接收端從中間開始讀浮點(diǎn)字節(jié)序不一致發(fā)送頻率超過主控解析能力。解決固定幀頭、長度、校驗(yàn)和序號接收端先找?guī)^再收長度校驗(yàn)失敗直接丟幀浮點(diǎn)統(tǒng)一小端發(fā)送頻率和主控解析頻率匹配。出現(xiàn)飛點(diǎn)時先看seq是否連續(xù)再看校驗(yàn)失敗計(jì)數(shù)不要先懷疑算法。6. 驗(yàn)收與答辯用五組可復(fù)現(xiàn)測試講清視覺部分的邊界視覺部分做完驗(yàn)收不要只說“能跟蹤”。我一般準(zhǔn)備五組可復(fù)現(xiàn)測試每組都有操作和通過標(biāo)準(zhǔn)答辯時直接拿數(shù)據(jù)說話。靜態(tài)靶看中心誤差和抖動階躍看響應(yīng)和過沖勻速看跟蹤滯后遮擋看丟幀保持和恢復(fù)光照變化看閾值魯棒性。測試前把相機(jī)曝光鎖定把云臺零位對齊把串口日志打開記錄幀序號和偏差序列。沒有日志的驗(yàn)收評委一問細(xì)節(jié)就只能憑感覺答。測試項(xiàng)操作通過標(biāo)準(zhǔn)靜態(tài)靶目標(biāo)固定在畫面中心附近 30 秒中心誤差小于 5 像素偏差峰峰值小于 3 像素階躍目標(biāo)從中心快速移到畫面一側(cè)云臺 1 秒內(nèi)跟上過沖小于 10%無持續(xù)振蕩勻速目標(biāo)沿畫面橫向勻速移動跟蹤滯后穩(wěn)定不出現(xiàn)周期性畫圈遮擋手動遮擋目標(biāo) 0.5 秒保持幀內(nèi)不報(bào)丟失恢復(fù)后 0.5 秒內(nèi)重新鎖定光照改變補(bǔ)光燈角度和亮度保守閾值下不誤框背景丟失后能切寬松閾值找回答辯講法我建議按“約束、鏈路、數(shù)據(jù)、邊界”四段走。先講現(xiàn)場約束光照不可控、云臺有慣量、串口有延遲再講鏈路采集、識別、解算、通信各做什么然后拿表格里的數(shù)據(jù)講靜態(tài)誤差、階躍響應(yīng)和丟幀恢復(fù)最后主動講失敗邊界比如強(qiáng)反光下會誤判、快速目標(biāo)在畫面邊緣會有滯后。主動講邊界比被評委問出來更加分。代碼不用逐行念挑extract_target的篩選邏輯和pack_frame的協(xié)議設(shè)計(jì)講清楚足夠說明你懂工程。從那以后我每次交付視覺代碼都強(qiáng)制先跑一遍靜態(tài)靶和階躍測試再談追蹤效果。沒有這兩組數(shù)據(jù)調(diào)參就是碰運(yùn)氣。希望幫到你。本文還有配套的精品資源點(diǎn)擊獲取