まえおき
ラズパイ4などBullseyeまではraspi-config等でカメラを有効にすることで
v4l2経由で専用カメラ(MIPI CSI)を使うことができていました。
ところがBookwormからカメラの設定項目が消えました。BusterまではOS側でカメラの
ドライバを管理してたのが順次libcamera(およびrpicam)へ移管する様です。
参考:えいあーるれいの技術日記様
Raspi-Bullseyeでpicameraを検出するプログラムを作成するさて、ラズパイ5でもOpenCV(C++)で画像処理を行いたいのですがラズパイ5は
Bookworm以降を使うので旧手段ではカメラを読み出せません。
PythonであればPicamera2で読み出せますがC++には対応していない様です。
そこで、libcameraを使ってOpenCV(C++)から専用カメラを読み出す環境を設定します。
libcameraのv4l2互換機能を使うとメインプログラムをそのまま使えるっぽいのですが、
未だ使い方を理解していないのでまずはlibcameraを直接使用する方法を試してみます。
※C++向けにOpenCVの環境が設定でき、
C++でビルドできたものとします。
※2025/06/20 カメラモジュール V3(IMX708)に関して追記
※2025/07/01 OV5647を読み出せないことがあったので修正
※2025/07/10 v4l2-compat.soの使い方を追記
libcamera-hello
とりあえず素の状態でカメラを読めるか確認しておきます。
カメラが
OV5647(Zero向けのスパイカメラ)の場合は特に何もしなくても
libcamera-helloを実行するだけで表示できる
と思います(たぶん)ことがあります。また、
libcamera-hello --list-camerasにて、カメラの情報が取得できる
と思いますことがあります。
※2025/07/01 環境によっては素の状態でOV5647を読み出せない場合もあるので修正
OV5647を検出できない場合はconfig.txtの
camera_auto_detect=0で自動検出を
停止しているとか
dtoverlayで違う機種をしているとかの可能性があります。
自動検出を停止している場合でも
dtoverlay=ov5647であれば読み出せると思います。
その他の
IMX219などを接続した場合は
ERROR: *** no cameras available ***とか
No camera available!とか出てきてカメラを認識していません。
IMX219を使う場合は
boot/firmware/config.txtへ
dtoverlay=imx219を追記します。config.txtは管理者権限でないと編集できないので
sudo pcmanfmで管理者権限でファイルマネージャーを起動するなど対応してください。
再起動後に再度
libcamera-hello
で映像が表示できればOKです。
なお、bullseyeで使えた
vcgencmd get_cameraはbookwormでは機能しません。
vcgencmdを実行するとvcgencmd commandsでコマンド一覧を取得できるとの説明が出るので
vcgencmd commandsで確認するとget_camera引数がリストに出てこないので対応していない様です。
Bookwormのboot/firmware/config.txt の挙動について
camera_auto_detect:標準設定のカメラ(OV5647)を自動検出する
標準カメラov5647はcamera_auto_detect=1で
検出される標準外カメラimx219はcamera_auto_detect=1で
検出されないBusterでは何方でも自動検出できたのでOS等の仕様違いに注意。
dtoverlay:カメラの設定を上書きする
ov5647/imx219共にdtoverlayで指定できる。
dtoverlayを複数回記述した場合は一番最後に記述したものが適用される。
ov5647が接続された状態で
camera_auto_detect=1
dtoverlay=
imx219とすると自動検出で
ov5647を検出できるはずのところ、
imx219で上書きされるので
正しく検出できません。
ラズパイ5で複数のカメラを個別に指定する場合は
ポート0にimx219、
ポート1にov5647を接続した例では
camera_auto_detect=1 dtoverlay=
imx219,cam0または
dtoverlay=
imx219,cam0 dtoverlay=
ov5647,cam1指定すると検出できます。
dtoverlay=
imx219,
cam1 dtoverlay=
ov5647,cam0と逆に指定しまうと検出できません。
※2025/07/04 追記※2025/07/09 追記ラズパイ4以前のカメラ接続ポートが1つの場合は
dtoverlay=imx219,cam0の様にポートを指定すると
認識する場合と
認識しない場合があるとの報告があります。
特にCM4を使う場合はベースボードの種類によって
dtoverlay=imx219
と dtoverlay=imx219,cam0を使い分ける必要がある様です。
要調査。
start_x:Bookwormでカメラに何の影響が出るか確認できず。
※2025/06/20 追記
ラズパイ4+Bookworm+Raspberry Pi カメラモジュール V3を組み合わせる場合でも
camera_auto_detect=1では認識しませんでした。
カメラモジュールV3の受光素子はIMX708なので
dtoverlay=
imx708と記載することで動作することを確認しています。
libcameraのビルド
素の状態だとlibcameraは使えるものの、ライブラリ
libcamea.soが使えないので
自分でビルドします。
公式と参考サイト様の手順に従ってビルドします。
公式
https://github.com/raspberrypi/libcamera参考:Zenn@hattori-sat様
libcameraの設定とりあえずラズパイを更新しておく
sudo apt updatesudo apt upgrade再起動
reboot必要な環境を入れる
sudo apt install -y python3-pip git python3-jinja2pipは仮想環境でなければ使えないので要らないかも
ライブラリを入れる
sudo apt install -y libboost-devsudo apt install -y libgnutls28-dev openssl libtiff-dev pybind11-devsudo apt install -y qtbase5-dev libqt5core5a libqt5widgets5sudo apt install -y meson cmakesudo apt install -y python3-yaml python3-plysudo apt install -y libglib2.0-dev libgstreamer-plugins-base1.0-dev※libqt5widgetsからlibqt5widgets
5へ名称が変わった?そもそも要るのか不明。
libcamera本体をダウンロードする
git clone https://github.com/raspberrypi/libcamera.git※zipでダウンロードしてunzipで展開してもOK
ダウンロードしたディレクトリへ移動
cd libcameraビルド環境を設定(cmakeみたいなやつ)
meson setup build --buildtype=release -Dpipelines=rpi/vc4,rpi/pisp -Dipas=rpi/vc4,rpi/pisp -Dv4l2=enabled -Dgstreamer=enabled -Dtest=false -Dlc-compliance=disabled -Dcam=disabled -Dqcam=disabled -Ddocumentation=disabled -Dpycamera=enabled※2025/07/01 true→enabledへ変更
ビルド(ninjaはmakeの高速っぽいやつ)+インストール
sudo ninja -C build install※2025/07/04修正 インストール時に権限エラーになるので
管理者で実行する
インストール時にパスワードを求められる
ことがある
ラズパイを実行中のユーザーのパスワードを入力
パスワードを求められる代わりに
Attempt to use /usr/bin/sudo to gain elevated privileges? [y/n]とか出ることもあります。
この場合は
yで許可しましょう。
とりあえずインストールできました。
pkg-configコマンドでライブラリのインストール先を確認できます。
ラズパイ5(bookworm)だとインクルードフォルダとライブラリが
pkg-config --cflags libcamera-I/usr/local/include/libcamera pkg-config --libs libcamera-L/usr/local/lib/aarch64-linux-gnu -lcamera -lcamera-baseとなっていました。
本記事を作成した時点では
libcamera.so.0.4.0が生成されています。
ここでもうひと手間この状態だとライブラリがフォルダに格納されパスが通っていますが、
追加したライブラリを認識できていない
様ですことがあります。
ビルドでエラーが出たり、ビルドできたとしても実行時にエラーに
なりますなる
ことがあります。
参考:Qiita@hachicomb様
共通ライブラリがみつからない(cannot open shared object file)エラー対処方法自作プログラムをビルド時
cannot open shared object file
実行時
symbol lookup error: /usr/local/lib/aarch64-linux-gnu/libcamera.so.0.4:
undefined symbol: _ZN7libpisp22compute_optimal_strideER24pisp_image_format_config
この症状が出たら、まずパスが通っているか確認しておきます。
cat /etc/ld.so.conf.d/*/usr/local/lib/aarch64-linux-gnu先ほどのディレクトリが出てくるのでパスは通っている様です。
パスが通っているのにライブラリが読めないときはOpenCVをインストールした時と同じく
sudo ldconfigを実行すればライブラリが使えるようになります。
念のため再起動
rebootこれで準備が整いました。
libcameraを使う
libcamera公式サンプルだと"event_loop.h"なるものをインクルードしておりなんだかよくわかりません。
調べていると分かりやすいサンプルを公開している方が居ました。
https://github.com/edward-ardu/libcamera-cpp-demo/この方のプログラムではlibcameraの設定項目をまとめた
LibCamera.cpp / LibCamera.hとメインプログラムの
main.cppに分かれています。
main.cppの中身を見るとOpenCVで処理するひな型になっているのでこれを利用させて頂きます。
とりあえず手順通りにビルドしてみます。
git cloneなり、zipファイルでダウンロードするなりして
git clone https://github.com/edward-ardu/libcamera-cpp-demo.gitフォルダの中に
・CMakeLists.txt
・LibCamera.cpp
・LibCamera.h
・main.cpp
がある状態にします。
フォルダ移動して
cd libcamera-cpp-demoビルドフォルダを作って移動
mkdir buildcd buildcmakeで設定してビルド
cmake ..make多分このままだとエラーでビルドが通りません。
error: 'class Libcamera::Camera Configuertion' has no member named 'transform'
このプログラムが公開されてからlibcameraの仕様が変わってしまった様です。
エラー箇所を見ると
config_->transform = transform;となっており、取得時に画像を回転させる処理っぽいですがOpenCV側でも対応できるので
とりあえず、LibCamera.cppの52行目付近にあるこの行をコメントアウトします。
//config_->transform = transform;これでビルドが通る様になりました。
ビルドが通るとビルドフォルダに
libcamera-demoが生成されているはずです。
./libcamera-demoで実行できれば成功です。
qキーでプログラムを終了します。
カメラの表示範囲がおかしい場合はウインドウを閉じれば表示されます。
ちなみに、pkg-configが設定されているのでmain.cppのあるlibcamera-cpp-demoフォルダで
g++ main.cpp -o main.out LibCamera.cpp `pkg-config --cflags --libs opencv4 libcamera`とか
コマンドを直接打ってもビルドできます。
Makefileを作っておけばGeanyとかからもMake(ビルド)できます。
サンプルプログラムの中身
main.cppを見てみます。
<カメラ初期設定>必須
カメラを起動※カメラ0固定
cam.initCamera();解像度、フォーマット、バッファ数、回転 を設定
cam.configureStill(width, height, formats::RGB888, 1, 0);この項目は設定しないと動きませんでした。
<カメラパラメータ設定>オプション
FrameDurationLimits:FPS相当、マイクロ秒
Brightness:明るさ
Contrast:コントラスト
ExposureTime:露光
の値を決めて
cam.set(controls_);にて設定しています。
これら項目は設定しなくても動作しました。
設定しない場合はデフォルト値が適用されるようです。
<キャプチャー処理>必須
カメラ開始
cam.startCamera();動画設定?
cam.VideoStream(&width, &height, &stride);生データ取得
flag = cam.readFrame(&frameData);取得したデータはOpenCVのフォーマットとは異なるので
Mat im(height, width, CV_8UC3, frameData.imageData, stride);でOpenCVのMat形式(定義名im)へ変換しています。
フレームデータへのアクセス終了
cam.returnFrameBuffer(frameData);これを実行しておかないと
次のデータを取得できずエラーになります。
<カメラ焦点設定>オプション
fキーでオートフォーカス
A/Dキーで手動フォーカスの設定ができるようです。
手持ちのカメラが固定焦点なので試せていません。
メインプログラムをちょっと修正
このプログラムでは
flagが
trueになるまで
cam.readFrameと
continueが繰り返されます。
で、これはひたすら空ループを繰り返している状態なので
CPU1コア分の使用率が100%となって
しまいます。(4コアなので25%表示)
無駄に空ループさせると処理が重いので
flagが
trueではない時に即
continueするのではなく
if (!flag){ usleep(10); continue;}の様に
10マイクロ秒待機するだけでもCPU使用率が大幅に軽減されます。
fpsを追い求めないのであれば
100マイクロ秒ぐらいで良いでしょう。
LibCamera.cpp / .h を編集する
カメラを指定できるように改造
int LibCamera::initCamera()を実行すると
cameraId = cm->cameras()[0]->id();にて
カメラ0にアクセスする仕様になっています。
これを
int LibCamera::initCamera(int index)および
cameraId = cm->cameras()[index]->id();としておけばカメラIDを指定することができます。
※
id指定バージョンのコミットもある?
※2025/07/08 追記
ラズパイ5にあるCSIポート2つの
CAM/DISP 0、
CAM/DISP 1の
どちらか片方のみカメラ
を接続している場合はカメラ0扱いになる様で、
CAM/DISP 1のみに接続している場合でもlibcamera上は
カメラ0として
認識されるようなので要注意。
ただし、同一プログラムから2つのカメラへアクセスしようとするとエラーになります。
プログラムを2つ起動してそれぞれアクセスする場合は同時でも動きます。
2台同時に使いたい場合の対応使っていないインクルードを除外
LibCamera.hにてヘッダファイルを沢山インクルードしていますが、仕様が変わったためか
インクルード不要なものもあります。
インクルードから除外する必要はとくにありませんが、整理してみます。
必要な物@libcamera.so.0.4.0(太字のみ)
//#include <atomic>//#include <iomanip>//#include <iostream>//#include <signal.h>#include <limits.h>//#include <memory>//#include <stdint.h>//#include <string>//#include <vector>//#include <unordered_map>#include <queue>//#include <sstream>#include <sys/mman.h>//#include <unistd.h>//#include <time.h>#include <mutex>//#include <libcamera/controls.h>//#include <libcamera/control_ids.h>//#include <libcamera/property_ids.h>#include <libcamera/libcamera.h>//#include <libcamera/camera.h>//#include <libcamera/camera_manager.h>//#include <libcamera/framebuffer_allocator.h>//#include <libcamera/request.h>//#include <libcamera/stream.h>//#include <libcamera/formats.h>//#include <libcamera/transform.h>unistd.hはusleepに
time.hはメイン関数(FPSの計算のみ)で使用しているので、
main.cppでインクルードするのが良いでしょう。
顔検出
恒例の顔検出をしておきます。
諸注意
using namespace cv;
using namespace libcamera;
でそれぞれ
cv::と
libcamera::を省略できるのですが、SizeとPointはそれぞれ
cv::Size、
cv::Point
libcamera::Size、
libcamera::Point
と両方に定義があり、
cv::を省略すると区別がつかなくなるため
error :reference to 'Size' is ambiguous等エラーが出ます。
OpenCVで使うSizeとPointはそれぞれ
cv::Size、
cv::Pointと記述する必要があります。
実行結果
いつもの検出条件
・640×480の倍率2 → 320x240
・スケール変化率1.3
・重複数4
にて実行してみます。
カメラのfps上限は限界確認のため
frame_time = 1000000 / 240;
としてみます。
ラズパイ5の性能が発揮され検出時間が10msを切りました

この状態でFPSも60fps以上出ています。
なお、IMX219、キャプチャのみ、その他処理なし、表示なし だと205fpsぐらいまで
出ており、IMX219の上限値206.65fpsで動かすこともできそうです。
ちなみにドルフラングレンは細かい検出条件にしてもあまり検出されません。

斜め向いてたり、上半身全体だったり、影がきつかったり で検出し辛い様です。
ヴァンダムも同じ?
v4l2-compat.soを使ってみる
自前でビルドしてv4l2-compat.soが生成されたので使ってみます。
参考:雑なログ様
libcameraのv4l2 compatibleを通してraw streamを取得ただし、v4l2-compat.soはビルドフォルダ内に生成されており共通のフォルダにはインストールされていないようです。

これを使ってOpenCVのサンプルプログラムを実行してみます。
サンプルは変更せずそのままビルドしただけのものを使います。
今回はvideocapture_cameraを実行してみます。
※自分の環境では
Geanyの設定を変更しているため実行ファイル名に.outがついています。
既存のプログラムをライブラリを指定して実行するには
LD_PRELOAD=ライブラリ 実行ファイルとすればいい様です。
今回の条件では
LD_PRELOAD=
/home/pi/libcamera/build/src/v4l2/v4l2-compat.so /home/pi/opencv-4.9.0/samples/cpp/videocapture_camera.outとなります。

既存のプログラムを未改造で実行することができました。

原因は分かりませんが、暫くするとエラーで終了してしまいます。
安定して実行させるためにはfps等を調整する必要があるかもしれません。