图像特征提取:Sobel边缘检测

图像特征提取: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边缘检测的函数:

 1 bool Sobel(const Mat& image,Mat& result,int TYPE)
 2 {
 3     if(image.channels()!=1)
 4         return false;
 5     // 系数设置
 6     int kx(0);
 7     int ky(0);
 8     if( TYPE==SOBEL_HORZ ){
 9         kx=0;ky=1;
10     }
11     else if( TYPE==SOBEL_VERT ){
12         kx=1;ky=0;
13     }
14     else if( TYPE==SOBEL_BOTH ){
15         kx=1;ky=1;
16     }
17     else
18         return false;
19
20     // 设置mask
21     float mask[3][3]={{1,2,1},{0,0,0},{-1,-2,-1}};
22     Mat y_mask=Mat(3,3,CV_32F,mask)/8;
23     Mat x_mask=y_mask.t(); // 转置
24
25     // 计算x方向和y方向上的滤波
26     Mat sobelX,sobelY;
27     filter2D(image,sobelX,CV_32F,x_mask);
28     filter2D(image,sobelY,CV_32F,y_mask);
29     sobelX=abs(sobelX);
30     sobelY=abs(sobelY);
31     // 梯度图
32     Mat gradient=kx*sobelX.mul(sobelX)+ky*sobelY.mul(sobelY);
33
34     // 计算阈值
35     int scale=4;
36     double cutoff=scale*mean(gradient)[0];
37
38     result.create(image.size(),image.type());
39     result.setTo(0);
40     for(int i=1;i<image.rows-1;i++)
41     {
42         float* sbxPtr=sobelX.ptr<float>(i);
43         float* sbyPtr=sobelY.ptr<float>(i);
44         float* prePtr=gradient.ptr<float>(i-1);
45         float* curPtr=gradient.ptr<float>(i);
46         float* lstPtr=gradient.ptr<float>(i+1);
47         uchar* rstPtr=result.ptr<uchar>(i);
48         // 阈值化和极大值抑制
49         for(int j=1;j<image.cols-1;j++)
50         {
51             if( curPtr[j]>cutoff && (
52                 (sbxPtr[j]>kx*sbyPtr[j] && curPtr[j]>curPtr[j-1] && curPtr[j]>curPtr[j+1]) ||
53                 (sbyPtr[j]>ky*sbxPtr[j] && curPtr[j]>prePtr[j] && curPtr[j]>lstPtr[j]) ))
54                 rstPtr[j]=255;
55         }
56     }
57
58     return true;
59 }
时间: 2024-11-03 05:36:33

图像特征提取:Sobel边缘检测的相关文章

图像特征提取:边缘检测

1. 边缘检测的概念 边缘检测是图像处理与计算机视觉中极为重要的一种分析图像的方法,至少在我做图像分析与识别时,边缘是我最喜欢的图像特征.边缘检测的目的就是找到图像中亮度变化剧烈的像素点构成的集合,表现出来往往是轮廓.在对现实世界的图像采集中,有下面4种情况会表现在图像中时形成一个边缘. 深度的不连续(物体处在不同的物平面上): 表面方向的不连续(如正方体的不同的两个面): 物体材料不同(这样会导致光的反射系数不同): 场景中光照不同(如被树萌投向的地面): 上面的图像是图像中水平方向7个像素点

OpenCV2.4.10之samples_cpp_tutorial-code_learn-----ImgTrans(Laplace边缘检测和Sobel边缘检测,图像重映射)

本系列学习笔记参考自OpenCV2.4.10之opencv\sources\samples\cpp\tutorial_code和http://www.opencv.org.cn/opencvdoc/2.3.2/html/genindex.html 在图像处理中,往往需要对图像提取有效的边缘.本博文将介绍Laplace边缘检测和Sobel边缘检测,以及图像的重映射. 1.Laplace_Demo.cpp(Laplace边缘检测) Demo源码及注释如下: #include "stdafx.h&qu

python+opencv实现机器视觉基础技术(边缘提取,图像滤波,边缘检测算子,投影,车牌字符分割)

目录 一:边缘提取 1.对图像进行阈值分割并反色 2.边缘提取 二:图像滤波 1.读取原图 2.均值滤波 3.中值滤波 4.高斯滤波 5.高斯边缘检测 三:边缘检测算子 1.显示原图 2.对图像进行反色 3.对图像用sobel方法进行边缘检测 4.对图像用robert方法进行边缘检测 四:投影 1.显示原图 2.垂直方向投影 3.水平方向投影 五:车牌字符分割 1.读取原图 2.灰度转换 3.反色 4.阈值分割 5.投影 6.字符识别匹配分割 ??机器视觉是人工智能正在快速发展的一个分支.简单说

Sobel边缘检测算法(转载)

转载请注明出处:  http://blog.csdn.net/tianhai110 索贝尔算子(Sobel operator)主要用作边缘检测,在技术上,它是一离散性差分算子,用来运算图像亮度函数的灰度之近似值.在图像的任何一点使用此算子,将会产生对应的灰度矢量或是其法矢量 Sobel卷积因子为: 该算子包含两组3x3的矩阵,分别为横向及纵向,将之与图像作平面卷积,即可分别得出横向及纵向的亮度差分近似值.如果以A代表原始图像,Gx及Gy分别代表经横向及纵向边缘检测的图像灰度值,其公式如下: 具体

基于FPGA的Sobel边缘检测的实现

前面我们实现了使用PC端上位机串口发送图像数据到VGA显示,通过MATLAB处理的图像数据直接是灰度图像,后面我们在此基础上修改,从而实现,基于FPGA的动态图片的Sobel边缘检测.中值滤波.Canny算子边缘检测.腐蚀和膨胀等.那么这篇文章我们将来实现基于FPGA的Sobel边缘检测. 图像边缘:简言之,边缘就是图像灰度值突变的地方,亦即图像在该部分的像素值变化速度非常之快,这就好比在坐标轴上一条曲线有刚开始的平滑突然来个大转弯,在变化出的导数非常大. Sobel算子主要用作边缘检测,在技术

Sobel边缘检测算法

Sobel边缘检测算法 转载请注明出处:  http://blog.csdn.net/tianhai110 索贝尔算子(Sobel operator)主要用作边缘检测,在技术上,它是一离散性差分算子,用来运算图像亮度函数的灰度之近似值.在图像的任何一点使用此算子,将会产生对应的灰度矢量或是其法矢量 Sobel卷积因子为: 该算子包含两组3x3的矩阵,分别为横向及纵向,将之与图像作平面卷积,即可分别得出横向及纵向的亮度差分近似值.如果以A代表原始图像,Gx及Gy分别代表经横向及纵向边缘检测的图像灰

Opencv图像识别从零到精通(19)----Robert,prewitt,Sobel边缘检测

图像的边缘检测,是根据灰度的突变或者说不连续来检测,对于其中的算子有一阶导数和二价导数,这里先说基础的三种方法---Robert,prewitt,Sobel边缘检测.  一.梯度 首先介绍下梯度,梯度并非是一个数值,梯度严格意义上是一个向量,这个向量指向当前位置变化最快的方向,可以这么理解,当你站在一个山上,你有360°的方向可以选择,哪个方向下降速度最快(最陡峭),便是梯度方向,梯度的长度,表示为向量的长度,表示最大的变化速率. 梯度的数学表达: 在二维中只取前两项,也就是由x方向的偏微分和y

[OpenCV-Python] OpenCV 中图像特征提取与描述 部分 V (一)

部分 V图像特征提取与描述 29 理解图像特征 目标本节我会试着帮你理解什么是图像特征,为什么图像特征很重要,为什么角点很重要等.29.1 解释 我相信你们大多数人都玩过拼图游戏吧.首先你们拿到一张图片的一堆碎片,要做的就是把这些碎片以正确的方式排列起来从而重建这幅图像.问题是,你怎样做到的呢?如果把你做游戏的原理写成计算机程序,那计算机就也会玩拼图游戏了.如果计算机可以玩拼图,我们就可以给计算机一大堆自然图片,然后就可以让计算机把它拼成一张大图了.如果计算机可以自动拼接自然图片,那我们是不是可

从视频文件中读入数据--&gt;将数据转换为灰度图--&gt;对图像做candy边缘检测

//从视频文件中读入数据-->将数据转换为灰度图-->对图像做candy边缘检测 //作者:sandy //时间:2015-10-10 #include <cv.h> #include <highgui.h> int main(int argc, char *argv[]){ //预备工作 CvCapture* capture=cvCreateFileCapture("E:\\Videos\\xx.avi");//让capture变量指向视频文件 i