1

画像処理 OpenCL アプリケーションを作成しようとしていますが、入力画像を変更しようとすると縦棒のようなアーティファクトが生成されるという問題があります。画像ピクセルを変更せずにコピーした場合、これは発生しません。たとえば、次の行はアーティファクトを生成します。

pixel = (uint4)(image1_pixel.x,
                image1_pixel.y,
                image1_pixel.z,
                255);

...しかし、これは期待どおりに機能します:

pixel = (uint4)(image1_pixel.x,
                image1_pixel.y,
                image1_pixel.z,
                image1_pixel.w);

入力は不透明な 32 ビット PNG 画像であるため、両方のコード行で同じ結果が生成されると予想されます。ただし、実際には、期待どおりに機能するのは 2 行目だけです。最初の行は、成果物を含む出力を提供します。

これが私のカーネルです:

__constant sampler_t sampler = CLK_NORMALIZED_COORDS_FALSE |
                              CLK_ADDRESS_CLAMP |
                              CLK_FILTER_NEAREST;

__kernel void test(__read_only image2d_t image1,
                  __write_only image2d_t out) {
  const int2 pos = (int2)(get_global_id(0), get_global_id(1) );
  uint4 image1_pixel = read_imageui(image1, sampler, pos);
  uint4 pixel = (uint4)(image1_pixel.x,
                        image1_pixel.y,
                        image1_pixel.z,
                        255);
  write_imageui(out, pos, pixel);
}

main.cpp コードの関連部分は次のとおりです。

  CImg<unsigned char> image1("../input.png");
  ...
  Image2D clImage1 = Image2D(context,
    CL_MEM_READ_ONLY | CL_MEM_COPY_HOST_PTR,
    ImageFormat(CL_RGBA, CL_UNSIGNED_INT8),
    image1.width(), image1.height(), 0, image1.data() );
  Image2D clResult = Image2D(context, CL_MEM_WRITE_ONLY,
    ImageFormat(CL_RGBA, CL_UNSIGNED_INT8),
    image1.width(), image1.height(), 0, NULL);
  Kernel test = Kernel(program, "test");
  test.setArg(0, clImage1); test.setArg(1, clResult);
  Event kernel_event, read_event;
  queue.enqueueNDRangeKernel(test, NullRange,
    NDRange(image1.width(), image1.height() ),
    NullRange, NULL, &kernel_event);
  cl::size_t<3> origin;
  origin.push_back(0); origin.push_back(0); origin.push_back(0);
  cl::size_t<3> region;
  region.push_back(image1.width() );
  region.push_back(image1.height() ); region.push_back(1);
  queue.enqueueReadImage(clResult, CL_TRUE,
                         origin, region, 0, 0,
                         image1.data(), NULL, NULL);
  kernel_event.wait();
  image1.save("../output.png");

ここから、テスト アプリケーションの完全なソース コードをダウンロードできます(30 行以下の短い main.cpp、CMakeLists.txt、コンパイル方法と実行方法を説明する readme.txt、入力イメージとカーネルが含まれています)。CImg ライブラリを使用して、画像の読み込みと保存を行います。入力が 32 ビット RGBA 画像として開くことを再確認しました。AMD または NVidia SDK でカーネルを実行しようとしましたが、同じ結果が得られました。

予期しない結果が得られる理由は何ですか?

4

2 に答える 2

0

カーネルは正しいですが、CImg は非常に間違ったことをしているように見えるため、この場合に使用するのはお勧めできません。代わりに、Magick++ を使用しました。CImg ほど単純ではありませんが、より信頼性が高く、機能します。

これは、ファイルから画像を読み取り、RGBA 形式に変換して、cl::Image2D で使用できるようにする方法です。

Magick::Image image1;
image1.read("input1/0.png");
long image1_size = 4 * image1.rows() * image1.columns();
uint8_t *image1_pixels = new uint8_t[image1_size];
image1.write(0, 0, image1.columns(), image1.rows(),
             "RGBA", CharPixel, image1_pixels);
...
Image2D clImage1 = Image2D(context,
  CL_MEM_READ_ONLY | CL_MEM_COPY_HOST_PTR,
  ImageFormat(CL_RGBA, CL_UNSIGNED_INT8),
  image1.columns(), image1.rows(), 0, image1_pixels);

そして、これは私が結果をファイルに書き込む方法です:

queue.enqueueReadImage(clResult, CL_TRUE,
                       origin, region, 0, 0,
                       image1_pixels, NULL, NULL);
image1.read(image1.columns(), image1.rows(),
            "RGBA", CharPixel, image1_pixels);
image1.write("../output.png");

ここから完全なソースコードをダウンロードできます。

于 2012-10-27T04:16:54.967 に答える