author:zox
实验环境:Matlab2019a
图像分割就是将一幅图像分成若干个部分、区域,然后将其中自己感兴趣的部分,或对自己有意义的区域提取出来,由此获得一些有用的图像特征和信息的过程。
图像分割有很多方法,其中基于阈值的分割方法最常使用。主要是利用图像中要提取的目标和背景在灰度上的差异,选择一个合适的阈值。
①直方图阈值法
:通过图像的灰度直方图来选择阈值,图象被处理为二值图像。
②半阈值选择法
:根据直方图或其他方法选择合适的阈值,但只对背景部分进行处理,这样目标物体就还是多值图像,背景是二值图像。
③迭代阈值法
:通过程序不断迭代出所需要的阈值,再对图像二值化处理。
④Otsu算法
:也叫最大类间差法,取一个最优阈值把原图像分为前景色(A部分)与背景色(B部分),两部分的类间方差越大,说明两部分差别越大,便能有效的分割图像。
⑤最大熵阈值分割法
:计算所有分割阈值下的图像总熵,找到最大的熵,将最大熵对应的分割阈值作为最终的阈值,图像中灰度大于此阈值的像素作为前景,否则作为背景。
迭代阈值法产生阈值,可以通过程序自动计算出比较合适的分割阈值。其计算步骤如下:
(1)选择灰度图的平均灰度值作为初始阈值 T 0 T0 T0 ,通过 T 0 T0 T0将图像的平均灰度值分为两组;
(2)计算小于等于 T 0 T0 T0的平均值 T 1 T1 T1, 和大于 T 0 T0 T0的平均值 T 2 T2 T2;
(3)新的阈值为 T = ( T 1 + T 2 ) / 2 T = (T1 + T2)/ 2 T=(T1+T2)/2;
(4)比较 T T T和 T 0 T0 T0,若相等,则返回 T T T,即为迭代阈值; 否则 T 0 = T T0 = T T0=T,重复(1)-(3)
最终的 T 0 T0 T0就是我们所需要的阈值,再根据阈值可对图像进行二值化处理。
O t s u Otsu Otsu(大津法或最大类间方差法)使用的是聚类的思想,把图像的灰度数按灰度级分成2个部分,使得两个部分之间的灰度值差异最大,每个部分之间的灰度差异最小,通过方差的计算来寻找一个合适的灰度级别来划分。该算法的具体流程如下:
(1)根据某个阈值t,把原图像分为A部分(每个像素值>=t)与B部分(每个像素值
(3)根据公式计算:类间方差 ( I C V ) = P A ∗ ( a v e A − a v e a l l ) 2 + P B ∗ ( a v e B − a v e a l l ) 2 (ICV)=PA*(ave_A-ave_all)^2+PB*(ave_B-ave_all)^2 (ICV)=PA∗(aveA−aveall)2+PB∗(aveB−aveall)2
(4)不断改变t,进行以上步骤,不断判断,得到最大类间方差的最优阈值。
O t s u Otsu Otsu算法被认为是图像分割中阈值选取的最佳算法,计算简单,不受图像亮度和对比度的影响。因此,使类间方差最大的分割意味着错分概率最小。
1) R o b e r t s Roberts Roberts算子: 利用局部差分算子寻找边缘, 边缘定位精度较高, 但容易丢失一部分边缘, 同时由于图像没经过平滑处理, 因此不具备能抑制噪声能力。 对陡峭边缘且含噪声少的图像效果较好。
首先使用以下模板分别对图像进行卷积操作:
m o d e l x = [ 0 0 0 0 − 1 0 0 0 1 ] m o d e l y = [ 0 0 0 0 0 − 1 0 1 0 ] \ \ modelx=\left[\begin{matrix}0&0&0\\0&-1&0\\0&0&1\\\end{matrix}\right]\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ modely=\left[\begin{matrix}0&0&0\\0&0&-1\\0&1&0\\\end{matrix}\right] modelx=⎣⎡0000−10001⎦⎤ modely=⎣⎡0000010−10⎦⎤
得到 Z x , Z y Z_x\ ,Z_y Zx ,Zy;
接着根据公式对图像的所有点进行处理: Z = Z x 2 + Z y 2 Z=\sqrt{Z_x^2+Z_y^2} Z=Zx2+Zy2;
2) S o b e l Sobel Sobel算子: 先做加权平滑处理, 再做微分运算, 平滑部分的权值有些差异, 对噪声具有一定的抑制能力, 但不能完全排除虚假边缘。 虽然这两个算子边缘定位效果不错, 但检测出的边缘容易出现多像素宽度。
首先使用以下模板分别对图像进行卷积操作:
m o d e l x = [ − 1 − 2 − 1 0 0 0 1 2 1 ] m o d e l y = [ 1 0 − 1 2 0 − 2 1 0 − 1 ] \ \ modelx=\left[\begin{matrix}-1&-2&-1\\0&0&0\\1&2&1\\\end{matrix}\right]\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ modely=\left[\begin{matrix}1&0&-1\\2&0&-2\\1&0&-1\\\end{matrix}\right] modelx=⎣⎡−101−202−101⎦⎤ modely=⎣⎡121000−1−2−1⎦⎤
得到 Z x , Z y Z_x\ ,Z_y Zx ,Zy;
接着根据公式对图像的所有点进行处理: Z = Z x 2 + Z y 2 Z=\sqrt{Z_x^2+Z_y^2} Z=Zx2+Zy2;
3) L O G LOG LOG算子: 先用高斯函数平滑滤波, 后用 L a p l a c i a n Laplacian Laplacian算子检测边缘, 克服 L a p l a c i a n Laplacian Laplacian算子抗噪声差的缺点, 但同时也平滑掉比较尖锐的边缘, 尖锐边缘无法检被测到。
使用以下模板对图像进行卷积操作:
m o d e l = [ − 2 − 4 − 4 − 4 − 2 − 4 0 8 0 − 4 − 4 8 24 8 − 4 − 4 0 8 0 − 4 − 2 − 4 − 4 − 4 − 2 ] model=\left[\begin{matrix}-2&-4&-4&-4&-2\\-4&0&8&0&-4\\-4&8&24&8&-4\\-4&0&8&0&-4\\-2&-4&-4&-4&-2\\\end{matrix}\right] model=⎣⎢⎢⎢⎢⎡−2−4−4−4−2−4080−4−48248−4−4080−4−2−4−4−4−2⎦⎥⎥⎥⎥⎤
通过以上四种算子对图像进行处理可以得到图像的边缘信息。实验时直接使用的是实验二中所编写的函数。
为了将肺部区域分割出来,要进行如下的操作:
(1)首先采用阈值分割法分割出粗略的肺部分,使用前面编写的myotsu函数来获取图像阈值,对图像进行二值化处理。
(2)分析得到的图片中胸腔部分为白色,而我们需要的是肺部分为白色,其他背景为黑色,所以对图像进行反色处理。
(3)然后通过系统函数bwlabel()标记连通区域,再统计各个连通区域的面积来对气管部分和背景置黑色来统一背景。
标记的原则如下:二值图像中值为 0 的区域 ( 对应于反色后图像中的胸腔内非肺区域 ) 作为背景,不予标记; 值≥1的区域 ( 对应于反色后图像中的目标肺组织区域、胸腔外区域和气管部分 ) 进行联通标记 , 并从数值 1 开始计数, 即标记 1 为第一个联通区域,标记2为第二个联通区域,以此类推。
由于反色后标记区域的面积不同,所以计算各个连通区域的面积,根据连通区域的标号规则得到背景和气管部分所在的标号。
再将根据面积大小找到的部分的像素点(即非肺区域)对应的原二值图像处赋值成 0,标记值大于 1 的像素点(即目标肺区域)对应的原二值图像处赋值成 1。
(1)imread(path)函数:从图像所在路径读取图像的数据信息存为矩阵。
(2)imshow(image)函数:将读取到的图像显示到figure中。
(3)subplot(m,n,p)函数:subplot函数是将多个图画到一个平面上的工具。其中m、n表示一个m行n列的大画框,可显示 m ∗ n m*n m∗n个图 ,p表示图所在位置。
(4)构造函数
function[输出形参]=函数名([输入形参])
函数体
(5)size()函数
[m,n] = size(X)
返回矩阵X的尺寸信息, 并存储在m、n中。其中m中存储的是行数,n中存储的是列数。
(6)zeros(m,n)函数:产生 m ∗ n m*n m∗n的double类型零矩阵。
(7)im2double(x):数据变为双精度,便于计算,且使计算更加准确。
(8)min():获得最小元素
(9)max():获得最大元素
(10)abs():求数组平均值
(11)find(A):获得符合条件A的元素
(12)mean():求数组平均值
(13)bwlabel():获取连通区域
(14)myconvolve():实验二中编写的实现卷积操作的函数
(15)mysharpen():实验二中编写的根据选择的算子获取图像的边缘的函数
clear all;close all;clc;
%% 1、采用阈值法实现图像分割,分别采用两种阈值选取方法实现。
I=imread('Fig1006(a).tif');
threshold1=myiteration(I);
threshold2=myotsu(I);
J1=im2bw(I,threshold1);
J2=im2bw(I,threshold2);
figure,suptitle('基于阈值的图像分割'); %Figure 1
subplot(131),imshow(I),axis on,title('原图') ;
subplot(132),imshow(J1),axis on,title('迭代阈值法');
subplot(133),imshow(J2),axis on,title('otsu阈值法') ;
%% 2、分别用Roberts,Sobel和拉普拉斯高斯算子对图像进行边缘检测,比较三种算子处理的不同之处。
E1=mysharpen(I,'Roberts');
E2=mysharpen(I,'Sobel');
E3=mysharpen(I,'Log');
figure,suptitle('边缘检测'); %Figure 2
subplot(221), imshow(I), title('原图');
subplot(222), imshow(E1), title('Roberts算子');
subplot(223), imshow(E2), title('Sobel算子');
subplot(224), imshow(E3), title('Log算子');
%% 3、实现肺的分割,结果包括两部分:肺(白色显示)和背景(黑色显示)。
Lung=imread('lung.jpg');
threshold=myotsu(Lung);
S1=im2bw(Lung,threshold);%二值化,将肺和胸腔等其他部分分隔开
S2=~S1;%反色,使肺部变为白色
X8=mycut(S2);%去掉胸腔外的背景和气管
figure,suptitle('肺的分割'); %Figure 3
subplot(221),imshow(Lung),axis on,title('原图') ;
subplot(222),imshow(S1),axis on,title('二值化');
subplot(223),imshow(S2),axis on,title('反色') ;
subplot(224),imshow(X8),axis on,title('分割后');
% 函数myiteration:迭代阈值法
% 输入参数:I:原图像
% 输出参数:阈值threshold
% 使用函数:im2double(I):变为双精度
% min():最小元素
% max():最大元素
% find(A):符合条件A的元素
% mean():求数组平均值
% abs():求绝对值
function threshold=myiteration(I)
I=im2double(I); %变为双精度,即0-1
T0=0.01; %参数T0
T1=(min(I(:))+max(I(:)))/2;%选取图像中最大像素和最小像素的中阈值作为T1
r1=find(I>T1);%灰度值大于T1的
r2=find(I<=T1);%其他
T2=(mean(I(r1))+mean(I(r2)))/2;%新的阈值T2 %mean函数是一个求数组平均值的函数
while abs(T2-T1)<T0
T1=T2;
r1=find(I>T1);%灰度值大于T1的
r2=find(I<=T1);%其他
T2=(mean(I(r1))+mean(I(r2)))/2;%新的阈值T2
end
threshold=T2;
% 函数myotsu:最大类间差法
% 输入参数:I:原图像
% 输出参数:阈值threshold
% 使用函数:size(I):求矩阵大小
% rgb2gray():rgb转化为灰度图像
% im2double():变为双精度,即0-1
function threshold=myotsu(I)
[M,N,i]=size(I); %得到图像行列值
if i>1
I=rgb2gray(I);%若不是灰度图像则先处理为灰度图像
end
I=im2double(I); %变为双精度,即0-1
number_all=M*N; %总像素值
hui_all=0; %预设图像总灰度值为0
ICV_t=0; %预设最大方差为0
for i=1:M
for j=1:N
hui_all=hui_all+I(i,j);%得到图像总灰度值
end
end
all_ave=hui_all*255/number_all; %图像灰度值的总平均值
%t为某个阈值,把原图像分为A部分(每个像素值>=t)与B部分(每个像素值<t)
for t=0:255 %不断试探最优t值
hui_A=0; %不断重置A部分总灰度值
hui_B=0; %不断重置B部分总灰度值
number_A=0; %不断重置A部分总像素
number_B=0; %不断重置B部分总像素
for i=1:M %遍历原图像每个像素的灰度值
for j=1:N
if (I(i,j)*255>=t) %分割出灰度值>=t的像素
number_A=number_A+1; %得到A部分总像素
hui_A=hui_A+I(i,j); %得到A部分总灰度值
elseif (I(i,j)*255<t) %分割出灰度值<t的像素
number_B=number_B+1; %得到B部分总像素
hui_B=hui_B+I(i,j); %得到B部分总灰度值
end
end
end
PA=number_A/number_all; %得到A部分像素总数与图像总像素的比列
PB=number_B/number_all; %得到B部分像素总数与图像总像素的比列
A_ave=hui_A*255/number_A; %得到A部分总灰度值与A部分总像素的比例
B_ave=hui_B*255/number_B; %得到B部分总灰度值与B部分总像素的比例
ICV=PA*((A_ave-all_ave)^2)+PB*((B_ave-all_ave)^2); %Otsu算法
if (ICV>ICV_t) %不断判断,得到最大方差
ICV_t=ICV;
k=t; %得到最大方差的最优阈值
end
end
threshold=k/255; %输出阈值
% 函数mycut:根据连通性去掉图片胸腔外的背景和气管
% 输入参数:I:原图像
% 输出参数:OUT:处理后的图片数据
% 使用函数:size(I):求矩阵大小
% zeros():建全零矩阵
function OUT=mycut(I)
[x,y]=size(I);
[X8,N] = bwlabel(I,8);%8连通
% s=regionprops(X8,'Area');
% X8=ismember(X8,find([s.Area]>=7000&[s.Area]<=40000));
%% 计算各个连通区域的面积
Area=zeros(N,1);
for i=1:x
for j=1:y
for k=1:N
if X8(i,j)==k
Area(k,1)=Area(k,1)+1;
end
end
end
end
%% 将白色部分连通区域的背景部分、气管部分置黑
for k=1:N
if Area(k,1)>=7000 && Area(k,1)<=40000
for i=1:x
for j=1:y
if X8(i,j)==k-1
X8(i,j)=0;
end
end
end
end
end
OUT=logical(X8);