图像处理 轮廓与边缘

2017-06-15 10:20:10 llh_1178 阅读数 13061

图像的边缘、轮廓检测在人类视觉和计算机视觉中均起着重要的作用。人类能够仅凭一张背景剪影或一张草图就能识别出物体的类型和姿态。OpenCV提供了许多边缘检测l滤波函数,包括Laplacian( )、Sobel()以及Scharr()。这些函数都能将边缘转化为白色或其他饱和的颜色,将非边缘转化为黑色,但是,这些函数不能有效的区分噪声错误的判断为边缘。解决这个问题的办法是对图像进行模糊处理。这里介绍一种很方便却很实用的函数——Canny边缘检测。

Canny函数中包含两个阈值这也是与其他边缘检测函数不同的地方。阈值是来确定哪里是边缘位置。阈值越低,能够检测出的边线越多,结果也就越容易受到图片噪声的影响,并且越容易从图像中挑出不相关的特性。与此相反,一个高的阈值将会遗失细的或者短的线段。因此,Canny函数中要设置两个阈值是有不同用处的。高的那个阈值是将要提取轮廓的物体与背景区分开来,就像阈值分割的那个参数一样,是决定目标与背景对比度的,低的那个阈值是用来平滑边缘的轮廓,有时高的阈值设置太大了,可能边缘轮廓不连续或者不够平滑,通过低阈值来平滑轮廓线,或者使不连续的部分连接起来。

import cv2
from matplotlib import pyplot as plt
img = cv2.imread("water_coins.jpg", 0)
edges = cv2.Canny(img, 200, 300)
plt.subplot(1,2,1), plt.imshow(img,cmap = 'gray')
plt.title('Original Image'), plt.xticks([]), plt.yticks([])
plt.subplot(1,2,2), plt.imshow(edges,cmap = 'gray')
plt.title('Edge Image'), plt.xticks([]), plt.yticks([])
plt.show()



那么对图像的轮廓检测,先要将图像二值化操作,然后再调用findContours()函数。

import cv2
import numpy as np

img = np.zeros((200, 200), dtype=np.uint8)
img[50:150, 50:150] = 255
# 二值化处理
ret, th = cv2.threshold(img, 127, 255, 0)
# findcontours()函数。有三个参数:输入图像、层次类型和轮廓逼近方法。
# 由函数返回的层次树相当重要:cv2.RETR_TREE参数会得到图像中轮廓的整体层次结构(contours)。如果只想得到最外面的轮廓,可以使用cv2.RETR_EXTERNAL。这对消除包含在其他轮廓中的轮廓很有用。
# 第三个参数有两种方法:
#cv2.CHAIN_APPROX_NONE存储所有的轮廓点,相邻的两个点的像素位置差不超过1,即max(abs(x1-x2),abs(y2-y1))==1 cv2.CHAIN_APPROX_SIMPLE压缩水平方向,垂直方向,对角线方向的元素,只保留该方向的终点坐标,例如一个矩形轮廓只需4个点来保存轮廓信息cv2.CHAIN_APPROX_TC89_L1,CV_CHAIN_APPROX_TC89_KCOS使用teh-Chinl chain 近似算法
image, contours, hierarchy = cv2.findContours(th, cv2.RETR_TREE, cv2.CHAIN_APPROX_SIMPLE)
# 色彩空间转换函数cv2.cvtColor()
color = cv2.cvtColor(img, cv2.COLOR_BAYER_BG2BGR)
# 画出轮廓,-1,表示所有轮廓,画笔颜色为(0, 255, 0),即Green,粗细为2
img = cv2.drawContours(color, contours, -1, (0, 255, 0), 2)
cv2.imwrite("contours.png", color)
cv2.waitKey()
cv2.destroyAllWindows()


参考:

《OpenCV 3计算机视觉Python语言实现》

  OpenCV帮助文档:http://docs.opencv.org/3.0.0/da/d22/tutorial_py_canny.html


2019-04-02 20:32:00 weixin_30670925 阅读数 534

Part1:先介绍几个关于图像处理的概念

1 图像锐化

图像锐化(image sharpening)是补偿图像的轮廓,增强图像的边缘及灰度跳变的部分,使图像变得清晰,分为空域处理和频域处理两类。图像锐化是为了突出图像上地物的边缘、轮廓,或某些线性目标要素的特征。这种滤波方法提高了地物边缘与周围像元之间的反差,因此也被称为边缘增强。

2图像平滑

概念

图像平滑是指用于突出图像的宽大区域、低频成分、主干部分或抑制图像噪声和干扰高频成分的图像处理方法,目的是使图像亮度平缓渐变,减小突变梯度,改善图像质量。

方法

图像平滑的方法包括:插值方法,线性平滑方法,卷积法等等。这样的处理方法根据图像噪声的不同进行平滑,比如椒盐噪声,就采用线性平滑方法!

3理解低频信号和高频信号

   图像中的低频信号和高频信号也叫做低频分量和高频分量。 简单一点说,图像中的高频分量,指的是图像强度(亮度/灰度)变化剧烈的地方,也就是我们常说的边缘(轮廓);图像中的低频分量,指的是图像强度(亮度/灰度)变换平缓的地方,也就是大片色块的地方。  人眼对图像中的高频信号更为敏感,举个例子,在一张白纸上有一行字,那么我们肯定直接聚焦在文字上,而不会太在意白纸本身,这里文字就是高频信号,而白纸就是低频信号。 

  图像的高低频是对图像各个位置之间强度变化的一种度量方法. 低频分量:主要对整副图像的强度的综合度量. 高频分量:主要是对图像边缘和轮廓的度量.   如果一副图像的各个位置的强度大小相等,则图像只存在低频分量,从图像的频谱图上看,只有一个主峰,且位于频率为零的位置. 

   如果一副图像的各个位置的强度变化剧烈,则图像不仅存在低频分量,同时也存在多种高频分量,从图像的频谱上看,不仅有一个主峰,同时也存在多个旁峰. 

Part2:常见的边缘检测算子的原理

 不同图像灰度不同,边界处一般会有明显的边缘,利用此特征可以分割图像。需要说明的是:边缘和物体间的边界并不等同,边缘指的是图像中像素的值有突变的地方,而物体间的边界指的是现实场景中的存在于物体之间的边界。有可能有边缘的地方并非边界,也有可能边界的地方并无边缘,因为现实世界中的物体是三维的,而图像只具有二维信息,从三维到二维的投影成像不可避免的会丢失一部分信息;另外,成像过程中的光照和噪声也是不可避免的重要因素。正是因为这些原因,基于边缘的图像分割仍然是当前图像研究中的世界级难题,目前研究者正在试图在边缘提取中加入高层的语义信息。

        在实际的图像分割中,往往只用到一阶和二阶导数,虽然,原理上,可以用更高阶的导数,但是,因为噪声的影响,在纯粹二阶的导数操作中就会出现对噪声的敏感现象,三阶以上的导数信息往往失去了应用价值。二阶导数还可以说明灰度突变的类型。在有些情况下,如灰度变化均匀的图像,只利用一阶导数可能找不到边界,此时二阶导数就能提供很有用的信息。二阶导数对噪声也比较敏感,解决的方法是先对图像进行平滑滤波,消除部分噪声,再进行边缘检测。不过,利用二阶导数信息的算法是基于过零检测的,因此得到的边缘点数比较少,有利于后继的处理和识别工作。

      各种算子的存在就是对这种导数分割原理进行的实例化计算,是为了在计算过程中直接使用的一种计算单位。

1.Sobel算子

        其主要用于边缘检测,在技术上它是以离散型的差分算子,用来运算图像亮度函数的梯度的近似值, Sobel算子是典型的基于一阶导数的边缘检测算子,由于该算子中引入了类似局部平均的运算,因此对噪声具有平滑作用,能很好的消除噪声的影响。Sobel算子对于象素的位置的影响做了加权,与Prewitt算子、Roberts算子相比因此效果更好。

       Sobel算子包含两组3x3的矩阵,分别为横向及纵向模板,将之与图像作平面卷积,即可分别得出横向及纵向的亮度差分近似值。实际使用中,常用如下两个模板来检测图像边缘。

                       

检测水平边沿 横向模板 :           检测垂直平边沿 纵向模板:

 

图像的每一个像素的横向及纵向梯度近似值可用以下的公式结合,来计算梯度的大小。

 

                                                                             

然后可用以下公式计算梯度方向。

                                                                           

 

在以上例子中,如果以上的角度Θ等于零,即代表图像该处拥有纵向边缘,左方较右方暗。

缺点是Sobel算子并没有将图像的主题与背景严格地区分开来,换言之就是Sobel算子并没有基于图像灰度进行处理,由于Sobel算子并没有严格地模拟人的视觉生理特征,所以提取的图像轮廓有时并不能令人满意。

 

2. Isotropic Sobel算子

 

        Sobel算子另一种形式是(Isotropic Sobel)算子,加权平均算子,权值反比于邻点与中心点的距离,当沿不同方向检测边缘时梯度幅度一致,就是通常所说的各向同性Sobel(Isotropic Sobel)算子。模板也有两个,一个是检测水平边沿的 ,另一个是检测垂直平边沿的 。各向同性Sobel算子和普通Sobel算子相比,它的位置加权系数更为准确,在检测不同方向的边沿时梯度的幅度一致。

 

3. Roberts算子

 

罗伯茨算子、Roberts算子是一种最简单的算子,是一种利用局部差分算子寻找边缘的算子,他采用对角线方向相邻两象素之差近似梯度幅值检测边缘。检测垂直边缘的效果好于斜向边缘,定位精度高,对噪声敏感,无法抑制噪声的影响。1963年,Roberts提出了这种寻找边缘的算子。
Roberts边缘算子是一个2x2的模板,采用的是对角方向相邻的两个像素之差。从图像处理的实际效果来看,边缘定位较准,对噪声敏感。适用于边缘明显且噪声较少的图像分割。Roberts边缘检测算子是一种利用局部差分算子寻找边缘的算子,Robert算子图像处理后结果边缘不是很平滑。经分析,由于Robert算子通常会在图像边缘附近的区域内产生较宽的响应,故采用上述算子检测的边缘图像常需做细化处理,边缘定位的精度不是很高。

 

 

4. Prewitt算子

        Prewitt算子是一种一阶微分算子的边缘检测,利用像素点上下、左右邻点的灰度差,在边缘处达到极值检测边缘,去掉部分伪边缘,对噪声具有平滑作用 。其原理是在图像空间利用两个方向模板与图像进行邻域卷积来完成的,这两个方向模板一个检测水平边缘,一个检测垂直边缘。

 对数字图像f(x,y),Prewitt算子的定义如下:

G(i)=|[f(i-1,j-1)+f(i-1,j)+f(i-1,j+1)]-[f(i+1,j-1)+f(i+1,j)+f(i+1,j+1)]|
G(j)=|[f(i-1,j+1)+f(i,j+1)+f(i+1,j+1)]-[f(i-1,j-1)+f(i,j-1)+f(i+1,j-1)]|
则 P(i,j)=max[G(i),G(j)]或 P(i,j)=G(i)+G(j)
经典Prewitt算子认为:凡灰度新值大于或等于阈值的像素点都是边缘点。即选择适当的阈值T,若P(i,j)≥T,则(i,j)为边缘点,P(i,j)为边缘图像。这种判定是欠合理的,会造成边缘点的误判,因为许多噪声点的灰度值也很大,而且对于幅值较小的边缘点,其边缘反而丢失了。

 

Prewitt算子对噪声有抑制作用,抑制噪声的原理是通过像素平均,但是像素平均相当于对图像的低通滤波,所以Prewitt算子对边缘的定位不如Roberts算子。

 

因为平均能减少或消除噪声,Prewitt梯度算子法就是先求平均,再求差分来求梯度。水平和垂直梯度模板分别为:

检测水平边沿 横向模板                 检测垂直平边沿 纵向模板:

该算子与Sobel算子类似,只是权值有所变化,但两者实现起来功能还是有差距的,据经验得知Sobel要比Prewitt更能准确检测图像边缘。

 

5.Laplacian算子

         Laplace算子是一种各向同性算子,二阶微分算子,在只关心边缘的位置而不考虑其周围的象素灰度差值时比较合适。Laplace算子对孤立象素的响应要比对边缘或线的响应要更强烈,因此只适用于无噪声图象。存在噪声情况下,使用Laplacian算子检测边缘之前需要先进行低通滤波。所以,通常的分割算法都是把Laplacian算子和平滑算子结合起来生成一个新的模板。

 

拉普拉斯算子也是最简单的各向同性微分算子,具有旋转不变性。一个二维图像函数的拉普拉斯变换是各向同性的二阶导数,定义

                                                                           

了更适合于数字图像处理,将拉式算子表示为离散形式:

另外,拉普拉斯算子还可以表示成模板的形式,如下图所示,

 

离散拉普拉斯算子的模板:, 其扩展模板: 。


      拉式算子用来改善因扩散效应的模糊特别有效,因为它符合降制模型。扩散效应是成像过程中经常发生的现象。

      Laplacian算子一般不以其原始形式用于边缘检测,因为其作为一个二阶导数,Laplacian算子对噪声具有无法接受的敏感性;同时其幅值产生算边缘,这是复杂的分割不希望有的结果;最后Laplacian算子不能检测边缘的方向;所以Laplacian在分割中所起的作用包括:(1)利用它的零交叉性质进行边缘定位;(2)确定一个像素是在一条边缘暗的一面还是亮的一面;一般使用的是高斯型拉普拉斯算子(Laplacian of a Gaussian,LoG),由于二阶导数是线性运算,利用LoG卷积一幅图像与首先使用高斯型平滑函数卷积改图像,然后计算所得结果的拉普拉斯是一样的。所以在LoG公式中使用高斯函数的目的就是对图像进行平滑处理,使用Laplacian算子的目的是提供一幅用零交叉确定边缘位置的图像;图像的平滑处理减少了噪声的影响并且它的主要作用还是抵消由Laplacian算子的二阶导数引起的逐渐增加的噪声影响。

6.Canny算子

      该算子功能比前面几种都要好,但是它实现起来较为麻烦,Canny算子是一个具有滤波,增强,检测的多阶段的优化算子,在进行处理前,Canny算子先利用高斯平滑滤波器来平滑图像以除去噪声,Canny分割算法采用一阶偏导的有限差分来计算梯度幅值和方向,在处理过程中,Canny算子还将经过一个非极大值抑制的过程,最后Canny算子还采用两个阈值来连接边缘。

Canny边缘检测算法

step1: 用高斯滤波器平滑图象;

step2: 用一阶偏导的有限差分来计算梯度的幅值和方向;

step3: 对梯度幅值进行非极大值抑制

step4: 用双阈值算法检测和连接边缘


几种算子的比较
Robert算子定位比较精确,但由于不包括平滑,所以对于噪声比较敏感。Prewitt算子和Sobel算子都是一阶的微分算子,而前者是平均滤波,后者是加权平均滤波且检测的图像边缘可能大于2个像素。这两者对灰度渐变低噪声的图像有较好的检测效果,但是对于混合多复杂噪声的图像,处理效果就不理想了。LOG滤波器方法通过检测二阶导数过零点来判断边缘点。LOG滤波器中的a正比于低通滤波器的宽度,a越大,平滑作用越显著,去除噪声越好,但图像的细节也损失越大,边缘精度也就越低。所以在边缘定位精度和消除噪声级间存在着矛盾,应该根据具体问题对噪声水平和边缘点定位精度要求适当选取。
讨论和比较了几种常用的边缘检测算子。梯度算子计算简单,但精度不高,只能检测出图像大致的轮廓,而对于比较细的边缘可能会忽略。Prewitt 和Sobel 算子比Roberts 效果要好一些。LOG 滤波器和Canny 算子的检测效果优于梯度算子,能够检测出图像较细的边缘部分。不同的系统,针对不同的环境条件和要求,选择合适的算子来对图像进行边缘检测。

Part3:算子代码

sobel算子MATLAB实现

 

 1 f=imread('D:/picture/ZiXia.jpg');
 2 f=rgb2gray(f);         %转化成灰度图
 3 f=im2double(f);           %函数im2double 将其值归一化到0~1之间
 4 %使用垂直Sobcl箅子.自动选择阈值
 5 [VSFAT Threshold]=edge(f, 'sobel','vertical');                    %边缘探测
 6 figure,imshow(f),title(' 原始图像,');                      %显示原始图像
 7 figure,imshow(VSFAT),title( '垂直图像边缘检测');
 8 %显示边缘探测图像
 9 %使用水平和垂直Sobel算子,自动选择阈值
10 SFST=edge(f,'sobel',Threshold);
11 figure,imshow(SFST),title('水平和垂直图像边缘检测');
12 %显示边缘探测图像
13 %使用指定45度角Sobel算子滤波器,指定阂值
14 s45=[-2 -1 0;-1 0 1;0 1 2];
15 SFST45=imfilter(f,s45,'replicate');%功能:对任意类型数组或多维图像进行滤波。
16 SFST45=SFST45>=Threshold;
17 figure,imshow(SFST45),title('45度角图像边缘检测') ;
18 %显示边缘探测图像 

 

Roberts算子MATLAB实现

 1 clear all;
 2 clc;
 3 sourcePic=imread('D:/picture/ZiXia.jpg');
 4 grayPic=mat2gray(sourcePic);
 5 [m,n]=size(grayPic);
 6 newGrayPic=grayPic;
 7 robertsNum=0;
 8 robertThreshold=0.2;
 9 for j=1:m-1
10     for k=1:n-1
11         robertsNum = abs(grayPic(j,k)-grayPic(j+1,k+1)) + abs(grayPic(j+1,k)-grayPic(j,k+1));
12         if(robertsNum > robertThreshold)
13             newGrayPic(j,k)=255;
14         else
15             newGrayPic(j,k)=0;
16         end
17     end
18 end
19 figure,imshow(newGrayPic);
20 title('roberts算子的处理结果')

 PreWitt边缘算子MATLAB实现

 1 clear;
 2 sourcePic=imread('D:/picture/ZiXia.jpg');
 3 grayPic=mat2gray(sourcePic);
 4 [m,n]=size(grayPic);
 5 newGrayPic=grayPic;
 6 PrewittNum=0;
 7 PrewittThreshold=0.5;%设定阈值
 8 for j=2:m-1 %进行边界提取
 9     for k=2:n-1
10         PrewittNum=abs(grayPic(j-1,k+1)-grayPic(j+1,k+1)+grayPic(j-1,k)-grayPic(j+1,k)+grayPic(j-1,k-1)-grayPic(j+1,k-1))+abs(grayPic(j-1,k+1)+grayPic(j,k+1)+grayPic(j+1,k+1)-grayPic(j-1,k-1)-grayPic(j,k-1)-grayPic(j+1,k-1));
11         if(PrewittNum > PrewittThreshold)
12             newGrayPic(j,k)=255;
13         else
14             newGrayPic(j,k)=0;
15         end
16     end
17 end
18 figure,imshow(newGrayPic);
19 title('Prewitt算子的处理结果')

Laplacian边缘算子

 1 clear;
 2 sourcePic=imread('lena.jpg');%图像读入
 3 grayPic=mat2gray(sourcePic);%实现图像的矩阵归一化操作
 4 [m,n]=size(grayPic);
 5 newGrayPic=grayPic;
 6 LaplacianNum=0;%经Laplacian操作得到的每个像素的值
 7 LaplacianThreshold=0.2;%设定阈值
 8 for j=2:m-1 %进行边界提取
 9     for k=2:n-1
10         LaplacianNum=abs(4*grayPic(j,k)-grayPic(j-1,k)-grayPic(j+1,k)-grayPic(j,k+1)-grayPic(j,k-1));
11         if(LaplacianNum > LaplacianThreshold)
12             newGrayPic(j,k)=255;
13         else
14             newGrayPic(j,k)=0;
15         end
16     end
17 end
18 figure,imshow(newGrayPic);
19 title('Laplacian算子的处理结果')

canny边缘算子

 

1 I = imread('D:/picture/ZiXia.jpg');  % 读入图像
2 I=rgb2gray(I);               % 转化为灰色图像
3 imshow(I);title('原图')
4 BW1 = edge(I,'canny');  % 调用canny函数
5 figure,imshow(BW1);     % 显示分割后的图像,即梯度图像
6 title('matlab canny')

 使用封装好的函数实现上述算子

 1 image=imread('C:/lenagray.jpg')
 2 image=im2double(image);
 3 image1=edge(image, 'roberts');;
 4 subplot(231);
 5 imshow(image1);
 6 title('roberts算子的处理结果')
 7 image2=imfilter(image,fspecial('prewitt'));
 8 subplot(232);
 9 imshow(image2);
10 title('Prewitt算子的处理结果')
11 image3=imfilter(image,fspecial('sobel'));
12 subplot(233);
13 imshow(image3);
14 title('sobel算子的处理结果')
15 image1=edge(image, 'canny');;
16 subplot(234);
17 imshow(image1);
18 title('canny算子的处理结果')
19 imfilter(image,fspecial('Laplacian'));
20 subplot(235);
21 imshow(image1);
22 title('Laplacian算子的处理结果')

 

 

转载于:https://www.cnblogs.com/henuliulei/p/10645109.html

2017-10-02 18:09:34 cymy001 阅读数 744

本文内容参考《数字图像处理基础》Wilhelm Burger等著。
根据图像数组获得边缘检测信息,然后循着已检测到的边缘点找到轮廓线。

轮廓跟踪:从那些边缘强度较大的地方开始,沿着两个不同方向跟踪边缘点,直到这两条轨迹相遇并形成一条闭合的轮廓线。(灰度梯度弱——>边缘消失;交叉边缘——>歧义)

边缘图:通过“阈值运算”对一个“图像像素”是否属于边缘点做“二值判断”(这里需要被判断的“图像像素”是指由“各种边缘检测算子得到的边缘强度”,“阈值”可以是固定的,也可以说是自适应的),经过“阈值运算”的结果存为一张“二值的边缘图像”,即“边缘图”。
全局阈值化处理的后处理方法,如霍夫变换,能很好处理不完整的边缘图。

边缘锐化:

从原图像函数f(x)上减去其二阶导数f′′(x)的一部分,如下图:
这里写图片描述
二维函数f(x,y)的拉普拉斯算子

Δf(x,y)=2f2x(x,y)+2f2y(x,y)

由中心差分公式易得
HLx=2f2x(x,y)=(121),HLy=2f2y(x,y)=121

HL=HLx+HLy=010141010

接下来对原图像I,用HL算子滤波,然后再用I减去此滤波结果,即得锐化结果

I˘Iω(HLI)

拉普拉斯滤波器对噪声相当敏感,可以采用预平滑措施(如高斯平滑)减弱噪声的影响。

2016-09-03 15:58:29 NNNNNNNNNNNNY 阅读数 13128

关于“轮廓检测”和“边缘检测”这两个自己也弄的不是特别清楚,可能确实比较相似吧。下面简单说一下自己的看法。
区别:
边缘检测主要是通过一些手段检测数字图像中明暗变化剧烈(即梯度变化比较大)像素点,偏向于图像中像素点的变化。如canny边缘检测,结果通常保存在和源图片一样尺寸和类型的边缘图中。
轮廓检测指检测图像中的对象边界,更偏向于关注上层语义对象。如OpenCV中的findContours()函数, 它会得到每一个轮廓并以点向量方式存储,除此也得到一个图像的拓扑信息,即一个轮廓的后一个轮廓、前一个轮廓、父轮廓和内嵌轮廓的索引编号。
联系:
我们在做图像的轮廓检测时通常可以先检测边缘,再将检测到的边缘进行进一步处理,得到图像的轮廓。

参考:
1. http://wangmurong.org.cn/2015/10/21/edge-detection-segmentation-contour-detection/
2. Opencv官方例程中的contours2.cpp
3. 《OpenCV3编程入门》 浅墨_毛星云

2017-04-19 19:54:00 The_star_is_at 阅读数 9136

实验三   图像轮廓提取与边缘检测


一、实验目的:

理解并掌握对二值图像进行轮廓提取的相关算法(比如,掏空内部点法),以及用于图像边缘检测和提取的典型微分算子(梯度算子和拉普拉斯算子)。

二、实验环境:

计算机、Windows XP操作系统,Matlab7.0

二、实验内容:

1、根据掏空内部点算法,运用Matlab编程实现二值图像的轮廓提取。

%以下适用于黑色背景白色前景的二值图像轮廓提取(以二值图像circles为例)

BW=imread('circles.png');     %二值图像circlesuint80黑,255

subplot(1,2,1);  imshow(BW);  title('二值图像');

[M, N]=size(BW);     %M行,N

BW_Buffer=BW;

for i=2: M-1

for j=2: N-1

if (BW(i, j)==255 & BW(i-1, j)==255 & BW(i+1, j)==255 & BW(i, j-1)==255 & BW(i, j+1)==255 & BW(i-1, j-1)==255 & BW(i-1, j+1)==255 & BW(i+1, j-1)==255 & BW(i+1, j+1)==255)    %说明BW(i, j)是前景中的一个内部点

       BW_Buffer(i, j)=0;    %掏空该内部点,即将该内部点置成与背景相同灰度

end

end

end

subplot(1,2,2);  imshow(BW_Buffer);  title('提取轮廓');


%以下适用于白色背景黑色前景的二值图像轮廓提取(以二值图像source为例)

BW=imread('source.bmp');      %二值图像sourceuint80黑,255

subplot(1,2,1);  imshow(BW);  title('二值图像');

[M, N]=size(BW);   %M行,N

BW_Buffer=BW;

for i=2: M-1

for j=2: N-1

if (BW(i, j)==0 & BW(i-1, j)==0 & BW(i+1, j)==0 & BW(i, j-1)==0 & BW(i, j+1)==0 & BW(i-1, j-1)==0 & BW(i-1, j+1)==0 & BW(i+1, j-1)==0 & BW(i+1, j+1)==0)      %说明BW(i, j)是前景中的一个内部点

       BW_Buffer(i, j)=255;   %掏空该内部点,即将该内部点置成与背景相同灰度

end

end

end

subplot(1,2,2);  imshow(BW_Buffer);  title('提取轮廓');

注意:使用掏空内部点的方法来提取二值图像的轮廓时,不能直接在原始二值图像矩阵上判断一个点掏空一个点,否则对前面像素的掏空操作会影响到对后面像素的判断结果。

解决方法:创建原始二值图像矩阵的副本(即图像矩阵BW_Buffer),在原始二值图像矩阵上执行判断操作,即依次判断每个像素点是否为前景中的内部点,如果是,则在图像矩阵BW_Buffer上执行掏空内部点的操作。

2、以灰度图像ricecameraman为例,利用Matlab图像处理工具箱中的edge函数,分别使用Roberts 算子、Sobel算子、Prewitt 算子对其进行边缘检测。

(1)函数格式: BW = edge(I, 'method', thresh)

(2)格式说明:edge函数输入灰度图像矩阵I,输出二值图像矩阵BW;参数'method'用于指定所使用的边缘检测算子,可以是'roberts''sobel''prewitt''log''canny';参数thresh用于指定梯度门限值(也称梯度阈值),图像中梯度值大于等于门限值thresh的像素用白色(1)表示,说明这些地方对应边缘,梯度值小于门限值thresh的像素用黑色(0)表示(edge function will ignore all edges that are not stronger than thresh)。若不指定参数thresh,则edge函数会自动选择阈值。所以edge函数最终将原始灰度图像中的边缘和背景用二值图像的形式展现出来,以突出边缘的位置,达到边缘检测的目的。

(3)程序如下:

I=imread('rice.png');

subplot(2,2,1);  imshow(I);  title('原始图像');

[BW1,thresh1]=edge(I,'roberts');  %进行Roberts算子边缘检测并返回门限值

[BW2,thresh2]=edge(I,'sobel');    %进行Sobel算子边缘检测并返回门限值

[BW3,thresh3]=edge(I,'prewitt');  %进行Prewitt算子边缘检测并返回门限值

subplot(2,2,2);  imshow(BW1);  title('Roberts算子边缘检测结果');

subplot(2,2,3);  imshow(BW2);  title('Sobel算子边缘检测结果');

subplot(2,2,4);  imshow(BW3);  title('Prewitt算子边缘检测结果');

若向原始图像中加入随机噪声(比如高斯噪声),之后再对噪声图像分别运用Roberts 算子、Sobel算子、Prewitt 算子、Log算子(高斯-拉普拉斯算子)进行边缘检测,观察检测结果,试比较4种边缘检测算子的抗噪声干扰能力。

I=imread('rice.png');

subplot(2,3,1);  imshow(I);  title('原始图像');

G=imnoise(I, 'gaussian');  %向原始图像中加入高斯噪声

subplot(2,3,2);  imshow(G);  title('噪声图像');

BW1=edge(G, 'roberts');  %进行Roberts算子边缘检测

BW2=edge(G, 'sobel');    %进行Sobel算子边缘检测

BW3=edge(G, 'prewitt');  %进行Prewitt算子边缘检测

BW4=edge(G, 'log');      %进行Log算子边缘检测

subplot(2,3,3);  imshow(BW1);  title('Roberts算子边缘检测结果');

subplot(2,3,4);  imshow(BW2);  title('Sobel算子边缘检测结果');

subplot(2,3,5);  imshow(BW3);  title('Prewitt算子边缘检测结果');

subplot(2,3,6);  imshow(BW4);  title('Log算子边缘检测结果');