MatLab - 图像分割以分离相互接触的物体

3
我正在使用regionprops函数来检测由无人机拍摄的图像上树木的数量。 原始图像 首先,我使用蓝色NDVI去除了地面: BNDVI图像 带有阈值的图像: 带有阈值的图像 然后,我使用regionprops函数来检测图像上的树木数量: Regionprops

但是在第15个区域存在一个问题,因为该区域的所有树木都相连并被检测为一棵树。我尝试使用分水岭分割来分离该区域的树木,但它没有起作用:

Watershed segmentation

我这样做是不是错了?有更好的方法来分开这些树吗?

如果有人能帮我解决这个问题,我将不胜感激。这里是没有地面的第15区域: Region 15

如果有帮助的话,这是梯度幅值图像: enter image description here


你能说出那里有多少棵树吗?如果可以,你是如何做到的?有哪些线索帮助你数清不同的树木? - Shai
可以肯定的是,我无法知道图像中有多少棵树,因为即使手动计数也很棘手。但是通过regionprops函数,我可以知道区域的面积。并且知道最多一棵树的面积为3000个像素,并且要研究的区域有112,000个像素的面积,因此该区域大约有37棵树。 - Pedro Marques
2个回答

8
这个问题问了一段时间了,但我希望现在回答还不算太晚。在类似的问题中,使用分水岭分割存在一个普遍的问题。有时,对象是独立的,彼此不接触,如这个例子。在这种情况下,仅对图像进行模糊处理就足以使用分水岭分割。有时,对象位于紧密且相互接触的位置,因此对象的边界不清晰,如这个例子。在这种情况下,使用距离变换-> 模糊-> 分水岭有所帮助。在这个问题中,逻辑方法应该使用距离变换。然而,由于树上和附近存在阴影,边界不清晰。在这种情况下,最好使用任何有助于分离对象的信息或强调对象本身。
在这个问题中,我建议使用颜色信息来强调树的像素。以下是MATLAB代码和结果。
im=imread('https://istack.dev59.com/aBHUL.webp');
im=im(58:500,86:585,:);
imOrig=im;

%% Emphasize trees

im=double(im);
r=im(:,:,1);
g=im(:,:,2);
b=im(:,:,3);

tmp=((g-r)./(r-b));

figure
subplot(121);imagesc(tmp),axis image;colorbar
subplot(122);imagesc(tmp>0),axis image;colorbar

%% Transforms

% Distance transform
im_dist=bwdist(tmp<0);

% Blur
sigma=10;
kernel = fspecial('gaussian',4*sigma+1,sigma);
im_blured=imfilter(im_dist,kernel,'symmetric');

figure
subplot(121);imagesc(im_dist),axis image;colorbar
subplot(122);imagesc(im_blured),axis image;colorbar

% Watershed
L = watershed(max(im_blured(:))-im_blured);
[x,y]=find(L==0);

figure
subplot(121);
imagesc(imOrig),axis image
hold on, plot(y,x,'r.','MarkerSize',3)

%% Local thresholding 

trees=zeros(size(im_dist));
centers= [];
for i=1:max(L(:))    
    ind=find(L==i & im_blured>1);
    mask=L==i;

    [thr,metric] =multithresh(g(ind),1);
    trees(ind)=g(ind)>thr*1;

    trees_individual=trees*0;
    trees_individual(ind)=g(ind)>thr*1;

    s=regionprops(trees_individual,'Centroid');
    centers=[centers; cat(1,[],s.Centroid)];
end

subplot(122);
imagesc(trees),axis image
hold on, plot(y,x,'r.','MarkerSize',3)

subplot(121);
hold on, plot(centers(:,1),centers(:,2),'k^','MarkerFaceColor','r','MarkerSize',8)

enter image description here

enter image description here

enter image description here


太棒了!:D - Hadi
这个建议一定会帮助我,也是目前为止最接近的近似值。非常感谢你。 - Pedro Marques

1
你可以尝试使用基于标记的分水岭算法。根据我的经验,传统的分水岭变换通常不能直接使用。一种方法是首先使用imdist()函数创建分割区域的距离图。然后通过调用imhmax()函数来抑制本地最大值。接着调用watershed()函数通常会表现得更好。
以下是一个示例脚本:
 bwTrees = imopen(bwTrees, strel('disk', 10));
 %stabilize the borders to lessen oversegmentation  

 distTrees = -bwDist(~bwTrees); %Distance transform 

 distTrees(~bwTrees) = -Inf; %set background to -Inf

 distTrees = imhmin(distTrees, 3); %suppress local minima

 basins = watershed(distTrees);
 ridges = basins == 0;

 segmentedTrees = bwTrees & ~ridges; %segment

 segmentedTrees = imopen(segmentedTrees, strel('disk', 2));
 %remove 'segmentation trash' caused by oversegmentation near the borders.

我尝试调整参数约10分钟,但结果相当糟糕:

segmented trees

你需要在形态学的前后处理中投入大量工作。如果你能降低分割的敏感度,增加曲率会有助于分割。h-minima变换的大小也是一个感兴趣的参数。这样做可能可以得到足够的结果。
也许更好的方法来自聚类技术领域。如果你有或能找到估计森林中树木数量的方法,你应该能够使用传统的聚类方法来分割树木。高斯混合模型或k-means与k-trees可能比基于标记的分水岭更好,如果你能近似地得到正确数量的树木。通常我会根据h-maxima变换上被抑制的最大值数量来估计树木数量,但你的标签可能有点不规则。不过还是值得一试的。

谢谢您的建议。我会尝试并在这里发布结果,看是否解决了问题。 - Pedro Marques

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接