背景知识

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

孤立点检测

使用<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. PAT 1001A+B Format

    Github 1001 题目速览 1.解题的思路过程 认真读题,题目为A+BFormat,简单的计算a+b问题,特殊在于输出的形式. 输入形式为每个输入文件包含一个测试样例,每个测试样例仅包含一对整型 ...

  2. Keepalived + haproxy双机高可用方案

    上一篇文章已经讲到了keepalived实现双机热备,且遗留了一个问题 master的网络不通的时候,可以立即切换到slave,但是如果只是master上的应用出现问题的时候,是不会 主动切换的. 上 ...

  3. c++中内存拷贝函数(C++ memcpy)详解

    原型:void*memcpy(void*dest, const void*src,unsigned int count); 功能:由src所指内存区域复制count个字节到dest所指内存区域. 说明 ...

  4. fastRPC服务使用

    现在出现了很多中间件解决跨语言问题,使用RPC远程调用:但是庞大是个问题,而且要按照格式使用.尤其是源码量比较庞大. 为了简单易用,我采用订阅发布模型,在此基础上创建了fastRPC,模拟RPC,调用 ...

  5. Linux基础命令之文件过滤及内容编辑处理(二)

    . wc 用于统计文件的行数,单词,或字节数 -l # 统计行数 -L # 打印最长行的长度,一般脚本中判断字符长度 -c # 统计字节数 -w # 统计单词数 -m 统计字符数 . iconv 转换 ...

  6. 一、Django的简介

    2019-04-09 22:58:22 大家好,我是一名普普通通的运维工程师,不甘平庸,想在工作之余多学习一些编程技能,不仅提升自我,还能应用于公司的运维自动化工作(代码的自动发布等).希望今后在这记 ...

  7. [Golang学习笔记] 02 命令源码文件

    源码文件的三种类型: 命令源文件:可以直接运行的程序,可以不编译而使用命令“go run”启动.执行. 库源码文件 测试源码文件 面试题:命令源码文件的用途是什么,怎样编写它? 典型回答: 命令源码文 ...

  8. springboot-web进阶(三)——统一异常处理

    补充 springboot中也是一样的可以对结果进行统一格式的包装,这样也就方便了前台的统一接收处理了: 1.结果集包装类 package com.example.demo.bean; /** * 结 ...

  9. flex“深拷贝”

    以前在<ActionScript殿堂之路>上就看到过的“深拷贝”概念一直没有好好地在实战中用到过,但是最近在开发过程中,我发现我在编写VO数据对象时的一个老习惯很浪费我的编码时间,这个习惯 ...

  10. 【转载】Direct3D HLSL介绍(上)

    原文路径:http://www.csharpwin.com/csharpspace/3087.shtml 写过Direct3D程序的朋友们可能还记得,在以往,大家常为如何表现更多真实的材质(如玻璃.金 ...