第6章

OpenCVで画像とカメラを扱う

Python環境を準備し、OpenCVで画像の読み込み、色変換、輪郭抽出、カメラ撮影を行います。

この章で学ぶこと

  • OpenCV・NumPy・YOLOの役割を分ける
  • 画像ファイル、動画、USBカメラを同じ流れで処理する
  • 色変換、エッジ検出、輪郭抽出を試す
  • 後のカメラ校正に使える未加工画像を撮影する

1. 実習環境を作る

この章以降はPython 3.11または3.12を目安に、PC上のターミナルで実行します。OpenCVは画像処理やカメラ入出力、NumPyは配列計算、UltralyticsのYOLOは学習済みモデルによる物体検出を担当します。GPUなしでも試せますが、動画の処理速度はPCによって変わります。

Windows PowerShellでは次のように準備します。

mkdir vision-lab
cd vision-lab
python -m venv .venv
.\.venv\Scripts\Activate.ps1
python -m pip install --upgrade pip

macOS・Linuxでは環境作成に python3 -m venv .venv、有効化に source .venv/bin/activate を使います。有効化後は同じ python コマンドで進められます。TensorFlowの実習環境とは別のフォルダーにします。

実習コード一式をダウンロード(ZIP)

ZIPを展開し、次のファイルが vision-lab の直下にある状態にしてください。ターミナルもこのフォルダーで開きます。

vision-lab/
  .venv/
  requirements.txt
  vision_common.py
  opencv_basics.py
  yolo_detect.py
  make_targets.py
  calibrate_camera.py
  marker_localization.py
  feature_matching.py
python -m pip install -r requirements.txt
python -m pip check
python -c "import cv2, ultralytics; print(cv2.__version__, ultralytics.__version__); print(hasattr(cv2.aruco, 'ArucoDetector'))"
python -m pip freeze > environment.txt

最後から2行目はバージョンと True を表示します。実行時のバージョンを保存して、結果と一緒に記録しましょう。教材はOpenCV 4.10以降の4系とUltralytics 8系のAPIを使います。インストール結果はOSやPythonで変わるため、配布ファイルでは許容範囲を指定しています。

OpenCVの配布パッケージは、この環境では opencv-python 一つにそろえます。opencv-contrib-python や headless 版を同じ環境に追加すると、同じ cv2 を共有して競合することがあります。指定したOpenCVには、この教材で使うArUco APIが含まれます。

2. 画像を処理する

本やコップなどを撮影したJPEG画像を desk.jpg として保存します。

python opencv_basics.py --source desk.jpg

opencv-output に元画像、グレースケール、エッジ、輪郭を描いた画像の4枚が保存されます。各出力フォルダーは再実行すると同名ファイルを上書きするので、比較するときは --output trial-02 のように変更してください。

処理の中心は次の部分です。

gray = cv2.cvtColor(image, cv2.COLOR_BGR2GRAY)
blurred = cv2.GaussianBlur(gray, (5, 5), 0)
edges = cv2.Canny(blurred, 80, 160)
contours, _ = cv2.findContours(
    edges, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE
)

OpenCVで読み込んだカラー画像は通常 BGR順です。NumPy配列では image[y, x] の順で画素を指定します。「座標のx・y」と「配列の行・列」を混同しないようにしましょう。

ぼかしは細かいノイズを弱め、Cannyは明るさが急に変化する場所を抽出します。輪郭抽出はその境界をまとめます。この処理だけでは、輪郭の内側が「コップ」か「本」かは分かりません。種類を推定する役割を次章のYOLOが担います。

3. カメラや動画で動かす

python opencv_basics.py --source 0 --show --max-frames 0

0 はカメラ番号です。複数接続している場合は 1 なども試します。表示ウィンドウにフォーカスを置き、s で未加工の画像を opencv-output/captures に保存、q で終了します。画面に描いた輪郭は撮影画像に入りません。PC側でカメラ権限を許可し、他のアプリが占有していないことを確認してください。

python opencv_basics.py --source desk.mp4 --output video-check

こちらは動画の先頭から最大300フレームを処理し、最後の画像を保存します。--max-frames 0 は動画の終端まで処理します。--show を付けなければGUIウィンドウを開きません。画像ファイルは1枚だけ処理します。

カメラには既定で640×480を要求しますが、対応していない機種もあります。最初に表示される shape が実際に取得したサイズです。校正と位置推定では、このサイズとカメラの設定をそろえる必要があります。

トラブル対処

症状 確認・対処
No module named vision_common ZIP内のPythonファイルを同じフォルダーに置く
cv2 や ultralytics が見つからない 仮想環境を有効にして python -m pip install -r requirements.txt を実行する
ArucoDetector がない OpenCVの版と重複インストールを確認し、必要なら新しい仮想環境を作る
入力を開けない ファイルの場所、カメラ番号、権限、他アプリの使用状況を確認する
ウィンドウが出ない GUIのあるローカルPCで --show を使う。サーバーではファイル出力で確認する
輪郭が大量に出る 背景の模様や影も境界になる。単純な背景と比較する

やってみよう

  1. Cannyのしきい値を変え、輪郭がどう変わるか比べてください。
  2. 同じ物を明るい場所と暗い場所で撮り、輪郭だけで検出する難しさを説明してください。
  3. (480, 640, 3) という shape の意味は何でしょうか。

3の答えは、高さ480、幅640、3チャンネルです。画像の右端へ進むとx、下へ進むとyが増えます。

詳しくはOpenCV公式Pythonチュートリアルを参照してください。