山东大学暑期项目实训
昨天分了任务做了一下人工的图像分拣,发现很多的图像效果并不是很良好。感觉是图像分割的效果不大好,导致骨干提取的效果不是很好。
同时,组长分配的任务是是去小邻域。二值化分割图像的结果,除了有我们想要的结果意外,还有很多其他的小邻域的噪声,关键就是如何找到算法去除这些小邻域。
开闭操作的去除方法
图像处理提到过的,利用形态学的方法,用膨胀和腐蚀对图像处理。其中,先腐蚀再膨胀的开操作,可以去除一些小邻域;先膨胀再腐蚀的闭操作可以填补图像中的空缺。
不过难点在于如何构造操作使用的矩阵
一开始使用的3*3的矩阵进行操作,感觉效果不是很明显,而且,很多小邻域都明显大于这个,去噪效果并不是很理想。
随后我浏览到了别的方法
最大连通域方法
转换了一下思路,并不去对小邻域进行处理,而是对所有的邻域进行划分,然后找最大的邻域,一般来说我们的结果就是二值图中最大的连通域。按照这个思路去寻找matlab中的相关方法,matlab中似乎对相关的函数有所实现,我的算法参考这里link
可见相关的连通域算法matlab中基本都有相关的实现
那么我们要做的事情比较简单了
1,提高图像分割的质量
2,使用开闭操作,尽量使小邻域边缘圆滑,不和主干部分相连,然后使用几次闭操作尽量尽量让主干部分连接在一起
3,寻找并保留最大的连通域,即是结果
%默认8领域
se=[0,1,0;
1,1,1;
0,1,0];
nse=mod(se+1,2);
I=imread('');
[width,height,dimension]=size(I);
subplot(1,4,1);
imshow(I);
title('原图');
I1=rgb2gray(I);
I1=tofloat(I1);
I2=stdfilt(I1);
m=imfilter(I1,1/9*ones(3),'replicate');
m2=mean2(I1);
I3=(I1>=28*I2)&(I1>=0.8*m);% (I1>15*I2)&(I1>0.4*m);
I9=uint8(ones(width, height ,dimension));
I9=I9*255;
for i=1:height
for j=1:width
if(I3(j,i)==0)
I9(j,i,:)=uint8(I(j,i,:));
end
end
end
subplot(1,4,2);
imshow(I3);% this is the result of the sf
title('8邻域局部阈值结果');
I5=close(close(I3));
subplot(1,4,3);
imshow(I5);
title('两次闭操作尽量连通');
I6=maxLian(I5);
subplot(1,4,4);
imshow(I6);
title('最大连通域结果');
function result=close(img)
se=[0,1,0;
1,1,1;
0,1,0];
fo=imopen(img,se);%直接开运算
result = fo;
end
function [out,revertclass] = tofloat(inputimage)
% 类型转换
% 单纯的取 x 用的匿名函数句柄(玩的有点花)
identify = @(x) x;
% 将输入转换为单精度的函数句柄
tosingle = @im2single;
table = {'uint8',tosingle,@im2uint8
'uint16',tosingle,@im2uint16
'logical',tosingle,@logical
'double',identify,identify
'single',identify,identify};
% strcmp(s1,s2),输入字符串的数组可以说任意类型组合
% find 找出其中的真值
classIndex = find(strcmp(class(inputimage),table(:,1)));
if isempty(classIndex)
error('不支持的图像类型');
end
% 找到对应的转换类型
out = table{classIndex,2}(inputimage);
% 记录对应逆转换类型
revertclass = table{classIndex,3};
end
function img=maxLian(I)
se=[1,1,1;
1,1,1;
1,1,1];
if length(size(I))>2
I = rgb2gray(I);
end
if ~islogical(I)
imBw = imbinarize(I); %转换为二值化图像
else
imBw = I;
end
imBw = im2bw(I); %转换为二值化图像
imBw=imcomplement(imBw);
%imBw=imopen(imBw, se);
imBw=imclose(imBw,se);
imBw=imopen(imBw,se);
imLabel = bwlabel(imBw); %对各连通域进行标记
stats = regionprops(imLabel,'Area'); %求各连通域的大小
area = cat(1,stats.Area);
index = find(area == max(area)); %求最大连通域的索引
img = ismember(imLabel,index); %获取最大连通域图像
end
仍是在原先我使用的8邻域局部算法的基础上进行处理,这次我将参数从15调高到28,图像尽量存在更多的特征,能够更好的连通。
这里的开闭运算用的矩阵没有统一…方法一个用的matlab自带的一个是自己添加的。
对图像的开闭操作完成连通域的整合和然后提取即可。个人感觉效果还可以
。
但是仍不可避免的,非常的吃图像分割的效果
而且图像分割效果差点,原来的二值化结果是比较割裂的情况下,那么连通域的结果将是比较毁灭的情况
matlab的代码需要转换到python,这是比较头疼的地方。