实现基于边缘检测、边界闭合等操作的分割算法。
连通区域边界检测:
img=imread('rice.png');
img=img>128;
imshow(img);
[m n]=size(img);
imgn=zeros(m,n); %边界标记图像
ed=[-1 -1;0 -1;1 -1;1 0;1 1;0 1;-1 1;-1 0]; %从左上角像素,逆时针搜索
for i=2:m-1
for j=2:n-1
if img(i,j)==1 && imgn(i,j)==0 %当前是没标记的白色像素
if sum(sum(img(i-1:i+1,j-1:j+1)))~=9 %块内部的白像素不标记
ii=i; %像素块内部搜寻使用的坐标
jj=j;
imgn(i,j)=2; %本像素块第一个标记的边界,第一个边界像素为2
while imgn(ii,jj)~=2 %是否沿着像素块搜寻一圈了。
for k=1:8 %逆时针八邻域搜索
tmpi=ii+ed(k,1); %八邻域临时坐标
tmpj=jj+ed(k,2);
if img(tmpi,tmpj)==1 && imgn(tmpi,tmpj)~=2 %搜索到新边界,并且没有搜索一圈
ii=tmpi; %更新内部搜寻坐标,继续搜索
jj=tmpj;
imgn(ii,jj)=1; %边界标记图像该像素标记,普通边界为1
break;
end
end
end
end
end
end
end
figure;
imgn=imgn>=1;
imshow(imgn,[]);
%不过要是真取二值图像内边界,通常是原图减去其腐蚀图就行了
se = strel('square',3);
imgn=img-imerode(img,se);
figure;
imshow(imgn)
基于像素邻域的边界检测:
img=imread('rice.png');
img=img>128;
imshow(img);
[m n]=size(img);
imgn=zeros(m,n); %边界标记图像
ed=[-1 -1;0 -1;1 -1;1 0;1 1;0 1;-1 1;-1 0]; %从左上角像素判断
for i=2:m-1
for j=2:n-1
if img(i,j)==1 %如果当前像素是前景像素
for k=1:8
ii=i+ed(k,1);
jj=j+ed(k,2);
if img(ii,jj)==0 %当前像素周围如果是背景,边界标记图像相应像素标记
imgn(ii,jj)=1;
end
end
end
end
end
figure;
imshow(imgn,[]);
%不过要是真取二值图像外边界,通常是原图膨胀图减去原图就行了
se = strel('square',3);
imgn=imdilate(img,se)-img;
figure;
imshow(imgn)
对于第一个算法(连通区域边界检测):
优点:
- 可以检测到连通区域的内部边界,对于复杂的对象形状有较好的效果。
- 通过追踪连通区域的边界,可以获得更准确的边界位置。
缺点:
- 对于每个连通区域,需要进行一次完整的环绕搜索,因此在处理大规模图像或包含多个连通区域的图像时,计算成本较高。
- 算法可能对噪声敏感,可能将噪声点标记为边界。
改进:
- 可以考虑添加阈值或其他策略来过滤掉较小的连通区域,以降低计算成本和减少噪声的影响。
- 可以尝试使用更快速的连通区域标记算法,如基于扫描线的算法或基于并查集的算法,以提高计算效率。
对于第二个算法(基于像素邻域的边界检测):
优点:
- 计算相对简单,不需要追踪连通区域,每个像素只需要检查周围的像素即可判断是否为边界。
- 计算成本较低,适用于处理大规模图像或包含多个连通区域的图像。
缺点:
- 只能检测到边界,无法获取连通区域的内部边界信息。
- 对于复杂的对象形状,边界检测可能不够精确。
改进:
- 可以尝试使用更复杂的像素邻域判断策略,例如考虑更大的邻域范围或根据像素值梯度进行判断,以提高边界检测的准确性。
- 可以结合边缘检测算法或轮廓追踪算法,以获得更精确的边界信息。
综上所述,两种算法各有优缺点,可以根据具体应用场景选择适合的算法。改进方面可以尝试优化计算效率、增强边界检测的准确性或结合其他算法进行改进。具体的改进方向取决于应用需求和算法性能要求。