cuda核函数处理图像像素的执行逻辑
·
目录
要直观理解 一个线程处理一个像素 的 CUDA 核函数执行逻辑,我们可以通过 三层结构示意图 来展示:GPU 线程网格(Grid)→ 线程块(Block)→ 线程(Thread)→ 图像像素 的映射关系。
以下是分层次的图示说明,结合之前的灰度化核函数案例(假设图像尺寸为 8×6=48 像素,线程块大小设为 16 线程 / 块)。
一、 整体映射关系总览
GPU Grid(线程网格)
├─ Block 0(16线程) → 处理 像素ID 0~15
├─ Block 1(16线程) → 处理 像素ID 16~31
└─ Block 2(16线程) → 处理 像素ID 32~47 (实际只用12个,剩余4个线程闲置)
↓ 每个线程ID 映射到 图像的(x,y)坐标
像素ID = y * 图像宽度 + x → x = ID % width; y = ID / width
二、 分层详细图示
1. 图像像素与像素 ID 的对应(行优先存储)
假设图像宽度 width=8,高度 height=6,像素 ID 从左到右、从上到下编号,对应关系如下:

核心公式:
像素 ID = y * width + x
反推坐标:x = ID % width; y = ID /width
例:ID=10 → x=10%8=2; y=10/8=1 → 对应 (x=2,y=1) 像素
2. 线程块(Block)与像素 ID 的映射
设置 线程块大小 = 16 线程(blockDim.x=16),总像素数 = 48,因此需要 ceil(48/16)=3 个线程块(gridDim.x=3)。
| 线程块 ID(blockIdx.x | 包含线程 ID 范围(threadIdx.x | 对应处理的像素 ID 范围 | 实际有效线程数 |
|---|---|---|---|
| 0 | 0~15 | 0~15 | 16(全部有效) |
| 1 | 0~15 | 16~31 | 16(全部有效) |
| 2 | 0~15 | 32~47 | 12(仅 0~11 有效,12~15 闲置 |
线程全局 ID 计算:
global_thread_idx = blockIdx.x * blockDim.x + threadIdx.x
例:blockIdx.x=1, threadIdx.x=5 → global ID=1*16+5=21 → 对应像素 ID=21
3. GPU 线程网格与线程的执行逻辑图示

4. 单个线程与单个像素的对应关系(核心并行逻辑)
每个线程只做 3 件事,完全独立无依赖:
- 计算全局 ID → 判断是否超过总像素数(边界检查);
- 全局 ID 映射为图像坐标 (x,y);
- 读取 (x,y) 彩色像素 → 计算灰度值 → 写入输出图像。
线程(global ID=10)
│
├─ 步骤1:10 < 48 → 有效线程
├─ 步骤2:x=10%8=2; y=10/8=1 → 坐标(2,1)
├─ 步骤3:读取 src[1*8*3 + 2*3] → BGR值 → 计算灰度 → 写入 dst[1*8+2]
└─ 完成任务,退出
线程(global ID=60)
│
├─ 步骤1:60 > 48 → 无效线程
└─ 直接return,不执行任何操作
三、 图示关键结论
并行粒度:
- 1 个线程对应 1 个像素,线程间无数据竞争、无同步开销,最大化 GPU 并行效率。
- 边界检查必要性:最后一个线程块通常会有闲置线程,必须通过 if (global_idx >= total_pixels) return 避免内存越界。
- 线程块大小选择:建议设为 32 的倍数(如 16、32、64、256),匹配 GPU 的 Warp 调度单元(32 线程为 1 个 Warp),减少调度浪费。
四、多维处理
先看一下这段代码
void VideoOsd::drawLine(cv::cuda::GpuMat& nv12Frame, TyPoint start, TyPoint end, int thickness, cv::Scalar color)
{
int Y = 0, U = 0, V = 0;
RGBtoYUV(color[2], color[1], color[0], Y, U, V);
const dim3 block(32, 16);
const dim3 grid(divUp(nv12Frame.cols, block.x), divUp(nv12Frame.rows, block.y));
if (!cudaStream) {
cudaSafeCall(cudaStreamCreate(&cudaStream));
}
drawLineKernel << <grid, block, 0, cudaStream >> > (nv12Frame, nv12Frame.step, nv12Frame.cols, nv12Frame.rows/3*2, start, end, thickness, (uchar)Y, (uchar)U, (uchar)V);
int ret = cudaGetLastError();
if (ret != cudaSuccess) {
printf("%s cudaGetLastError:%d\n", __FUNCTION__, ret);
}
if (!cudaStream)
cudaSafeCall(cudaStreamSynchronize(cudaStream));
}
- dim3:CUDA 用于表示三维线程 / 块维度的结构体,这里用二维(x/y);
- block(32,16):线程块大小为 32×16=512 线程 / 块(x 方向 32 线程,y 方向 16 线程),是 GPU 友好的配置(32 的倍数,匹配 warp 大小);
- divUp:自定义向上取整函数(如 divUp(a,b) = (a + b - 1) / b),用于计算网格大小;
- grid(divUp(cols,32), divUp(rows,16)):线程网格大小,x 方向块数 = 图像宽度 / 32(向上取整),y 方向块数 = 图像高度 / 16(向上取整);
- 对比之前 “1 线程 1 像素” 的一维配置,这里用二维线程块更贴合图像的二维结构(x 对应列,y 对应行),减少坐标映射计算。
更多推荐

所有评论(0)