【MATLAB】图像分割实验

实验目的

充分利用所学各种图像处理技术,实现对图像的综合处理,加深对基础知识的理解和应用。

实验内容

(1)将已知图像进行消噪处理;
(2)对彩色图像进行目标和背景分析;
(3)自编多种分割算法(其中必须包含:最大类间分割、基于迭代的阈值分割、基于Hough变换、基于kmeans分割)将图像进行分割;
(4)提取目标。

代码区:

clc;
clear;
close all;
%(1)将已知图像进行消噪处理
Image=imread('apple.png');
figure;
subplot(221),imshow(Image),title('原图');

%均值滤波
R=imfilter(Image(:,:,1),fspecial('average',[3,3]),'conv');
G=imfilter(Image(:,:,2),fspecial('average',[3,3]),'conv');
B=imfilter(Image(:,:,3),fspecial('average',[3,3]),'conv');
result1=cat(3,R,G,B);
subplot(222),imshow(result1),title('3*3均值滤波');
%高斯滤波
R=imfilter(Image(:,:,1),fspecial('gaussian',[3,3],0.6),'conv');
G=imfilter(Image(:,:,2),fspecial('gaussian',[3,3],0.6),'conv');
B=imfilter(Image(:,:,3),fspecial('gaussian',[3,3],0.6),'conv');
result2=cat(3,R,G,B);
subplot(223),imshow(result2),title('高斯滤波,标准差0.6');
%中值滤波
R=medfilt2(Image(:,:,1),[3 3]);
G=medfilt2(Image(:,:,2),[3 3]);
B=medfilt2(Image(:,:,3),[3 3]);
result3=cat(3,R,G,B);
subplot(224),imshow(result3),title('3*3中值滤波')

结果:
在这里插入图片描述
基于分类思路的三种阈值分割方法

clc;
clear;
close all;
%OTSU方法二值化
Image=rgb2gray(imread('apple.png'));
subplot(121),imshow(Image),title('原始图像');
result=imbinarize(Image);
subplot(122),imshow(result),title('OTSU方法二值化图像');

%最大熵法
tic;
Image=rgb2gray(imread('apple.png'));
subplot(121),imshow(Image),title('原图');
hist=imhist(Image);
bottom=min(Image(:))+1; %图中最小灰度+1,防止下标为0
top=max(Image(:))+1;    %图中最大灰度
J=zeros(256,1);
for t=bottom:top-1
    po=sum(hist(bottom:t));%当前阈值t下的,目标区域概率
    pb=sum(hist(t+1:top)); %当前阈值t下的,背景区域概率
    ho=0;hb=0;
    for j=bottom:t
        ho=ho-log(hist(j)/po+0.01)*hist(j)/po;%当前阈值t下的,目标区域熵计算
    end
    for j=t+1:top
        hb=hb-log(hist(j)/pb+0.01)*hist(j)/pb;%当前阈值t下的,背景区域熵计算
    end
    J(t)=ho+hb;%当前阈值下,熵函数的计算
end
[maxJ,pos]=max(J(:));%熵函数最大值
result=zeros(size(Image));
result(Image>pos)=1;
subplot(122),imshow(result),title('最大熵法分割图像');
toc;
%%
%最小误差法
Image=rgb2gray(imread('apple.png'));
% Image=imread('limi.jpg');
subplot(121),imshow(Image),title('原图');
hist=imhist(Image);
bottom=min(Image(:))+1;top=max(Image(:))+1;%灰度值范围
J=zeros(256,1)+256;     %这样预设置矩阵会有些灰度级值为0,影响选择,故初始化值为0+256,以防有些未处理的0被选为最小。
alpha=0.3;                                %目标区域占总的比重
scope=find(hist>5);%估计概率密度时,每一类要保证一定的样本数目,排除直方图两端
                   %概率很小的灰度级,避免估计不准确导致计算偏差
minthresh=scope(1);maxthresh=scope(end);
if maxthresh>=top
    maxthresh=top-1;
end
for t=minthresh+1:maxthresh
    miuo=0; sigmaho=0;
    for j=bottom:t
        miuo=miuo+hist(j)*double(j);
    end
    pixelnum=sum(hist(bottom:t));
    miuo=miuo/pixelnum;     %当前阈值下,求目标区域的均值
    for j=bottom:t
        sigmaho=sigmaho+(double(j)-miuo)^2*hist(j);
    end
    sigmaho=sigmaho/pixelnum;%当前阈值下,求目标区域的方差
    miub=0;sigmahb=0;
    for j=t+1:top
        miub=miub+hist(j)*double(j);
    end
    pixelnum=sum(hist(t+1:top));
    miub=miub/pixelnum;     %当前阈值下,求背景区域的均值
    for j=t+1:top
        sigmahb=sigmahb+(double(j)-miub)^2*hist(j);
    end
    sigmahb=sigmahb/pixelnum;%当前阈值下,求背景区域的方差
    Epsilonb=0;              %各区域误判概率初始化
    Epsilono=0;
    for j=bottom:t
        pb=exp(-(double(j)-miub)^2/(sigmahb*2+eps))/(sqrt(2*pi*sigmahb)+eps);%当前阈值下背景区域的误判概率
        Epsilonb=Epsilonb+pb;
    end
    for j=t+1:top
        po=exp(-(double(j)-miuo)^2/(sigmaho*2+eps))/(sqrt(2*pi*sigmaho)+eps);%当前阈值下目标区域的误判概率
        Epsilono=Epsilono+po;
    end
    J(t)=alpha*Epsilono+(1-alpha)*Epsilonb;%当前阈值下,整体误判概率
end
[minJ,pos]=min(J(:));%求最小误判概率
result=zeros(size(Image));
result(Image>pos)=1;
subplot(122),imshow(result),title('最小误差分割图像'); 

在这里插入图片描述在这里插入图片描述在这里插入图片描述

自编多种分割算法(其中必须包含:最大类间分割、基于迭代的阈值分割、基于Hough变换、基于kmeans分割)将图像进行分割;

%自编最大类间方差法
clc;
clear;
close all;
Image=imread('apple.png');
subplot(221),imshow(Image),title('原图');
[M,N]=size(Image);
pixelnum=M*N;
% for n=1:256%循环
% hist(n)=length(find(Image==n-1));
% p1(n)=hist(n)/pixelnum;
% end
hist=imhist(Image);%向量实现
p1=hist/pixelnum;
bottom=min(Image(:))+1;%最小灰度+1,防止下标为0
top=max(Image(:))+1;   %图中最大灰度
miub=zeros(256,1);
miuin=zeros(256,1)+10000;%取最小值时加一个较大的常数,消除0对结果的影响
T=zeros(256,1)+10000;
for t=bottom:top%这里bottom+1防止t与bottom相等,top-1防止t与top相等
    miuO=0;miuB=0;sigmaho=0;sigmahb=0;miu=0;
    po=sum(p1(bottom:t));%计算当前阈值下,目标区域在图像中的分布概率
    pB=sum(p1(t+1:top));  %计算当前阈值下,背景区域在图像中的分布概率
    for j=bottom:t
        miuO=miuO+double(j)*p1(j);   %double(j)是为了能够进行浮点数运算
    end
    miuO=miuO/po;         %计算当前阈值下,目标区域在图像中的均值
    for j=t+1:top
        miuB=miuB+double(j)*p1(j);  %double(j)是为了能够进行浮点数运算
    end
    miuB=miuB/pB;         %计算当前阈值下,背景区域在图像中的均值
    miu=po*miuO+pB*miuB;  %计算当前阈值下,图像总体的灰度均值
    for j=bottom:t
        sigmaho=sigmaho+p1(j)*(double(j)-miuO)^2;
    end
    sigmaho=sigmaho/po;%计算当前阈值下,目标区域的方差
    for j=t+1:top
        sigmahb=sigmahb+p1(j)*(double(j)-miuB)^2;%double(j)是为了能够进行浮点数运算
    end
    sigmahb=sigmahb/pB;%计算当前阈值下,背景区域的方差
    %总类类内方差
    miuin(t)=po*sigmaho+pB*sigmahb;
    %两类类间方差
    miub(t)=po*(miuO-miu)^2+pB*(miuB-miu)^2;
    T(t)= miuin(t)/miub(t);
end
[maxmiub,pos]=max(miub(:));%求最大类间方差的值
subplot(222);imshow(im2bw(Image,graythresh(Image)));  title('matlab自带');
subplot(223),imshow(im2bw(Image,pos/256)),title('自编OTSU(最大类间方差的值)');


%%
%基于迭代的阈值分割
clc;
clear;
close all;
Image=imread('apple.png');
% Image=imread('qiang1.jpg');
subplot(121),imshow(Image),title('原图');
T=(max(Image(:))+min(Image(:)))/2;%初始化阈值
equal=false;
while ~equal
    ro=find(Image<T);  %获取目标的像素点
    rb=find(Image>=T); %获取背景的像素点
    NewT=(mean(Image(ro))+mean(Image(rb)))/2;%新的阈值
    equal=(NewT-T)<(1/256);
    T=NewT;
end
subplot(122),imshow(im2bw(Image,T/256)),title('自编迭代方法二值化图像');


%%
%基于Hough变换
clear;
close all;
clc;
Image=rgb2gray(imread('apple.png'));
bw=edge(Image,'canny');%canny算子边缘检测得二值边缘图像
figure,imshow(bw);
[h,t,r]=hough(bw,'RhoResolution',0.5,'Thetaresolution',0.5);
figure,imshow(imadjust(mat2gray(h)),'XData',t,'YData',r,'InitialMagnification','fit');
xlabel('\theta'),ylabel('\rho');
axis on,axis normal,hold on;
P=houghpeaks(h,2);
x=t(P(:,2));y=r(P(:,1));
plot(x,y,'s','color','r');
lines=houghlines(bw,t,r,P,'FillGap',5,'Minlength',7);%检测图像中得直线段
figure,imshow(Image);
hold on;
max_len=0;
for i=1:length(lines)
    xy=[lines(i).point1;lines(i).point2];
    plot(xy(:,1),xy(:,2),'LineWidth',2,'Color','g');
    plot(xy(1,1),xy(1,2),'x','LineWidth',2,'Color','y');
    plot(xy(2,1),xy(2,2),'x','LineWidth',2,'Color','r');
end
hold off


%%
%kmeans
clc;
clear;
close all;
Image=im2double(imread('apple.png'));
[M,N]=size(Image);
subplot(221),imshow(Image),title('原图');
hsv=rgb2hsv(Image);
h=hsv(:,:,1);
h(h>330/360)=0;%接近360°的色调认为是0°
training=h(:);%获取训练数据
startdata=[0;60/360;120/360;180/360;240/360;300/360];%初始点数据
% [IDX,C]=kmeans(training,6,'start',startdata);
[IDX,C]=kmeans(training,6,'start',startdata);%调用自带函数
[MinVal,Num]=k_means(training,6,startdata);%调用自编函数
idbw1=(IDX==1);%取边缘
template1=reshape(idbw1,size(h));%二值化图像
idbw2=(Num==1);
template2=reshape(idbw2,size(h));
subplot(222),imshow(template1),title('k均值聚类分割');
subplot(223),imshow(template2),title('自编k均值聚类分割(逃课版)');
% for m=1:M
%  for n=1:N/3
%   if template2(m,n)==1
%     template2(m,n)=0; 
%   else
%     template2(m,n)=1;
%   end
%  end
% end
R=Image(:,:,1);
G=Image(:,:,2);
B=Image(:,:,3);
R1=R.*double(template1);
G1=G.*double(template1);
B1=B.*double(template1);
templateR=cat(3,R1,G1,B1);
subplot(224),imshow(templateR),title('自编k均值聚类分割(逃课版)');


%%
%自编k均值聚类分割
%通过计算欧式距离来迭代的k均值版本
clear;
clc;
close;
Image=rgb2gray(imread('apple.png'));
subplot(121),imshow(Image),title('原图');
% Image=imread('qiang.jpg');
[M,N]=size(Image);%获取图像的大小
%随机初始化聚类中心
h=double(Image);
k=4;
training=h(:);%training是N*n的向量,每行对应一个点,每点为n维度;k为要聚成的类别数
startdata=randperm(size(training,1));%随机生成初始点
startdata=double(Image(startdata(1:k)));%获取对应初始点的灰度值
startdata(1)=0;%设置第一类灰度值中心为;
flag=false;%设置脱离循环的变量
dist=zeros(size(training,1),k);%预设置dist的大小(理论上能提高运算速度)

while ~flag%为ture时运行,flag==false取反运行,false==0,ture==1
 for m=1:k
 dist(:,m)=sqrt((training-startdata(m)).^2);%计算每个点到初始点的距离
 end
 [MinVal,Num]=min(dist,[],2);%min(dist,[],2)函数选出每行最小的点放于MinVal,
                            %并选出的它的列索引(分类依据,第几列就是第几类)放于Num
 for m=1:k
 Temp(:,m)=mean(Image(find(Num==m)));%计算每个类别的均值
 end
 
 flag=max(Temp-startdata)<0.1;%判断前后两次迭代的中心点灰度值的差值是否相同,0.1为判断的阈值
 if flag==1%如果两次迭代中心点取值相同flag==1跳出循环;
    break
 else
 startdata=Temp;%否则再次迭代
 end
end
% [MinVal,IDX]=min(dist,[],2);
idbw=(Num==1);
template=reshape(idbw,size(h));
subplot(122),imshow(template),title('k均值聚类分割');

第一段代码结果
在这里插入图片描述
第二段代码结果
在这里插入图片描述
第三段代码结果
在这里插入图片描述
第四段代码结果

在这里插入图片描述

该目标提取基于在HSV空间中的kmeans聚类分割方法。

%目标提取
clc;
clear;
close all;
Image=im2double(imread('apple.png'));
R=imfilter(Image(:,:,1),fspecial('gaussian',[3,3],0.6),'conv');%对图像进行平滑处理
G=imfilter(Image(:,:,2),fspecial('gaussian',[3,3],0.6),'conv');
B=imfilter(Image(:,:,3),fspecial('gaussian',[3,3],0.6),'conv');
% R=imfilter(Image(:,:,1),fspecial('average',[3 3]),'conv');
% G=imfilter(Image(:,:,2),fspecial('average',[3 3]),'conv');
% B=imfilter(Image(:,:,3),fspecial('average',[3 3]),'conv');
Image=cat(3,R,G,B);
[M,N]=size(Image);
subplot(221),imshow(Image),title('原图');
hsv=rgb2hsv(Image);
h=hsv(:,:,1);
h(h>330/360)=0;%接近360°的色调认为是0°
training=h(:);%获取训练数据
startdata=[0;60/360;120/360;180/360;240/360;300/360];%初始点数据。注:设为列向量,方便后续处理
[IDX,C]=kmeans(training,6,'start',startdata);%调用自带函数
[MinVal,Num]=k_means(training,6,startdata);%调用自编函数
idbw1=(IDX==1);%取边缘
template1=reshape(idbw1,size(h));%二值化图像
idbw2=(Num==1);
template2=reshape(idbw2,size(h));
subplot(222),imshow(template1),title('k均值聚类分割');
subplot(223),imshow(template2),title('自编k均值聚类分割(逃课版)');
R=Image(:,:,1);
G=Image(:,:,2);
B=Image(:,:,3);
Template=rem(template2+1,2);%将模板中1变成00变成1,从而将背景变成白色,也不影响目标的提取
R1=R.*template2+Template;
G1=G.*template2+Template;
B1=B.*template2+Template;
templateR=cat(3,R1,G1,B1);
subplot(224),imshow(templateR),title('目标提取');

在这里插入图片描述
以下是k_means()自编函数的定义:

function [MinVal,Num] = k_means(training,k,startdata)
%KMEANS 此处显示有关此函数的摘要
%   此处显示详细说明
%MinVal是HSV中V的距离最小值,Num是N*1的向量,其元素为每个点所属类别的类序号

%training是N*n的向量,每行对应一个点,每点维度为n
%这里由于取得是hsv色彩空间下得v分量(该分量是以角度表示的)为一维,故n为1;
%即training是N*1的一个列向量

%k为要聚成的类别数(如k=6时,将360划分为六个区间)

%startdata是预先设定好的中心点的集合,如30°点等等
%在上面的代码段中创建的,n*1的列向量

%创建一个和training等大的向量,用0填充
dist=zeros(size(training,1),k);

%循环计算出每个点到每个中心点的距离,然后将该距离存为N*k的矩阵
%N等于点的个数,有多少个点,N就是多大,k=6是类别数
for m=1:k
dist(:,m)=sqrt((training-startdata(m)).^2);
end

%min(A,[],2)取每行数取最小值,这样就找到最近中心点了
[MinVal,Num]=min(dist,[],2);
end

总结:

对于彩色图像的目标提取和背景分析,步骤基本如下:
1, 读取目标图像
2, 对目标图像消去噪声
3, 对目标图像灰度化;
4, 通过诸如OTSU,最大类间,最小误差,迭代,hough,kmeans等分割方法,将图像的目标和背景分割开
5, 进行目标提取
在实验过程中,可以发现,根据图像的色彩的复杂程度,不同的算法有着不同的效果。
在对色彩较为复杂的图处理时,以kmeans分割法在HSV空间对V进行分割的效果最好。基本上可以把目标和背景进行分割,便于目标的提取。但由于与书上讲述的计算欧式距离的kmeans算法相比。在HSV空间聚类的算法,更为简单易懂。就像游戏里的逃课打法一样,简化了聚类的计算。故称为逃课版。
然而,matlab自带的kmeans函数处理结果与逃课版的处理结果基本一致,而按书本理论上的计算欧式距离,进行k均值聚类的结果,却差强人意,令人感慨。
而在RGB空间中,分割下来的情况,实在不尽人意,目标和背景时常混杂在一起,无法分割开来。
PS:由于当时一时疏忽,忘记将自编代码段上传(当时期末压力太大,人晕了),导致阅读不便,深感抱歉。已于2022/10/12下午16时补全,本人能力有限,如有纰漏,望不吝赐教,万分感谢。
还有一点,由于csdn私信充斥各种广告,本人随缘看私信的。如果私信一两天没回,后续时间长了,也就更不会回复了,见谅。
2022/11/30,本文章的收藏增加。故重新审视一番,修复了几处排版不合理,文字表达不当之处。以报各位厚爱之情。

猜你喜欢

转载自blog.csdn.net/Wuyeyu2001/article/details/125485885
今日推荐