昨天,我已經讓 Python 訂閱 /camera/image_raw,並透過 cv_bridge 把 ROS 2 的影像訊息轉成 OpenCV 可以處理的畫面。現在程式收得到影像了,下一步就是讓它從畫面中找出要追蹤的東西。
我的第一個目標,是 Gazebo 場景中的紅色方塊。今天先不急著讓 TurtleBot3 追上去,而是先回答一個問題:程式能不能從相機畫面裡,找出紅色目標的位置?
專題後續希望加入 YOLO,辨識比紅色方塊更複雜的目標。不過,如果一開始就同時處理模型辨識、影像傳遞和機器人控制,出了問題會很難知道是哪一段造成的。
所以我先從顏色辨識開始,主要是因為想先使用較簡單的 OpenCV 方法,建立完整的影像辨識與機器人控制流程。透過 HSV 顏色篩選,可以先確認相機影像是否正常取得、目標位置是否能正確計算,以及 TurtleBot 是否能根據辨識結果做出對應的轉向。
好處是,當程式出現問題時,比較容易判斷是影像處理、目標定位,還是機器人控制出了錯,也能降低一開始除錯的難度。等到基本流程穩定之後,再加入 YOLO 進行物件辨識,就不需要同時處理太多新的問題。前面建立好的流程,也能讓我之後加入 YOLO 時,不需要重新從頭建立整套影像與控制流程。
在 Day 5 中,我用 cv_bridge 將相機影像轉成 OpenCV 常用的 BGR 格式。BGR 用藍、綠、紅三個數值描述像素,但如果要直接設定「哪些像素算紅色」,還得同時考慮各通道的組合。
| 項目 | 代表什麼 | 可以怎麼理解 |
|---|---|---|
| H(Hue,色相) | 顏色的種類 | 偏紅、偏黃,還是偏藍? |
| S(Saturation,飽和度) | 顏色有多鮮明 | 數值低時,顏色看起來比較灰、比較淡 |
| V(Value,明度) | 顏色有多亮 | 數值低時,畫面會比較暗 |
因此,我會先把 BGR 影像轉成 HSV,再指定紅色可能落在哪些 H、S、V 範圍。HSV 並不是直接告訴電腦「這是一個方塊」;它做的是挑出符合紅色條件的像素。要找出畫面中的目標,還得接著分析這些像素聚集在哪裡。
色相可以想成一個環,紅色剛好落在環的起點與終點交界。也就是說,紅色會同時出現在 H 值較低與較高的位置。OpenCV 處理 8 位元 HSV 影像時,H 的範圍是 0~179,所以紅色通常要分成兩段來抓:
低 Hue 紅色:
0 ~ 10
高 Hue 紅色:
170 ~ 179
這裡的數字是方便理解的示例範圍,實際還要配合 S、V 的門檻,並依相機畫面、場景光線和方塊顏色調整。如果只設定其中一段,可能會漏掉一部分看起來同樣是紅色的像素。
我會分別產生兩張遮罩(Mask),再把它們合併。遮罩可以想成一張黑白的篩選圖:符合條件的地方顯示為白色,其餘顯示為黑色。這樣程式就能先把注意力放在紅色區域。
有了遮罩,還不能直接說「找到方塊」:畫面中可能有零散的紅色像素,甚至出現其他紅色物體。接下來要在遮罩中尋找輪廓,也就是一塊塊連在一起的區域邊界。
對目前這個只有紅色方塊的練習場景,我可以先從輪廓中挑出面積夠大的區域,再取得它在畫面中的位置。如果有許多紅色區域,還需要額外的規則決定哪一個才是目標。這個方法依賴場景設定,只能說找到了紅色區域,不能單靠顏色證明它一定是方塊。
整體流程整理如下:
/camera/image_raw
↓
Python Subscriber
↓
cv_bridge
↓
OpenCV BGR Image
↓
轉換成 HSV
↓
設定紅色範圍
↓
產生 Mask
↓
尋找輪廓
↓
找到紅色候選區域
這一步完成後,程式拿到的就不只是「畫面中有沒有紅色」,還能進一步知道紅色區域大約出現在畫面的哪裡。下一步,才有辦法比較目標位置與畫面中心,判斷 TurtleBot3 應該往哪個方向轉。
下一篇會接著處理目標的位置:紅色目標出現在畫面的左邊、右邊還是中央?程式又要怎麼計算它與畫面中心之間的偏差?