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共に同じ結果が得られた。