第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を展開し、次のファイルが 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 を使う。サーバーではファイル出力で確認する |
| 輪郭が大量に出る | 背景の模様や影も境界になる。単純な背景と比較する |
やってみよう
- Cannyのしきい値を変え、輪郭がどう変わるか比べてください。
- 同じ物を明るい場所と暗い場所で撮り、輪郭だけで検出する難しさを説明してください。
(480, 640, 3)というshapeの意味は何でしょうか。
3の答えは、高さ480、幅640、3チャンネルです。画像の右端へ進むとx、下へ進むとyが増えます。
詳しくはOpenCV公式Pythonチュートリアルを参照してください。