What I Read(2) 地理空间数据库原理(B) 三维地理数据模型

引用部分均为笔者思考.

1. 何为真三维GIS

二维数据我们很熟悉,但并非二维数据加上Z值就成了三维数据.

在2D GIS和真3D GIS间,还有过度阶段:

2.5D GIS准3D GIS真3D GIS
数学模型F=f(x,y)和Z=f(x,y)F=f(x,y,z)F=f(x,y,z)
高程特征一对(x,y)对应一个z值一对(x,y)对应多个z值一对(x,y)对应多个z值
属性特征表面抽象无体内特征有体内特征
构建方式2D矢量或栅格面元构模3D矢量,体元构模
典型实例DEM,DTM3D城市模型地下TEN,GTP模型

1.1 2.5D GIS

在2.5 DGIS(如DEM或DTM)中,高程仅仅作为一个属性值.它们与真三维数据的核心差异在于:

  • 它们是表面模型,无法描述其内部的信息.
  • 理论上可以展开到二维平面上,可以看成是高于二维但小于三维的分数维度.

1.2 准3D GIS

如果将多个表面模型组合(如DTM叠加建筑设施的3D模型),就离真三维更进一步(维数离三更近),可以被称为准3D GIS.

它们与真三维数据的核心差异在于:

  • 无法进行任意面的剖分,因为地面与其上的面元模型是分离的.

  • 只适合于展示,不方便进行空间查询/分析等真三维操作.

1.3 真3D GIS

由3D体元或3D矢量构成,因而可以进行可视化,也方便进行各种分析.

我们何时需要真3D GIS?

我们获取数据的数量/维度随着技术的更新而越来越多是必然的趋势,但正如同牛顿力学没有被量子力学完全替代一样,在大多数情况下,准3D GIS甚至2.5D GIS都是够用的,真3D GIS带来的复杂度提升如果每次都在实际使用中降维到准3D或2.5D,那么就无需采用真3D的底层.

真3D的杀手锏在于分析,因为展示的需求可以通过巧妙的业务设计,使用准3D甚至2.5D GIS模拟真3D效果(展示的需求其实是比较单一的).而如果是分析的场景,通过业务设计模拟真3D会让灵活性大打折扣,而如果想要保持灵活性,又会使业务复杂化,这时就不如底层就采用真3D的结构了.

2. 三维空间模型构建方法论

如果不区分是否为真三维,可以按构模方法分类.其中较为典型的有:

  • 面模型:

    • 非封闭面:

      • 格网(GRID)
      • 不规则三角网(TIN)
    • 封闭面:

      • 边界表示模型(B-REP)
  • 体模型

    • 规则体元:

      • 结构实体几何(CSG)
    • 不规则体元:

      • 四面体网格(TEN)
  • 混合模型

2.1 面模型

面模型是一种侧重于3D空间实体表面表示的构模方法:

  • 优点:便于展示和数据更新
  • 缺点:缺少内部描述,难以进行3D空间查询和分析.

不难发现,展示的技术远远走在分析的前面,但展示技术的发展是有上限的,因为人的进化并不遵循摩尔定律,当超过某一限度后,技术的提升带来的感官提升是难以感知的.

对于地理分析这种场景,可视化的效果好坏与否并非决定性的,二维地图所包含的信息量已经足以抵消人脑对于看图的优势,三维场景要么包含少量但精确的信息,要么包含大量但粗略的信息,否则基本不具备实际可读性,所以三维地图的可视化方向应该是所谓的一升一降:降低信息量(甚至降低到二维地图的水平),提升信息冗余,不过这两点似乎并不会吃到硬件制程提升和算法升级的红利.

其底层思想是用细分的平面拟合现实中的曲面,不同种类的构模法归根结底是在不同使用场景下平衡细分精度/体积/计算效率.

当前GPU就是面向平面拟合曲面的需求而创造的.

2.1.1 非封闭面

DEM是典型的非封闭三维面,我们以GRID和TIN两种DEM组织方式分析面模型的构模法.

2.1.1.1 格网模型(GRID)

格网的实质是规则间隔的经纬网点阵列:

  • 任意格网点的实际位置由起点坐标/格网点间隔距离/行列号决定.
  • 任意格网点的值就是高程值.
  • 格网间的任意位置采用插值的方式取得.

常用的编码方式:

  • 行程编码
  • 四叉树结构
  • 霍夫曼编码

优点:

  • 矩阵结构简单规则,操作方便.
  • 与栅格影像类似,可以使用处理影像的方法压缩数据.

缺点:

  • 格网的疏密决定了整体的精度,无法提高部分区域的精度,只能整体提高,随之整体体积就会变大

    • 使用复杂的编码方式会减小体积,但计算调用的时候就比较麻烦

格网法并不适合描述一般地物,因为实际的地物很难会极其均匀的分布,所以反而适合描述大气现象/高程这种无法精确描述边界同时也没有天然分布粒度的概念.

2.1.1.2 三角网模型(TIN)

TIN可以与GRID对比来看:

GRIDTIN
采样方式均匀采样按地形特征采样
图形单元大小完全相等的矩形大小不等的三角形
存储方式信息角点坐标/格网点间距/行列信息/数据体数据体/三角形表/三角形邻接表
特点粗略时体积小/精确时体积大/压缩后难以直接参与计算/编辑方便体积适中/便于进行各种分析/不便于编辑

理论上,表达同等精度的数据,TIN会比非压缩编码的GRID小一些.压缩后的GRID应该会成为更好的数据存储交换模型,适合落地在硬盘上.TIN更适合于分析和加工操作,适合放在内存里.

2.1.2 封闭面

封闭面描述的是有明确边界的地物.

2.1.2.1 边界表示模型(B-REP)

B-REP模型的核心思想是以物体的边界表面为基础,定义和描述几何体,即:

  1. 一个三维物体可以通过包容它的面描述(拓扑信息)
  2. 每个面可以用构成它的边描述(拓扑信息)
  3. 每条边可以通过构成它的点描述(拓扑信息)
  4. 每个点可以通过x,y,z三个坐标描述(几何信息)

B-REP模型的优点:

  • 显式描述几何要素,更容易理解
  • 方便进行局部操作
  • 便于在结构上附加非几何信息,如精度,表面光滑度,颜色等
  • 原则上可以表示任何物体

B-REP模型的缺点:

  • 数据结构复杂
  • 维护/存储/修改不便

基于三角网的B-REP是相当普遍的构模法,仅需两张表(坐标表/面顶点表)即可完成绝大多数模型的描述.

坐标表:

点号xyz
0x0y0z0
1x1y1z1
2x2y2z2

面顶点表:

面号顶点1顶点2顶点3
0012
1123
2234
  • 三角网构模法拟合光滑曲面的时候会很不方便,面向显示需求时问题不大,参与计算的时候可能会浪费很多资源(存储/计算资源),因为一些曲面函数无法使用.

2.2 体模型

体模型使用体元信息代替表面信息来描述对象的内部.

2.2.1 规则体元

2.2.1.1 构造实体几何模型(CSG)

CSG模型的核心思想是复杂的物体可由简单的形体(体素)经过布尔运算得到:

  • 立方体/球体/环体等都可以用数学公式描述,通过参数调整.被称为体元.

  • 体元间可以通过相加/相交/求交/求并等方式形成复杂的形体.

  • 通过调整体元的参数,可以修改物体的位置和形状.

CSG的存储结构一般为记录生成过程的有序二叉树,任何子树表示其下两个节点的组合或变换结果:

  • 根节点:最终得到的实体

  • 中间节点:

    • 正则集合运算

    • 刚体的几何变换

  • 叶节点:

    • 基本体元

    • 刚体变换参数

CSG模型的优点:

  • 数据结构简单,数据量小,易于管理

  • CSG树便于修改生成的各个环节

  • 可以方便的转换为B-REP表示

在实际的系统应用中,往往采用CSG作为用户输入输出接口(便于用户理解与操作),内部以B-REP形式存储,便于存储更详细的信息.

CSG模型的缺点:

  • 不能像B-REP模型那样适用于所有的物体

    • 总有体元覆盖不到的形状

    • 总有不方便用布尔操作描述的场景

  • 不方便直接显示.

  • 不方便作为交换格式,因为每种体元的参数都不一样,序列化/反序列化会比较麻烦

CSG更适合描述简单的人造物场景(如BIM).

2.2.2 不规则体元

2.2.2.1 四面体格网模型(TEN)

TEN的实质是2D TIN结构在三维空间的扩展:

  • 将2D-Voronoi格网扩展到3D-Voronoi.

  • 将TIN结构扩展到3D形成四面体网格.

TEN的特点:

  • 由点/线/面/体四类基本元素构成.

  • 整个格网的集合变换可以视为每个四面体变换后的组合.

  • 具有体结构模型的特征:

    • 可以快速几何变换.

    • 可以快速显示.

  • 具有边界模型的特征:

    • 方便处理拓扑关系

TEN的组织结构:

  • 四面体表:
体号面号
1A,B,C,D
2
  • 三角形表:
面号线段号
Aa,b,c
Bb,d,e
Cc,e,f
Da,e,f
E
  • 线段表:
线段号起点号终点号
a12
b13
c32
d14
e
  • 点表:
点号XYZ
11032
2432
381.53
410.5-10
5

如何通过数据结构描述TEN的组织结构是一个重要课题,随着需求的不同而不同.(在此省略)

2.3 混合模型

混合模型是目的是综合面模型/体模型/规则体元/非规则体元的优点:

  • TIN-CSG混合模型:

    • TIN存储地形表面

    • CSG存储城市建筑物

    • 通过公共边界连接

    • 对TIN/CSG的操作都是分开的,通过业务逻辑关联

  • TIN-Octree(八叉树)混合模型:

    • TIN表达三维空间物体的表面

      • 用于可视化和拓扑关系表达
    • Octree表达内部结构

      • 需要随着TIN变化而重新划分树
  • Octree-TEN混合模型:

    • Octree作为全局描述

    • Octree内部的子树嵌入TEN做局部描述

    • 适合内部破碎,表面规整的三维对象

混合模型并不适合作为通用的底层存储逻辑,而应该作为作为业务逻辑构建.

3. 总结

相比二维数据,高于二维非整数的维度都会使得底层逻辑大大复杂,更别说真三维,可见维度的些许上升都会带来信息量的极大增加,进而对整个系统都有了更多要求.

真三维数据的存储并没有万能的解决模型,都有着各自鲜明的优缺点,适合于不同的应用场景.从使用统一的数据组织形式就能解决绝大多数问题的二维时代走过来的人可能不会对此感到满意,因为这并不"优雅".

针对不同领域的构模法差异很大,但在各自的领域中又确实好用,所以,追求一个解决所有问题的模型可能就像追求"统一场论"一样,在当前环境下,必要性不大.

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
很高兴为您回答这个问题。在ROS2中,将深度图数据转换为三维标可以使用以下C++示例代码: ```cpp #include <rclcpp/rclcpp.hpp> #include <sensor_msgs/msg/image.hpp> #include <geometry_msgs/msg/point_cloud2.hpp> #include <image_geometry/pinhole_camera_model.h> #include <pcl_conversions/pcl_conversions.h> #include <pcl_ros/point_cloud.h> #include <cv_bridge/cv_bridge.h> #include <opencv2/opencv.hpp> using namespace cv; class DepthToPCLNode : public rclcpp::Node { public: DepthToPCLNode() : Node("depth_to_pcl_node") { depth_camera_info_sub_ = this->create_subscription<sensor_msgs::msg::CameraInfo>( "camera_info", rclcpp::SensorDataQoS(), std::bind(&DepthToPCLNode::depthCameraInfoCallback, this, std::placeholders::_1)); depth_image_sub_ = this->create_subscription<sensor_msgs::msg::Image>( "depth_image", rclcpp::SensorDataQoS(), std::bind(&DepthToPCLNode::depthImageCallback, this, std::placeholders::_1)); point_cloud_pub_ = this->create_publisher<geometry_msgs::msg::PointCloud2>( "point_cloud", rclcpp::SensorDataQoS()); } private: void depthCameraInfoCallback(const sensor_msgs::msg::CameraInfo::SharedPtr camera_info_msg) { image_geometry::PinholeCameraModel camera_model; camera_model.fromCameraInfo(camera_info_msg); fx_ = camera_model.fx(); fy_ = camera_model.fy(); cx_ = camera_model.cx(); cy_ = camera_model.cy(); camera_info_received_ = true; } void depthImageCallback(const sensor_msgs::msg::Image::SharedPtr depth_image_msg) { if (!camera_info_received_) { return; } cv_bridge::CvImagePtr depth_image_ptr; try { depth_image_ptr = cv_bridge::toCvCopy(depth_image_msg, sensor_msgs::image_encodings::TYPE_32FC1); } catch (cv_bridge::Exception& e) { RCLCPP_ERROR(this->get_logger(), "cv_bridge exception: %s", e.what()); return; } pcl::PointCloud<pcl::PointXYZ>::Ptr point_cloud(new pcl::PointCloud<pcl::PointXYZ>()); for (size_t v = 0; v < depth_image_ptr->image.rows; ++v) { for (size_t u = 0; u < depth_image_ptr->image.cols; ++u) { float depth = depth_image_ptr->image.at<float>(v, u); if (!std::isnan(depth) && depth > 0.0f) { pcl::PointXYZ point_cloud_point; point_cloud_point.x = (u - cx_) * depth / fx_; point_cloud_point.y = (v - cy_) * depth / fy_; point_cloud_point.z = depth; point_cloud->points.push_back(point_cloud_point); } } } geometry_msgs::msg::PointCloud2 point_cloud_msg; pcl::toROSMsg(*point_cloud, point_cloud_msg); point_cloud_msg.header = depth_image_msg->header; point_cloud_pub_->publish(point_cloud_msg); } rclcpp::Subscription<sensor_msgs::msg::CameraInfo>::SharedPtr depth_camera_info_sub_; rclcpp::Subscription<sensor_msgs::msg::Image>::SharedPtr depth_image_sub_; rclcpp::Publisher<geometry_msgs::msg::PointCloud2>::SharedPtr point_cloud_pub_; bool camera_info_received_ = false; float fx_, fy_, cx_, cy_; }; int main(int argc, char **argv) { rclcpp::init(argc, argv); rclcpp::spin(std::make_shared<DepthToPCLNode>()); rclcpp::shutdown(); return 0; } ``` 这个示例代码包括ROS2中的所有必需头文件和订阅/发布相关的示例代码。当收到深度相机信息和深度图像时,它将创建一个点云并将其转换为ROS PointCloud2消息发布到`point cloud`主题。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值