平滑化フィルタであるcv::blurとcv::gpu::blurを窓サイズや画像の解像度を変えながら30回分の処理時間を計測して比較する実験です。
実験に使ったCPUはcore-i7 930、GPUはQuadro FX 580です。性能的にちょっとGPUが不利なので、それを踏まえて実験結果を見る必要があります。
まずこちらは4096x4096の画像に対して平滑化カーネルサイズを2x2から10x10まで2ずつ増やしながらCPUとGPUで比較したものです。
カーネルサイズが4x4まではGPUの方が速度が上回っています。カーネルサイズが大きくなるほどGPUの処理速度は2次曲線的に増加しているのに対してCPUの処理速度は直線的に増加しています。
平滑化カーネルサイズが小さいほど、すなわち単純な処理ほどGPUは高速化できるという特徴がよく表れている実験結果が得られました。
こちらのグラフは横軸に画像の解像度をとり、平滑化カーネルサイズごとにグラフを作ってみたものです。
画像の解像度が大きくなるとCPUとGPUで速度の差がはっきりと表れてきます。やはり、平滑化カーネルのサイズが小さくないとGPUの方が遅くなってしまう。
これらの実験結果からGPUで高速化しやすい処理対象は1画素辺りの処理が単純(1つの処理におけるプロセッサの仕事量とメモリの使用量が少なめ)でかつ、画像の解像度が大きい場合(並列化できる処理が多い場合)であるということが改めて実感できました。
ついでにGPGPUを利用すると消費電力もCPUで処理するより抑えられるとか。
私の環境ではGPUで高速化できた平滑化カーネルサイズが4x4程度ということで、そんなにGPUの恩恵を受けられそうにないのが少し残念です。もっとプロセッサ数が多くてかつクロック周波数が高くて、メモリを多く積んでいれば並列処理の恩恵をたくさん受けられるのに。性能の高いGPUで試してみたいです。
CUDAで画像処理を高速化させたいならQuadroにする必要ないし、GeForce GTX580辺りを買った方がコストパフォーマンスはかなり高そうですね。今までMayaのためにQuadroにしてましたが描画の速さであまりメリットを感じていません。これを期にGeForceに買い替えようか迷います。
ついでに実験に使ったソースコードも載せておきます。
#include <sys/timeb.h>
#include <time.h>
#include <iostream>
#include<opencv2/gpu/gpu.hpp>
static struct _timeb g_tstruct;
void StartTimer()
{
_ftime(&g_tstruct);
}
float StopTimer()
{
struct _timeb tstruct_new;
float t;
_ftime(&tstruct_new);
t = (float)(tstruct_new.time - g_tstruct.time) + (float)(tstruct_new.millitm - g_tstruct.millitm)/(float)1000;
return t;
}
int main()
{
cv::gpu::DeviceInfo di(cv::gpu::getDevice());
std::cout << di.name() << std::endl;
double time_gpu, time_cpu;
int numRepeat, w_st, w_max;
numRepeat=30;
w_st=2;
w_max=10;
//** Gaussian Filter CPU
printf("CPU Processing Time\n");
for(int wsize=w_st; wsize<=w_max; wsize+=2){
printf(" %d", wsize);
}
printf("\n");
for(int size=16; size<=4096; size*=2){
time_cpu=0.0;
printf("%dx%d ", size, size);
for(int wsize=w_st; wsize<=w_max; wsize+=2){
for(int i=0; i<numRepeat; i++){
cv::Mat mat(size, size, CV_8U,cv::Scalar(0));
StartTimer();
cv::blur(mat, mat, cv::Size(wsize, wsize));
time_cpu+=StopTimer();
}
printf("%.5f ", time_cpu);
}
printf("\n");
}
//** Gaussian Filter GPU
printf("GPU Processing Time\n");
for(int size=16; size<=4096; size*=2){
time_gpu=0.0;
printf("%dx%d ", size, size);
for(int wsize=w_st; wsize<=w_max; wsize+=2){
for(int i=0; i<numRepeat; i++){
cv::gpu::GpuMat gpumat(size, size, CV_8U, cv::Scalar(0));
StartTimer();
cv::gpu::blur(gpumat, gpumat, cv::Size(wsize, wsize));
time_gpu+=StopTimer();
}
printf("%.5f ", time_gpu);
}
printf("\n");
}
return 0;
}
コメント(0 件)