こんにちは.若尾です.
全開でラズパイのセットアップが終わっているはずなのでUSBカメラを接続してカラートラッキングまでの手順を記しました.
面白味が欲しければ考えるのでコメントしてください.
前の記事
目次
対象読者
1. USBカメラ と RaspberryPi との接続
2. guvcviewでカメラのテスト
3. 仮想環境の構築 ~ OpenCVの立ち上げ
4. USBカメラのリアルタイム表示
5. カラートラッキング
6. コード解説
7. まとめ
対象読者
- ラズパイで画像処理を始めたい人
- OpenCV初心者
- ロボット制御へ応用したい人
1. USBカメラ と RaspberryPi との接続
USBカメラ と RaspberryPi(以降 ラズパイ) との接続を確認します.USBカメラとラズパイを繋いで,ターミナルを立ち上げます.
私の場合(OS:2026-04-21-raspios-trixie-arm64)は左上のラズパイロゴマーク > アクセサリ > LXTerminalで立ち上げました.
コマンドを立ち上げたら,順番に以下のコマンドを実行していきます.
繋がれているUSBデバイスの確認
lsusb
↓ 実行結果
Bus 001 Device 001: ID 1d6b:0002 Linux Foundation 2.0 root hub
Bus 001 Device 002: ID 2109:3431 VIA Labs, Inc. Hub
Bus 001 Device 004: ID 0566:3107 Monterey International Corp. Keyboard
Bus 001 Device 005: ID 093a:2510 Pixart Imaging, Inc. Optical Mouse
Bus 001 Device 007: ID 0bda:58b0 Realtek Semiconductor Corp. FULL HD 1080P Webcam
Bus 002 Device 001: ID 1d6b:0003 Linux Foundation 3.0 root hub
ラズパイがカメラを認識しているかの確認
ls /dev/video*
↓ 実行結果
/dev/video0 /dev/video12 /dev/video16 /dev/video21
/dev/video1 /dev/video13 /dev/video18 /dev/video22
/dev/video10 /dev/video14 /dev/video19 /dev/video23
/dev/video11 /dev/video15 /dev/video20 /dev/video31
/dev/video0があればOKです.
2. guvcviewでカメラのテスト
guvcview というソフトウェアを用いて,USBカメラとの接続を確認します.
ターミナルで以下を実行してください.
sudo apt update
sudo apt upgrade -y
sudo apt install guvcview
インストールが終われば,ターミナルで以下を実行するとUSBカメラの映像が見れます.
guvcview
ウィンドウが複数開いている可能性があるので,映像が映っているウィンドウ以外が開いていても慌てずに探してみてください.
3. 仮想環境の構築 ~ OpenCVの立ち上げ
現在のラズパイOSは,仮想環境(venv)を使用することが推奨されています.そのため,仮想環境の構築をして,そこに依存関係をインストールしていきます.
Python関連の確認
python3 --version
pip3 --version
venvのインストール
sudo apt install python3-venv -y
仮想環境の構築
mkdir ~/opencv-project
cd ~/opencv-project
python3 -m venv venv
source venv/bin/activate
OpenCVインストール(ついでにNumPyも)
pip install opencv-python
pip install numpy
動作確認
python
import cv2
print(cv2.__version__)
↓ 実行結果
4.13.0
上記のように,バージョンが表示されればOKです.
exit() で抜けることができます.
今後の立ち上げ方
cd ~/opencv-project
source venv/bin/activate
4. USBカメラのリアルタイム表示
ファイル作成
nano camera_test.py
コード
import cv2
cap = cv2.VideoCapture(0)
if not cap.isOpened():
print("カメラを開けません")
exit()
while True:
ret, frame = cap.read()
if not ret:
print("フレーム取得失敗")
break
cv2.imshow("Camera", frame)
# qキーで終了
if cv2.waitKey(1) & 0xFF == ord('q'):
break
cap.release()
cv2.destroyAllWindows()
実行
python camera_test.py
5. カラートラッキング
できること
- 写されている画面で,マウスで囲うことで対象物体を指定
- 対象物体(と同じ色)の物体を1つ検知
- 対象物体を囲う四角形を描画
- 対象物体の中心座標を表示
ファイル作成
nano camera_test.py
コード
import cv2
import numpy as np
# グローバル変数
drawing = False
ix, iy = -1, -1
selected = False
hsv_lower = None
hsv_upper = None
frame_for_select = None
# マウスイベント
def select_color(event, x, y, flags, param):
global ix, iy, drawing
global hsv_lower, hsv_upper
global selected
global frame_for_select
if event == cv2.EVENT_LBUTTONDOWN:
drawing = True
ix, iy = x, y
elif event == cv2.EVENT_LBUTTONUP:
drawing = False
x1, y1 = min(ix, x), min(iy, y)
x2, y2 = max(ix, x), max(iy, y)
roi = frame_for_select[y1:y2, x1:x2]
if roi.size == 0:
return
hsv_roi = cv2.cvtColor(roi, cv2.COLOR_BGR2HSV)
h_mean = np.mean(hsv_roi[:, :, 0])
s_mean = np.mean(hsv_roi[:, :, 1])
v_mean = np.mean(hsv_roi[:, :, 2])
# HSV範囲設定
hsv_lower = np.array([
max(h_mean - 15, 0),
max(s_mean - 60, 50),
max(v_mean - 60, 50)
])
hsv_upper = np.array([
min(h_mean + 15, 179),
min(s_mean + 60, 255),
min(v_mean + 60, 255)
])
selected = True
print("HSV Lower:", hsv_lower)
print("HSV Upper:", hsv_upper)
cap = cv2.VideoCapture(0)
cv2.namedWindow("Color Tracking")
cv2.setMouseCallback("Color Tracking", select_color)
while True:
ret, frame = cap.read()
if not ret:
break
frame_for_select = frame.copy()
# 軽量化
frame = cv2.resize(frame, (640, 480))
if selected:
hsv = cv2.cvtColor(frame, cv2.COLOR_BGR2HSV)
# 色抽出
mask = cv2.inRange(hsv, hsv_lower, hsv_upper)
# ノイズ除去
kernel = np.ones((5, 5), np.uint8)
mask = cv2.morphologyEx(mask, cv2.MORPH_OPEN, kernel)
mask = cv2.morphologyEx(mask, cv2.MORPH_CLOSE, kernel)
# 輪郭検出
contours, _ = cv2.findContours(
mask,
cv2.RETR_EXTERNAL,
cv2.CHAIN_APPROX_SIMPLE
)
if contours:
# 最大輪郭
largest = max(contours, key=cv2.contourArea)
area = cv2.contourArea(largest)
if area > 500:
x, y, w, h = cv2.boundingRect(largest)
# 中心座標
cx = x + w // 2
cy = y + h // 2
# 描画
cv2.rectangle(
frame,
(x, y),
(x + w, y + h),
(0, 255, 0),
2
)
cv2.circle(frame, (cx, cy), 5, (0, 0, 255), -1)
cv2.putText(
frame,
f"Center: ({cx}, {cy})",
(x, y - 10),
cv2.FONT_HERSHEY_SIMPLEX,
0.6,
(0, 255, 0),
2
)
cv2.imshow("Color Tracking", frame)
key = cv2.waitKey(1)
if key == ord('q'):
break
cap.release()
cv2.destroyAllWindows()
実行
python color_tracking.py
6. コード解説
カラートラッキングのコードの解説だけ記しておきます.
全体の流れ
今回のコードでは,以下の流れでカラートラッキングを行っています.
カメラ映像取得
↓
マウスで対象物体を選択
↓
選択範囲の色(HSV)を取得
↓
同じ色の領域を抽出
↓
輪郭検出
↓
最も大きい物体を選択
↓
中心座標を計算して表示
グローバル変数
drawing = False
ix, iy = -1, -1
selected = False
これらは,マウス操作の状態を保持するための変数です.
-
drawing
マウスドラッグ中かどうか -
ix, iy
ドラッグ開始位置 -
selected
色選択が完了したかどうか
HSVとは?
今回のコードでは,色検出に HSV 色空間を用いています.
OpenCVでは,RGBよりもHSVを使用する方が色検出に適しています.
RGB
R : 赤
G : 緑
B : 青
RGBでは明るさ変化に弱く,
- 照明
- 影
- 光の反射
などで色が変わりやすいです.
HSV
H : Hue(色相)
S : Saturation(彩度)
V : Value(明度)
HSVでは,
- 色そのもの
- 鮮やかさ
- 明るさ
を分離して扱えるため,色検出に強いです.
マウスで色を選択
cv2.setMouseCallback("Color Tracking", select_color)
OpenCVでは,setMouseCallback()を使用することで,
ウィンドウ上のマウスイベントを取得できます.
今回は,
- 左クリック押下
- ドラッグ
- 左クリック離す
を利用して,対象物体を矩形選択しています.
ROI(Region Of Interest)
roi = frame_for_select[y1:y2, x1:x2]
ROI は「注目領域」を意味します.
今回は,「ユーザが囲った範囲」を切り出し,その領域を ROI としています.
HSVへ変換
hsv_roi = cv2.cvtColor(roi, cv2.COLOR_BGR2HSV)
OpenCVのカメラ画像は,標準では BGR 形式です.そのため,色検出を行う前に HSV へ変換しています.
平均色の取得
h_mean = np.mean(hsv_roi[:, :, 0])
s_mean = np.mean(hsv_roi[:, :, 1])
v_mean = np.mean(hsv_roi[:, :, 2])
選択した領域の平均HSV値を取得しています.
例えば赤色物体を選択すると,
H : 赤系
S : 高い
V : 明るい
のような値になります.
色の範囲設定
hsv_lower = np.array([
max(h_mean - 15, 0),
max(s_mean - 60, 50),
max(v_mean - 60, 50)
])
hsv_upper = np.array([
min(h_mean + 15, 179),
min(s_mean + 60, 255),
min(v_mean + 60, 255)
])
OpenCVでは,「完全一致」ではなく,「ある範囲内」の色を検出します.
そのため,上下限値を設定しています.
色抽出
mask = cv2.inRange(hsv, hsv_lower, hsv_upper)
色検出の中心処理です.
inRange()は,
条件を満たす画素 → 白
条件を満たさない画素 → 黒
の**二値画像(マスク画像)**を生成します.
ノイズ除去
mask = cv2.morphologyEx(mask, cv2.MORPH_OPEN, kernel)
mask = cv2.morphologyEx(mask, cv2.MORPH_CLOSE, kernel)
色抽出後は,小さなノイズが多く発生します.
そのため,
- OPEN処理
- 小ノイズ除去
- CLOSE処理
- 小さな穴埋め
を行っています.
輪郭検出
contours, _ = cv2.findContours(
mask,
cv2.RETR_EXTERNAL,
cv2.CHAIN_APPROX_SIMPLE
)
findContours()により,
白色領域の輪郭を取得しています.
今回では,「同色物体の形状」を取得しています.
最大輪郭の取得
largest = max(contours, key=cv2.contourArea)
複数物体が見つかった場合でも,最も大きい物体を対象としています.
面積による除外
if area > 500:
小さなノイズまで追跡しないよう,一定以上の面積のみを対象にしています.
外接矩形
x, y, w, h = cv2.boundingRect(largest)
物体を囲う矩形を取得しています.
中心座標
cx = x + w // 2
cy = y + h // 2
矩形中心(中心座標)を計算しています.
これにより,
- ロボット制御
- 物体追跡
などに利用できます.
実際に,天井に吊るしたカメラでオレンジ色のゴルフボールを認識し,自立型ロボットがサッカーをしている大会がある.
-> 公式サイト:RoboCup Soccer Small-Size-League
描画
矩形描画
cv2.rectangle()
対象物体を囲っています.
中心点描画
cv2.circle()
重心位置を赤点で表示しています.
座標表示
cv2.putText()
画面上に座標を描画しています.
7. まとめ
今回は,
- RaspberryPi と USBカメラの接続
- OpenCV環境構築
- リアルタイム映像表示
- HSVを用いたカラートラッキング
を行いました.
OpenCVを用いることで,比較的簡単にリアルタイム画像処理を実装できます.
次回は,
- 複数物体の追跡
- 複数色別の認識
- ロボットアーム制御
などへ発展させていきたいと思います.

