OpenCVのGpuMatは非常に便利だけど、GPGPUの仕組みを全く理解せずにBlack Boxとして使うと時々問題になる。 例えばcv::gpu::flip()関数。 CPUのみを使う関数cv::flipでは入出力に同じ変数を用いても問題にならなかったが、 cv::gpu::flip()の場合は正常にflipされない(OpenCV2.6.4で確認)。 次の有名な標準画像を入力として試してみた。
#include <opencv2/opencv.hpp>
#include <opencv2/gpu/gpu.hpp>
void main(int argc, char *argv[])
{
cv::Mat image = cv::imread("lena_std.png");
cv::gpu::GpuMat image_gpu;
//画像をCPUからGPUに送る
image_gpu.upload(image);
//CPU上で画像の上下反転、保存
cv::flip(image, image, 0);
cv::imwrite("fliped_lena_cv.png", image);
//GPU上で画像の上下反転(srcとdstを同じにしている)
cv::gpu::flip(image_gpu, image_gpu, 0);
//画像をGPUからCPU側に戻しファイルに保存
image_gpu.download(image);
cv::imwrite("image_gpu.png", image);
}
上記コードで出力される画像は次のとおり。 左はcv::flip()、右はcv::gpu::flip()の結果。 GPUの方は、正常に画像が生成されていないことが分かる。
次のコードは上記コードを少し修正して、GpuMatを2つ用意して、 cv::gpu::flip()の入出力の変数を変えてみた。
#include <opencv2/opencv.hpp>
#include <opencv2/gpu/gpu.hpp>
void main(int argc, char *argv[])
{
cv::Mat image = cv::imread("lena_std.png");
cv::gpu::GpuMat image_gpu;
cv::gpu::GpuMat image_gpu2;
//画像をCPUからGPUに送る
image_gpu.upload(image);
//CPU上で画像の上下反転、保存
cv::flip(image, image, 0);
cv::imwrite("fliped_lena_cv.png", image);
//GPU上で画像の上下反転(srcとdstを変えた)
cv::gpu::flip(image_gpu, image_gpu2, 0);
//画像をGPUからCPU側に戻しファイルに保存
image_gpu2.download(image);
cv::imwrite("image_gpu22.png", image);
}
左はcv::flip()、右はcv::gpu::flip()の結果。 今回はCPU、GPU共に同じ結果が得られた。




