LoginSignup
6
3

More than 5 years have passed since last update.

OpenCV 3.3.1のUMatで処理時間の短縮を確認してみた

Posted at

lenas.PNG
Lena の検出結果画像 (1/2に縮尺)

はじめに

  • この記事は、OpenCV Advent Calendar 2017 16日目の記事です。
  • 予定では、”仮) OpenCV 3.4 RC版で何か” を書く予定でしたが、まだRC版がリリースされていないので変更しました。
  • 代わりに、今年のAdvent Calendar でも高速化に関していくつかエントリーされており、特に3日目の記事 ASUS tinker boardのMali T764をOpenCV 3.3.1のOpenCLで酷使してみる を読み気になったので、OpenCL を利用している UMat を試してみた。
  • 実は、4年前にOpenCLを試してみたことがあったのですが、想像していたよりも使えなかったために、それ以降触れる機会がほとんどありませんでした。

UMatとは

  • UMatは、OpenCV 3.0 から取り入れられた高速化の手法の1つです。OpenCL をベースとしており、OpenCV 2系では、OCLクラスとして実装されていました。

  • 3系でもOCLクラスは、実装されていますが、OCLクラスを意識しなくても、利用できるようになっており、"Transparent API" designと呼ばれています。

テスト環境

マシンスペック

  • CPU Intel(R) Core(TM) i3-6006U CPU @ 2.00GHz
  • グラフィックス: Intel(R) HD Graphics 520 とほぼエントリーマシンに近い性能のものです。

ソフトウェア

  • ほとんど素に近いWindows10 Home 64bit
  • windwos 版バイナリの OpenCV 3.3.1 ダウンロードして展開
  • Visual Studio 2017 community Editionをインストール

今では、OpenCL SDK は、インストールしなくても利用できるようになっているようです。

テストプログラム

  • 今回時間があまりとれませでしたので、OpenCVの定番である顔検出に利用される detectMultiScale で処理時間を計測しました。パラメータは、デフォルトのままです。
  • CPU 利用の Mat と グラフィックスモジュール利用の UMat を用い、ばらつきを抑えるため10回実行の平均値を求めています。
  • また、UMatに関しては、カーネルのコンパイル時間が加算される1回めを計測から外し、また、グラフィックスモジュールへのデータ転送と ch変換の処理時間も別途計測しています。
  • 計測対象の画像は、お馴染みのLena、画像サイズは、512 x 512

ソース

計測プログラムから、関連部分のみ抜粋
インクルード関連

#include <opencv2/opencv.hpp>
#include <opencv2/core/ocl.hpp>
#pragma comment(lib, "opencv_world331d.lib")

Matによる10回計測部

    cv::Mat mat = cv::imread("c:\\tmp\\lena.jpg");
    cv::CascadeClassifier faceCascade("c:\\tmp\\haarcascade_frontalface_alt.xml");

    std::vector<cv::Rect> facesM, facesU;

    cv::TickMeter t1;
    t1.start();
    for (int i = 0; i < 10; i++) {
        faceCascade.detectMultiScale(mat, facesM);
    }
    t1.stop();

UMat 最初の計測部。この時、カーネルのバイナリコードがコンパイルされ、メモリにキャッシュされるために、2回め以降は、コンパイルのオーバーヘッドがない。

    cv::TickMeter t2;
    t2.start();
    cv::UMat umat = mat.getUMat(cv::ACCESS_READ);
    t2.stop();

    t2.reset();
    t2.start();
    faceCascade.detectMultiScaleumat, facesU);
    t2.stop();

UMatによる 10計測部

    cv::TickMeter t3;
    t3.start();
    for (int i = 0; i < 10; i++) {
        umat = mat.getUMat(cv::ACCESS_READ);
    }
    t3.stop();

    t3.reset();
    t3.start();
    for (int i = 0; i < 10; i++) {
        faceCascade.detectMultiScale(umat, facesU);
    }
    t3.stop();

計測結果

Mat 10回平均の処理時間

  • detectMultiScale 211.374ms

UMat 1回め処理時間

  • 作成 0.238522ms
  • detectMultiScale 1196.11ms

UMat 10回平均の処理時間

  • 作成 0.0102297ms
  • detectMultiScale 84.8129ms

結論

エントリーマシンでも、一部のAPIに限定されるが、従来のソースへの少しの変更点で、高速化の恩恵を受けることが確認できた。

UMat の使用上の注意

  • 一部のAPIしか対応していません。
  • 最初の呼び出しでは、カーネルコンパイルのオーバヘッドが生じる
  • CPUでの計算結果と一致しない場合がある。
  • デフォルトでは、最初に認識されたGPUベースのOpenCLデバイスが使用される。変更できるが簡単ではない

最後に

明日は、te20 さんの番です。
今回、時間の都合で省いたことをBlogに追記する予定です。

6
3
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
6
3