CUDA中二维三角形平滑的正确网格和块尺寸是多少
What are the right Grid and Block Dimensions for 2D triangular smooth in CUDA?
我有一个顺序平滑算法
void triangularSmooth(unsigned char *grayImage, unsigned char *smoothImage, const int width, const int height, const float *filter, NSTimer &timer, dim3 grid_size, dim3 block_size) {
for ( int y = 0; y < height; y++ ) {
for ( int x = 0; x < width; x++ ) {
unsigned int filterItem = 0;
float filterSum = 0.0f;
float smoothPix = 0.0f;
for ( int fy = y - 2; fy < y + 3; fy++ ) {
for ( int fx = x - 2; fx < x + 3; fx++ ) {
if ( ((fy < 0) || (fy >= height)) || ((fx < 0) || (fx >= width)) ) {
filterItem++;
continue;
}
smoothPix += grayImage[(fy * width) + fx] * filter[filterItem];
filterSum += filter[filterItem];
filterItem++;
}
}
smoothPix /= filterSum;
smoothImage[(y * width) + x] = static_cast< unsigned char >(smoothPix);
}
}
}
我正在CUDA中实现,并希望使用共享变量来保持grayImage中的像素。然而在此之前,我正在尝试按原样运行它
__global__ void smooth(unsigned char *grayImage, unsigned char *smoothImage, const int width, const int height, const float *filter)
{
int x = blockIdx.x*blockDim.x + threadIdx.x;
int y = blockIdx.y*blockDim.y + threadIdx.y;
unsigned int filterItem = 0;
float filterSum = 0.0f;
float smoothPix = 0.0f;
for ( int fy = y - 2; fy < y + 3; fy++ ) {
for ( int fx = x - 2; fx < x + 3; fx++ ) {
if ( ((fy < 0) || (fy >= height)) || ((fx < 0) || (fx >= width)) ) {
filterItem++;
continue;
}
smoothPix += grayImage[(fy * width) + fx] * filter[filterItem];
filterSum += filter[filterItem];
filterItem++;
}
}
smoothPix /= filterSum;
smoothImage[(y * width) + x] = static_cast< unsigned char >(smoothPix);
}
并呼叫:
const float filter[] = {1.0f, 1.0f, 1.0f, 1.0f, 1.0f, 1.0f, 2.0f, 2.0f, 2.0f, 1.0f, 1.0f, 2.0f, 3.0f, 2.0f, 1.0f, 1.0f, 2.0f, 2.0f, 2.0f, 1.0f, 1.0f, 1.0f, 1.0f, 1.0f, 1.0f};
dim3 gridSize((width*height)/1024,(width*height)/1024,1);
dim3 blockSize(256,256,1);
smooth <<< gridSize, blockSize >>> (grayImage, smoothImage, width, height, filter);
cudaDeviceSynchronize();
问题是,得到的平滑图像看起来像是像素都在错误的另一个(混淆)。这是来自网格和块的尺寸吗?我已经尝试了很多其他可能的维度。什么是正确的方式?
我使用的是GTX480,版本-2.x,线程块网格的最大维度-3,线程块的最大x、y或z维度65535,每个块的最大线程数1024
首先,维度完全无效。在这种情况下,以下内容应该有效;
dim3 blockSize(16, 16, 1);
dim3 gridSize((width + blockSize.x - 1)/ blockSize.x, (height + blockSize.y - 1) / blockSize.y, 1);
smooth <<< grid_size, block_size >>> (grayImage, smoothImage, width, height);
修正后,使用cuda memcheck产生了类似于的结果;
========= Invalid __global__ read of size 4
========= at 0x00000120 in cudaFilter
========= by thread (4,1,0) in block (1,0,0)
========= Address 0x05100190 is out of bounds
这表明内核代码中的值越界(很可能是数组索引)。通过检查各种变量,可以确定筛选器[]为空。
最后,如果要将filter[]传递到内核,则应该使用之类的东西将其从CPU复制到GPU
cudaMemcpy(filterGpu, filter, 25 * sizeof(float), cudaMemcpyHostToDevice);
或者,如果在其他地方不需要过滤器(就像这里的情况一样),可以在内核中声明它。
看看这个与图像过滤相关的答案,我建议您为图像创建如下的块和网格:
dim3 blockSize(16,16,1);
dim3 gridSize((width + blockSize.x - 1)/blockSize.x,(height + blockSize.y - 1)/blockSize.y,1);
您正在犯的另一个非常常见的错误是,传递给内核的筛选器数组是在主机上分配的。在设备上创建一个相同大小的数组,并将系数从主机复制到设备。将该设备数组传递给内核。
此外,强烈建议在主机端计算滤波器系数的总和,并将其作为参数传递给内核,而不是在每个线程中一次又一次地计算总和。
边界条件可能导致超出范围的存储器访问。在内核中显式处理边界条件。或者,简单的方法是对输入图像使用CUDA纹理,以便自动处理边界条件。
相关文章:
- 复制列表初始化的隐式转换的等级是多少
- while循环中while循环的时间复杂度是多少
- 如何检查一个c++字符串中有多少相同的字符/数字
- C++有多少类型的循环
- 求出有多少个数字是完美平方,而sqrt()是L,R范围内的素数
- 在条件变量中触发错误信号的频率是多少
- 函数的时间复杂度是多少?
- 必须为 C++20 协程帧保留多少内存?
- 对于四轴飞行器,PID中I控制器的理想值应该是多少
- C++,数组有多少个地址?
- 使用对象文件读取三角形数据网格
- 在C++中使用并行化的预期速度是多少(不是 OpenMp,而是 <thread>)
- 在 Linux 中存储区域设置名称的缓冲区大小应该是多少?
- 在内存不足之前,我可以声明多少个 const 变量?
- 如何从 Skia 路径几何体中获取网格?
- 可以读入进程内存的最大块大小是多少?
- 如何在不知道C++中有多少可选参数的情况下在循环中使用va_arg?
- 在二维向量或数组中可以存储的最大元素数是多少?
- CGAL:如何创建填充边界曲线的曲面网格?
- CUDA中二维三角形平滑的正确网格和块尺寸是多少