
PS: 计算机视觉课程中的一项重要任务. 作为一个外行,我在互联网上搜索信息以学习和复制时踩到了一些陷阱. 分配后,我分享了它.
1. 问题描述
在计算机视觉/机器视觉领域,图像分割的应用非常普遍. 它指的是将数字图像细分为多个图像子区域的过程. 图像分割的目的是简化或更改图像的表示形式,使图像更易于理解和分析. 它的基本形式通常是在图像中定位对象和边界,结果是图像上一些子区域或轮廓线的集合. 图像分割方法包括阈值处理(二值化),聚类,边缘检测和区域增长. 没有统一的范式可以解决图像分割问题. 通常,它必须与领域知识完全结合才能更有效地解决问题.
边缘检测是基于灰度的突然变化分割图像的常用方法. 其本质是提取图像中不连续部分的特征. 目前,常见的边缘检测算子包括差分算子,罗伯茨算子,Sobel算子,Prewitt算子,Log算子和Canny算子. 其中,Canny算子是计算机科学家John F. Canny在1986年提出的边缘检测算子. 它是目前理论上最完整的边缘检测算法. Canny操作员API已内置在常用的图像处理工具中,例如MATLAB和OpenCV. 这项大工作将根据Canny运算符的算法原理在MATLAB环境中重现canny算子边缘检测的简单理解,并与MATLAB内置的Canny运算符的效果进行比较.
2. 算法原理
基于Canny算子的边缘检测分五个步骤,依次为高斯滤波,像素梯度计算,非最大抑制,滞后阈值处理和孤立弱边缘抑制.
(1)高斯滤波
高斯滤波使用的高斯核是(c: a: f: 7: b: d: 4: f: 2: 2: b: f: 1: d: 6: 3: 8: 9: e: 9: 5: c: 8: 4: 2: 4: e: 0: a: 6: 2: d: 0}和二维高斯函数,二维的标准偏差通常相同,形式为:

高斯滤波,即使用一定大小的二维高斯核对图像进行卷积. 因为数字图像的数据形式是离散矩阵,所以高斯核是连续高斯函数的离散近似,它是通过对高斯表面进行离散采样和归一化而获得的. 例如,大小为,标准偏差为
高斯内核为:
确定高斯核后,可以将其与图像离散卷积.
(2)使用Sobel运算符计算像素梯度
Sobel运算符是两个,即
和
. 前者用于计算图像
方向像素梯度矩阵
,用于计算图像
方向像素梯度矩阵
. 具体形式为:

其中是灰度图像矩阵,
表示互相关运算(在将卷积核旋转180°之后,卷积运算可以被视为互相关运算. 应当注意,图像矩阵坐标系的原点在左上角,
正面方向是从左到右,
正面方向是从上到下. 由
可以计算梯度强度矩阵.
(3)非最大像素梯度抑制
非最大像素梯度抑制的目的是消除边缘检测带来的虚假响应,并起到“使边缘变薄”的作用. 基本方法是将当前像素的梯度强度与相邻像素在正和负梯度方向上的梯度强度进行比较. 如果它是最大的(即极值),则将像素作为边缘点. 不使用它作为边缘点就可以抑制它. 为了获得更准确的计算结果,通常在沿梯度方向的两个相邻像素之间使用线性插值,以获得要比较的像素梯度.
图1.像素梯度方向的线性插值
如图1所示,一个像素的邻接关系可分为4个区域,每个区域包含上下两部分. 如果中心像素(c: a: f: 7: b: d: 4: f: 2: 2: b: f: 1: d: 6: 3: 8: 9: e: 9: 5: c: 8: 4 : 2: 2: 4: e: 0: a: 6: 2: d: 0}方向梯度强度为,
方向梯度强度为
,渐变强度为
,然后根据
和
可以先确定渐变方向所属的区域,然后再根据其像素再确定其方向像素梯度方向对相邻点的像素梯度进行线性插值,以在正和负梯度方向上获得两个梯度强度(c: 8: 9: b: d: 1: 7: 6: 7: a: 1: 7 : 3: 3: b: c: 7: e: 3: a: d: 2: 5: e: 5: 3: b: 1: 9: b: f: d}和
. 公式如下:

其他三个区域的计算方法相似. 应该注意的是,如果,表示像素没有像素梯度,是非边缘.
(4)阈值滞后处理
定义一个高阈值和一个低阈值. 梯度强度低于低阈值的像素被抑制,不被视为边缘点;高阈值以上的像素定义为强边缘,并保留为边缘点;高和低阈值之间的那些被定义为弱边缘,并留待进一步处理.
(5)孤立弱边缘抑制
通常,将由真实边缘引起的弱边缘像素连接到强边缘像素,并且不连接噪声响应. 通过查看弱边缘像素及其8个相邻像素,可以基于它们与强边缘的连接进行判断. 通常,可以定义为只要相邻像素之一是强边缘像素点,就可以将弱边缘保留为强边缘,即真实边缘点.
3. 程序流程图
图2.程序流程图

4. 实验结果
在MATLAB R2016a中,实现了基于Canny运算符的边缘检测,并使用MATLAB中内置的Canny边缘检测API进行了四组比较实验. 其中,“ Lena”和“ House”是计算机视觉领域常用的测试图片canny算子边缘检测的简单理解,“ Wing”是出差时手机拍摄的照片,“ Little Liu Ya”是微信表情包图片
图3.实验结果-Lena
,
图4.实验结果库
图5.实验结果翼{6: 2: a: 4: a: 5: 4: 0: 3: 6: 6: b: e: e: d: b: b: d: 7: 9: 0: a: 0: f: 7: c: 9: 1: 1: 1: 5: c: f)
图6.实验结果-小刘娅
为了获得更好的检测结果,必须反复调整自写边缘检测程序中的滤波器参数以及滞后阈值处理中的高低阈值. MATLAB的Canny边缘检测API使用其默认参数. 推测可以通过自适应算法来计算高阈值和低阈值. 图3和图4的结果表明,与API相比,由自己编写的Canny检测程序提取了更多详细信息,但还保留了更多的本地噪声. API提取的轮廓特征更清晰,但局部失真相对较重. 图5中的结果表明,与API相比,一个自编写程序可以提取更清晰的机翼轮廓,并保留较少的云纹理. 图6中的效果差别不大. 从实验过程中可以看出,Canny运算符仍然对过滤参数的选择和高低阈值敏感,这需要在实际应用过程中进行反复调试. 由于时间和能力的原因,目前尚无进一步研究和尝试进行参数自适应选择.
5. 源代码
clc;
clear;
%--------------------------------------------------%图片导入与预处理
% f_original = imread('lena.png'); %导入lena图片
% f_original = imread('house.png'); %导入房屋图片
% f_original = imread('wing.tif'); %导入机翼图片
f_original = imread('xiaoliuya.jpg'); %导入小刘鸭
f_grey = rgb2gray(f_original); %转换为灰度图像
%------------------------------------------------- %图片导入与预处理
%--------------------------------------------------%自行编写的CANNY算子边缘检测
%1-高斯滤波
gw = fspecial('gaussian',[5,5],0.5); %高斯滤波设置核,5*5,标准差为0.5
f_filter = imfilter(f_grey,gw,'replicate'); %高斯滤波
f = f_filter;
%2-利用Sobel算子计算像素梯度
Sobel_X = [-1,0,1;-2,0,2;-1,0,1]; %X方向Sobel算子(互相关算子,非卷积算子)
Sobel_Y = [-1,-2,-1;0,0,0;1,2,1]; %Y方向Sobel算子(互相关算子)
[rowNum,columnNum] = size(f);
f_extend = zeros(rowNum+2,columnNum+2); %图像扩充,边界补充为0
for i = 2:rowNum+1
for j = 2:columnNum+1
f_extend(i,j) = f(i-1,j-1);
end
end
Gx = zeros(rowNum,columnNum);
Gy = zeros(rowNum,columnNum);
for i = 2:rowNum+1 %计算x向和y向梯度
for j = 2:columnNum+1
window = [f_extend(i-1,j-1),f_extend(i-1,j),f_extend(i-1,j+1);...
f_extend(i,j-1),f_extend(i,j),f_extend(i,j+1);...
f_extend(i+1,j-1),f_extend(i+1,j),f_extend(i+1,j+1)];
Gx(i-1,j-1) = sum(sum(Sobel_X .* window)); %计算x向梯度
Gy(i-1,j-1) = sum(sum(Sobel_Y .* window)); %计算y向梯度
end
end
Sxy = sqrt(Gx.*Gx + Gy.*Gy); %梯度强度矩阵计算
%3-非极大值抑制
indexD = zeros(rowNum,columnNum);
for i = 1:rowNum %判断梯度方向所属区间,Gx=Gy=0,则令其为5,肯定不是边界点
for j = 1:columnNum
ix = Gx(i,j);
iy = Gy(i,j);
if (iy<=0 && ix>-iy) || (iy>=0 && ix<-iy) %梯度方向属于区间1
indexD(i,j) = 1;
elseif (ix>0 && ix<=-iy) || (ix<0 && ix>=-iy) %梯度方向属于区间2
indexD(i,j) = 2;
elseif (ix<=0 && ix>iy) || (ix>=0 && ix<iy) %梯度方向属于区间3
indexD(i,j) = 3;
elseif (iy<0 && ix<=iy) || (iy>0 && ix>=iy) %梯度方向属于区间4
indexD(i,j) = 4;
else %Gx和Gy均为0,无梯度,肯定非边缘
indexD(i,j) = 5;
end
end
end
Gup = zeros(rowNum,columnNum);
Gdown = zeros(rowNum,columnNum);
for i = 2:rowNum-1 %计算非边界处的插值梯度强度
for j = 2:columnNum-1
ix = Gx(i,j);
iy = Gy(i,j);
if indexD(i,j) == 1 %计算区间1内插值梯度,Gup为上方区间的梯度,Gdown为下方区间的梯度
t = abs(iy./ix);
Gup(i,j) = Sxy(i,j+1).*(1-t) + Sxy(i-1,j+1).*t;
Gdown(i,j) = Sxy(i,j-1).*(1-t) + Sxy(i+1,j-1).*t;
elseif indexD(i,j) == 2 %计算区间2内插值梯度
t = abs(ix./iy);
Gup(i,j) = Sxy(i-1,j).*(1-t) + Sxy(i-1,j+1).*t;
Gdown(i,j) = Sxy(i+1,j).*(1-t) + Sxy(i+1,j-1).*t;
elseif indexD(i,j) == 3 %计算区间3内插值梯度
t = abs(ix./iy);
Gup(i,j) = Sxy(i-1,j).*(1-t) + Sxy(i-1,j-1).*t;
Gdown(i,j) = Sxy(i+1,j).*(1-t) + Sxy(i+1,j+1).*t;
elseif indexD(i,j) == 4 %计算区间4内插值梯度
t = abs(iy./ix);
Gup(i,j) = Sxy(i,j-1).*(1-t) + Sxy(i-1,j-1).*t;
Gdown(i,j) = Sxy(i,j+1).*(1-t) + Sxy(i+1,j+1).*t;
end
end
end
Sxy_NMX = zeros(rowNum,columnNum); %判断是否为梯度方向极大值
for i = 1:rowNum
for j = 1:columnNum
if Sxy(i,j) >= Gup(i,j) && Sxy(i,j) >= Gdown(i,j) %若为梯度方向极大值,则保留;
Sxy_NMX(i,j) = Sxy(i,j); %否则,进行抑制(置0)
end
end
end
%4-滞后阈值法+5-抑制孤立的弱边缘
f_final = zeros(rowNum,columnNum);
%Tl为高阈值,Th为低阈值,connectNum为联通参数,一般为1
% Tl = 60; %lena
% Th = 120;
% connectNum = 1;
% Tl = 40; %房屋
% Th = 120;
% % connectNum = 1;
% Tl = 22; %机翼
% Th = 40;
% connectNum = 1;
Tl = 15; %小刘鸭
Th = 35;
connectNum = 1;
for i = 2:rowNum-1
for j = 2:columnNum-1
if Sxy_NMX(i,j) >= Th %高于高阈值的像素为强边缘
f_final(i,j) = 1;
elseif Sxy_NMX(i,j) <= Tl %低于低阈值的像素为非边缘
f_final(i,j) = 0;
else %位于高低阈值之间的像素为弱边缘,进行孤立性检测
count = 0;
if Sxy_NMX(i-1,j-1)~=0 %左上方像素
count = count+1;
end
if Sxy_NMX(i-1,j)~=0 %上方像素
count = count+1;
end
if Sxy_NMX(i-1,j+1)~=0 %右上方像素
count = count+1;
end
if Sxy_NMX(i,j-1)~=0 %左方像素
count = count+1;
end
if Sxy_NMX(i,j+1)~=0 %右方像素
count = count+1;
end
if Sxy_NMX(i+1,j-1)~=0 %左下方像素
count = count+1;
end
if Sxy_NMX(i+1,j)~=0 %下方像素
count = count+1;
end
if Sxy_NMX(i+1,j+1)~=0 %右下方像素
count = count+1;
end
if count >= connectNum %弱边缘非孤立,则为边缘
f_final(i,j) = 1;
end
end
end
end
%--------------------------------------------------%自行编写的CANNY算子边缘检测
%--------------------------------------------------%MATLAB的CANNY算子边缘检测
[fCanny_dafault,tc] = edge(f_grey,'canny'); %使用默认参数
%--------------------------------------------------%MATLAB的CANNY算子边缘检测
%--------------------------------------------------%测试
subplot(1,3,1);
imshow(f_original);
title('原始图像','fontsize',20);
subplot(1,3,2);
imshow(f_final);
title('自行编写的Canny边缘检测','fontsize',20);
subplot(1,3,3);
imshow(fCanny_dafault);
title('MATLAB内置的Canny边缘检测','fontsize',20);
%--------------------------------------------------%测试
6. 参考文献
[1] blog.csdn.net/mary_0830/article/details/89597672
[2] blog.csdn.net/jmu201521121021/article/details/80622011
[3]维基百科
本文来自电脑杂谈,转载请注明本文网址:
http://www.pc-fly.com/a/jisuanjixue/article-145933-1.html
小王子
我怎么感觉你是来秀优越感的呢
这文章也真是醉了