- ubuntu12.04环境下使用kvm ioctl接口实现最简单的虚拟机
- Ubuntu 通过无线网络安装Ubuntu Server启动系统后连接无线网络的方法
- 在Ubuntu上搭建网桥的方法
- ubuntu 虚拟机上网方式及相关配置详解
CFSDN坚持开源创造价值,我们致力于搭建一个资源共享平台,让每一个IT人在这里找到属于你的精彩世界.
这篇CFSDN的博客文章python点云地面点滤波(Progressive Morphological Filter)算法介绍(PCL库)由作者收集整理,如果你对这篇文章有兴趣,记得点赞哟.
本篇博客参考keqi zhang的文章“a progressive morphological filter for removing nonground measurements from airborne lidar data”以去除大型建筑、树木等常见地物.
不方便的小伙伴可以在此:资源链接下载.
机载lidar可以获取快速、低成本地获取大区域的高精度地形测量值。为了获取高精度dtm/dem需要区分测量点中的地面点(由地面直接返回)及非地面点(建筑、车、植被)。众多学者采用了各种各样的方法来进行"点云地面点滤波"。(此篇博客中也进行了相关介绍,不再骜述) 。
膨胀/腐蚀是其中的两个基础操作,通俗的说膨胀/腐蚀可以扩大/减小特征的尺寸,并以此组合为开/闭操作。针对lidar测量点p(x, y, z),高程 z 值在(x, y)处对应的膨胀操作可以定义为:
式中:(xp, yp, zp) 代表p点的相邻点,w为操作窗口(可以为一维“线”也可以为二维“矩形/圆/其他形状等”)。膨胀操作完成后会输出p点在窗口w内具有最大高程值的近邻点。 与之类似的,腐蚀操作为在p点窗口w内找到具有最低高程值的近邻点。可以通过下式进行定义:
了解膨胀/腐蚀这两个基础操作之后,可以通过对其进行简单组合来来形成开/闭操作,其中开操作为先进行腐蚀再进行膨胀操作,而闭操作为先膨胀再进行腐蚀。在lidar数据处理中使用了“开”操作,处理效果如下图中所示:
可以从图中得知:“虚线”是先进行“腐蚀”操作所形成的表面,这个表面剔除了“树木”点,但是大型建筑物却变得不完整。“实线”是对“腐蚀”操作结果进行“膨胀”操作所形成的表面,可以看出其又恢复了大型建筑的形状。基于此,我们可以知道,“开操作”具备去除地面上的细小地物,保留大型地物的能力,这种能力对于后续处理是非常重要的.
上述的“开操作”只是去除了细小地物,保留了大型地物,并没有去除所有非地面点去除,而且仅仅通过一个“开操作”也不可能实现对复杂地表的提取。因此,怎么利用好“开操作”的能力进行下一步骤的提取是进一步提升的关键。 kilian等人提出,可以在“开操作”处理后的结果中的每一个“窗口”内找到一个“最低点”,然后此窗口内的其他点若落在“最低点”的一个高程范围内则认为是地面点。这个高程范围通常根据机载lidar系统扫描的精度来定义,正常为20-30cm。 此方法中有两个方面对最后的结果好坏非常重要:
1.滤波窗口的尺寸,如果窗口尺寸设置的比较小,则可以很好的保留地面起伏的细节,但是只能去除像汽车、树木等细小地物,而对建筑物则去除效果较差(屋顶通常被认为是地面)。相反,若窗口尺寸设置的较大,则会过度去除一些“地面点”,例如,一条道路与一条小水沟相邻,若窗口尺寸大于道路的宽度,则道路可能就会被认为是非地面点(因为小水沟中的点高程较低,会被认为是窗口内的最低点,而道路点较高,被判断为非地面点)。此外,一些局部的小山丘、沙丘都极可能被“切除”.
2.建筑与树木在特定/局部区域的分布.
注:一个最理想的情况是我们可以设置一个“窗口”,这个“窗口”的尺寸可以足够小,能够保留地面细节。同时,还可以足够大,能够去除建筑、汽车、树木等地物。但是,这种理想情况在实际数据集中国并不存在.
为了解决这一问题,kilian等人继续提出了可以通过改变窗口大小来多次进行滤波。每个点都被赋予一个与窗口大小相关的权重,窗口尺寸越大,点的权重越高。这种方法虽然得到了更好一些的效果,但是没有从"point level"进行区分地面点与非地面点。("point level"区分的地面点与非地面点之后可以通过插值的方法使得dem/dtm的生成效果更好。) 。
由上述2.2节中的分析可知,传统的形态学滤波很难通过一个固定大小的窗口去检测出各种尺寸变化的不同地物。这一问题可以通过逐渐改变窗口大小来解决。 如下图中所示,首先使用一个尺寸为l1的窗口来对原始数据进行开操作。由图中的“虚线”可以看出树木等尺寸小于l1的地物被去除,且地形特征中小于l1的部分被“切除”(山丘顶部高程被替换成了l1中的最小值),但是,尺寸大于l1的建筑物被保留了下来。接着,进行下一次迭代,窗口尺寸变为l2,对上一次的处理结果进行开操作处理,结果从“实线”中可以看出,l2大于建筑的尺寸,所以建筑也被去除,但同时山丘顶部被“切除”的范围更大.
需要注意的是: 通过逐渐增加窗口尺寸解决了去除不同大小地物的问题,但是又引入了"山丘"顶部等小于窗口尺寸的地形特征部分被“切除”的问题.
为了解决这一新出现的问题,可以通过引入一个高度差阈值来解决。建筑屋顶和地面点之间的高程差是“突变”(abrupt change),而地面高程是“渐变”(gradual change)。因此,二者之间高程变化中的明显区别可以帮助我们进行区分。假设dhp,1代表原始lidar测量值与在任意给定p点处第一次迭代表面之间的高程差,dht,1代表高程差阈值,则如果dhp,1 ≤ dht,1点p就被认为是地面点,反之如果dhp,1 > dht,1就认为点p是一个非地面点。此后,令dhmax(t),1为当前迭代中初始地面点与滤波表面之间差值的最大值,则如果选取的dht,1 > dhmax(t),1则所有的测量值都会保留。 在第二次迭代中假设上一次滤波表面和本次滤波表面的最大高程差为dhmax(t),2,则如果dhmax(t),2 < dht,2,则高程差值在dhmax(t),2范围内的地面点都会被保留。类似的,假设在上次迭代和本次迭代之间建筑高程差值最小为dhmin(b),2(通常近似为建筑的高度),如果dhmin(b),2 > dht,2,则建筑就会被移除。 通常设置dht,k为研究区域第k次迭代中建筑物的最矮高程值。以dht,k作为阈值,对于第k次迭代中的任意点p如果dhp,k < dht,k则将其标记为地面点,反之为非地面点。通过这种方式,不同尺寸的建筑物(树)可以随着迭代窗口尺寸的增加逐步被去除。 综上所述,progressive morphological filters的详细流程如下图所示:
我们可以对上图总结以下四个步骤:
注意:每一次迭代中的“开操作”实际都是作用在步骤1)所划分网格中的点,所以progressive morphological filters是"point level"来对lidar测量值进行滤波处理的.
在上述步骤3)中我们要变化窗口尺寸 wk和高程差阈值 dht,k两个参数的值,以进行下一次迭代,那么这两个值是怎么计算的呢?
首先是窗口尺寸 wk有两种计算方式,第一种是:
式中,k为迭代次数,b是初始窗口大小(由用户进行输入),最后+1是为了保证 wk为一个奇数,窗口对称。但是,如果一个研究区域具有非常大的地物,这种增加窗口尺寸速度太慢则会耗费较多时间。因此,可以使用第二种方式,通过指数增长来改变窗口大小,计算如下式:
同样的,式中k为迭代次数,b是初始窗口大小(由用户进行输入),这种方式的增长速度较第一种方式快很多.
高程差阈值与研究区域的地形坡度密不可分,因此可以通过下式进行计算:
式中,dh0为初始高程差阈值,s为坡度,c为格网大小,dhmax为最大高程差阈值.
在城市区域,树木、汽车相对于建筑的尺寸小很多,所以通常是最后滤除建筑,最大高程差阈值dhmax可以设置为一个固定值(如最矮建筑物高度)。而在山区,主要的非地面点为植被,所以并没有必要设置固定的最大高程差阈值dhmax,于是dhmax通常被设置为测区内的最大高程差.
此外,坡度s通过第k次迭代的最大高程差dhmax(t),k,以及窗口尺寸wk进行计算,如下式所示:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
|
#include <iostream>
#include <pcl/io/pcd_io.h>
#include <pcl/point_types.h>
#include <pcl/filters/extract_indices.h>
#include <pcl/segmentation/progressive_morphological_filter.h>
int
main (
int
argc, char
*
*
argv)
{
pcl::pointcloud<pcl::pointxyz>::ptr cloud (new pcl::pointcloud<pcl::pointxyz>);
pcl::pointcloud<pcl::pointxyz>::ptr cloud_filtered (new pcl::pointcloud<pcl::pointxyz>);
pcl::pointindicesptr ground (new pcl::pointindices);
/
/
fill
in
the cloud data
pcl::pcdreader reader;
/
/
replace the path below with the path where you saved your
file
reader.read<pcl::pointxyz> (
"samp11-utm.pcd"
,
*
cloud);
std::cerr <<
"cloud before filtering: "
<< std::endl;
std::cerr <<
*
cloud << std::endl;
/
/
create the filtering
object
pcl::progressivemorphologicalfilter<pcl::pointxyz> pmf;
pmf.setinputcloud (cloud);
pmf.setmaxwindowsize (
20
);
pmf.setslope (
1.0f
);
pmf.setinitialdistance (
0.5f
);
pmf.setmaxdistance (
3.0f
);
pmf.extract (ground
-
>indices);
/
/
create the filtering
object
pcl::extractindices<pcl::pointxyz> extract;
extract.setinputcloud (cloud);
extract.setindices (ground);
extract.
filter
(
*
cloud_filtered);
std::cerr <<
"ground cloud after filtering: "
<< std::endl;
std::cerr <<
*
cloud_filtered << std::endl;
pcl::pcdwriter writer;
writer.write<pcl::pointxyz> (
"samp11-utm_ground.pcd"
,
*
cloud_filtered, false);
/
/
extract non
-
ground returns
extract.setnegative (true);
extract.
filter
(
*
cloud_filtered);
std::cerr <<
"object cloud after filtering: "
<< std::endl;
std::cerr <<
*
cloud_filtered << std::endl;
writer.write<pcl::pointxyz> (
"samp11-utm_object.pcd"
,
*
cloud_filtered, false);
return
(
0
);
}
|
到此这篇关于python点云地面点滤波(progressive morphological filter)算法介绍(pcl库)的文章就介绍到这了,更多相关python点云地面点滤波pcl库内容请搜索我以前的文章或继续浏览下面的相关文章希望大家以后多多支持我! 。
原文链接:https://blog.csdn.net/wxc_1998/article/details/107010826 。
最后此篇关于python点云地面点滤波(Progressive Morphological Filter)算法介绍(PCL库)的文章就讲到这里了,如果你想了解更多关于python点云地面点滤波(Progressive Morphological Filter)算法介绍(PCL库)的内容请搜索CFSDN的文章或继续浏览相关文章,希望大家以后支持我的博客! 。
我应该在 Angular 应用程序中使用哪个,为什么? array.filter(o => o.name === myName); 或 $filter('filter')(array, {name:
以下两个调用是否解析为 Django 中的等效 SQL 查询? 链接多个调用 Model.objects \ .filter(arg1=foo) \ .filter(arg2=bar) \ ... 将
我正在尝试在 hbase-1.0.0 上运行 completebulkload。但是遇到错误, "java.lang.NoClassDefFoundError: org/apache/hadoop/h
我从这篇文章中学习了“树”和“索引”:Learning Git Internals by Example 但是当谈到“git filter-branch”命令时,我不知道“--tree-filter”
我正在尝试构建我的自定义过滤器以进行身份验证,但是当我尝试运行我的 WebAPI 解决方案时遇到了这个问题: The given filter instance must implement on
我想保留一个过滤器函数的列表,并通过返回true的过滤器来标记这些项。这是接近但不完全。。主要问题是std::stringify!总是返回“ADF”,可能是我声明为ADF的变量名。。第二个问题是,在定
我想保留一个筛选器函数列表,并通过返回True的筛选器来标记这些项目。这已经很接近了,但还不完全是。。主要问题是std::stringify!总是返回“ADF”,可能是我声明为ADF的变量名。。第二个
我尝试在 graphql 查询中使用 where: filter 但不幸的是我遇到了一些错误。我做错了什么? shoeposts { data { attributes(where: {s
几周以来,我一直在使用 Zend Framework 2,尽管在线文档非常不完整,但我还是设法建立了我的网站的初稿。 不幸的是,我在尝试实现 Zend\Filter\File\Rename 过滤器的自
我正在尝试在 APC 中使用 apc.filter 等功能。但是我所做的一切都不起作用 我应该完成 2 项任务。 1)需要包含1个目录用于缓存。我的代码在apc.ini apc.cache by de
我想使用一个可能返回 Err 的过滤器函数结果,并将其冒泡到包含函数: mycoll.into_iter() .filter(|el| { if el == "bad" { E
每个 Controller 都应该有方法filters(),在那里你可以指定一些类,我想知道,这些类是如何被框架包含的?这些类是如何配置的,以及何时配置,也许有人可以给我一个使用filters()并包
我想在一维信号上使用巴特沃斯滤波器。在 Matlab 中,脚本如下所示: f=100; f_cutoff = 20; fnorm =f_cutoff/(f/2); [b,a] = butter
我想比较两个列表,以便找到第一个列表中不在第二个列表中的值并返回它们。提前谢谢大家代码返回:不再支持过滤器有没有其他方法可以做到这一点 MATCH (cu:Customer{name: "myCust
在 Android 应用程序中,我有一个通用设置 -- 一个带有 ArrayAdapter 的 ListView。在某一时刻,我调用了适配器的 getFilter().filter() 方法,它很好地
所以我有如下数据: [ { "id": 0, "title": "happy dayys", "owner": {"id": "1", "username
阅读Mastering Web Development with AngularJS ,我正在尝试创建并使用一个使用 $filter 模块/关键字的新过滤器。 HTML
所以我的理解是 halt 命令应该停止当前过滤器中的请求,但它似乎继续。下面是一个非常简单的 Sinatra 应用程序,演示了这一点。 服务器.rb require 'sinatra' before
我正在尝试将散列传递给 URL 以设置 UIkit 过滤器。 All
我正在使用 django-filter应用程序。但是有一个问题我不知道如何解决。它几乎与 django 文档中描述的完全相同: https://docs.djangoproject.com/en/1.
我是一名优秀的程序员,十分优秀!