Main Content

顔の追跡 (Raspberry Pi2)

この例では、MATLAB® Coder™ を使用して MATLAB ファイルから C コードを生成し、ARM ターゲットにアプリケーションを展開する方法を説明します。

ここでは Web カメラからビデオ フレームを読み取ります。Viola-Jones 顔検出アルゴリズムを使用して顔を検出し、KLT アルゴリズムを使用してライブ ビデオ ストリームで顔を追跡します。最後に、追跡される顔の周りに境界ボックスと一連のマーカーが描かれたフレームが表示されます。MATLAB ホストでのシミュレーションには、'MATLAB Support Package for USB Webcams' の関数 webcam と、Computer Vision System Toolbox™ の VideoPlayer オブジェクトが使用されます。これらの 2 つの機能では ARM ターゲットがサポートされないため、OpenCV ベースの Web カメラ リーダーとビデオ ビューアー機能を使用して展開が行われます。

ターゲットには OpenCV Version 3.4.0 ライブラリ (GTK でビルド) および標準の C++ コンパイラが必要です。展開には Raspbian Stretch オペレーティング システムがインストールされた Raspberry Pi 2 を使用しています。この例はどの ARM ターゲットでも機能するはずです。

この例には MATLAB Coder のライセンスが必要です。

この例は、本体部分が上部にあり、ヘルパー ルーチンが入れ子関数の形式で下部に置かれた関数です。

function FaceTrackingARMCodeGenerationExample()

C++ コンパイラの設定

この例を実行するには C++ コンパイラへのアクセスが必要です。コンパイラは 'mex -setup c++' コマンドを使用して構成しなければなりません。詳細については、C++ コンパイラの選択を参照してください。

アルゴリズムにおける計算部分を独立した MATLAB 関数として分割

MATLAB Coder で C コードを生成するには、MATLAB コードが関数の形式を取っていなければなりません。この例のメイン アルゴリズムのコードは、faceTrackingARMKernel.m という関数内で定義されています。この関数は、Web カメラからイメージを入力として受け取ります。顔の周りに境界ボックスと一連のマーカーが描かれたイメージが出力されます。[ビデオ ビューアー] ウィンドウに出力イメージが表示されます。MATLAB コードを変更してコード生成に対応させる方法については、特徴のマッチングとレジストレーションを使ったコード生成の紹介の例を参照してください。

fileName = 'faceTrackingARMKernel.m';

I/O 機能を使用した main 関数の作成

スタンドアロン実行可能ターゲットの場合、MATLAB Coder を使用するには "main" という名前の関数を含む C ファイルを作成する必要があります。この例では faceTrackingARMMain.c ファイルを使用します。このファイルの main 関数によって次のタスクが実行されます。

  • Web カメラからのビデオ フレームの読み取り

  • 顔追跡アルゴリズムへのビデオ フレームの送信

  • 顔の周りの境界ボックスとマーカーを含む出力フレームの表示

MATLAB ホストでのシミュレーションのために、faceTrackingARMMain.c ファイルで実行されるタスクが faceTrackingARMMain.m に実装されています。

Web カメラ リーダーとビデオ ビューアー

この例では ARM への展開のために OpenCV 関数を使用して Web カメラ リーダー機能を実装します。さらに、OpenCV 関数を使用してビデオ ビューアーを実装します。これらの OpenCV ベースのユーティリティ関数は、次のファイルに実装されています。

  • helperOpenCVWebcam.hpp

  • helperOpenCVWebcam.cpp

  • helperOpenCVVideoViewer.cpp

  • helperOpenCVVideoViewer.hpp

この例では MATLAB ホストでのシミュレーションのために 'MATLAB Support Package for USB Webcams' の関数 webcam と、Computer Vision System Toolbox の VideoPlayer オブジェクトを使用します。MATLAB® コマンド ラインで faceTrackingARMMain と入力して MATLAB ホストでシミュレーションを実行します。

ARM ターゲット用の OpenCV

この例では、ARM ターゲットに OpenCV 3.4.0 ライブラリをインストールする必要があります。ビデオ ビューアーを使用するには、GTK をインストールした状態で ARM ターゲット用に OpenCV の highgui ライブラリをビルドする必要があります。

手順に従って、Raspbian Stretch がプレインストールされた Raspberry Pi 2 に OpenCV 3.4.0 をダウンロードしてビルドします。システム構成に応じてシステム ファームウェアを更新したり、他の開発者ツールやパッケージをインストールしたりする必要がある場合は、OpenCV のビルドを始める前に行わなければなりません。

https://github.com/opencv/opencv/issues/5851 の問題のため、INSTALL_C_EXAMPLES をオフにします。

https://github.com/opencv/opencv/issues/9942 の問題のため、ENABLE_PRECOMPILED_HEADERS をオフにします。

  • $ wget -O opencv-3.4.0.zip https://github.com/opencv/opencv/archive/3.4.0.zip

  • $ unzip opencv-3.4.0.zip

  • $ cd opencv-3.4.0

  • $ mkdir build

  • $ cd build

  • $ cmake -D CMAKE_BUILD_TYPE=RELEASE -D CMAKE_INSTALL_PREFIX=/usr/local -D INSTALL_C_EXAMPLES=OFF -D BUILD_EXAMPLES=ON -D WITH_GTK=ON -D WITH_FFMPEG=OFF -D ENABLE_PRECOMPILED_HEADERS=OFF ..

OpenCV をコンパイルしてインストールするには、次の手順に従います。

  • $ make

  • $ sudo make install

この例の正式な展開では、OpenCV ライブラリが Raspberry Pi 2 のディレクトリにインストールされます。

   /usr/local/lib

また関連付けられたヘッダーは以下に配置されました。

   /usr/local/include

コード生成引数の構成

EXE 出力用のコード生成構成オブジェクトを作成します。

codegenArgs = createCodegenArgs();

コードの生成

codegen コマンドを呼び出します。

fprintf('-> Generating Code (it may take a few minutes) ....\n');
codegen(codegenArgs{:}, fileName);
% During code generation, all dependent file information is stored in a mat
% file named buildInfo.mat.
-> Generating Code (it may take a few minutes) ....
Code generation successful.

パッケージ化された zip ファイルの作成

buildInfo.mat に保存されているビルド情報を使用し、packNGo を使用して zip フォルダーを作成します。

fprintf('-> Creating zip folder (it may take a few minutes) ....\n');
bInfo = load(fullfile('codegen','exe','faceTrackingARMKernel','buildInfo.mat'));
packNGo(bInfo.buildInfo, {'packType', 'hierarchical', ...
                          'fileName', 'faceTrackingARMKernel'});
% The generated zip folder is faceTrackingARMKernel.zip
-> Creating zip folder (it may take a few minutes) ....

プロジェクト フォルダーの作成

faceTrackingARMKernel.zip を FaceTrackingARM という名前のフォルダーに解凍します。すべてのファイルを解凍して .zip ファイルを削除します。

packngoDir = hUnzipPackageContents();
Warning: Directory already exists. 

makefile の更新とプロジェクト フォルダーへのコピー

この例で makefile として示している faceTrackingARMMakefile.mk は、Raspberry PI 2 向けに特定の最適化フラグを指定して記述されています。makefile は、Linux 環境の GCC、および /usr/local/lib に配置されている OpenCV ライブラリで機能するように記述されています。ターゲットの構成に基づいて、makefile を更新できます。makefile をプロジェクト フォルダーにコピーします。

copyfile('faceTrackingARMMakefile.mk', packngoDir);
% Also move the file containing the main function in the top level folder.
copyfile('faceTrackingARMMain.c', packngoDir);
% For simplicity, make sure the root directory name is matlab.
setRootDirectory(packngoDir);

ARM への展開

プロジェクトを ARM に展開します。

disp('Follow these steps to deploy your project on ARM');
Follow these steps to deploy your project on ARM

ARM ターゲットへのコードの転送

任意のファイル転送ツールで FaceTrackingARM という名前のプロジェクト フォルダーを ARM ターゲットに転送します。(Raspbian Stretch がインストールされた) Raspberry Pi 2 には既に SSH サーバーが設定されているため、SFTP を使用してホストからターゲットにファイルを転送できます。

この例の正式な展開では、ホスト マシンに FileZilla SFTP クライアントがインストールされ、ホストから Raspberry Pi の /home/pi/FaceTrackingARM フォルダーにプロジェクト フォルダーが転送されます。

disp('Step-1: Transfer the folder ''FaceTrackingARM'' to your ARM target');
Step-1: Transfer the folder 'FaceTrackingARM' to your ARM target

ARM での実行可能ファイルのビルド

makefile を実行して、ARM で実行可能ファイルをビルドします。(Raspbian Stretch がインストールされた) Raspberry Pi 2 の場合、コマンド ライン ターミナルを開き、'cd' コマンドを実行して /home/pi/FaceTrackingARM に移動します。次のコマンドを使用して実行可能ファイルをビルドします。

make -f faceTrackingARMMakefile.mk

このコマンドにより、実行可能ファイル faceTrackingARMKernel が作成されます。

disp('Step-2: Build the executable on ARM using the shell command: make -f faceTrackingARMMakefile.mk');
Step-2: Build the executable on ARM using the shell command: make -f faceTrackingARMMakefile.mk

ARM での実行可能ファイルの実行

上記の手順で生成された実行可能ファイルを実行します。(Raspbian Stretch がインストールされた) Raspberry Pi 2 の場合、シェル ウィンドウで次のコマンドを使用します。

./faceTrackingARMKernel

GTK に関連するエラーを回避するため、コマンド ライン ターミナルからだけでなく、ウィンドウ マネージャーで Raspberry Pi に接続していることを確認します。これは追跡ウィンドウを表示するために必要です。

Raspberry Pi2 で実行可能ファイルを実行している間にビデオ ビューアーを閉じるには、ビデオ ビューアーをクリックして Esc キーを押します。

disp('Step-3: Run the executable on ARM using the shell command: ./faceTrackingARMKernel');
Step-3: Run the executable on ARM using the shell command: ./faceTrackingARMKernel

付録 - 補助関数

    % Configure coder to create executable. Use packNGo at post code
    % generation stage.
    function codegenArgs = createCodegenArgs()
        % Create arguments required for code generation.

        % First - create configuration object
        %
        % For standalone executable a main C function is required. The
        % faceTrackingARMMain.c created for this example is compatible
        % with the content of the file faceTrackingARMKernel.m
        mainCFile = 'faceTrackingARMMain.c';

        % Include helper functions
        camCPPFile = 'helperOpenCVWebcam.cpp';
        viewerCPPFile = 'helperOpenCVVideoViewer.cpp';

        % Handle path with space
        if contains(mainCFile, ' ')
            mainCFile     = ['"' mainCFile '"'];
            camCPPFile    = ['"' camCPPFile '"'];
            viewerCPPFile = ['"' viewerCPPFile '"'];
        end

        % Create configuration object
        cfg = coder.config('exe');
        cfg.CustomSource       = sprintf('%s\n%s\n%s',mainCFile,camCPPFile,viewerCPPFile);
        cfg.CustomInclude      = pwd;
        % Set production hardware to ARM to generate ARM compatible portable code
        cfg.HardwareImplementation.ProdHWDeviceType = 'ARM Compatible->ARM Cortex';
        cfg.EnableOpenMP       = false;

        % Create input arguments
        inRGB_type = coder.typeof(uint8(0),[480 640 3]);
        % Use '-c' option to generate C code without calling C++ compiler.
        codegenArgs = {'-config', cfg, '-c', '-args', {inRGB_type}};

    end

    % Unzip the packaged zip file
    function packngoDir   = hUnzipPackageContents()

        packngoDirName = 'FaceTrackingARM';

        % create packngo directory
        mkdir(packngoDirName);

        % get the name of the single zip file generated by packngo
        zipFile = dir('*.zip');
        assert(numel(zipFile)==1);

        unzip(zipFile.name,packngoDirName);

        % unzip internal zip files created in hierarchical packNGo
        zipFileInternal = dir(fullfile(packngoDirName,'*.zip'));

        for i=1:numel(zipFileInternal)
            unzip(fullfile(packngoDirName,zipFileInternal(i).name), ...
                packngoDirName);
        end
        % delete internal zip files
        delete(fullfile(packngoDirName,'*.zip'));
        packngoDir = fullfile(packngoDirName);
    end

    % Set root directory as matlab
    function setRootDirectory(packngoDir)
        dirList = dir(packngoDir);
        if isempty(find(ismember({dirList.name},'matlab'), 1))
            % root directory is not matlab. Change it to matlab
            for i=1:length(dirList)
                thisDir = fullfile(packngoDir,dirList(i).name, 'toolbox', 'vision');
                if isfolder(thisDir)
                    % rename the dir
                    movefile(fullfile(packngoDir,dirList(i).name), ...
                             fullfile(packngoDir,'matlab'));
                    break;
                end
            end
        end
    end
end