embeddedなブログ

組み込みシステムに関することや趣味に関することをダラダラと書いていきます(^^)

Windows 10ユニバーサルアプリ(Universal Windows Application)でOpenCVを使う(その2)

2016-02-15 22:48:44 | Windows Embedded CompactまたはCE

Windows 10ユニバーサルアプリ(Universal Windows Application)でOpenCVを使う(その1)の続きです。

3. ARM用OpenCVライブラリをビルド

OpenCVを使ったユニバーサルアプリをビルドするためには、準備としてまずはアプリで使用するためのOpenCVライブラリとdllをビルドする必要があります。

GitHubのvs2015-samplesをコピーします。[Download ZIP]ボタンをクリックしてvs2015-samples.zipをダウンロードし、適当なフォルダに展開します。私の環境では、D:\Visual Studio Projects\opencv-vs2015-samplesフォルダに展開したので、以降ではこのフォルダを前提として説明します。みなさんの環境に読み替えて設定してください。

次に、ビルドするために必要な環境変数を新規作成します。OCV2015_ROOTという名前の環境変数を作成し、値としてさきほど展開したフォルダ「D:\Visual Studio Projects\opencv-vs2015-samples」を設定します。

次に、VisualStudio 2015でOpenCVプロジェクトを開き、ビルドします。opencv-vs2015-samples\vs2015\WS\10.0\ARM\OpenCV.slnを開きます。OpenCV.slnをダブルクリックすれば開くことが出来ます。 そして、VisualStudio 2015の[ビルド]-[ソリューションのビルド]でOpenCVプロジェクトをビルドします。ビルドエラーが出るときは、環境変数のパスがうまく通っていない可能性もあるので、VisualStudioを再起動してみてください。

 ビルドが正常に終了すれば、opencv-vs2015-samples\vs2015\WS\10.0\ARMフォルダ以下のlibとbinフォルダにlibとdllが生成されているはずです。

4. OpenCVを使用するユニバーサルアプリのビルド

[ファイル]-[新規作成]-[プロジェクト]で「新しいプロジェクト」ウィンドウを開きます。

[テンプレート]-[Visual C++]で「空白のアプリ(ユニバーサル Windows) Visual C++」を選択し、名前として「RaspberryCV」と入力して[OK]をクリックしてRaspberryCVプロジェクトを作成します。

まず、ソリューションを選択します。ソリューション構成を「Debug」、ソリューションプラットフォームを「ARM」を選択します。

OpenCVのインクルードパスを設定します。[プロジェクト]-[RaspberryCVのプロパティ]で「RaspberryCVのプロパティ ページ」画面を開きます。[構成]コンボボックスで「すべての構成」を選択します。左側ウィンドウで[構成プロパティ]-[C/C++]-[全般]を選択し、右側ウィンドウの[追加のインクルードディレクトリ]に「$(OCV2015_ROOT)\include;$(OCV2015_ROOT)\vs2015\WS\10.0\include;」と入力して、OpenCVのインクルードパスを追加します。

次にライブラリパスの追加です。左側ウィンドウで[構成プロパティ]-[リンカー]-[全般]を選択し、右側ウィンドウの[追加のライブラリディレクトリ]に「$(OCV2015_ROOT)\vs2015\WS\10.0\ARM\lib\$(Configuration)」と入力して、OpenCVのライブラリパスを追加します。

次は依存ファイルの追加です。左側ウィンドウで[構成プロパティ]-[リンカー]-[入力]を選択し、右側ウィンドウの[追加の依存ファイル]に「opencv_core300d.lib;opencv_imgproc300d.lib;opencv_imgcodecs300d.lib;opencv_objdetect300d.lib」を入力して、OpenCVのライブラリファイルを追加します。

画像ファイルを追加します。opencv-vs2015-samples\samples\winrt_universal\RaspberryCV\RaspberryCV\Assetsフォルダにある下記3つのファイルを作成中のプロジェクトのRaspberryCV\RaspberryCV\Assetsフォルダにコピーします。

  • grpPC1.jpg
  • haarcascade_frontalface_alt.xml
  • haarcascade_fullbody.xml

そして、ソリューション エクスプローラーでソリューション名「ソリューション'RaspberryCV'」の下の「RaspberryCV(Universal Windows)-Assets」上で右クリックして、コンテキストメニューから[追加]-[既存の項目]を選択し、先ほど追加した3つのファイルを選択してプロジェクトに追加します。

次に、さきほどビルドしたDllを追加します。ソリューション エクスプローラーでソリューション名「ソリューション'RaspberryCV'」の下の「RaspberryCV(Universal Windows)」上で右クリックして、コンテキストメニューから[追加]-[既存の項目]を選択します。

「既存のソリューション項目の追加」画面にて下記Dllを選択して追加します。

ARM\bin\Debug\opencv_core300d.dll
ARM\bin\Debug\opencv_imgcodecs300d.dll
ARM\bin\Debug\opencv_imgproc300d.dll
ARM\bin\Debug\opencv_ml300d.dll
ARM\bin\Debug\opencv_objdetect300d.dll
ARM\bin\Release\opencv_core300.dll
ARM\bin\Release\opencv_imgcodecs300.dll
ARM\bin\Release\opencv_imgproc300.dll
ARM\bin\Release\opencv_ml300.dll
ARM\bin\Release\opencv_objdetect300.dll

追加した項目をそれぞれマウスで選択、項目のプロパティ画面で「コンテンツ」を[True]に変更します。

実際にビルドして実行する際にopencv_core300d.dll関連のエラーが出たら、RaspberryCV.vcxprojを直接テキストエディタで開いて、下記のようにopencv_core300d.dllの定義部分を変更します。

   None Include="$(OCV2015_ROOT)\vs2015\WS\10.0\ARM\bin\Debug\opencv_core300d.dll"

画面に部品を追加します。ソリューションエクスプローラーで「MainPage.xaml」をダブルクリックすると、VisualStudioに画面のデザインが表示されます。VisualStudio左側に[ツールボックス]という表示があるので、それを選択してツールボックスを表示します。無ければ、メニューで[表示]-[ツールボックス]を選択すると表示されます。

ツールボックスの[Button]をドラッグしてMainPage.xamlのデザイン上に持ってきます。さきほどドラッグしたButtonをクリックして選択状態にして、ソリューションエクスプローラーのプロパティで[名前]に「btn1」、[Content]に「Test Image」と入力します。同様に、順番に[Image]、[Button]、[Button]をドラッグして、さきほど設定したButtonも含め、最終的に4つの部品のプロパティに以下のように入力します。

部品 名前 Content
Button btn1 Test Image
Image img1  
Button btn2 Canny
Button btn3 Detect

 ボタンのイベントハンドラーを追加します。btn1を選択した状態で、プロパティで稲妻のマークを選択し、[Click]横の箱をダブルクリックすると「btn1_Click」というイベントハンドラーが追加されます。

同様にbtn2とbtn3のイベントハンドラーを追加します。

それでは、ソースを書いていきます。ソリューションエクスプローラーで[MainPage.xaml]の左側の三角形をクリックしてツリーを展開し、[MainPage.xaml.h]を選択し、以下のインクルードを追加します。

#include 

MainPageクラスに以下の定義を追加します。

    private:
        cv::Mat Lena;
        void UpdateImage(const cv::Mat& image);

次に[MainPage.xaml.cpp]を選択し、以下のインクルードを追加します。

#include  
#include  
#include  
#include  
#include  
#include 

using namespace Windows::UI::Xaml::Media::Imaging;
using namespace Windows::Storage::Streams;
using namespace Microsoft::WRL;

cv:Matをイメージコントロールに(img1)表示さるためのUpdateImage関数を実装します。

void  RaspberryCV::MainPage::UpdateImage(const cv::Mat& image)
{
    // Create the WriteableBitmap
    WriteableBitmap^ bitmap = ref new WriteableBitmap(image.cols, image.rows);

    // Get access to the pixels
    IBuffer^ buffer = bitmap->PixelBuffer;
    unsigned char* dstPixels;

    // Obtain IBufferByteAccess
    ComPtr pBufferByteAccess;
    ComPtr pBuffer((IInspectable*)buffer);
    pBuffer.As(&pBufferByteAccess);

    // Get pointer to pixel bytes
    pBufferByteAccess->Buffer(&dstPixels);
    memcpy(dstPixels, image.data, image.step.buf[1] * image.cols*image.rows);

    // Set the bitmap to the Image element
    img1->Source = bitmap;
}

btn1のイベントハンドラーにimg1にイメージをロードするための以下のような実装をします。

void RaspberryCV::MainPage::btn1_Click(Platform::Object^ sender, Windows::UI::Xaml::RoutedEventArgs^ e)
{
    cv::Mat image = cv::imread("Assets/grpPC1.jpg");
    Lena = cv::Mat(image.rows, image.cols, CV_8UC4);
    cv::cvtColor(image, Lena, CV_BGR2BGRA);
    UpdateImage(Lena);

}

btn2のイベントハンドラーにCanny filterでエッジ検出を実験するための以下のような実装をします。

void RaspberryCV::MainPage::btn2_Click(Platform::Object^ sender, Windows::UI::Xaml::RoutedEventArgs^ e)
{
    //Canny filter
    cv::Mat result;
    cv::Mat intermediateMat;
    cv::Canny(Lena, intermediateMat, 80, 90);
    cv::cvtColor(intermediateMat, result, CV_GRAY2BGRA);
    UpdateImage(result);

}

btn3用のイベントハンドラーと関連関数に顔検出ためのコードとして以下を入力します。

cv::String face_cascade_name = "Assets/haarcascade_frontalface_alt.xml";
cv::CascadeClassifier face_cascade;

cv::String body_cascade_name = "Assets/haarcascade_fullbody.xml";
cv::CascadeClassifier body_cascade;

void internalDetectObjects(cv::Mat& inputImg, std::vector & objectVector, std::vector & objectVectorBodies)
{
    cv::Mat frame_gray;

    cvtColor(inputImg, frame_gray, CV_BGR2GRAY);
    cv::equalizeHist(frame_gray, frame_gray);

    // Detect faces
    face_cascade.detectMultiScale(frame_gray, objectVector, 1.1, 2, 0 | CV_HAAR_SCALE_IMAGE, cv::Size(30, 30));
    //detect bodies
    body_cascade.detectMultiScale(frame_gray, objectVectorBodies, 1.1, 2, 0 | CV_HAAR_SCALE_IMAGE, cv::Size(30, 300));
}
void RaspberryCV::MainPage::btn3_Click(Platform::Object^ sender, Windows::UI::Xaml::RoutedEventArgs^ e)
{
    if (!face_cascade.load(face_cascade_name)) {
        printf("Couldnt load Face detector '%s'\n", face_cascade_name);
        exit(1);
    }

    if (!body_cascade.load(body_cascade_name)) {
        printf("Couldnt load Body detector '%s'\n", body_cascade_name);
        exit(1);
    }

    cv::Mat frame = cv::imread("Assets/grpPC1.jpg");

    if (frame.empty())
        return;

    std::vector faces;
    std::vector bodies;

    internalDetectObjects(frame, faces, bodies);

    for (unsigned int i = 0; i < faces.size(); i++)
    {
        auto face = faces[i];

        cv::rectangle(Lena, face, cv::Scalar(0, 0, 255, 255), 5);

    }

    for (unsigned int i = 0; i < bodies.size(); i++)
    {
        auto body = bodies[i];

        cv::rectangle(Lena, body, cv::Scalar(0, 0, 0, 255), 5);

    }

    UpdateImage(Lena);

}

 

ビルドする環境とターゲットデバイスを設定します。VisualStudioのメニューから[ビルド]-[構成マネージャ]を実行して構成マネージャ画面を開きます。[アクティブソリューション構成]で[Debug]を選択、[アクティブプラットフォーム]で[ARM]を選択します。[配置]にチェックが入っていることを確認して、プロパティページを閉じて、ビルドをしてください。

今回はここまでで、次回は実際にRaspberry Pi 2に対して接続して実行してみます。


最新の画像もっと見る