2013年11月9日土曜日

cv::gpu::flipの入出力に同じ変数は使えない

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