You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何在cv::cuda::GpuMat上创建指定的多边形遮罩?

OpenCV CUDA 环境下GpuMat填充三角形遮罩实现方案

目标遮罩效果

方案1:CPU-GPU拷贝折中方案

适合遮罩尺寸小、调用频率不高的场景,代码改动量最小:

  • 在CPU内存创建同规格的cv::Mat遮罩,沿用原有cv::fillConvexPoly完成三角形绘制
  • 调用upload方法将CPU遮罩上传到GPU的cv::cuda::GpuMat即可

代码示例:

// 入参准备:三个顶点坐标、遮罩尺寸
std::vector<cv::Point> triangle_pts = {A, B, C};
int mask_w = 1920;
int mask_h = 1080;

// CPU侧绘制遮罩
cv::Mat mask_cpu(mask_h, mask_w, CV_8UC1, cv::Scalar(0));
cv::fillConvexPoly(mask_cpu, triangle_pts, cv::Scalar(255));

// 上传到GPU
cv::cuda::GpuMat mask_gpu;
mask_gpu.upload(mask_cpu);

优缺点:实现简单无额外开发成本,仅多一次CPU到GPU的数据拷贝,性能要求不高的场景可直接使用。

方案2:纯CUDA管线实现

适合高性能场景,全流程跑在GPU上无数据拷贝开销,自己实现三角形光栅化逻辑:
核心思路是用重心坐标法判断每个像素是否在三角形内部,直接在CUDA核函数中写入遮罩值。

代码示例:

// CUDA核函数:逐像素判断是否在三角形内,生成遮罩
__global__ void fill_triangle_kernel(uint8_t* mask_data, int width, int height, size_t step,
                                     float ax, float ay, float bx, float by, float cx, float cy) {
    int x = blockIdx.x * blockDim.x + threadIdx.x;
    int y = blockIdx.y * blockDim.y + threadIdx.y;
    if (x >= width || y >= height) return;

    // 计算重心坐标权重
    float v0x = cx - ax, v0y = cy - ay;
    float v1x = bx - ax, v1y = by - ay;
    float v2x = x - ax, v2y = y - ay;

    float dot00 = v0x * v0x + v0y * v0y;
    float dot01 = v0x * v1x + v0y * v1y;
    float dot02 = v0x * v2x + v0y * v2y;
    float dot11 = v1x * v1x + v1y * v1y;
    float dot12 = v1x * v2x + v1y * v2y;

    float denom = dot00 * dot11 - dot01 * dot01;
    // 避免三个点共线导致除零错误
    if (fabs(denom) < 1e-6) {
        mask_data[y * step + x] = 0;
        return;
    }
    float inv_denom = 1.0f / denom;
    float u = (dot11 * dot02 - dot01 * dot12) * inv_denom;
    float v = (dot00 * dot12 - dot01 * dot02) * inv_denom;

    // 权重均非负且和不超过1即为三角形内部点
    mask_data[y * step + x] = (u >= 0 && v >= 0 && u + v <= 1.0f) ? 255 : 0;
}

// 核函数调用逻辑
cv::cuda::GpuMat mask_gpu(mask_h, mask_w, CV_8UC1, cv::Scalar(0));
dim3 block_size(16, 16);
dim3 grid_size((mask_w + block_size.x - 1) / block_size.x, (mask_h + block_size.y - 1) / block_size.y);
fill_triangle_kernel<<<grid_size, block_size>>>(mask_gpu.data, mask_gpu.cols, mask_gpu.rows, mask_gpu.step,
                                                A.x, A.y, B.x, B.y, C.x, C.y);
// 可选:同步等待核函数执行完成,后续要立刻操作mask_gpu的情况下需要加
cudaDeviceSynchronize();

注意点:如果需要抗锯齿效果,可对边缘像素的权重做插值计算,生成带透明度的遮罩。

内容的提问来源于stack exchange,提问作者user16532502

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.09.30 20:18:03