分割结果有点粗糙,凑合着看,原始代码是来自冈萨雷斯的数字图像处理,需要电子书可以后台询问。
区域生长
regiongrow函数,要新建一个脚本:
function [g, NR, SI, TI] = regiongrow(f, S, T)
%REGIONGROW Perform segmentation by region growing.
% [G, NR, SI, TI] = REGIONGROW(F, SR, T). S can be an array (the
% same size as F) with a 1 at the coordinates of every seed point
% and 0s elsewhere. S can also be a single seed value. Similarly,
% T can be an array (the same size as F) containing a threshold
% value for each pixel in F. T can also be a scalar, in which
% case it becomes a global threshold.
%
% On the output, G is the result of region growing, with each
% region labeled by a different integer, NR is the number of
% regions, SI is the final seed image used by the algorithm, and TI
% is the image consisting of the pixels in F that satisfied the
% threshold test.
% Copyright 2002-2004 R. C. Gonzalez, R. E. Woods, & S. L. Eddins
% Digital Image Processing Using MATLAB, Prentice-Hall, 2004
% $Revision: 1.4 $ $Date: 2003/10/26 22:35:37 $
f = double(f);
% If S is a scalar, obtain the seed image.
f=im2gray(f);
if numel(S) == 1
SI = f == S;
S1 = S;
else
% S is an array. Eliminate duplicate, connected seed locations
% to reduce the number of loop executions in the following
% sections of code.
SI = bwmorph(S, 'shrink', Inf);
J = find(SI);
S1 = f(J); % Array of seed values.
end
TI = false(size(f));
for K = 1:length(S1)
seedvalue = S1(K);
S = abs(f - seedvalue) <= T;
TI = TI | S;
end
% Use function imreconstruct with SI as the marker image to
% obtain the regions corresponding to each seed in S. Function
% bwlabel assigns a different integer to each connected region.
[g, NR] = bwlabel(imreconstruct(SI, TI));
主函数,丢另一个脚本里:
clc
clear
f = imread('E:\数字图像\第二次作业\草莓.jpg');
subplot(221),imshow(f);
title('原始图像');
%函数regiongrow返回的NR为是不同区域的数目,参数SI是一副含有种子点的图像
%TI是包含在经过连通前通过阈值测试的像素
f=im2gray(f);
[g,NR,SI,TI]=regiongrow(f,100,55);%种子的像素值为100,55为阈值
subplot(222),imshow(SI);
title('种子点的图像');
subplot(223),imshow(TI);
title('所有通过阈值测试的像素');
subplot(224),imshow(g);
title('对种子点进行8连通分析后的结果');
区域分割:
splitmerge函数,新建脚本:
function g=splitmerge(f,mindim,fun)%f是待分割的原图,mindim是定义分解中所允许的最小的块,必须是2的正整数次幂
f= rgb2gray(f); % 如果 f 是 RGB 彩色图像
Q=2^nextpow2(max(size(f)));
[M,N]=size(f);
padsize = max([Q-M, Q-N], 0);
f=padarray(f,padsize,'post');%:填充图像或填充数组。f是输入图像,输出是填充后的图像,先将图像填充到2的幂次以使后面的分解可行
%然后是填充的行数和列数,post:表示在每一维的最后一个元素后填充,B = padarray(A,padsize,padval,direction)
%不含padval就用0填充,Q代表填充后图像的大小。
S=qtdecomp(f,@split_test,mindim,fun);%S传给split_test,qtdecomp divides a square image into four
% equal-sized square blocks, and then tests each block to see if it
% meets some criterion of homogeneity. If a block meets the criterion,
% it is not divided any further. If it does not meet the criterion,
% it is subdivided again into four blocks, and the test criterion is
% applied to those blocks. This process is repeated iteratively until
% each block meets the criterion. The result can have blocks of several
% different sizes.S是包含四叉树结构的稀疏矩阵,存储的值是块的大小及坐标,以稀疏矩阵形式存储
Lmax=full(max(S(:)));%将以稀疏矩阵存储形式存储的矩阵变换成以普通矩阵(full matrix)形式存储,full,sparse只是存储形式的不同
g=zeros(size(f));
MARKER=zeros(size(f));
for k=1:Lmax
[vals,r,c]=qtgetblk(f,S,k);%vals是一个数组,包含f的四叉树分解中大小为k*k的块的值,是一个k*k*个数的矩阵,
%个数是指S中有多少个这样大小的块,f是被四叉树分的原图像,r,c是对应的左上角块的坐标如2*2块,代表的是左上角开始块的坐标
if ~isempty(vals)
for I=1:length(r)
xlow=r(I);
ylow=c(I);
xhigh=xlow+k-1;
yhigh=ylow+k-1;
region=f(xlow:xhigh,ylow:yhigh);%找到对应的区域
flag=feval(fun,region);%evaluates the function handle, fhandle,using arguments x1 through xn.执行函数fun,region是参数
if flag%如果返回的是1,则进行标记
g(xlow:xhigh,ylow:yhigh)=1;%然后将对应的区域置1
MARKER(xlow,ylow)=1;%MARKER矩阵对应的左上角坐标置1
end
end
end
end
g=bwlabel(imreconstruct(MARKER,g));%imreconstruct默认2D图像8连通,这个函数就是起合的作用
g=g(1:M,1:N);%返回原图像的大小
end
%%%%%%%%%%%%%%%%%%%%%%%%%%%%
function v=split_test(B,mindim,fun)
K=size(B,3);%B就是qtdecomp函数传过来的,代表当前size(B,3)返回的是B的层数,就是B是几维的,这里实际上就是有几个B这样大小的图像块
%这句代码的意思是从qtdecomp函数传过来的B,是当前分解成的K块的m*m的图像块,K表示有多少个这样大小的图像块
v(1:K)=false;
for I=1:K
quadregion=B(:,:,I);
if size(quadregion,1)<=mindim%如果分的块的大小小于mindim就直接结束
v(I)=false;
continue
end
flag=feval(fun,quadregion);%quadregion是fun函数的参数
if flag%如果flag是1,代表需要再分
v(I)=true;%这里就相当于split_test是起一个调用predicate的作用,返回的就是ppredicate的值
end
end
end
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
predicate函数,需要新建脚本:
function flag = predicate( region )
sd = std2(region);
m = mean2(region);
flag = (sd > 10) & (m > 0) & (m < 255);
end
主函数,需要新建脚本:
clc
clear
f = imread('E:\数字图像\第二次作业\草莓.jpg');
subplot(231),imshow(f);
title('区域分割原始图像');
g32=splitmerge(f,32,@predicate);%32代表分割中允许最小的块
subplot(232),imshow(g32);
title('mindim为32时的分割图像');
g16=splitmerge(f,16,@predicate);%32代表分割中允许最小的块
subplot(233),imshow(g16);
title('mindim为16时的分割图像');
g8=splitmerge(f,8,@predicate);%8代表分割中允许最小的块
subplot(234),imshow(g8);
title('mindim为8时的分割图像');
g4=splitmerge(f,4,@predicate);%4代表分割中允许最小的块
subplot(235),imshow(g4);
title('mindim为4时的分割图像');
g2=splitmerge(f,2,@predicate);%2代表分割中允许最小的块
subplot(236),imshow(g2);
title('mindim为2时的分割图像');
然后是分水岭分割,这个效果相比前两个来说差一点,但是代码简单:
I=imread('E:\数字图像\第二次作业\草莓.jpg');
g=im2bw(I,graythresh(I));
figure(1),subplot(321),imshow(g);
gc=~g;
subplot(322),imshow(gc);
d=bwdist(gc);
figure(1),subplot(323),imshow(d);
L=watershed(-d);
figure(1),subplot(324),imshow(L);
w=L==0;
g2=g&~w;
figure(1),subplot(325),imshow(g2);
title('分割图');
%距离变换分水岭分割
结果大概是这样:
原始图
区域生长:
区域分割:
分水岭: