背景知识
边缘像素是图像中灰度突变的像素,而边缘是连接边缘像素的集合。边缘检测是设计用来检测边缘像素的局部图像处理方法。
孤立点检测
使用<https://www.cnblogs.com/GoldBeetle/p/9744625.html>中介绍的拉普拉斯算子
输出图像为
卷积模板
之前有过代码实现,这篇文章中不再进行测试
基本边缘检测
图像梯度
梯度向量大小
在图像处理过程中,因平方和和开方运算速度较慢,因此简化为如下计算方法
梯度向量方向与x轴夹角
对应与不同的偏导数计算方法,得出边缘检测的不同模板
检测垂直或水平边缘
原图
使用Sobel模板检测水平边缘
使用Sobel模板检测垂直边缘
两者相加
代码实现
void edge_detection(short** in_array, short** out_array, long height, long width)
{
short gx = , gy = ;
short** a_soble1;
short** a_soble2; a_soble1 = allocate_image_array(, );
a_soble2 = allocate_image_array(, );
for (int i = ; i < ; i++){
for (int j = ; j < ; j++){
a_soble1[i][j] = soble1[i][j];
a_soble2[i][j] = soble2[i][j];
}
}
for (int i = ; i < height; i++){
for (int j = ; j < width; j++){
gx = convolution(in_array, i, j, height, width, a_soble1, );
gy = convolution(in_array, i, j, height, width, a_soble2, );
// out_array[i][j] = gx;
// out_array[i][j] = gy;
out_array[i][j] = gx + gy;
if (out_array[i][j] < )
out_array[i][j] = ;
else if (out_array[i][j] > 0xff)
out_array[i][j] = 0xff;
}
}
free_image_array(a_soble1, );
free_image_array(a_soble2, );
}
检测对角边缘
Sobel 45°检测模板
Sobel -45°检测模板
两者相加
代码实现通上,只需替换模板值即可
Marr-Hildreth边缘检测算法
1. 对二维高斯函数进行取样,得高斯低通滤波器,对输入图像滤波,滤波器模板大小为大于等于6*σ的最小奇整数
算法实现
void generate_gaussian_filter(double** gaussian_filter, long sigma)
{
double x, y;
long filter_size = * sigma + ; for (int i = ; i < filter_size; i++){
for (int j = ; j < filter_size; j++){
x = i - filter_size / ;
y = j - filter_size / ;
gaussian_filter[i][j] = exp(-1.0 * ((pow(x, ) + pow(y, )) / * sigma * sigma));
}
}
}
2. 计算第一步得到图像的拉普拉斯,利用如下模板
算法实现
void laplace(short** in_array, short** out_array, long height, long width)
{
short** a_sharpen; a_sharpen = allocate_image_array(, );
for (int i = ; i < ; i++){
for (int j = ; j < ; j++){
a_sharpen[i][j] = sharpen[i][j];
}
}
for (int i = ; i < height; i++){
for (int j = ; j < width; j++){
out_array[i][j] = convolution(in_array, i, j, height, width, a_sharpen, );
}
}
free_image_array(a_sharpen, );
}
运行结果
3. 寻找零交叉,对任意像素p,测试上/下,左/右,两个对角线四个位置,当有两对符号不同并且绝对值差大于某一阈值时为零交叉点
算法实现
int is_cross(short** in_array, long row, long column)
{
int cross_num = ; if (in_array[row-][column-] * in_array[row+][column+] < &&
abs(abs(in_array[row-][column-]) - abs(in_array[row+][column+])) > 0x66)
cross_num++;
if (in_array[row-][column] * in_array[row+][column] < &&
abs(abs(in_array[row-][column]) - abs(in_array[row+][column])) > 0x66)
cross_num++;
if (in_array[row-][column+] * in_array[row+][column-] < &&
abs(abs(in_array[row-][column+]) - abs(in_array[row+][column-])) > 0x66)
cross_num++;
if (in_array[row][column-] * in_array[row][column+] < &&
abs(abs(in_array[row][column-]) - abs(in_array[row][column+])) > 0x66)
cross_num++; if (cross_num >= )
return ;
else
return ;
}
void marr(short** in_array, short** out_array, long height, long width)
{
long sigma = ;
long filter_size = * sigma + ;
double** gaussian_filter;
short **gauss_array, **laplace_array; gaussian_filter = allocate_double_array(filter_size, filter_size);
gauss_array = allocate_image_array(height, width);
laplace_array = allocate_image_array(height, width);
generate_gaussian_filter(gaussian_filter, sigma); for (int i = ; i < height; i++){
for (int j = ; j < width; j++){
gauss_array[i][j] = convolutiond(in_array, i, j, height, width, gaussian_filter, filter_size);
}
}
printf("Gasuuian filter done\n");
laplace(gauss_array, laplace_array, height, width);
printf("Laplace done\n");
zero_cross(laplace_array, out_array, height, width);
printf("Zero cross done\n"); free_double_array(gaussian_filter, filter_size);
free_image_array(gauss_array, height);
free_image_array(laplace_array, height);
}
最终运行结果
可以看出,该算法检测出的边缘更加符合物体的真实边缘,但是这些边缘是由离散的点构成的,因此需要进行边缘连接来进一步加工,本文对此不再进行详述,读者有兴趣可以进行更加深入的研究。