1.原理
Sobel算子是一离散性差分算子,用来运算图像亮度函数的梯度的近似值。索伯算子的公式包含两个3x3的矩阵,分别为横向及纵向,将其与图像作平面卷积,即可分别得出横向及纵向的亮度差分近似值。如果以 A 代表原始图像, Gx 及 Gy 分别代表经横向及纵向边缘检测的图像,* 表示卷积运算,其公式如下:
图像的每一个像素的横向及纵向梯度近似值可用以下的公式结合,来计算梯度的大小:
G\ =\ \sqrt{G_x^2\ +\ G_y^2}\ \
然后可用以下公式计算梯度方向:
\theta=\arctan{\left(\frac{G_y}{G_x}\right)}
2.算法流程及实现
索伯算子的公式包含两个3x3的矩阵对图像进行卷积运算,算法流程如下:
1) 选取3 * 3 像素区域;
2) 计算x,y两个方向的横向及纵向边缘,即差分;
3) 近似像素的梯度G;
4)用阈值threshold判断像素(x,y)是否属于边缘,若梯度大于阈值 ,则是边缘,小于阈值则不是边缘;
5) 迭代步骤1)~4),直至所有像素遍历完全,最终输出经过边缘检测的二值图像或标准化后的x或y轴方向梯度图像。
3.关键代码
ref:是选择存储方式;
threshold:选择阈值。
// sobel算子
void sobel(unsigned char *data, unsigned char *output, int width, int height, int sef, int threshold)
{
int sobel_x[3][3] = {{-1, 0, 1}, {-2, 0, 2}, {-1, 0, 1}};
int sobel_y[3][3] = {{-1, -2, -1}, {0, 0, 0}, {1, 2, 1}};
int _x = 0, _y = 0;
int gx = 0, gy = 0;
int g = 0;
int pad = 1;
int x, y, i, j; // 提前声明,减少反复创建
for (y = 0; y < height; y++)
{
for (x = 0; x < width; x++)
{
gx = 0;
gy = 0;
for (j = 0; j < 3; j++)
{
for (i = 0; i < 3; i++)
{
_y = y + j - pad;
_x = x + i - pad;
if (_y >= 0 && _y < height && _x >= 0 && _x < width)
{
gx += data[_y * width + _x] * sobel_x[j][i];
gy += data[_y * width + _x] * sobel_y[j][i];
}
}
}
g = sqrt(gx*gx + gy*gy);
//g=abs(gx)+abs(gy);
// 两种存储方式,一种是存储梯度,一种是存储边缘
if (sef == 1)
{
output[y * width + x] = (unsigned char)g > threshold ? 255 : 0; // 判断边缘,大于阈值的为边缘,存边缘
}
else
{
output[y * width + x] = (unsigned char)gx > threshold ? 255 : 0;
}
}
}
}