OpenCL 实现Sobel边界检测过滤

1. Sobel边界检测过滤器

        Sobel算子是计算机视觉领域的一种重要处理方法。主要用于获得数字图像的一阶梯度,常见的应用和物理意义是边缘检测。 Sobel算子是把图像中每个像素的上下左右四邻域的灰度值加权差,在边缘处达到极值从而检测边缘。

        在边缘检测中,常用的一种模板是Sobel 算子。Sobel 算子有两个,一个是检测水平边缘的 ;另一个是检测垂直边缘的 。与Prewitt算子相比,Sobel算子对于象素的位置的影响做了加权,可以降低边缘模糊程度,因此效果更好。

        Sobel算子另一种形式是各向同性Sobel(Isotropic Sobel)算子,也有两个,一个是检测水平边缘的 ,另一个是检测垂直边缘的 。各向同性Sobel算子和普通Sobel算子相比,它的位置加权系数更为准确,在检测不同方向的边沿时梯度的幅度一致。将Sobel算子矩阵中的所有2改为根号2,就能得到各向同性Sobel的矩阵。

        该算子包含两组3x3的矩阵,分别为横向及纵向,将之与图像作平面卷积,即可分别得出横向及纵向的亮度差分近似值。如果以A代表原始图像,Gx及Gy分别代表经横向及纵向边缘检测的图像,其公式如下:

G_{x} = \begin{bmatrix} -1& 0 & +1\\ -2& 0 & +2\\ -1& 0 & +1 \end{bmatrix}             G_{y} = \begin{bmatrix} -1& -2 & -1\\ 0& 0 & 0\\ -1& +2 & +1 \end{bmatrix}   

        图像的每一个像素的横向及纵向梯度近似值可用以下的公式结合,来计算梯度的大小。

G = \sqrt{G_{x}^{2} + G_{y}^{2}}

2. OpenCL 内核实现Sobel

2.1 RGB方式实现

sobel_rgb.cl代码:

/**
//         Gx = {{-1, 0, +1},
//               {-2, 0, +2},
//               {-1, 0, +1}}
//         Gy = {{-1, -2, -1},
//               { 0,  0,  0},
//               {+1, +2, +1}}

kernel void sobel_rgb(read_only image2d_t src, write_only image2d_t dst)
{
    int x = (int)get_global_id(0);
    int y = (int)get_global_id(1);
    if (x >= get_image_width(src) || y >= get_image_height(src))
        return;
    float4 p00 = read_imagef(src, sampler, (int2)(x - 1, y - 1));
    float4 p10 = read_imagef(src, sampler, (int2)(x, y - 1));
    float4 p20 = read_imagef(src, sampler, (int2)(x + 1, y - 1));

    float4 p01 = read_imagef(src, sampler, (int2)(x - 1, y));
    float4 p21 = read_imagef(src, sampler, (int2)(x + 1, y));

    float4 p02 = read_imagef(src, sampler, (int2)(x - 1, y + 1));
    float4 p12 = read_imagef(src, sampler, (int2)(x, y + 1));

    float4 p22 = read_imagef(src, sampler, (int2)(x + 1, y + 1));

    float3 gx = -p00.xyz + p20.xyz + 2.0f * (p21.xyz - p01.xyz) - p02.xyz + p22.xyz;

    float3 gy =  -p00.xyz + p20.xyz + 2.0f * (p12.xyz - p10.xyz) - p02.xyz + p22.xyz;

    float3 g = native_sqrt(gx * gx + gy * gy);
    write_imagef(dst, (int2)(x, y), (float4)(g.x, g.y, g.z, 1.0f));
}

2.2 灰度图实现

sobel_grayscale.cl

/**
//         Gx = {{-1, 0, +1},
//               {-2, 0, +2},
//               {-1, 0, +1}}
//         Gy = {{-1, -2, -1},
//               { 0,  0,  0},
//               {+1, +2, +1}}

kernel void sobel_grayscale(read_only image2d_t src, write_only image2d_t dst)
{
    int x = (int)get_global_id(0);
    int y = (int)get_global_id(1);
    if (x >= get_image_width(src) || y >= get_image_height(src))
        return;
    float4 p00 = read_imagef(src, sampler, (int2)(x - 1, y - 1));
    float4 p10 = read_imagef(src, sampler, (int2)(x, y - 1));
    float4 p20 = read_imagef(src, sampler, (int2)(x + 1, y - 1));

    float4 p01 = read_imagef(src, sampler, (int2)(x - 1, y));
    float4 p21 = read_imagef(src, sampler, (int2)(x + 1, y));

    float4 p02 = read_imagef(src, sampler, (int2)(x - 1, y + 1));
    float4 p12 = read_imagef(src, sampler, (int2)(x, y + 1));

    float4 p22 = read_imagef(src, sampler, (int2)(x + 1, y + 1));

    float3 gx = -p00.xyz + p20.xyz + 2.0f * (p21.xyz - p01.xyz) - p02.xyz + p22.xyz;

    float3 gy =  -p00.xyz + p20.xyz + 2.0f * (p12.xyz - p10.xyz) - p02.xyz + p22.xyz;

    float gs_x = 0.3333f * (gx.x + gx.y + gx.z);
    float gs_y = 0.3333f * (gy.x + gy.y + gy.z);
    float3 g = native_sqrt(gs_x * gs_x + gs_y * gs_y);
    write_imagef(dst, (int2)(x, y), (float4)(g, g, g, 1.0f));
}

3.参考文献

1. 《OpenGL编程指南》

2.《百度百科 Sobel算子》

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值