背景知识

边缘像素是图像中灰度突变的像素,而边缘是连接边缘像素的集合。边缘检测是设计用来检测边缘像素的局部图像处理方法。

孤立点检测

使用<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);
}

最终运行结果

可以看出,该算法检测出的边缘更加符合物体的真实边缘,但是这些边缘是由离散的点构成的,因此需要进行边缘连接来进一步加工,本文对此不再进行详述,读者有兴趣可以进行更加深入的研究。

c语言数字图像处理(九):边缘检测的更多相关文章

  1. c语言数字图像处理(三):仿射变换

    仿射变换及坐标变换公式 几何变换改进图像中像素间的空间关系.这些变换通常称为橡皮模变换,因为它们可看成是在一块橡皮模上印刷一幅图像,然后根据预定的一组规则拉伸该薄膜.在数字图像处理中,几何变换由两个基 ...

  2. c语言数字图像处理(二):图片放大与缩小-双线性内插法

    图像内插 假设一幅大小为500 * 500的图像扩大1.5倍到750 * 750,创建一个750 * 750 的网格,使其与原图像间隔相同,然后缩小至原图大小,在原图中寻找最接近的像素(或周围的像素) ...

  3. c语言数字图像处理(一):bmp图片格式及灰度图片转换

    本篇文章首先介绍了bmp图片格式,主要参考wiki上的内容,包括bmp文件的存储方式,对于一些常见的bmp文件格式都给了例子,并且对8位 16位RGB555 16位RGB565格式的bmp文件进行了简 ...

  4. c语言数字图像处理(十):阈值处理

    定义 全局阈值处理 假设某一副灰度图有如下的直方图,该图像由暗色背景下的较亮物体组成,从背景中提取这一物体时,将阈值T作为分割点,分割后的图像g(x, y)由下述公式给出,称为全局阈值处理 多阈值处理 ...

  5. c语言数字图像处理(八):噪声模型及均值滤波器

    图像退化/复原过程模型 高斯噪声 PDF(概率密度函数) 生成高斯随机数序列 算法可参考<http://www.doc.ic.ac.uk/~wl/papers/07/csur07dt.pdf&g ...

  6. c语言数字图像处理(七):频率域滤波

    代码运行了两个小时才出的结果,懒得测试了,这一部分先鸽了,等对DFT算法进行优化后再更

  7. c语言数字图像处理(六):二维离散傅里叶变换

    基础知识 复数表示 C = R + jI 极坐标:C = |C|(cosθ + jsinθ) 欧拉公式:C = |C|ejθ 有关更多的时域与复频域的知识可以学习复变函数与积分变换,本篇文章只给出DF ...

  8. c语言数字图像处理(五):空间滤波

    空间滤波原理 使用大小为m*n的滤波器对大小为M*N的图像进行线性空间滤波,将滤波器模板乘以图像中对应灰度值,相加得模板中心灰度值 a = (m-1)/2, b = (n-1)/2 若f(x+s, y ...

  9. c语言数字图像处理(四):灰度变换

    灰度变换 灰度变换函数 s = T(r)   其中r为输入图像在(x, y)点处的灰度值,s为输出图像在(x, y)点处的灰度值 灰度变换的作用 上图所示的两幅T(s)函数的图像曲线,第一幅图可以增强 ...

随机推荐

  1. 工作中碰到的一个问题(cookie相关)

    今天上线了一个API,6台机器做的集群.API的第一步是读取cookie,判断用户是否登录. 例如,线上服务器分别是 10.255.242.1 10.255.242.2 10.255.242.3 10 ...

  2. Spark系列-初体验(数据准备篇)

    Spark系列-初体验(数据准备篇) Spark系列-核心概念 在Spark体验开始前需要准备环境和数据,环境的准备可以自己按照Spark官方文档安装.笔者选择使用CDH集群安装,可以参考笔者之前的文 ...

  3. 【洛谷】【st表+模拟】P1311 选择客栈

    [题目描述:] 丽江河边有n 家很有特色的客栈,客栈按照其位置顺序从 1 到n 编号.每家客栈都按照某一种色调进行装饰(总共 k 种,用整数 0 ~ k-1 表示),且每家客栈都设有一家咖啡店,每家咖 ...

  4. 10、Android--技巧

    10.1.全局获取Context的技巧 在实践中有很多的地方都可以使用到Context 弹出Toast的时候需要,启动活动的时候需要.发送广播的时候需要. 操作数据库的时候需要.使用通知的时候需要.. ...

  5. Python自动化之logging模块

    Logging模块构成 主要分为四个部分: Loggers:提供应用程序直接使用的接口 Handlers:将Loggers产生的日志传到指定位置 Filters:对输出日志进行过滤 Formatter ...

  6. ajax和原生ajax、文件的上传

    ajax理解: ajax发送的请求是异步处理的.也就是说如下形式: function f1(){ $.ajax( { ....... success:function(){ a= return a } ...

  7. Spring源码分析(十三)缓存中获取单例bean

    摘要:本文结合<Spring源码深度解析>来分析Spring 5.0.6版本的源代码.若有描述错误之处,欢迎指正. 介绍过FactoryBean的用法后,我们就可以了解bean加载的过程了 ...

  8. KMP算法之从懵逼到入门

    写本文的目的: 1.加深自己的理解,以便自己日后复习 2.给看到此文的人一点启发 KMP算法看懂了就觉得特别简单,思路也好理解,但是看不懂之前,查各种资料看大佬的博客,都很懵逼...... 1.  算 ...

  9. iPhone将NSString转换编码集为gb2312或者gbk的方法

    很多时候软件读取的中文网页编码集是gb2312,所以显示出来的是乱码.这时需要将NSString文字编码转换.你可以试试以下代码 NSURL *url = [NSURL URLWithString:u ...

  10. docker kafka 外网访问不到

    linux虚拟机中的kafka docker 容器外网显示: 原因: kafka的外网IP端口配置参数设置错误. 原-->设置了容器的IP端口. 改-->设置宿主机的ip以及宿主机上的端口 ...