C++でラズパイカメラv2の画像を読み込むライブラリ「raspivideocap」

Raspberry Piカメラモジュールの画像を自作のC++プログラムから取得するためのライブラリ「raspivideocap」を紹介します。今のトレンドはちゃんと追えてないのですが、、少なくとも数年前まではC++でカメラ画像を取得するための使いやすいライブラリが無かったため自作したものです。細かいカメラパラメータの設定や高速化のためのバッファ設定などができるようになっています。また、OpenCVベースで作っているのでOpenCVへのインターフェースはやりやすいと思います。

環境の準備

以下の環境でテストしていますが、新しいほうなら動くと思います(OpenCV4系が動くかは微妙)。

もしラズパイカメラを使うのが初めての場合、オフィシャルのチュートリアルを参考にしてカメラモジュールを接続し、カメラを使えるようにConfigurationを設定します。そして、以下のコマンドなどで画像を取得/保存できていることを確認します。

> raspistill -o Desktop/image.jpg

次に、OpenCVの3.4系がインストールされていない場合、OpenCVのチュートリアルを参考にしてソースコードからインストールしておきます。動作確認しているのはOpenCV 3.4.3ですが、3.4系なら問題なく動くと思います。ただ、4系はあまり使ったことがないので微妙ですが、動かないにしても少し手を入れれば動かせるとは思います。

インストールとテスト

以上の準備ができたら、raspivideocapのインストールです。まずはソースコードを落としてきます。

> git clone https://github.com/coyote009/raspivideocap.git

そして、ソースコードをコンパイルし、インストールします。

> cd raspivideocap
> mkdir build
> cd build
> cmake ..
> make
> sudo make install

最後に、テストプログラムを動かして動作確認をします。

> cd ../test
> mkdir build
> cd build
> cmake ..
> make
> ./test_raspivideocap

これで、リアルタイムに画像が取得されて表示されるはずです。

ライブラリの使い方

では、ライブラリの使い方を説明します。基本的な流れとしては、まずRaspiVideoCaptureクラスのオブジェクトを作成し、open()関数に所望のパラメータを渡すことで準備ができます。あとは、read()関数を順番に呼んでいけば画像が順次取得できます。OpenCVのVideoCaptureクラスを意識したAPIなので、OpenCVに慣れている方であれば難しくないと思います。

#include <opencv2/opencv.hpp>
#include "raspivideocap.h"

int main()
{
    RaspiVideoCapture cap();

    if( !cap.open( 640, 480, 30 ) )
    {
        fprintf( stderr, "Failed to open camera\n" );
        return 1;
    }


    while( 1 )
    {
        cv::Mat img_in;
        cap.read( img_in );

        cv::imshow( "img_in", img_in );

        if( cv::waitKey( 1 ) == 27 )
        {
            break;
        }
    }
}

次に、RaspiVideoCaptureクラスのいくつかあるパラメータの説明をします。

class RaspiVideoCapture
{
public:
    RaspiVideoCapture( int num_buffers = 10 );

    bool open( int width, int height, int framerate, int monochrome = 0,
               int vflip = 0, int hflip = 0,
               EXPOSURE_MODE exposure_mode = EXPOSUREMODE_AUTO,
               float analog_gain = 0, float digital_gain = 0, int shutter_speed = 0,
               AWB_MODE awb_mode = AWBMODE_AUTO,
               float awb_gains_r = 0.0, float awb_gains_b = 0.0 );
}

まず、RaspiVideoCaptureクラスのコンストラクタにnum_buffersというパラメータを渡すことができます(デフォルトでは10)。これは、HWが持つ内部バッファの数を指定するのですが、高速に読み込む場合(フレームレートを高めに設定した場合)に大きめにとっておいたほうがフレームレートが上がりやすいです(フレームレートを設定しても処理の遅延で設定したとおりのレートが出ない場合があるということです)。ただ、大きくとりすぎるとメモリが足りなくなることがあるので注意してください(特に画像サイズを大きくとった場合は注意が必要です)。

次にopen()関数にカメラのパラメータを設定します。以下のパラメータを設定可能です。

width画像幅(pix)
height画像高さ(pix)
framerateフレームレート(frame/sec)
monochromeグレースケール
vflip上下フリップ
hflip左右フリップ
exposure_mode露光モード
analog_gainアナログゲイン
digital_gainデジタルゲイン
shutter_speedシャッター速度(露光時間)
awb_modeホワイトバランスモード
awb_gain_r赤ゲイン
awb_gain_b青ゲイン

ただし、画像幅×画像高×フレームレートの組合せは任意の数値を設定できるわけではありません。メジャーなもの(例えば、640×480@30fps、1280×720@30fps、1920×1080@30fpsなど)であれば問題ありませんが、中途半端なサイズやフレームレートが高すぎる場合など、中で勝手に別のサイズにして出されたりします。また、露光やホワイトバランスのパラメータも効く場合と効かない場合があったります。これは、実際のところこれらのパラメータはあとで説明するMMALというAPIをたたいているだけなので、中で何が起こっているかは分かりません(そこまで追っていません)。なので使いながらどこまでできるかを探ってみてください。

最後に、自分でライブラリに手を入れたい人のために少しだけライブラリの中身(というかラズパイのカメラハードウェアまわり)について説明します。ラズパイカメラはCPUチップであるBCM283Xの中のVideoCoreIVというハードウェアにつながっています。ソフトウェア的にはハードウェアを叩くデバイスドライバ層があり、それを叩くOpenMaxというAPIがあり、そしてその上にMMAL(Multi-Media Abstraction Layer)というAPI層があります(ここら辺の説明はこのサイトが詳しいです)。raspivideocapライブラリはこのMMALのAPIを叩いています。Raspbianに最初からついてくるraspistillやraspividもMMALを叩いているアプリです。MMALやraspistill/raspividはオープンソース化されており、これらのソースを読めばより細かいカメラの制御をすることができるはずです。