图像特征提取:Sobel边缘检测
前言
点和线是做图像分析时两个最重要的特征,而线条往往反映了物体的轮廓,对图像中边缘线的检测是图像分割与特征提取的基础。文章主要讨论两个实际工程中常用的边缘检测算法:Sobel边缘检测和Canny边缘检测,Canny边缘检测由于算法复杂将在另一篇文章中单独介绍,文章不涉及太多原理,因为大部分的图像处理书籍都有相关内容介绍,文章主要通过Matlab代码,一步一步具体实现两种经典的边缘检测算法。
Sobel边缘检测
Soble边缘检测算法比较简,实际应用中效率比canny边缘检测效率要高,但是边缘不如Canny检测的准确,但是很多实际应用的场合,sobel边缘却是首选,尤其是对效率要求较高,而对细纹理不太关心的时候。
Soble边缘检测通常带有方向性,可以只检测竖直边缘或垂直边缘或都检测。
所以我们先定义两个梯度方向的系数:
kx=0;ky=1;% horizontal
kx=1;ky=0;% vertical
kx=1;ky=1;% both
然后我们来计算梯度图像,我们知道边缘点其实就是图像中灰度跳变剧烈的点,所以先计算梯度图像,然后将梯度图像中较亮的那一部分提取出来就是简单的边缘部分。
Sobel算子用了一个3*3的滤波器来对图像进行滤波从而得到梯度图像,这里面不再详细描述怎样进行滤波及它们的意义等。
竖起方向的滤波器:y_mask=op = [-1 -2 -1;0 0 0;1 2 1]/8;
水平方向的滤波器:op的转置:x_mask=op’;
定义好滤波器后,我们就开始分别求垂直和竖起方向上的梯度图像。用滤波器与图像进行卷积即可:
bx = abs(filter2(x_mask,a));
by = abs(filter2(y_mask,a));
上面bx为水平方向上的梯度图像,by为垂直方向上的梯度图像。为了更清楚的说明算法过程,下面给出一张示例图像的梯度图像。
原图:

竖直方向梯度图像:by

水平方向梯度图像:bx

而最终的梯度图像为:b = kx*bx.*bx + ky*by.*by;当然这里如果定义了检测方向,就会得到对应上面的图像。
这里值得注意的是为了计算效率并没有对b开平方。而涉及滤波等操作时对图像边界的处理是值得注意的一个地方。我们这里应该将梯度图像的四周1像素点都设置为0。
得到梯度图像后,我们需要的是计算阈值,这是Sobel算法很核心的一部分,也是对效果影响较大的地方,同理讲到canny边缘检测时,用到的双阈值法也是canny算法的核心。
同样这里,我并不太多的介绍算法原理,相关文献可以直接百度。阈值也可以通过自己期待的效果进行自定义阈值,如果没有,则我们计算默认阈值。
scale = 4;
cutoff = scale*mean2(b);
thresh = sqrt(cutoff);
其中mean2函数是求图像所有点灰度的平均值。scale是一个系数。
有了阈值后,我们就可以地得到的梯度图像进行二值化。二值化过程,不做详细说明,遍历图像中的像素点,灰度大于阈值的置为白点,灰度小于阈值的则置为黑点。
下面是示例图像梯度图像二值化后的效果:

其实很多介绍Soble算法的文章介绍到这里就结束了,印象中OpenCv的算法也是到此步为止。但是我们注意到上面的边缘图像,边缘较粗,如果我们在做边界跟踪或轮廓提取时,上面图像并不是我们期望的结果。
所以下面要介绍一个很重要的算法,用非极大值抑制算法对边缘进行1像素化。本人在开始的时候也一直以为这里用一个普通的细化算法就可以了,可是总得到到想要的结果,最后查找matlab早期版本的源码才找到方法,其实跟canny算法里原理差不多。
我们需要遍历刚才得到的梯度图像二值化结果b,对于b内的任意一点(i,j),如果满足下面条件,则保持白点,否则置为黑点。条件简单的说即是:如果是竖直边缘,则它的梯度值要比左边和右边的点都大;如果是水平连续,则该点的梯度值要比上边和下边的都大。
bx(i,j)>kx*by(i,j) && b(i,j-1)<b(i,j) && b(i,j+1)<b(i,j)
或者
by(i,j)>ky*bx(i,j) && b(i-1,j)<b(i,j) &&b (i+1,j)<b(i,j)
经过这样的非极大值抑制我们就可以得到比较理想的边缘图像。

下面给出利用OpenCV里的一些滤波函数,从新写的一个Sobel边缘检测的函数:
bool Sobel(const Mat& image,Mat& result,int TYPE)
{
if(image.channels()!=)
return false;
// 系数设置
int kx();
int ky();
if( TYPE==SOBEL_HORZ ){
kx=;ky=;
}
else if( TYPE==SOBEL_VERT ){
kx=;ky=;
}
else if( TYPE==SOBEL_BOTH ){
kx=;ky=;
}
else
return false; // 设置mask
float mask[][]={{,,},{,,},{-,-,-}};
Mat y_mask=Mat(,,CV_32F,mask)/;
Mat x_mask=y_mask.t(); // 转置 // 计算x方向和y方向上的滤波
Mat sobelX,sobelY;
filter2D(image,sobelX,CV_32F,x_mask);
filter2D(image,sobelY,CV_32F,y_mask);
sobelX=abs(sobelX);
sobelY=abs(sobelY);
// 梯度图
Mat gradient=kx*sobelX.mul(sobelX)+ky*sobelY.mul(sobelY); // 计算阈值
int scale=;
double cutoff=scale*mean(gradient)[]; result.create(image.size(),image.type());
result.setTo();
for(int i=;i<image.rows-;i++)
{
float* sbxPtr=sobelX.ptr<float>(i);
float* sbyPtr=sobelY.ptr<float>(i);
float* prePtr=gradient.ptr<float>(i-);
float* curPtr=gradient.ptr<float>(i);
float* lstPtr=gradient.ptr<float>(i+);
uchar* rstPtr=result.ptr<uchar>(i);
// 阈值化和极大值抑制
for(int j=;j<image.cols-;j++)
{
if( curPtr[j]>cutoff && (
(sbxPtr[j]>kx*sbyPtr[j] && curPtr[j]>curPtr[j-] && curPtr[j]>curPtr[j+]) ||
(sbyPtr[j]>ky*sbxPtr[j] && curPtr[j]>prePtr[j] && curPtr[j]>lstPtr[j]) ))
rstPtr[j]=;
}
} return true;
}
图像特征提取:Sobel边缘检测的更多相关文章
- opencv-学习笔记(6)图像梯度Sobel以及canny边缘检测
opencv-学习笔记(6)图像梯度Sobel以及canny边缘检测 这章讲了 sobel算子 scharr算子 Laplacion拉普拉斯算子 图像深度问题 Canny检测 图像梯度 sobel算子 ...
- Sobel边缘检测
Sobel算子:[-1 0 1 -2 0 2 -1 0 1] 用此算子与原图像做卷积,可以检测出垂直方向的边缘.算子作用在图像的第二列,结果是:200,200,200:作用在第三列,结果是 ...
- Sobel边缘检测算法(转载)
转载请注明出处: http://blog.csdn.net/tianhai110 索贝尔算子(Sobel operator)主要用作边缘检测,在技术上,它是一离散性差分算子,用来运算图像亮度函数的灰 ...
- 数字图像处理之sobel边缘检测
在前两部文章介绍了几种边缘检测算法,和位图的内存结构.如果对前两篇文章已经理解透彻 了,那么本文将带你进入数字图像处理的世界. 本文通过C代码实现基本的sobel边缘检测,包括8个方向和垂直方向: 代 ...
- 基于FPGA的Sobel边缘检测的实现
前面我们实现了使用PC端上位机串口发送图像数据到VGA显示,通过MATLAB处理的图像数据直接是灰度图像,后面我们在此基础上修改,从而实现,基于FPGA的动态图片的Sobel边缘检测.中值滤波.Can ...
- [OpenCV-Python] OpenCV 中图像特征提取与描述 部分 V (一)
部分 V图像特征提取与描述 OpenCV-Python 中文教程(搬运)目录 29 理解图像特征 目标本节我会试着帮你理解什么是图像特征,为什么图像特征很重要,为什么角点很重要等.29.1 解释 我相 ...
- 基于MATLAB的Sobel边缘检测算法实现
图像边缘就是图像灰度值突变的地方,也就是图像在该部分的像素值变化速度非常之快,就比如在坐标轴上一条曲线有刚开始的平滑突然来个大转弯,在变化出的导数非常大. Sobel算子主要用作边缘检测,它是一离散型 ...
- opencv 5 图像转换(1 边缘检测)
边缘检测 一般步骤 canny算子 步骤 canny函数 彩色canny #include<opencv2/opencv.hpp> #include<opencv2/highgui/ ...
- 【转】基于FPGA的Sobel边缘检测的实现
前面我们实现了使用PC端上位机串口发送图像数据到VGA显示,通过MATLAB处理的图像数据直接是灰度图像,后面我们在此基础上修改,从而实现,基于FPGA的动态图片的Sobel边缘检测.中值滤波.Can ...
随机推荐
- Object C学习笔记19-枚举
一. 枚举类型 枚举类型是一个基本类型,不能再分为为任何其他的类型.在一般的编程语言中都有枚举(enum)这种数据结构类型.枚举类型主要用于将一个变量限定在特定的范围内.比如一周有七天,那么一周的值就 ...
- SSRS用自定义对象绑定报表
有一个报表的数据源是一个对象的List, 这个对象List中还有层级,其中还有其他的对象List,这样的层级有三层.其数据是从数据库中取出来的.其LINQ的操作太多了而且复杂,所以不太可 能从LINQ ...
- 定一个小目标:明年1024能成功转行web前端,光荣地成为一个程序员!
第一次在博客园写博,我为什么要选择这里吗? 据说博客园这里的IT大牛如云,作为一个求知若渴的小白,我屁颠屁颠的跟着过来了. 于是今天早上兴高采烈的注册了账号,迫不及待的打开我的博客,呃!注册账号成功了 ...
- java编程
Java编程:五子棋游戏源代码 import java.awt.*; import java.awt.event.*; import java.applet.*; import javax.swing ...
- Git代码管理心得
一.概述: 这次按照要求进行了看似复杂,实则非常复杂并且麻烦(网上教程众多且啰嗦)的对git使用的学习,从星期六晚18:48我准备这次作业开始,直到了晚上22:44才结束电脑上的操作···(导致这篇随 ...
- Ibatis学习总结7--SqlMapClient 执行 SQL 语句
SqlMapCient 类提供了执行所有 mapped statement 的 API.这些方法如下: public int insert(String statementName, Object p ...
- DELL R720系统内存指南
该文章摘自于:http://www.dell.com/support/article/cn/zh/cndhs1/SLN153646/zh#issue3,仅供个人作为笔记使用 PowerEdge R72 ...
- hdu1281 二分匹配
求重要的点.那就可以通过枚举来找:先做一次最大匹配,求出匹配数.然后逐一枚举这些点.如果匹配数改变,那就是重要点: #include<stdio.h> #include<string ...
- 解决启动Biee控制台乱码问题
在安装完Biee后,大家都可以看到在程序中可以找到启动BI服务的地方 点击上图中的启动bi服务则在window系统中会弹出一个dos窗口,来显示执行启动服务的操作,如下图 上图显示的是正常情况,本人安 ...
- POJ3579 Median
Description Given N numbers, X1, X2, ... , XN, let us calculate the difference of every pair of numb ...