1. Sobel边界检测过滤器
Sobel算子是计算机视觉领域的一种重要处理方法。主要用于获得数字图像的一阶梯度,常见的应用和物理意义是边缘检测。 Sobel算子是把图像中每个像素的上下左右四邻域的灰度值加权差,在边缘处达到极值从而检测边缘。
在边缘检测中,常用的一种模板是Sobel 算子。Sobel 算子有两个,一个是检测水平边缘的 ;另一个是检测垂直边缘的 。与Prewitt算子相比,Sobel算子对于象素的位置的影响做了加权,可以降低边缘模糊程度,因此效果更好。
Sobel算子另一种形式是各向同性Sobel(Isotropic Sobel)算子,也有两个,一个是检测水平边缘的 ,另一个是检测垂直边缘的 。各向同性Sobel算子和普通Sobel算子相比,它的位置加权系数更为准确,在检测不同方向的边沿时梯度的幅度一致。将Sobel算子矩阵中的所有2改为根号2,就能得到各向同性Sobel的矩阵。
该算子包含两组3x3的矩阵,分别为横向及纵向,将之与图像作平面卷积,即可分别得出横向及纵向的亮度差分近似值。如果以A代表原始图像,Gx及Gy分别代表经横向及纵向边缘检测的图像,其公式如下:
图像的每一个像素的横向及纵向梯度近似值可用以下的公式结合,来计算梯度的大小。
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算子》
标签:src,Sobel,read,xyz,OpenCL,imagef,边界检测,int2,float4 From: https://blog.csdn.net/dengfuma/article/details/143321943