opencv——边缘检测算法(总结)
前言
笔记。
一、边缘检测算法
边缘检测算法是指利用灰度值的不连续性质,以灰度突变为基础分割出目标区域。对铝铸件表面进行成像后会产生一些带缺陷的区域,这些区域的灰度值比较低,与背景图像相比在灰度上会有突变,这是由于这些区域对光线产生散射所引起的。因此边缘检测算子可以用来对特征的提取。
1、一阶算子
一种是基于一阶微分的算子,也称基于搜索的算子,首先通过一阶导数计算边缘强度,然后采用梯度的方向来对边缘的局部方向进行寻找,同时根据该方向来寻找出局部梯度模的最大值,由此定位边缘,如Roberts Cross算子,Prewitt算子Sobel算子,Kirsch算子,Canny算子,罗盘算子等;
图像中的边缘区域,像素值会发生“跳跃”,对这些像素求导,在其一阶导数在边缘位置为极值,这就是Sobel算子使用的原理——极值处就是边缘。
2、二阶算子
另一种是基于二阶微分的算子,也称基于零交叉的算子,通过寻找由图像得到的二阶导数的过零点来定位检测边缘,如Marr-Hildreth算子,Laplacian算子,LOG算子等。如果对像素值求二阶导数,会发现边缘处的导数值为0。
二、一阶算子分析
一阶微分算子进行边缘检测的思路大致就是通过指定大小的核(kernal)(也称为算子)与图像进行卷积,将得到的梯度进行平方和或者最大值作为新的梯度赋值给对应的像素点,不同的一阶微分算子主要的不同在于其算子即核的元素不同以及核的大小不一样
以下是连续函数的一阶导数求导公式:因为图像是一个面,就相当于是灰度值关于x,y两个方向的函数,要求某一点的导数,则是各个方向的偏导数的平方和再进行开方运算。
离散函数的一阶导数公式:
y'=[y(x0+h)-y(x0-h)]/(2h);这是一维函数的一阶求导,h是步长,在图像处理中一般为1
首先复习一下什么是卷积?
卷积就是对应的元素相乘再进行累加的过程
实例图片:
1、Roberts算子
Robert算子是用于求解对角线方向的梯度,因为根据算子GX和GY的元素设置可以看到,只有对角线上的元素非零,其本质就是以对角线作为差分的方向来检测。
检测垂直边缘的效果好于斜向边缘,定位精度高,对噪声敏感,无法抑制噪声的影响。
不同方向的算子模板: 梯度的计算:
代码示例:
#include<opencv2/opencv.hpp> #include<opencv2/core/core.hpp>#include<opencv2/imgproc/imgproc.hpp> #include<opencv2/highgui/highgui.hpp>#include<iostream>using namespace std; using namespace cv; Mat roberts(Mat srcImage); int main(int argc, char** argv) {Mat src,src_binary,src_gray;src = imread("D:/opencv练习图片/薛之谦.jpg");imshow("原图", src);cvtColor(src, src_gray, COLOR_BGR2GRAY);GaussianBlur(src_gray, src_binary, Size(3, 3),0, 0, BORDER_DEFAULT);Mat dstImage = roberts(src_binary);imshow("dstImage", dstImage);waitKey(0);return 0; } //roberts 边缘检测Mat roberts(Mat srcImage) {Mat dstImage = srcImage.clone();int nRows = dstImage.rows;int nCols = dstImage.cols;for (int i = 0; i < nRows - 1; i++) {for (int j = 0; j < nCols - 1; j++) {//根据公式计算int t1 = (srcImage.at<uchar>(i, j) -srcImage.at<uchar>(i + 1, j + 1))*(srcImage.at<uchar>(i, j) -srcImage.at<uchar>(i + 1, j + 1));int t2 = (srcImage.at<uchar>(i + 1, j) -srcImage.at<uchar>(i, j + 1))*(srcImage.at<uchar>(i + 1, j) -srcImage.at<uchar>(i, j + 1));//计算g(x,y)dstImage.at<uchar>(i, j) = (uchar)sqrt(t1 + t2);}}return dstImage; }
效果展示:
2、Sobel算子
Sobel算子是主要用于边缘检测的离散微分算子,它结合了高斯平滑和微分求导,用于计算图像灰度函数的近似梯度。
因为Sobel算子结合了高斯平滑和分化,因此结果会具有更多的抗噪性。
不同方向的算子模板: 梯度的计算:
opencv中sobel函数的参数如下:
void cv::Sobel ( InputArray src, // 输入图像OutputArray dst, // 输出图像int ddepth, // 输出图像深度,-1 表示等于 src.depth()int dx, // 水平方向的阶数int dy, // 垂直方向的阶数int ksize = 3, // 卷积核的大小,常取 1, 3, 5, 7 等奇数double scale = 1, // 缩放因子,应用于计算结果double delta = 0, // 增量数值,应用于计算结果int borderType = BORDER_DEFAULT // 边界模式 )
3、Prewitt算子
Prewitt算子利用像素点上下、左右邻点的灰度差,在边缘处达到极值检测边缘,去掉部分伪边缘,对噪声具有平滑作用 。其原理是在图像空间利用两个方向模板与图像进行邻域卷积来完成的。
这两个方向模板一个检测水平边缘,一个检测垂直边缘。
不同方向的算子模板:
Prewitt算子定位精度不如Sobel算子,在真正的使用中,一般不会用到这个算子,效果较差,因此不多做分析。
4、Canny算子
可以说,Canny 边缘检测算法是被业界公认的性能最为优良的边缘检测算法之一。Canny算法不是像Roberts、Prewitt、Sobel等这样简单梯度算子或锐化模板,它是在梯度算子基础上,引入了一种能获得抗噪性能好、定位精度高的单像素边缘的计算策略。
Canny 算子,在一阶微分的基础上,增加了非最大值抑制和双阈值检测,是边缘检测算子中最常用的一种,常被其它算子作为标准算子来进行优劣比较。
4.1算法步骤
1) 用高斯滤波器对输入图像做平滑处理 (大小为 5x5 的高斯核)去噪
2) 计算图像的梯度强度和角度方向 ( x 和 y 方向上的卷积核)
角度方向近似为四个可能值,即 0, 45, 90, 135
3) 对图像的梯度强度进行非极大抑制
可看做边缘细化:只有候选边缘点被保留,其余的点被移除
4) 利用双阈值检测和连接边缘
若候选边缘点大于上阈值,则被保留;小于下阈值,则被舍弃;处于二者之间,须视其所连接的像素点,大于上阈值则被保留,反之舍弃
opencv中canny函数的参数如下:
void cv::Canny ( InputArray image, // 输入图像 (8位)OutputArray edges, // 输出图像 (单通道,8位)double threshold1, // 下阈值double threshold2, // 上阈值int apertureSize = 3,bool L2gradient = false )
一般 上阈值 / 下阈值 = 2 ~ 3
L2gradient 默认 flase,表示图像梯度强度的计算采用近似形式;若为 true,则表示采用更精确的形式
5、Laplace(拉普拉斯算子)
索贝尔算子 (Sobel) 和拉普拉斯算子 (Laplace) 都是用来对图像进行边缘检测的,不同之处在于,前者是求一阶导,后者是求二阶导。
常用算子模块:
opencv中Laplace函数的参数如下:
void Laplacian ( InputArray src,OutputArray dst,int ddepth,int ksize = 1,double scale = 1,double delta = 0,int borderType = BORDER_DEFAULT )
简单对比
在进行 Sobel,Laplacian 和 Canny 边缘检测之前,统一调用 GaussianBlur 来降低图像噪声
using namespace std; using namespace cv; int main(int argc, char** argv) {Mat src,src_binary,src_gray;Mat grad_x, grad_y;Mat abs_grad_x, abs_grad_y, dst;src = imread("D:/opencv练习图片/薛之谦.jpg");imshow("原图", src);GaussianBlur(src, src, Size(3, 3), 0);cvtColor(src, src_gray, COLOR_BGR2GRAY);Sobel(src_gray, grad_x, CV_16S, 1, 0, 3, 1, 1, BORDER_DEFAULT);//求x方向梯度convertScaleAbs(grad_x, abs_grad_x);//转换格式 8uSobel(src_gray, grad_y, CV_16S, 0, 1, 3, 1, 1, BORDER_DEFAULT);//求y方向梯度 convertScaleAbs(grad_y, abs_grad_y);//合并梯度addWeighted(abs_grad_x, 0.5, abs_grad_y, 0.5, 0, dst);imshow("solbel算子", dst); Canny(src_gray, dst, 100, 300);imshow("Canny算子", dst);Laplacian(src_gray, dst, -1, 3);imshow("Laplace算子", dst);waitKey(0);return 0;}
效果展示:
六.LOG算子
LOG(Laplacian of Gaussian)边缘检测算子是David Courtnay Marr和Ellen Hildreth在1980年共同提出的,也称为Marr & Hildreth算子,它根据图像的信噪比来求检测边缘的最优滤波器。该算法首先对图像做高斯滤波,然后再求其拉普拉斯(Laplacian)二阶导数,根据二阶导数的过零点来检测图像的边界,即通过检测滤波结果的零交叉(Zero crossings)来获得图像或物体的边缘。
LOG算子该综合考虑了对噪声的抑制和对边缘的检测两个方面,并且把Gauss平滑滤波器和Laplacian锐化滤波器结合了起来,先平滑掉噪声,再进行边缘检测,所以效果会更好。 该算子与视觉生理中的数学模型相似,因此在图像处理领域中得到了广泛的应用。它具有抗干扰能力强,边界定位精度高,边缘连续性好,能有效提取对比度弱的边界等特点。
常见的LOG算子是5*5模板,如下所示:
由于LOG算子到中心的距离与位置加权系数的关系曲线像墨西哥草帽的剖面,所以LOG算子也叫墨西哥草帽滤波器,如图所示。
LOG算子的边缘提取实现代码如下所示:
# -*- coding: utf-8 -*-
import cv2
import numpy as np
import matplotlib.pyplot as plt#读取图像
img = cv2.imread('lena.png')
lenna_img = cv2.cvtColor(img, cv2.COLOR_BGR2RGB)#灰度化处理图像
grayImage = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)#先通过高斯滤波降噪
gaussian = cv2.GaussianBlur(grayImage, (3,3), 0)#再通过拉普拉斯算子做边缘检测
dst = cv2.Laplacian(gaussian, cv2.CV_16S, ksize = 3)
LOG = cv2.convertScaleAbs(dst)#用来正常显示中文标签
plt.rcParams['font.sans-serif']=['SimHei']#显示图形
titles = [u'原始图像', u'LOG算子']
images = [lenna_img, LOG]
for i in xrange(2): plt.subplot(1,2,i+1), plt.imshow(images[i], 'gray') plt.title(titles[i]) plt.xticks([]),plt.yticks([])
plt.show()
其运行结果如下图所示:
LOG滤波器方法通过检测二阶导数过零点来判断边缘点。LOG滤波器中的a正比于低通滤波器的宽度,a越大,平滑作用越显著,去除噪声越好,但图像的细节也损失越大,边缘精度也就越低。所以在边缘定位精度和消除噪声级间存在着矛盾,应该根据具体问题对噪声水平和边缘点定位精度要求适当选取。
讨论和比较了几种常用的边缘检测算子。梯度算子计算简单,但精度不高,只能检测出图像大致的轮廓,而对于比较细的边缘可能会忽略。Prewitt 和Sobel 算子比Roberts 效果要好一些。LOG 滤波器和Canny 算子的检测效果优于梯度算子,能够检测出图像较细的边缘部分。不同的系统,针对不同的环境条件和要求,选择合适的算子来对图像进行边缘检测。
opencv——边缘检测算法(总结)相关推荐
- 【学习OpenCV4】OpenCV边缘检测算法总结
本文分享内容来自图书<学习OpenCV 4:基于Python的算法实战>,该书内容如下: 第1章 OpenCV快速入门: 第2章 图像读写模块imgcodecs: 第3章 核心库模块cor ...
- OpenCV+python:Canny边缘检测算法
1,边缘处理 图像边缘信息主要集中在高频段,通常说图像锐化或检测边缘,实质就是高频滤波.我们知道微分运算是求信号的变化率,具有加强高频分量的作用. 在空域运算中来说,对图像的锐化就是计算微分.由于数字 ...
- opencv 图像边缘检测 Canny边缘检测算法使用
图解边缘检测 opencv 应用Canny算法进行边缘检测 import cv2 as cv import numpy as npimg = cv.imread('baby_g.jpg', 0) # ...
- opencv图片矩形网格边线_图像算法在数值计算中的应用(1):Canny边缘检测算法...
引言 有限差分方法(FDM)是计算机数值模拟最早采用的方法,至今仍在广泛应用.该方法将求解域划分为差分网格,用有限个网格节点代替连续的求解域.在直角坐标系下,求解域差分网格通常为均匀的矩形,在表达非矩 ...
- SUSAN边缘检测算法,及其Matlab和OpenCV实现
1.SUSAN边缘检测计算步骤 (1)在图像上放置一个37个像素的圆形模板,模板在图像上滑动,依次比较模板内各个像素点的灰度与模板核的灰度,判断是否属于USAN区域.判别函数如下: 其中,r⃗0{{\ ...
- Opencv(python)图像梯度和边缘检测算法
1.图像梯度 图像梯度计算的是图像的边缘信息 ,图像梯度计算的是图像变化的速度.对于图像的边缘部分,其灰度值变化较大,梯度值也较大,对于图像中比较平滑的部分,其灰度值变化较小,相应的梯度值也较小.图像 ...
- OpenCV:用C++绘制彩色铅笔画(Canny边缘检测算法)
之前写的博客感觉太严肃了,学习应该是一件很开心,很有成就感的事情,所以我觉得我们可以利用所学知识,做一点有趣的事情. 在这里,我们需要用到的知识是Canny边缘检测算法.也就是通过边缘提取,外加一点小 ...
- OpenCV从入门到精通——边缘检测算法Canny
Canny 算法 边缘:我的理解是在图像处理的过程中,针对我们图像处理的过程中,梯度变化以较大的地方能够让我们能够快速辨识,针对一个人脸,脸上有一些平滑的地方(没错我针对美颜的),与头发的接壤处,会让 ...
- 机器视觉边缘检测算法详解
点击上方"小白学视觉",选择加"星标"或"置顶" 重磅干货,第一时间送达 边缘检测相关算法的步骤如下: 1.滤波: 边缘检测算法主要是基于图 ...
最新文章
- Spring MVC 入门示例讲解
- 如何获取 Teams Meeting 的上下文信息
- csv处理数据后存入数据库
- Oracle服务启动的问题
- Python数据可视化案例一:自定义曲线频率、颜色与线型
- spark加载数据的方式
- 转 oracle 监控执行计划突然变化
- 几种流行Webservice框架性能对比(转载、拼接)
- 关于广州“开四停四“违法逻辑实现
- Dreamweaver CS6安装教程
- html- 颜色代码
- 职业学校计算机和机电哪个好,职业学校都有什么专业10大热门专业
- 跟我学大数据分析之五:2019中国城市发展潜力排名
- 生物信息学在生物医药领域的应用
- easypoi利用模板导出图片到Excel;解决easypoi导出图片到合并单元格单元格被拉伸的问题
- PCB电路板3D模型3D渲染思路
- 《Beyond Short Clips: End-to-End Video-Level Learning with Collaborative Memories》论文笔记
- 阿翔编程学-Axis
- 当下最流行的10大H5前端框架
- vue中destroyed方法的使用
热门文章
- MDK5.25以上版本解决j-link “the connected j-link is defective“ 问题
- 初创企业的九个基本数字营销技巧
- python中的颜色_Python中的颜色函数
- 感谢 驱动精灵2011
- 李峋同款爱心代码,表白神器!
- 对linux防火墙规则的优化,Linux防火墙规则优化的研究
- 投影参数_购买家用投影仪主要看什么参数?
- 爬虫项目-人大法律文件
- linux切换盘符,挂载Windows盘符
- 模拟频率 模拟角频率 数字频率