Raspberry PiとOpenCVによる自動ビジョンベース物体追跡
コンピュータビジョンを用いて色物体を自動追跡するパン/チルトサーボシステム。
ストーリー
はじめに
前回のチュートリアルでは、パン/チルトサーボを制御してRaspberry Piカメラを位置決めする方法を学びました。今回は、カメラが色物体を自律的に追跡できるよう、そのセットアップを拡張します。
これは私のOpenCV初体験ですが、このオープンソースコンピュータビジョンライブラリの虜になりました。
OpenCVは学術/商用利用無料、C++、C、Python、Javaインターフェースを提供、Windows、Linux、macOS、iOS、Androidで動作。このシリーズでは、OpenCVが計算効率とリアルタイムアプリケーション向けに構築されているため、Raspberry Pi(Raspbian)とPythonに焦点を当てます—まさにフィジカルコンピューティングプロジェクトに必要なものです。
ステップ1:BOM – 部品表
主要パーツ:
- Raspberry Pi V3 – 32.00ドル
- 500万画素 1080p OV5647 ミニカメラビデオモジュール – 13.00ドル
- TowerPro SG90 9G 180度マイクロサーボ(2個) – 4.00ドル
- ミニパン/チルトカメラプラットフォーム アンチバイブレーションマウント(サーボ2個付き)(*) – 8.00ドル
- 赤色LED
- 抵抗 220Ω
- 抵抗 1kΩ(2個) – オプション
- その他:金属パーツ、バンド等(自作パン/チルト機構の場合)
(*) 完成品パン/チルトプラットフォーム(サーボ付き)を購入するか、自作可能。
ステップ2:OpenCV 3のインストール
最新Raspbian Stretch搭載Raspberry Pi V3では、 Adrian Rosebrockのチュートリアル (Raspbian Stretch: Install OpenCV 3 + Python on your Raspberry Pi)に従うのが最も確実です。ソースからOpenCVをビルドし、専用Python仮想環境をセットアップする手順をガイドします。
チュートリアル完了後、仮想環境をアクティブ化してインストール確認:
source ~/.profile
workon cv
python
import cv2
print(cv2.__version__)
バージョン3.3.0以降が表示されるはず。 cv 仮想環境内でOpenCVが使用可能であることを確認。
ステップ3:カメラのテスト
OpenCVインストール後、PiCameraが正しくストリーミングするか検証。以下のスクリプトを実行(または simpleCamTest.py をダウンロード):
import cv2
cap = cv2.VideoCapture(0)
while True:
ret, frame = cap.read()
frame = cv2.flip(frame, -1) # 必要に応じて垂直反転
gray = cv2.cvtColor(frame, cv2.COLOR_BGR2GRAY)
cv2.imshow('frame', frame)
cv2.imshow('gray', gray)
if cv2.waitKey(1) & 0xFF == ord('q'):
break
cap.release()
cv2.destroyAllWindows()
q または Ctrl+C で終了。正常実行時、カラーとグレースケールの両フィードが表示されます。
ステップ4:OpenCVによるPythonでの色検出
OpenCVはHSV(色相、彩度、明度)空間で動作し、人間の色知覚により適合。特定色を検出するには、まずBGR値を特定し、HSVに変換して下限/上限境界を設定。
例:黄色物体の追跡。カラーピッカー(例:PowerPoint)でBGR値 (71, 234, 213) を取得。以下のスクリプトでHSVに変換(または bgr_hsv_converter.py をダウンロード):
import sys, numpy as np, cv2
blue, green, red = int(sys.argv[1]), int(sys.argv[2]), int(sys.argv[3])
color = np.uint8([[[blue, green, red]]])
hsv = cv2.cvtColor(color, cv2.COLOR_BGR2HSV)
hue = hsv[0][0][0]
print('Lower bound:', [hue-10, 100, 100])
print('Upper bound:', [hue+10, 255, 255])
python bgr_hsv_converter.py 71 234 213 実行結果:
Lower bound: [24, 100, 100] Upper bound: [44, 255, 255]
これらの境界で画像内の色をマスク:
import cv2, numpy as np
img = cv2.imread('yellow_object.JPG', 1)
img = cv2.resize(img, (0,0), fx=0.2, fy=0.2)
hsv = cv2.cvtColor(img, cv2.COLOR_BGR2HSV)
lower = np.array([24, 100, 100], dtype=np.uint8)
upper = np.array([44, 255, 255], dtype=np.uint8)
mask = cv2.inRange(hsv, lower, upper)
cv2.imshow('mask', mask)
cv2.imshow('image', img)
while True:
k = cv2.waitKey(0)
if k == 27:
break
cv2.destroyAllWindows()
colorDetection.py として保存し、 python colorDetection.py で実行(画像を同ディレクトリに配置)。
ステップ5:リアルタイム物体追跡
マスクを基に、フレームごとに物体の重心を追跡。以下のコードは、Adrian Rosebrockの Ball Trackingチュートリアル を参考に、先ほど定義したHSV境界を組み込んでいます。
まず imutils ライブラリをインストール:
pip install imutils
その後 ball_tracking.py を実行:
python ball_tracking.py
スクリプトはフレームを垂直反転(必要に応じて)し、マスクを適用。物体検知時に円と重心を描画。
ステップ6:GPIOのテスト
赤色LEDをPiに追加し、GPIO制御可能か確認。
配線:LEDカソードをGPIO 21、アノードを220Ω抵抗経由でグラウンドに接続。
cv 環境に RPi.GPIO が未インストールの場合:
pip install RPi.GPIO
テストスクリプト(LED_simple_test.py):
import sys, time, RPi.GPIO as GPIO
led = int(sys.argv[1])
freq = int(sys.argv[2])
GPIO.setmode(GPIO.BCM)
GPIO.setup(led, GPIO.OUT)
GPIO.setwarnings(False)
print(f'GPIO {led} のLEDを {freq}秒ごとに点滅、5回実行。')
for _ in range(5):
GPIO.output(led, GPIO.LOW)
time.sleep(freq)
GPIO.output(led, GPIO.HIGH)
time.sleep(freq)
GPIO.cleanup()
python LED_simple_test.py 21 1 でLEDを1秒ごとに5回点滅。
ステップ7:色認識とGPIO連携
追跡ロジックとGPIO制御を組み合わせ、対象色検知時にLED点灯。核心追加部分:
import RPi.GPIO as GPIO
led = 21
GPIO.setmode(GPIO.BCM)
GPIO.setwarnings(False)
GPIO.setup(led, GPIO.OUT)
GPIO.output(led, GPIO.LOW)
ledOn = False
検知ループ内で有効な半径確認後、以下を追加:
if not ledOn:
GPIO.output(led, GPIO.HIGH)
ledOn = True
完全スクリプト: object_detection_LED.py。 python object_detection_LED.py で実行。物体の色がHSV境界内にあるときのみLED点灯。
ステップ8:パン/チルト機構
OpenCVとGPIOが動作したら、サーボを外部5V電源に接続。データピン配線:
- GPIO 17 → チルトサーボ
- GPIO 27 → パンサーボ
Pi、サーボ、電源のグラウンドを共通化。オプションで、Pi GPIOとサーボデータピン間に1kΩ抵抗を直列挿入し、電流スパイクからPiを保護。
angleServoCtrl.py でサーボ制御テスト:
from time import sleep
import RPi.GPIO as GPIO
GPIO.setmode(GPIO.BCM)
GPIO.setwarnings(False)
def setServoAngle(servo, angle):
pwm = GPIO.PWM(servo, 50)
pwm.start(8)
duty = angle / 18. + 3.
pwm.ChangeDutyCycle(duty)
sleep(0.3)
pwm.stop()
if __name__ == '__main__':
import sys
servo = int(sys.argv[1])
GPIO.setup(servo, GPIO.OUT)
setServoAngle(servo, int(sys.argv[2]))
GPIO.cleanup()
例: python angleServoCtrl.py 17 45 でチルトサーボを45°に移動。
ステップ9:物体のリアルタイム位置特定
カメラでターゲットを中央に捉えるには、まず物体の重心座標が必要。 objectDetect_LED.py を修正し、 x と y を出力:
def mapObjectPosition(x, y):
print(f'[INFO] Object center at X={x}, Y={y}')
座標範囲: x は0〜500(左→右)、 y は0〜350(上→下)。物体を動かしライブ出力を観察。
ステップ10:物体位置追跡システム
「中央」領域を定義(例: 220 < x < 280 かつ 160 < y < 210)。領域外ならパン/チルトサーボを調整:
def mapServoPosition(x, y):
global panAngle, tiltAngle
if x < 220:
panAngle = min(panAngle + 10, 140)
positionServo(panServo, panAngle)
if x > 280:
panAngle = max(panAngle - 10, 40)
positionServo(panServo, panAngle)
if y < 160:
tiltAngle = min(tiltAngle + 10, 140)
positionServo(tiltServo, tiltAngle)
if y > 210:
tiltAngle = max(tiltAngle - 10, 40)
positionServo(tiltServo, tiltAngle)
ヘルパー positionServo(servo, angle) は単に angleServoCtrl.py を呼び出し:
import os
def positionServo(servo, angle):
os.system(f'python angleServoCtrl.py {servo} {angle}')
print(f'[INFO] Positioning servo GPIO {servo} to {angle}°')
すべてのスクリプトは同一ディレクトリに配置。完全実装は objectDetectTrack.py からダウンロード。
ステップ11:結論
このプロジェクトは、OpenCV、Raspberry Pi GPIO、パン/チルトサーボマウントを組み合わせ、自律的な色物体追跡システムを作成する方法を示します。異なる色、形状、サーボ速度で自由に実験してください。
全コードと追加リソースは GitHub と MJRoBot.org ブログで公開中。
お読みいただきありがとうございました—次回のチュートリアルでお会いしましょう!
製造プロセス
- OpenCVでRaspberry Pi上級卓球球追跡
- Speathe:麻痺ユーザーのための呼吸駆動コミュニケーション
- Raspberry Piでリアルタイム顔認識:エンドツーエンドガイド
- 自動プレス機の理解:機能、メリット、用途
- 自動パワープレスの特長・メリット・用途:金属成形現場の自動化核心機器
- 自動パイプベンダーの理解:機能、メリット、用途
- 自動ロータリーテーブルの理解:金属加工における精度と効率
- モーションキャプチャシステムにおける動的物体追跡精度の測定手法
- 新フィルターでロボットビジョン強化:精密な6D姿勢推定を実現
- Pythonオブジェクト指向プログラミング完全ガイド:クラス、継承、カプセル化、ポリモーフィズム
- Pythonオブジェクト指向プログラミング完全ガイド:クラスと継承をマスター