顔の検出 (Raspberry Pi2)
この例では、MATLAB® Coder™ を使用して MATLAB ファイルから C コードを生成し、ARM ターゲットにアプリケーションを配布する方法を説明します。
ここでは Web カメラからビデオ フレームを読み取り、Viola-Jones 顔検出アルゴリズムを使用して各フレームで顔を検出します。検出された顔は、境界ボックス付きで表示されます。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 FaceDetectionARMCodeGenerationExample()
C++ コンパイラの設定
この例を実行するには C++ コンパイラへのアクセスが必要です。コンパイラは 'mex -setup c++' コマンドを使用して構成しなければなりません。詳細については、C++ コンパイラの選択を参照してください。
アルゴリズムにおける計算部分を独立した MATLAB 関数として分割
MATLAB Coder で C コードを生成するには、MATLAB コードが関数の形式を取っていなければなりません。この例のメイン アルゴリズムのコードは、faceDetectionARMKernel.m という関数内で定義されています。この関数は、Web カメラからイメージを入力として受け取ります。検出された顔の周りに境界ボックスが描かれたイメージが出力されます。[ビデオ ビューアー] ウィンドウに出力イメージが表示されます。MATLAB コードを変更してコード生成に対応させる方法については、特徴のマッチングとレジストレーションを使ったコード生成の紹介の例を参照してください。
fileName = 'faceDetectionARMKernel.m';
I/O 機能を使用した main 関数の作成
スタンドアロン実行可能ターゲットの場合、MATLAB Coder を使用するには "main" という名前の関数を含む C ファイルを作成する必要があります。この例では faceDetectionARMMain.c ファイルを使用します。このファイルの main 関数によって次のタスクが実行されます。
Web カメラからのビデオ フレームの読み取り
顔検出アルゴリズムへのビデオ フレームの送信
検出された顔の周りの境界ボックスを含む出力フレームの表示
MATLAB ホストでのシミュレーションのために、faceDetectionARMMain.c ファイルで実行されるタスクが faceDetectionARMMain.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® コマンド ラインで faceDetectionARMMain と入力して MATLAB ホストでシミュレーションを実行します。
ARM ターゲット用の OpenCV
この例では、ARM ターゲットに OpenCV 3.4.0 ライブラリをインストールする必要があります。ビデオ ビューアーを使用するには、GTK をインストールした状態で ARM ターゲット用に OpenCV の highqui ライブラリをビルドする必要があります。
手順に従って、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','faceDetectionARMKernel','buildInfo.mat')); packNGo(bInfo.buildInfo, {'packType', 'hierarchical', ... 'fileName', 'faceDetectionARMKernel'}); % The generated zip folder is faceDetectionARMKernel.zip
-> Creating zip folder (it may take a few minutes) ....
プロジェクト フォルダーの作成
faceDetectionARMKernel.zip を FaceDetectionARM という名前のフォルダーに解凍します。すべてのファイルを解凍して .zip ファイルを削除します。
packngoDir = hUnzipPackageContents();
Warning: Directory already exists.
makefile の更新とプロジェクト フォルダーへのコピー
この例で makefile として示している faceDetectionARMMakefile.mk は、Raspberry PI 2 向けに特定の最適化フラグを指定して記述されています。makefile は、Linux 環境の GCC、および /usr/local/lib に配置されている OpenCV ライブラリで機能するように記述されています。ターゲットの構成に基づいて、makefile を更新できます。makefile をプロジェクト フォルダーにコピーします。
copyfile('faceDetectionARMMakefile.mk', packngoDir); % Also move the file containing the main function in the top level folder. copyfile('faceDetectionARMMain.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 ターゲットへのコードの転送
任意のファイル転送ツールで FaceDetectionARM という名前のプロジェクト フォルダーを ARM ターゲットに転送します。(Raspbian Stretch がインストールされた) Raspberry Pi 2 には既に SSH サーバーが設定されているため、SFTP を使用してホストからターゲットにファイルを転送できます。
この例の正式な配布では、ホスト マシンに FileZilla SFTP クライアントがインストールされ、ホストから Raspberry Pi の /home/pi/FaceDetectionARM フォルダーにプロジェクト フォルダーが転送されます。
disp('Step-1: Transfer the folder ''FaceDetectionARM'' to your ARM target');
Step-1: Transfer the folder 'FaceDetectionARM' to your ARM target
ARM での実行可能ファイルのビルド
makefile を実行して、ARM で実行可能ファイルをビルドします。(Raspbian Stretch がインストールされた) Raspberry Pi 2 の場合、Linux シェルを開き、cd コマンドを実行して /home/pi/FaceDetectionARM に移動します。次のコマンドを使用して実行可能ファイルをビルドします。
make -f faceDetectionARMMakefile
このコマンドにより、実行可能ファイル faceDetectionARMKernel が作成されます。
disp('Step-2: Build the executable on ARM using the shell command: make -f faceDetectionARMMakefile.mk');
Step-2: Build the executable on ARM using the shell command: make -f faceDetectionARMMakefile.mk
ARM での実行可能ファイルの実行
上記の手順で生成された実行可能ファイルを実行します。(Raspbian Stretch がインストールされた) Raspberry Pi 2 の場合、シェル ウィンドウで次のコマンドを使用します。
./faceDetectionARMKernel
GTK に関連するエラーを回避するため、コマンド ライン ターミナルからだけでなく、ウィンドウ マネージャーで Raspberry Pi に接続していることを確認します。これは追跡ウィンドウを表示するために必要です。
Raspberry Pi2 で実行可能ファイルを実行している間にビデオ ビューアーを閉じるには、ビデオ ビューアーをクリックして Esc キーを押します。
disp('Step-3: Run the executable on ARM using the shell command: ./faceDetectionARMKernel');
Step-3: Run the executable on ARM using the shell command: ./faceDetectionARMKernel
付録 - 補助関数
% 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 % faceDetectionARMMain.c created for this example is compatible % with the content of the file faceDetectionARMKernel.m mainCFile = 'faceDetectionARMMain.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 = 'FaceDetectionARM'; % 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 = 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