我正在尝试编写图像处理 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 图像,所以我希望两行代码都能产生相同的结果。然而,实际上,只有第二行按预期工作。第一行给出了 artifacts 的输出。
这是我的内核:
__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 运行内核并得到相同的结果。
知道为什么我会得到意想不到的结果吗?