基于shp数据实现obj模型的切割(模型单体化思路)


目的

在三维仿真的场景中,无人机影像的建模是一种快速可靠的对大场景地形三维重现的方式,但是无人机影像的建模无法对单个场景的属性进行分析,如对单个楼层、居民区进行属性分析查询。在GIS中,我们通过shp数据描述空间信息,这些数据通常以点线面的形式,即概括了地物的空间关系也包含地物的属性信息。通过shp数据和无人机影像建模的结合,可以将大范围三维场景的模型进行分割,使之成为一个个独立的单元并且赋予属性信息,本文通过一个小实验来实现shp面对obj模型中某个单个建筑的分割。
image.png

数据准备

采用网上公开无人机影像数据,通过contextcapture对影像进行建模,生成倾斜摄影数据和obj模型,本文采用obj模型进行切割。
无人机影像的空三建模.png
由于模型场景很大,本文采用截取一个单体建筑的方式来对场景进行裁剪,后期需要裁剪所有建筑,则需要迭代计算并优化效率(黑框全选为需要裁剪的建筑)。
image.png

shp数据为建筑面数据

算法思路

由于obj模型包含顶点和纹理,而shp数据基本处于二维平面,那么需要考虑顶点落在shp面数据xy平面内的数据,同时,一个面最少由三个顶点构成,如果一个面的部分在shp范围内,部分在范围外,则需要重新分割,生成新的顶点并构建网格。

obj数据的格式

通常简单的obj数据包含顶点信息,纹理信息,面信息,有的obj还包含一个mtl文件
其中常见的obj数据的组成形式为:

  • 首行:mtllib *.mtl 表示使用哪个mtl文件,以mtllib开头
  • 顶点坐标: v x y z 表示一个顶点的坐标,以v开头
  • 纹理坐标: vt u v 表示一个纹理的坐标,以vt开头
  • 引用的材质:usemtl * 表示引用mtl文件的哪部分纹理,以usemtl开头
  • 面索引:f v_i1/u_i1 v_i2/u_i2 v_i3/u_i3 ,以f开头,分别记录 顶点的序号和纹理的序号,序号从1开始,一个面由三个顶点组成,所以有三个顶点序号和纹理序号

mtl文件的格式

mtl记录了纹理的一些配置信息,主要有:

  • newmtl *: 创建一个材质,材质名为*,对应obj中的usemtl *
  • ka * * *: 环境颜色
  • kd * * *:漫反射颜色
  • d *: 透明度
  • Ns: *: 高光指数
  • illum: * : 光照模型
  • map_kd: *.jpg:纹理图片的名称

以上可以得出一个结论,一个mtl可以创建多个材质,那么在obj的面索引前面,可以多次引入材质信息,这个材质信息下面对应的面索引的顶点和纹理坐标,使用该材质

解析obj数据

实验采用python语言,通过pywavefront库解析obj模型

model = pywavefront.Wavefront(r"D:\data\osgb\mec\Production_1 (3)\Data\Model\2.obj",collect_faces=True)

解析后的数据存在在model对象上,那么就需要知道model对象对应的成员有哪些:
  • materials: 记录了材质信息
    • vertices: 一个坐标数组,五个数据一组,前两位表示纹理坐标,后三位表示顶点坐标
  • mtllibs: 模型使用的mtl文件名,以数组形式存储
  • vertices: 顶点坐标数组
  • meshes: 格网列表,表示面数据索引集合

由于每个材质对应了一部分三角格网数据,格网数据对应了相应的顶点和纹理坐标数据,因此在解析数据的时候以材质进行分类,先记录每个材质的相关信息,在根据材质读取对应的顶点坐标和纹理坐标,进行裁剪和划分。

for mesh_name in model.materials:
    model_mesh = model.materials[mesh_name]
    if model_mesh.texture == None:
        continue
    newmtl = model_mesh.name
    #环境颜色
    Ka = model_mesh.ambient
    #漫反射颜色
    Kd = model_mesh.diffuse
    #透明度
    d = model_mesh.transparency
    #高光指数
    Ns = model_mesh.specular
    #光照模型
    illum = model_mesh.illumination_model
    #材质
    map_Kd = model_mesh.texture.file_name
    file_path = model_mesh.texture.path
    vertices = model_mesh.vertices
    new_faces = []
    new_mtls = []
    split_faces = []
    split_mtls = []
    flag = False
	#获取顶点和纹理坐标
	#检查面的顶点是否在多边形内
	#实现面的分割逻辑
            
    if flag:
        materials = {
   
   
            "Ka": Ka,
            "Kd": Kd,
            "d": d,
            "Ns": Ns,
            "illum": illum,
            "map_Kd": map_Kd,
            "file_path": file_path,
            "new_faces": new_faces,
            "new_mtls": new_mtls,
            "split_faces": split_faces,
            "split_mtls": split_mtls,
            "newmtl":newmtl
        } 
        newObj.append(materials)

        

如上所示,首先根据材质读取材质信息,然后检查面的顶点是否在多边形内,如果面的所有顶点都在多边形内,那么只需要保留这个面的顶点和纹理坐标就行;如果面的部分顶点在多边形内,部分不在,则需要进行分割。
由于顶点和纹理信息存储在model_mesh.vertices中,只需要遍历该数据,即可获取对应的顶点坐标和纹理坐标。

  for index in range(int(len(vertices) /5/3) ):
        #计算每一个面
        projected_vertices = []
        new_mtl = []
        for i in range(3):
            projected_vertices.append([vertices[15*index+2 + 5*i],vertices[15*index+3+5*i],vertices[15*index+4+5*i]])
            new_mtl.append([vertices[15*index+0 + 5*i],vertices[15*index+1 + 5*i]])
        #检查面的顶点是否在多边形内
       
        #实现面的分割逻辑
           

进行分割和裁剪面的构建

​ 多边形的构建采用shapely库,由于是对一个shp要素进行裁剪,因此可以直接通过shapely构建一个多边形要素作为该建筑轮廓,实际分割中也可以采取读取shp要素,依次构建的方式。

# 定义多边形
polygon = shapely.geometry.Polygon([(12730175.00000000 ,3571689.50000000),(12730175.00000000 ,3571656.25000000),(12730189.00000000,3571656.25000000),(12730189.00000000 ,3571625.25000000),(12730175.00000000,3571625.00000000),(12730175.00000000,3571628.75000000),(12730113.00000000,3571628.50000000),(12730113.00000000,3571626.00000000),(12730099.00000000,3571626.00000000),(12730099.00000000,3571651.25000000),(
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

水塔鸡丝

创作不易,感谢支持

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值