gpt4 book ai didi

c++ - 图像过滤器 : Results with OpenCL differ from CPU version

转载 作者:太空宇宙 更新时间:2023-11-04 11:36:55 27 4
gpt4 key购买 nike

我正在尝试用 OpenCL 编写一个简单的图像过滤器。滤镜应采用 32bpp 彩色图像(通过 LockBits(..)System::Drawing::Bitmap 获得),将像素转换为灰度并应用 3x3过滤矩阵。生成的图像应该能够显示为 8bpp Bitmap,即使用 Format8bppIndexed

我有一个内核可以做一些事情,还有一个我认为应该做同样事情的单线程 CPU 解决方案。然而,问题是生成的图像不同的:OpenCL 处理的图像更亮,几乎全身都是白色,而 CPU 图像看起来还不错——几乎就像只转换为灰度图像一样。

这是 CPU 解决方案:

static float filter[] = { -1.0f, -1.0f, -1.0f, -1.0f, 9.0f, -1.0f, -1.0f, -1.0f, -1.0f };
static float filterNorm = 1.0f;

for (int y = 0; y < height; ++y) {
for (int x = 0; x < width; ++x) {
float gray = 0.0f;

size_t ia = 0;
for (int yi = -1; yi <= 1; ++yi) {
for (int xi = -1; xi <= 1; ++xi) {
int xx = x + xi;
if (xx < 0) xx = 0;
if (xx >= width) xx = width - 1;
int yy = y + yi;
if (yy < 0) yy = 0;
if (yy >= height) yy = height - 1;
size_t idx = 4 * (yy * width + xx);
float r = ((float)inputData32bpp[idx + 0] / 255.0f);
float g = ((float)inputData32bpp[idx + 1] / 255.0f);
float b = ((float)inputData32bpp[idx + 2] / 255.0f);
gray += (filter[ia] * ((r + g + b)/3.0f));
++ia;
}
}
gray /= filterNorm;

if (gray < 0.0f) gray = 0.0f;
if (gray > 1.0f) gray = 1.0f;

size_t idx8 = y * width + x;
outputData8bpp[idx8] = (unsigned char)(gray * 255.0);
}
}

我正在转换为 float ,因为我想实现类似于 OpenCL 内核的行为,由于图像格式 (CL_UNORM_INT8),它也适用于 floats。我知道 channel 顺序可能是 BGR 而不是 RGB,但是在像这里这样转换为灰度时这应该无关紧要。

OpenCL 主机代码是这样的:

static cl::ImageFormat formatBGRA(CL_BGRA, CL_UNORM_INT8);
static cl::ImageFormat formatGray(CL_LUMINANCE, CL_UNORM_INT8);

cl_int err = 0;
cl::Image2D inputImage(context, CL_MEM_READ_ONLY | CL_MEM_USE_HOST_PTR,
formatBGRA, width, height, 0U, inputData32bpp, &err);
cl::Image2D outputImage(context, CL_MEM_READ_WRITE,
formatGray, width, height, 0U, NULL, &err);

cl::Kernel& imgKernel = kernels[1];
err = imgKernel.setArg(0, inputImage);
err = imgKernel.setArg(1, outputImage);

err = queue.enqueueNDRangeKernel(imgKernel, cl::NDRange(0, 0), cl::NDRange(width, height));

err = queue.enqueueReadImage(outputImage, true, cl::size_t<3>(), getRegion(width, height),
width * sizeof(unsigned char), 0, outputData8bpp);

我使用的是 C++ OpenCL API,而不是 C 语言 API。主机代码确实工作;我一直在成功地将它与更简单的内核一起使用。现在,这里的内核是这样的:

__constant sampler_t sampler = CLK_NORMALIZED_COORDS_FALSE |
CLK_ADDRESS_CLAMP_TO_EDGE | CLK_FILTER_NEAREST;

__kernel void sharpening(__read_only image2d_t inputImg, __write_only image2d_t outputImg) {

int2 coord0 = (int2)(get_global_id(0), get_global_id(1));
float matrix[9] = { -1.0f, -1.0f, -1.0f, -1.0f, 9.0f, -1.0f, -1.0f, 1.0f, 1.0f };

float gray = 0.0f;
int k = 0;
for (int y = -1; y <= 1; ++y) {
for (int x = -1; x <= 1; ++x) {
int2 coord = coord0 + (int2)(x, y);
float4 color = read_imagef(inputImg, sampler, coord);
gray += (matrix[k] * ((color.x + color.y + color.z) / 3.0f));
++k;
}
}

gray = clamp(gray, 0.0f, 1.0f);
write_imagef(outputImg, coord0, (float4)(gray, gray, gray, 1));
}

为什么这个和CPU版本不一样?我想有一个我现在看不到的低级问题。我看过that question ,这让我担心我在这里遇到了类似的问题?

以防万一:我在 Surface Pro 2(即 Intel HD Graphics)上运行代码。

抱歉这么长的问题,希望有人能帮忙!

最佳答案

好吧,抱歉,显然这只是一个愚蠢的错误:OpenCL 内核中的过滤器矩阵是错误的,即与 CPU 版本不同,因此存在亮度差异。

关于仅关于 32bpp 或整数/ float 问题的谣言:是的,在 OpenCL 中可能有 8bpp 灰度图像。格式必须是CL_UNORM_INT8,这意味着像素必须通过read_imagef读取。读取内核中的像素总是返回具有四个分量的 vector 这一事实并不意味着图像总是 32bpp。它可能在内部看起来是这样表示的,但也可以从 8bpp 灰度图像中输入或读取 - 我问题中的代码证明了这一点。

关于c++ - 图像过滤器 : Results with OpenCL differ from CPU version,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/22755727/

27 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com