はじめに
近年、人工知能などで莫大な計算量や情報量が要求されるソフトウェアが増えている。
これを処理するために、「CPUだけ」での能力では役不足になってきている。
そこで注目されるのは、以前は映像処理専門だったグラフィックボード(GPU)である。
これは、映像処理はもちろんの事、大容量の専用メモリーがあり、処理能力もCPUに引けを取らいないものであれば、データをGPUにアップロードして、処理をGPUに投げて、処理完了後にダウンロードして結果を受け取れば、CPUはその空き時間で別の処理を行うことが可能である。また、GPUは専用メモリーを使うので、メインメモリの圧迫が軽減されることが期待される。
OpenCVでは「GpuMat」と言う、GPUで処理させるMatが存在するが、これを利用するにはN社製のグラフィックボードとCUDAのインストールがあって、初めて利用可能となる。
逆に言えば、初めからマザーボードに張り付いている、I社製などのGPUでは利用することは出来ない。
そこで登場するのが「UMat」である。UMatはGpuMatが使えない環境でも、OpenCVからGPUを利用することが出来る。これを使用することでソフトウェアの動作速度の向上などが期待されるのである。
UMatの簡単な使い方
UMatは概念的には仮想のデバイスであり、直接そのメモリ空間にアクセスする事は出来ない。これはGpuMatでも同様である。
そこで一旦Matにデータをセットして、それをCopyTo()関数でアップロードする。
処理が終わったらCopyTo()関数でダウンロードする。
int main()
{
cv::Mat img;
cv::Mat gray;
cv::UMat u_img;
cv::UMat u_gray;
//画像読み込み
img = cv::imread("apple.jpg");
//UMatへアップロード
img.copyTo(u_img);
//Gpuで処理する内容を記述(この場合はカラーからグレイスケール変換)
cv::cvtColor(u_img,u_gray,cv::COLOR_BGR2GRAY);
//Matへダウンロード
u_gray.copyTo(gray);
//表示
cv::imshow("gray",gray);
//u_grayを直接表示する事も可能
cv::imshow("u_gray",u_gray);
cv::waitKey();
}
UMatの簡単なベンチマーク
以下のようなコードを記述して、実行時間を計測した。
#include <opencv2/opencv.hpp>
#include <windows.h>
#include <stdio.h>
int main(int argc, char* argv[])
{
const int LOOP_NUM = 100;
cv::Mat src = cv::imread("apple.jpg");
cv::Mat gray;
DWORD st;
//UMat時間計測開始
st = GetTickCount();
//アップロード
cv::UMat u_src;
cv::UMat u_gray;
src.copyTo(u_src);
//時間稼ぎループ
for(int cnt=0;cnt < LOOP_NUM;cnt++)
{
//グレイスケール画像に変換
cv::cvtColor(u_src,u_gray,cv::COLOR_BGR2GRAY);
}
//ダウンロード
u_gray.copyTo(gray);
//UMat時間計測完了
std::cout << "UMat時間" << GetTickCount() - st << "[ms]" << std::endl;
//UMat画像表示
cv::imshow("u_gray",gray);
cv::waitKey(30);
//Mat時間計測開始
st = GetTickCount();
//時間稼ぎループ
for(int cnt=0;cnt < LOOP_NUM;cnt++)
{
//グレイスケール画像に変換
cv::cvtColor(src,gray,cv::COLOR_BGR2GRAY);
}
//Mat時間計測完了
std::cout << "Mat時間" << GetTickCount() - st << "[ms]" << std::endl;
//Mat画像表示
cv::imshow("Mat",gray);
cv::waitKey();
return 0;
}
実行時間
UMat時間 7719[ms]
Mat時間 78[ms]
以上からUMatの方が著しく遅い結果となった。
おわりに
Umatの実行時間はよろしくなかったが、実際別件でUmatを組み込んで使って見ても、
速度性能向上は見られず、かえってメモリ違反などが出ていたので、
ある意味予想通りだった。
C/C++プログラマであれば、ポインタやC言語の標準関数などを駆使するのが、
現実的と考える。
Windowsであれば、Direct3D/2Dの利用を検討するのもありかと思います。