系統(tǒng)實(shí)戰(zhàn):從YOLOv8檢測(cè)到機(jī)械臂抓取標(biāo)定)
簡(jiǎn)介計(jì)算機(jī)視覺(jué)在果蔬機(jī)械采摘中的應(yīng)用研究是一份PDF格式的學(xué)術(shù)參考文獻(xiàn)面向農(nóng)業(yè)自動(dòng)化、智能采摘及計(jì)算機(jī)視覺(jué)方向的研究人員與在校學(xué)生。資源針對(duì)傳統(tǒng)人工采摘?jiǎng)趧?dòng)強(qiáng)度大、目標(biāo)識(shí)別困難等問(wèn)題系統(tǒng)講解計(jì)算機(jī)視覺(jué)系統(tǒng)的工作原理包括成像裝置與計(jì)算機(jī)兩大部分、照明裝置的作用以及單色/彩色攝像機(jī)的選型隨后構(gòu)建雙目立體視覺(jué)數(shù)學(xué)模型給出利用視差計(jì)算目標(biāo)深度的定位公式并介紹機(jī)械采摘系統(tǒng)硬件組成與軟件流程。全文源自期刊論文配有系統(tǒng)工作原理圖和視覺(jué)模型示意圖結(jié)構(gòu)嚴(yán)謹(jǐn)適合作為課題研究、課程設(shè)計(jì)或論文寫(xiě)作的專(zhuān)業(yè)指導(dǎo)。壓縮包僅含1個(gè)PDF文件大小1.35MB已有91人瀏覽學(xué)習(xí)。讀者可從中掌握從成像裝置配置、圖像處理與特征提取、雙目視差計(jì)算到機(jī)械臂執(zhí)行控制聯(lián)動(dòng)的完整技術(shù)鏈條為優(yōu)化果蔬采摘系統(tǒng)的識(shí)別精度和魯棒性提供直接參考。1. 果蔬采摘不是“換個(gè)場(chǎng)景跑模型”為什么視覺(jué)方案卡在果園而不是測(cè)試集計(jì)算機(jī)視覺(jué)在果蔬機(jī)械采摘里的地位比很多人想象的要重。采摘機(jī)器人的機(jī)械臂和末端執(zhí)行器這些年已經(jīng)做得比較成熟真正決定“能不能摘下來(lái)”的往往是視覺(jué)系統(tǒng)給出的目標(biāo)位置和成熟度判斷準(zhǔn)不準(zhǔn)。我在這類(lèi)項(xiàng)目里見(jiàn)過(guò)最多的翻車(chē)現(xiàn)場(chǎng)是檢測(cè)模型在測(cè)試集上 mAP 高得漂亮一裝到果園平臺(tái)車(chē)上遇上逆光、枝葉晃動(dòng)和果實(shí)互相遮擋框就開(kāi)始亂跳機(jī)械臂跟著空抓。這類(lèi)以 PDF 形式流傳的研究資料拆開(kāi)來(lái)看講的不是某一個(gè)模型的調(diào)參記錄而是從圖像采集、目標(biāo)識(shí)別、三維定位到機(jī)械臂引導(dǎo)的一整套工程鏈路。如果你正處在計(jì)算機(jī)視覺(jué)入門(mén)的階段或者做完課程項(xiàng)目想往農(nóng)業(yè)現(xiàn)場(chǎng)遷移這份拆解能幫你少走不少?gòu)澛?。它適合采摘機(jī)器人方向的工程師也適合打算把實(shí)驗(yàn)室視覺(jué)方案搬去果園的團(tuán)隊(duì)。2. 果蔬采摘視覺(jué)系統(tǒng)要解決的三件事識(shí)別、定位與成熟度判斷2.1 采摘場(chǎng)景與工業(yè)質(zhì)檢場(chǎng)景的差異目標(biāo)會(huì)動(dòng)、光線會(huì)變、枝條會(huì)擋工業(yè)視覺(jué)質(zhì)檢的場(chǎng)景通常是零件固定、光源固定、相機(jī)位置固定視覺(jué)系統(tǒng)要做的就是在恒定條件下找缺陷。果蔬采摘完全是另一個(gè)極端果實(shí)長(zhǎng)在樹(shù)上姿態(tài)隨機(jī)枝葉遮擋比例可能達(dá)到 20%陽(yáng)光角度從早上到下午能變六十度。計(jì)算機(jī)視覺(jué)和機(jī)器學(xué)習(xí)區(qū)別在這類(lèi)項(xiàng)目里體現(xiàn)得最明顯——目標(biāo)檢測(cè)和成熟度判斷依賴機(jī)器學(xué)習(xí)模型而相機(jī)標(biāo)定、坐標(biāo)變換、手眼關(guān)系這一類(lèi)是純幾何問(wèn)題模型再?gòu)?qiáng)也沒(méi)法替代標(biāo)定。這帶來(lái)三個(gè)直接后果。第一檢測(cè)模型不能只學(xué)“完整果實(shí)”的模板必須對(duì)截?cái)嗪驼趽豸敯舴駝t遮了一半的果實(shí)直接漏檢。第二機(jī)械臂要的是一個(gè)三維抓取點(diǎn)2D 檢測(cè)框本身不夠用還需要深度信息或額外的幾何計(jì)算。第三成熟度判斷不能簡(jiǎn)單看 RGB 像素均值因?yàn)橥瑯拥奶O(píng)果在正午陽(yáng)光和傍晚樹(shù)蔭下RGB 值可能差出一大截。如果你剛走完一版計(jì)算機(jī)視覺(jué)學(xué)習(xí)路線照著 CS231N 公開(kāi)課里的 PPT 把目標(biāo)檢測(cè)、圖像分類(lèi)刷了一遍很容易掉進(jìn)“模型精度第一”的思維定式。課程大作業(yè)教的是在標(biāo)準(zhǔn)數(shù)據(jù)集上刷分果園里卻沒(méi)有現(xiàn)成數(shù)據(jù)集只有一臺(tái)相機(jī)和一片你控制不了光照的樹(shù)。所以采摘視覺(jué)的第一步不是調(diào)模型而是選好相機(jī)、定好拍攝策略、把數(shù)據(jù)閉環(huán)建立起來(lái)。想明白這件事后面所有環(huán)節(jié)的推進(jìn)都會(huì)順很多。2.2 成熟度判斷顏色空間直方圖與深度學(xué)習(xí)回歸怎么選成熟度判斷在論文里會(huì)有各種高光譜、遙感指數(shù)的方法但真正落地時(shí)主流只有兩條路線傳統(tǒng)顏色閾值和深度學(xué)習(xí)分類(lèi)/回歸。傳統(tǒng)顏色閾值常用 HSV 空間而不是 RGB。原因很簡(jiǎn)單HSV 把亮度放在獨(dú)立的 V 通道色調(diào) H 和飽和度 S 對(duì)光照變化相對(duì)不敏感。對(duì)番茄、柑橘這類(lèi)成熟后果色變化明顯的果實(shí)設(shè)定“色調(diào)在某個(gè)區(qū)間、飽和度高于某個(gè)下限”就能把可采果和青果分開(kāi)。這個(gè)方法沒(méi)有標(biāo)注成本算力幾乎為零適合作為第一版基線。深度學(xué)習(xí)方法則把成熟度當(dāng)成一個(gè)分類(lèi)或回歸任務(wù)。常見(jiàn)做法是訓(xùn)練一個(gè)小型 CNN輸入果實(shí)區(qū)域圖像輸出 1~5 的成熟度等級(jí)或者直接回歸一個(gè) 0~1 的成熟度分?jǐn)?shù)。它的優(yōu)勢(shì)是能處理顏色不規(guī)律的品種例如有些蘋(píng)果成熟后仍帶青底單靠色調(diào)閾值會(huì)誤判。代價(jià)是需要對(duì)每顆果實(shí)做成熟度標(biāo)注標(biāo)注一致性還很難保證。下表是我常用的選型對(duì)比方法光照魯棒性標(biāo)注成本算力需求適用場(chǎng)景HSV 色調(diào)閾值中無(wú)極低番茄、柑橘、紅蘋(píng)果等顏色分級(jí)清晰的果實(shí)色差指數(shù)Lab 空間中無(wú)極低需要連續(xù)量化顏色指標(biāo)時(shí)CNN 成熟度分類(lèi)較高高中顏色不規(guī)律、遮擋多的露天環(huán)境高光譜成像高很高高溫室或設(shè)施農(nóng)業(yè)光照可控我在實(shí)際項(xiàng)目里的順序是先用 HSV 規(guī)則跑半個(gè)月現(xiàn)場(chǎng)視頻統(tǒng)計(jì)誤判率如果超過(guò) 10% 再考慮訓(xùn)練成熟度分類(lèi)器。采摘系統(tǒng)的核心訴求是“可采/不可采”的決策穩(wěn)而不是成熟度等級(jí)分得有多細(xì)。很多論文把成熟度切成五級(jí)但機(jī)械臂只需要知道現(xiàn)在能不能摘。2.3 相機(jī)選型2D、雙目、結(jié)構(gòu)光與 ToF 的取舍既然機(jī)械臂要三維坐標(biāo)單顆 2D 相機(jī)就滿足不了要求。常見(jiàn)的深度獲取方式有四種2D RGB、雙目立體視覺(jué)、結(jié)構(gòu)光、ToF 飛行時(shí)間。表面上看都能給坐標(biāo)實(shí)際田間表現(xiàn)差別很大。方案深度原理露天抗光性典型精度主要坑2D RGB無(wú)需另算深度一般像素級(jí)沒(méi)有深度必須搭配其他方案雙目左右視差匹配中mm 到 cm弱紋理區(qū)域視差空洞結(jié)構(gòu)光投射編碼光斑差mm 級(jí)陽(yáng)光直射下光斑失效ToF光飛行時(shí)間較好cm 級(jí)邊緣飛點(diǎn)、多徑干擾結(jié)構(gòu)光相機(jī)在室內(nèi)精度很高但露天果園里陽(yáng)光直射時(shí)編碼光斑直接被環(huán)境光淹沒(méi)基本不可用。雙目相機(jī)在近距離效果不錯(cuò)問(wèn)題是果樹(shù)枝葉表面紋理太碎視差圖里經(jīng)常出現(xiàn)一塊塊空洞果實(shí)邊緣的深度值不穩(wěn)定。ToF 在陽(yáng)光下相對(duì)能扛但深度邊緣的飛點(diǎn)很麻煩果實(shí)和葉子交界處的深度會(huì)突然跳變。我一般推薦“一臺(tái)彩色相機(jī) 一臺(tái) ToF 或雙目”的組合彩色圖負(fù)責(zé)檢測(cè)和成熟度深度圖負(fù)責(zé)定位。兩個(gè)相機(jī)先做外參標(biāo)定把彩色圖上的檢測(cè)框中心映射到深度圖坐標(biāo)系上然后在深度圖上取中心鄰域的深度中值作為抓取深度。這個(gè)方案比純雙目多了一個(gè)標(biāo)定環(huán)節(jié)但每一路的算法都能做到簡(jiǎn)單穩(wěn)定后期排障也容易。如果想省掉外參標(biāo)定也可以直接用高質(zhì)量雙目相機(jī)在左目圖上做檢測(cè)再通過(guò)視差圖找深度。這幾年邊緣算力提升后這種方案開(kāi)始可行只是在反光葉片多的果園里雙目視差空洞的問(wèn)題仍然存在。選型取舍可以按“先求穩(wěn)、再求集成度”來(lái)定第一版系統(tǒng)里模塊越獨(dú)立越好別把深度和檢測(cè)耦合在同一個(gè)算法里。3. 用 YOLOv8 在本地跑通果蔬檢測(cè)數(shù)據(jù)集、訓(xùn)練、導(dǎo)出與成熟度規(guī)則3.1 果蔬數(shù)據(jù)集準(zhǔn)備實(shí)拍數(shù)量、YOLO 標(biāo)注格式與增強(qiáng)采摘數(shù)據(jù)集和公開(kāi)數(shù)據(jù)集最大的差別是背景復(fù)雜度和目標(biāo)姿態(tài)。COCO 里也有水果但大多是貨架商品圖或者擺拍圖背景干凈、光線均勻、目標(biāo)完整。果園實(shí)拍圖的背景是枝條、葉子、天空和地面果實(shí)之間互相遮擋顏色還隨環(huán)境強(qiáng)烈變化。所以第一原則是訓(xùn)練數(shù)據(jù)必須盡量來(lái)自目標(biāo)果園現(xiàn)場(chǎng)不能用公開(kāi)圖湊數(shù)。我一般每個(gè)果實(shí)類(lèi)別準(zhǔn)備 800~1500 張實(shí)拍圖覆蓋陰天、晴天、上午、下午四種條件物候期至少兩個(gè)階段比如青果期和轉(zhuǎn)色期。圖像保留相機(jī)原始分辨率訓(xùn)練時(shí)統(tǒng)一縮放到 640。標(biāo)注格式用 YOLO 文本格式每行一條目標(biāo)類(lèi)別ID 中心x/圖寬 中心y/圖高 目標(biāo)寬/圖寬 目標(biāo)高/圖高坐標(biāo)全部歸一化到 0~1 之間。標(biāo)注工具用 LabelImg 或 X-AnyLabeling 這類(lèi)帶 YOLO 導(dǎo)出的工具就行重點(diǎn)是把“枝條”也標(biāo)成一個(gè)類(lèi)別。注意如果數(shù)據(jù)集里沒(méi)有枝條類(lèi)別強(qiáng)烈建議在標(biāo)注階段就補(bǔ)上。機(jī)械臂避障需要它現(xiàn)在不標(biāo)后面補(bǔ)標(biāo)的時(shí)間和溝通成本高好幾倍。數(shù)據(jù)增強(qiáng)里值得做的依次是亮度對(duì)比度擾動(dòng)、隨機(jī)旋轉(zhuǎn)±30°、隨機(jī)裁剪、馬賽克增強(qiáng)。不建議做的是水平翻轉(zhuǎn)和垂直翻轉(zhuǎn)。果子有上垂下掛的天然姿態(tài)翻轉(zhuǎn)后模型學(xué)到的是在圖像里“倒掛的果子”定位和姿態(tài)后續(xù)都會(huì)出問(wèn)題。YOLO 訓(xùn)練時(shí)自動(dòng)增強(qiáng)默認(rèn)開(kāi)著通常夠用別再疊加一層隨機(jī)翻轉(zhuǎn)。3.2 訓(xùn)練命令和關(guān)鍵參數(shù)epochs、imgsz、batch、patience 怎么給先給一個(gè)最小配置文件。項(xiàng)目根目錄下建一個(gè)agri.yaml# agri.yaml path: ./datasets/agri train: images/train val: images/val nc: 2 names: 0: apple 1: branch訓(xùn)練命令我一般這樣寫(xiě)在 PyCharm 或 VS Code 的終端里直接跑# 在獨(dú)立虛擬環(huán)境里執(zhí)行Python 3.10 以上即可 yolo detect train \ dataconfig/agri.yaml \ modelyolov8n.pt \ epochs120 \ imgsz640 \ batch16 \ patience15 \ project./runs \ nameapple_v1幾個(gè)關(guān)鍵參數(shù)值得單獨(dú)說(shuō)明。model 選擇yolov8n.pt是因?yàn)椴烧獧C(jī)器人邊緣設(shè)備的算力有限n 版最快如果設(shè)備是 Jetson Orin 這類(lèi)可以換yolov8s.pt或yolov8m.ptm 版在遮擋場(chǎng)景的召回率明顯更好。沒(méi)有把握時(shí)先用 n 跑通全流程再往大模型遷移。imgsz 設(shè) 640 是精度和速度的平衡點(diǎn)。設(shè) 416 對(duì)小目標(biāo)召回差設(shè) 1280 雖然精度更高但算力需求翻好幾倍邊緣設(shè)備很難實(shí)時(shí)。batch 看顯存16 不行就降到 8batch 對(duì)最終精度的貢獻(xiàn)遠(yuǎn)不如 imgsz 和模型尺寸明顯。patience 設(shè) 15意思是驗(yàn)證集指標(biāo)連續(xù) 15 個(gè) epoch 不漲就早停。采摘數(shù)據(jù)分布雜這個(gè)值太大會(huì)讓訓(xùn)練拖到過(guò)擬合太小又可能沒(méi)跑到位就停了。跑完后看runs/apple_v1/weights/下的best.pt它是對(duì)驗(yàn)證集最優(yōu)的權(quán)重。3.3 推理腳本檢測(cè)框疊加成熟度評(píng)分模型訓(xùn)好之后一個(gè)比較完整的推理腳本長(zhǎng)這樣。它同時(shí)輸出檢測(cè)框和成熟度評(píng)分from ultralytics import YOLO import cv2 import numpy as np model YOLO(runs/apple_v1/weights/best.pt) img_bgr cv2.imread(test_frame.jpg) img_rgb cv2.cvtColor(img_bgr, cv2.COLOR_BGR2RGB) results model.predict(img_rgb, conf0.45, imgsz640, verboseFalse) def estimate_maturity(crop_rgb): 用色調(diào)和飽和度粗判成熟度返回 0~1 分?jǐn)?shù)。 hsv cv2.cvtColor(crop_rgb, cv2.COLOR_RGB2HSV) sat_mask hsv[:, :, 1] 60 # 只統(tǒng)計(jì)有顏色信息的像素 hue hsv[:, :, 0][sat_mask] if len(hue) 0: return 0.0 # 紅色果實(shí)的色調(diào)集中在 0 附近用高斯曲線把距離轉(zhuǎn)為分?jǐn)?shù) red_score np.mean(np.exp(-((hue - 5.0) / 20.0) ** 2)) return float(red_score) for r in results: for box in r.boxes: cls int(box.cls[0]) if model.names[cls] ! apple: continue x1, y1, x2, y2 map(int, box.xyxy[0].tolist()) crop img_rgb[y1:y2, x1:x2] score estimate_maturity(crop) print(f框({x1},{y1})-({x2},{y2}) 成熟度{score:.2f})這里用 HSV 而不是 RGB 判成熟度是因?yàn)?HSV 把亮度剝離開(kāi)了。拍攝角度和陰影變化主要影響亮度通道色調(diào)相對(duì)穩(wěn)定。hue - 5.0的基準(zhǔn)針對(duì)紅色果實(shí)換成柑橘類(lèi)要把基準(zhǔn)調(diào)到 15 附近或者先用一小段驗(yàn)證集統(tǒng)計(jì)色調(diào)分布再定。3.4 導(dǎo)出 ONNX 并接入采摘控制程序訓(xùn)練完成后把權(quán)重導(dǎo)出成 ONNX后續(xù)不管是 Python 還是 C 控制程序都能加載同一個(gè)模型文件yolo export modelruns/apple_v1/weights/best.pt formatonnx imgsz640 opset12導(dǎo)出后拿 ONNX Runtime 做一個(gè)最小推理import onnxruntime as ort import numpy as np import cv2 sess ort.InferenceSession(best.onnx, providers[CPUExecutionProvider]) input_name sess.get_inputs()[0].name def preprocess(img_bgr): img cv2.resize(img_bgr, (640, 640)) img cv2.cvtColor(img, cv2.COLOR_BGR2RGB) img img.astype(np.float32) / 255.0 img img.transpose(2, 0, 1) return np.expand_dims(img, 0).astype(np.float32) def postprocess(output): # YOLOv8 輸出形狀 [1, 4nc, 8400] preds output[0] boxes preds[:4].T # 中心點(diǎn)格式 scores preds[4:].T.max(axis1) cls_ids preds[4:].T.argmax(axis1) keep scores 0.45 return boxes[keep], scores[keep], cls_ids[keep]ONNX 導(dǎo)出的后處理最容易被漏掉。YOLOv8 的輸出不是直接可用的框坐標(biāo)而是 8400 個(gè)候選目標(biāo)的中心點(diǎn)、寬高和各類(lèi)別分?jǐn)?shù)需要自己做閾值過(guò)濾。opset 設(shè) 12 兼容性比較好部署到老版本 OpenCV 或者工業(yè)相機(jī)配套的 SDK 環(huán)境時(shí)不容易報(bào)錯(cuò)。在采摘控制程序里檢測(cè)線程和機(jī)械臂控制線程最好分開(kāi)檢測(cè)結(jié)果放進(jìn)共享隊(duì)列控制線程按最新一幀坐標(biāo)執(zhí)行這樣即使某幀檢測(cè)慢了也不至于讓機(jī)械臂停下等待。4. 從像素坐標(biāo)到機(jī)械臂抓取手眼標(biāo)定與坐標(biāo)映射的完整走法4.1 手眼標(biāo)定選型eye-in-hand 與 eye-to-hand 在果園里的取舍手眼標(biāo)定解決的是“相機(jī)看到的點(diǎn)”和“機(jī)械臂能抓的點(diǎn)”之間的關(guān)系。兩種接法都有eye-in-hand 是相機(jī)裝在機(jī)械臂末端跟著臂一起動(dòng)eye-to-hand 是相機(jī)固定在工作區(qū)域外臂在相機(jī)視野里作業(yè)。室內(nèi)機(jī)器人常用 eye-in-hand因?yàn)樗梢钥拷繕?biāo)精度高而且機(jī)械臂運(yùn)動(dòng)時(shí)視野可以換。但果園里這套會(huì)吃虧采摘平臺(tái)在地里會(huì)顛簸機(jī)械臂運(yùn)動(dòng)劇烈時(shí)末端相機(jī)圖像模糊線纜隨著關(guān)節(jié)反復(fù)彎曲故障率也高。eye-to-hand 把相機(jī)固定在采摘平臺(tái)的支架上視野覆蓋整棵樹(shù)的作業(yè)區(qū)域一次標(biāo)定能用很長(zhǎng)時(shí)間。我建議第一版采摘系統(tǒng)直接用 eye-to-hand相機(jī)固定在平臺(tái)上標(biāo)定一次后只要平臺(tái)不換位置就不用重新標(biāo)。平臺(tái)移動(dòng)后需要重新標(biāo)定所以整個(gè)標(biāo)定流程必須能在田間快速重跑一遍。如果你走的是計(jì)算機(jī)視覺(jué)學(xué)習(xí)路線可能更熟悉物體識(shí)別這一套手眼標(biāo)定的幾何部分會(huì)顯得枯燥但它恰恰是采摘定位誤差的主要來(lái)源。4.2 用 OpenCV 標(biāo)定相機(jī)內(nèi)參棋盤(pán)格拍攝與 calibrateCamera內(nèi)參標(biāo)定是為了拿到相機(jī)的焦距、主點(diǎn)坐標(biāo)和畸變系數(shù)。采摘現(xiàn)場(chǎng)的光線不可控標(biāo)定這一步不能省。用棋盤(pán)格照片標(biāo)定的流程如下import cv2 import numpy as np # 棋盤(pán)格內(nèi)角點(diǎn)數(shù)量建議 9x6 objp np.zeros((6 * 9, 3), np.float32) objp[:, :2] np.mgrid[0:9, 0:6].T.reshape(-1, 2) * 25.0 # 25mm 一格 obj_points, img_points [], [] calib_files [calib_01.jpg, calib_02.jpg, ...] # 15~20 張 for f in calib_files: img cv2.imread(f) gray cv2.cvtColor(img, cv2.COLOR_BGR2GRAY) ret, corners cv2.findChessboardCorners(gray, (9, 6), None) if ret: obj_points.append(objp) img_points.append(corners) ret, mtx, dist, rvecs, tvecs cv2.calibrateCamera( obj_points, img_points, gray.shape[::-1], None, None ) print(內(nèi)參矩陣:\n, mtx) print(畸變系數(shù):\n, dist)拍攝經(jīng)驗(yàn)就一條15 到 20 張圖必須覆蓋整個(gè)視野并且每張圖的角度都不一樣——有正對(duì)、有左傾、有右傾、有俯仰。全正對(duì)著拍是標(biāo)不出來(lái)的畸變參數(shù)會(huì)退化。果園現(xiàn)場(chǎng)光線強(qiáng)棋盤(pán)格會(huì)反光最好在樹(shù)蔭下標(biāo)定或者用啞光打印材料。標(biāo)定后保存mtx和dist后面每一步都用同一份內(nèi)參不要在多個(gè)環(huán)節(jié)各自重新標(biāo)。4.3 從 2D 檢測(cè)框到三維抓取點(diǎn)solvePnP 與齊次變換鏈拿到內(nèi)參之后把像素坐標(biāo)變成三維坐標(biāo)有兩種常見(jiàn)路徑。如果目標(biāo)有已知尺寸和姿態(tài)比如果箱或者人工放好的標(biāo)記物可以用 solvePnP 直接求位姿。果實(shí)沒(méi)有固定姿態(tài)通常用深度圖反投影更直接。反投影代碼import numpy as np # mtx 來(lái)自標(biāo)定depth_mm 是深度圖在像素 (u,v) 處的深度值 def image_to_camera(u, v, depth_mm, mtx): fx mtx[0, 0]; fy mtx[1, 1] cx mtx[0, 2]; cy mtx[1, 2] x (u - cx) * depth_mm / fx y (v - cy) * depth_mm / fy z depth_mm return np.array([x, y, z]) # 相機(jī)到機(jī)械臂基座的齊次變換矩陣由手眼標(biāo)定得到 T_base_cam np.load(T_base_cam.npy) # shape (4, 4) def camera_to_base(p_cam): p np.append(p_cam, 1.0) p_base T_base_cam p return p_base[:3]這里有兩處最容易踩。第一深度值不要取單像素。ToF 和雙目在果實(shí)邊緣都有噪聲單點(diǎn)可能跳變好幾厘米常見(jiàn)做法是取檢測(cè)框中心區(qū)域 5x5 鄰域的深度中位數(shù)。第二T_base_cam的平移單位必須和深度圖一致深度圖是毫米平移向量也得是毫米。注意深度圖單位是毫米手眼矩陣的平移向量也必須用毫米。米和毫米混用的結(jié)果是機(jī)械臂直接抓到空氣里。計(jì)算機(jī)視覺(jué)幾何偏置在采摘定位里是繞不開(kāi)的坎矩陣?yán)锏姆?hào)、單位、行序錯(cuò)一個(gè)地方末端位置就偏出好幾厘米而且這種錯(cuò)誤很難在屏幕上用肉眼發(fā)現(xiàn)。4.4 抓取目標(biāo)點(diǎn)怎么定果梗優(yōu)先還是果心優(yōu)先檢測(cè)框給的是果實(shí)的包圍盒中心點(diǎn)不一定適合抓。像蘋(píng)果、梨這類(lèi)有果梗的水果抓果梗不容易損傷果體但果梗在圖像里細(xì)、短、容易被葉子擋住。番茄、柑橘則適合直接抓果心只要末端夾爪力度控制好就行。我一般會(huì)在檢測(cè)框基礎(chǔ)上單獨(dú)找果梗在框內(nèi)圖像上用邊緣檢測(cè)或一個(gè)小分割模型把果梗區(qū)域提出來(lái)取它的質(zhì)心作為抓取點(diǎn)。找不到果梗時(shí)再退回果心這時(shí)候機(jī)械臂會(huì)多一個(gè)“保護(hù)性動(dòng)作”比如降低夾持力度或者先碰觸再用力。前面在數(shù)據(jù)集里加branch類(lèi)別也是給這一步用的——抓取路徑規(guī)劃時(shí)視覺(jué)系統(tǒng)同時(shí)把枝條障礙輸給機(jī)械臂避障路徑會(huì)好做很多。如果只檢測(cè)果實(shí)不管枝條采摘過(guò)程中機(jī)械臂和枝條糾纏會(huì)是家常便飯。如果論文方案里提到抓取姿態(tài)估計(jì)說(shuō)的是在坐標(biāo)之外還給一個(gè)果梗朝向角。小場(chǎng)景下可以先省略讓機(jī)械臂沿著相機(jī)到果心的方向逼近連續(xù)抓取成功率足夠驗(yàn)證時(shí)再引入姿態(tài)估計(jì)也不遲。5. 果蔬采摘視覺(jué)系統(tǒng)的 5 個(gè)踩坑現(xiàn)場(chǎng)與排查方法5.1 檢測(cè)框一抖機(jī)械臂就開(kāi)始亂抓NMS 閾值與目標(biāo)平滑現(xiàn)象果實(shí)被風(fēng)吹動(dòng)時(shí)同一顆果子的檢測(cè)置信度在 0.45 左右來(lái)回跳這一幀有框、下一幀沒(méi)框機(jī)械臂按瞬時(shí)坐標(biāo)執(zhí)行抓空率明顯提高。原因目標(biāo)檢測(cè)器本身是逐幀獨(dú)立推理的沒(méi)有時(shí)序記憶。果實(shí)擺動(dòng)、遮擋變化、快門(mén)模糊都會(huì)讓置信度抖動(dòng)。置信度閾值再低一點(diǎn)就會(huì)在“有框”和“沒(méi)框”之間反復(fù)橫跳。解決把檢測(cè)置信度閾值調(diào)到 0.6然后對(duì)檢測(cè)框中心做指數(shù)移動(dòng)平均。下面這段可以用在任何檢測(cè)后端上# 對(duì)檢測(cè)框中心做 EMA 平滑alpha 越大跟隨越快 def smooth_center(prev_pt, new_pt, alpha0.4): if prev_pt is None: return new_pt x alpha * new_pt[0] (1 - alpha) * prev_pt[0] y alpha * new_pt[1] (1 - alpha) * prev_pt[1] return (x, y)更完整的做法是接一個(gè) IOU Tracker 或者 ByteTrack 之類(lèi)的追蹤器給每個(gè)目標(biāo)分配 ID目標(biāo)丟幀后在短暫生命周期內(nèi)沿用上一幀位置。這樣機(jī)械臂不需要每秒都拿到新坐標(biāo)也能保持連續(xù)動(dòng)作。先平滑再追蹤順序不要反。5.2 大晴天果實(shí)過(guò)曝檢測(cè)框直接消失曝光鎖定與偏振片現(xiàn)象晴天下午的果園里自動(dòng)曝光模式下檢測(cè)率驟降向陽(yáng)面的果實(shí)變成一片白色圖里幾乎沒(méi)有紋理。原因相機(jī)的自動(dòng)曝光會(huì)被大面積天空和葉片帶偏局部過(guò)曝導(dǎo)致果實(shí)失去顏色和邊緣信息。自動(dòng)白平衡也會(huì)隨著畫(huà)面內(nèi)容漂移同一種果實(shí)早上和下午測(cè)出來(lái)的色調(diào)都不一樣。解決手動(dòng)固定曝光時(shí)間和 ISO關(guān)閉自動(dòng)曝光白平衡也用手動(dòng)對(duì)著一張灰卡或者葉片區(qū)域做一次基準(zhǔn)校正。鏡頭前加圓偏振片CPL可以減少葉片表面的高光反射讓果實(shí)顏色更飽和。注意偏振片會(huì)吃掉 1~2 擋進(jìn)光量陰天拍攝時(shí)要么拆掉要么配合補(bǔ)光燈。這個(gè)坑在實(shí)驗(yàn)室里永遠(yuǎn)遇不到只有在太陽(yáng)底下跑系統(tǒng)才會(huì)暴露。5.3 葉片遮擋讓同一顆果子一會(huì)有一會(huì)無(wú)多幀記憶與多視角現(xiàn)象果實(shí)被葉子遮住時(shí)檢測(cè)框消失風(fēng)把葉子吹開(kāi)后又出現(xiàn)機(jī)械臂執(zhí)行到一半失去目標(biāo)干脆停下報(bào)警。原因單幀檢測(cè)模型在嚴(yán)重遮擋時(shí)的召回率天然偏低模型沒(méi)有“這地方剛才有顆果子”的狀態(tài)記憶。解決接追蹤器并給目標(biāo)設(shè)置 2~3 秒的生命周期。當(dāng)前幀檢測(cè)不到時(shí)沿用上一幀坐標(biāo)并標(biāo)記為“推測(cè)狀態(tài)”推測(cè)狀態(tài)持續(xù)超過(guò)生命周期再刪除。同時(shí)用深度圖判斷果實(shí)和遮擋葉子的前后關(guān)系——如果深度圖上目標(biāo)區(qū)域被一片更近的葉子覆蓋則表明果實(shí)被遮擋不急著更新位置。條件允許的話在平臺(tái)低位再加一個(gè)側(cè)向相機(jī)補(bǔ)盲區(qū)效果比任何算法都直接。5.4 果園里標(biāo)定板沒(méi)法用ArUco 標(biāo)記與場(chǎng)景參照物現(xiàn)象棋盤(pán)格標(biāo)定板在果園里被風(fēng)吹倒、沾上泥打印的角點(diǎn)反光識(shí)別失敗采集中途標(biāo)定失效。原因標(biāo)準(zhǔn)棋盤(pán)格要求平面平整、對(duì)比度高、畫(huà)面完整。果園地面不平光線直射葉片還時(shí)不時(shí)擋住半塊板子現(xiàn)場(chǎng)條件滿足不了。解決改用 ArUco 碼。ArUco 對(duì)部分遮擋魯棒即使葉子擋住一半也能識(shí)別出來(lái)而且單個(gè)標(biāo)記就能提供位姿不用像棋盤(pán)格那樣必須看到完整角點(diǎn)陣。做法是打印幾張不同尺寸的 ArUco 碼貼在硬質(zhì)板上插入到工作區(qū)域顯眼的位置用cv2.aruco.detectMarkers實(shí)時(shí)檢測(cè)并求位姿。田間快速恢復(fù)外參時(shí)還可以找兩個(gè)已知距離的固定參照物果箱、支架立柱做尺度估計(jì)先恢復(fù)姿態(tài)再現(xiàn)場(chǎng)微調(diào)。5.5 實(shí)驗(yàn)室精度高、下地就不行品種差異與光照域遷移現(xiàn)象驗(yàn)證集 mAP 0.92拿到目標(biāo)果園同一天晴天測(cè)試檢出率掉到 0.6 以下?lián)Q個(gè)品種的果園更是慘不忍睹。原因深度學(xué)習(xí)模型對(duì)訓(xùn)練集的成像條件很敏感。實(shí)驗(yàn)室樣本的相機(jī)型號(hào)、光源色溫、背景紋理和果園現(xiàn)場(chǎng)差得遠(yuǎn)模型記住的是“實(shí)驗(yàn)室內(nèi)的一套外觀”而不是果實(shí)本身的普遍特征。這就是典型的域遷移問(wèn)題。解決把測(cè)試結(jié)果按“同園同品種、同園異品種、異園同品種”三組分別統(tǒng)計(jì)。如果同園異品種掉得厲害說(shuō)明模型只記住了表面顏色紋理需要補(bǔ)該品種的樣本微調(diào)如果異園同品種掉得厲害說(shuō)明光照和背景變了要去目標(biāo)果園先拍 500 張左右圖做一輪快速標(biāo)注再微調(diào)。下地之前盡量用目標(biāo)果園的現(xiàn)場(chǎng)圖做最后驗(yàn)證不要拿實(shí)驗(yàn)室照片做結(jié)果匯報(bào)。6. 從試驗(yàn)田到連續(xù)作業(yè)模型輕量化、驗(yàn)證路徑與數(shù)據(jù)回灌6.1 用剪枝、量化和 TensorRT 把模型壓到能上邊緣設(shè)備采摘機(jī)器人上常見(jiàn)的邊緣設(shè)備是 Jetson 系列或工控機(jī)加顯卡算力比實(shí)驗(yàn)室的 GPU 弱很多。YOLOv8n 導(dǎo)出 ONNX 后在 Jetson 上用 TensorRT 轉(zhuǎn)成 FP16 引擎通常能把推理時(shí)間壓到十幾毫秒級(jí)別。命令很簡(jiǎn)單trtexec --onnxbest.onnx --fp16 --saveEnginebest_fp16.engine不建議一上來(lái)就做 INT8 量化果園場(chǎng)景光照變化大INT8 需要帶標(biāo)定的校準(zhǔn)集做不好會(huì)讓召回率掉幾個(gè)點(diǎn)。先上 FP16實(shí)測(cè)召回率和 FP32 基本一致。如果算力仍然緊張?jiān)倏紤]對(duì)不重要的卷積層做剪枝但剪枝后的模型要重新微調(diào)時(shí)間成本不低。我的原則是能通過(guò)換小模型解決的問(wèn)題不優(yōu)先用剪枝解決。6.2 下地前先做視覺(jué)分離驗(yàn)證不看機(jī)械臂只看“判得準(zhǔn)不準(zhǔn)”視覺(jué)系統(tǒng)最忌和機(jī)械臂一起聯(lián)調(diào)因?yàn)閱?wèn)題會(huì)被互相掩蓋。下地之前先單獨(dú)把視覺(jué)系統(tǒng)跑在目標(biāo)果園的實(shí)拍視頻上連續(xù)回放一整天的數(shù)據(jù)人工核對(duì)每一幀的檢測(cè)、成熟度和坐標(biāo)輸出。推薦的驗(yàn)收指標(biāo)如下指標(biāo)推薦目標(biāo)說(shuō)明果實(shí)檢出召回率≥ 0.95每棵樹(shù)上的果實(shí)有沒(méi)有查全誤檢次數(shù)每天 ≤ 5 次葉片被當(dāng)成果實(shí)算誤檢成熟度一致率≥ 0.90和人工判斷結(jié)果比對(duì)定位誤差均值≤ 2 cm與實(shí)測(cè)坐標(biāo)比對(duì)可接受范圍按果實(shí)大小調(diào)整這個(gè)階段不花機(jī)械臂一分錢(qián)但能暴露檢測(cè)、標(biāo)定、深度映射里的大部分問(wèn)題。等離線視頻驗(yàn)證通過(guò)再做在線空跑和實(shí)際采摘。很多人把順序搞反一上來(lái)就全系統(tǒng)聯(lián)調(diào)出了問(wèn)題根本分不清是視覺(jué)錯(cuò)還是機(jī)械臂錯(cuò)。6.3 錯(cuò)例集回灌讓模型在采摘季里越用越準(zhǔn)系統(tǒng)上線后模型還會(huì)遇到訓(xùn)練時(shí)沒(méi)見(jiàn)過(guò)的場(chǎng)景比如新品種、新光照條件。所以每天下地回來(lái)把當(dāng)天被判錯(cuò)的圖像導(dǎo)出人工修正標(biāo)注積累成一個(gè)“錯(cuò)例集”。錯(cuò)例集積累到 200 張左右就可以觸發(fā)一次增量微調(diào)。訓(xùn)練腳本不變只是在原權(quán)重基礎(chǔ)上繼續(xù)訓(xùn)幾十個(gè) epoch。我習(xí)慣把訓(xùn)練分成采摘季前、季中、季后三個(gè)版本第一版用于測(cè)試第二版根據(jù)錯(cuò)例集修正第三版做全年數(shù)據(jù)全量重訓(xùn)。真正讓系統(tǒng)穩(wěn)定下來(lái)的往往不是某個(gè)模型結(jié)構(gòu)而是這套“采集-錯(cuò)例-重訓(xùn)”的循環(huán)。錯(cuò)例集比公開(kāi)數(shù)據(jù)集值錢(qián)它是現(xiàn)場(chǎng)真實(shí)分布的濃縮。希望你從這篇筆記開(kāi)始把視覺(jué)部分先獨(dú)立跑通再讓機(jī)械臂慢慢跟上能少走不少?gòu)澛?。希望幫到你。本文還有配套的精品資源點(diǎn)擊獲取