🧊

OpenCVからラズパイの公式カメラを使おうとしたら、思ったより大変だった

2023/11/08に公開

はじめに

会社のハッカソンイベントで、IoTで画像AI系の処理をしようとしました。
とりあえず、RaspberryPi4に公式CameraModule3を挿して、OpenCVでcv2.VideoCapture(0)すれば動くだろ。と軽く思っていたのですが、環境構築でめちゃくちゃ苦戦したのでその記録です。

一緒にラズパイと戦ったメンバー

動かなかった罠を羅列する

ラズパイOSは最新(2023/11時点)のBookwormを使う:✗

最新OSでは動きませんでした。カメラを認識しませんでした。
1個前のBullseyeを使うと認識しました。

32bit OSを使う:✗

32bitOSでは動きませんでした。カメラは認識しますが、OpenCVをインストール出来ませんでした。
自力でビルドすればもしかしたら動くかもしれません。ググると64bitはカメラに対応していない的な情報が見つかり32bitで試したのですが、実際は現時点では64bitでも問題なくカメラに対応していました。

カメラをレガシーモードで使う:✗

レガシーモードでは動きませんでした。カメラは認識しましたが、画像を取得出来ませんでした。
新しいドライバ(libcamera)を使う必要がありました。
ググるとレガシーモードでないとOpenCVが対応出来ないような情報が見つかりましたが、OpenCVで直接カメラを開くのではなく、入力にpicamera2というlibcameraを使うライブラリを使用しOpenCVにデータをわたすことで対応できました。

OpenCVのVideoCaptureで画像を取得する:✗

OpenCVのVideoCaptureでは動きませんでした。libcameraに対応していないようでした。
カメラ画像の取得にはpicamera2を使う必要がありました。
ググるとレガシーモードならOpencvで画像を取得できるといった情報が見つかりましたが、試しても何故か取得できませんでした。

こちらのissueにイロイロ知見が書いてあるので、解決策はあるかもしれません。
https://github.com/opencv/opencv/issues/22820

picamera (pythonのライブラリ) でカメラ画像を取得する:✗

picameraでは動きませんでした。picameraは64bitのOSに対応していないようです。
新しいライブラリであるpicamera2を使う必要がありました。

pythonアプリを仮想環境で動かす:✗

仮想環境上では動きませんでした。なぜかpicamera2がインストールできませんでした。
素のグローバルなpython環境では、なぜか動きました。

成功パターン

OSはBullseye 64bit版を使う

Raspberry Pi Imagerでは階層が深いところにしかいないので探しましょう。

カメラは、新しいドライバ(libcamera)を使う

libcamera使用するために、/boot/config.txtの最後にカメラの型番を追加して、リブートする必要があります。公式のCamera Module3の場合は以下のように設定します。

/boot/config.txt
dtoverlay=imx708

公式カメラの情報ぐらい最初から埋め込んでおいてほしいと思うのは私だけでしょうか?

venv等で仮想環境を作るようなことはせずに、素のpythonをそのまま使う

タイトルそのままです。環境構築を頑張らずに、素のpythonを使いましょう。
仮想環境で動かないのは管理上非常にツラいので、仮想環境でpicamera2をインストールする方法を募集したいです。。。

カメラ画像の取得は新しいライブラリ(picamera2)を使う

カメラのInterfaceはpicamera2に任せ、取得結果をopencvにわたすことで画像処理が出来ました。

pip install picamera2
pip install opencv-python

以下は、カメラ画像を取得してopencvでjpgに保存する最低限のコードになります。

import cv2
from picamera2 import Picamera2

# Picameraを起動
camera = Picamera2()
camera.configure(camera.create_preview_configuration(main={
	"format": 'XRGB8888',
	"size": (640, 480)
}))
camera.start()
camera.set_controls({'AfMode': controls.AfModeEnum.Continuous})

# カメラから画像を取得
image = camera.capture_array()

# 画像が3チャンネル以外の場合は3チャンネルに変換する
channels = 1 if len(image.shape) == 2 else image.shape[2]
if channels == 1:
	image = cv2.cvtColor(image, cv2.COLOR_GRAY2BGR)
if channels == 4:
	image = cv2.cvtColor(image, cv2.COLOR_BGRA2BGR)

# jpgに保存
cv2.imwrite('test.jpg', image)

以上で、OpenCVからラズパイの公式カメラを使うことが出来ました。

感想

  • 公式カメラなので挿せば動くと思っていたのですが、めちゃくちゃ大変でした。
  • カメラもまともに使えない状態のOSをリリースするなよ。。。と思ってしまいます。
  • Bullseye以降でいろいろ変わったようなのですが、情報が少なすぎ&錯綜しすぎていてかなり苦戦しました。
  • 情報が少ない理由としては、以下のようなことが考えられます。
    • 半導体不足でラズパイが市場に存在していなかった影響で触る人が少ないので情報も少ない
    • 簡単には上手く行かないので、試行錯誤した結果の中途半端な情報だけがネット上に残る
      • それを参考にした人は、やっぱり上手く行かない。。。

Hardwareが絡む開発はツラいなぁと思いました。。。

実際にラズパイカメラとOpenCVであそんだ記事はこちら
https://zenn.dev/ncdc/articles/665eeefb1205ac

NCDCエンジニアブログ

Discussion