3

我正在使用功能 regionprops 来检测无人机拍摄的图像上的树木数量。 原始图像

首先,我使用 Blue NDVI 移除了地面: 图片BNDVI

带阈值的图像: 带阈值的图像

然后我使用函数 regionprops 来检测图像上的树木数量: 区域道具

但是区域 15 存在问题,因为该区域上的所有树都是连接的,并且它检测为一棵树。我尝试使用Watershed Segmentation分离该区域的树木,但它不起作用:

流域分割

我这样做是错误的吗?有没有更好的方法来分离树木?

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

如果有帮助,这里是梯度幅度图像: 在此处输入图像描述

4

2 回答 2

8

自从提出这个问题以来已经有一段时间了。我希望现在给出答案还为时不晚。我看到在类似问题中使用分水岭分割的一般问题。有时物体是分开的,不像这个例子那样相互接触。在这种情况下,仅模糊图像就足以使用分水岭分割。有时对象位置很近并且相互接触,因此对象的边界不清晰,如本例所示。在这种情况下,使用距离变换-->模糊-->分水岭会有所帮助。在这个问题中,逻辑方法应该是使用距离变换。然而,这一次由于树上和附近的阴影,边界并不清晰。在这种情况下,最好使用任何有助于分离对象的信息如这里或强调对象本身。

在这个问题中,我建议使用颜色信息来强调树像素。
这是 MATLAB 代码和结果。

im=imread('https://i.stack.imgur.com/aBHUL.jpg');
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)

在此处输入图像描述

在此处输入图像描述

在此处输入图像描述

于 2017-03-19T20:21:19.697 回答
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 分钟的参数,但结果相当糟糕:

分段树

你需要为此投入工作。主要是通过形态学进行预处理和后处理。如果您可以降低第一部分的分割灵敏度,则更多的曲率将有助于分割。h-minima 变换的大小也是一个感兴趣的参数。您可能可以通过这种方式获得足够的结果。

可能更好的方法来自聚类技术领域。如果您有或可以找到一种方法来估计森林中的树木数量,您应该能够使用传统的聚类方法来分割树木。如果您获得几乎正确数量的树,则高斯混合模型或带有 k-tree 的 k-means 可能比基于标记的分水岭工作得更好。通常我会根据 h 最大值变换上抑制的最大值的数量来估计树的数量,但你的标签可能有点太香肠了。不过值得一试。

于 2017-02-27T18:29:47.260 回答