1.前言 我想着进行土方计算,后来用了 kimi 进行分析,结果给出了方案: (1)方案一: OSGB(文件夹) → 点云(PotreeConverter) → DEM(GDAL) → 差值(GDAL) → 3D-Tiles(CesiumLab CLI) → Cesium(Web)。,理论上是没有什么毛病的。我一步步的按照步骤操作,结果出现各种问题,我按照问题去解决,最后还是没有解决,浪费了很长时间,后来告诉我 PotreeConverter 无法处理 osgb 格式啊,真是操蛋。
(2)方案二: PotreeConverter 读不到点云 → OSGB 不是点云 → 用 ContextCapture 重新导出 LAS,或用 CloudCompare 采样成点云,再继续后续流程。用 CloudCompare,结果折腾了大半天,又发现 CloudCompare 也不支持 osgb 转换,又是浪费时间的一天。“CloudCompare 不支持直接读取 OSGB(倾斜摄影纹理模型);它只能处理 点云或网格,而 OSGB 属于 带纹理的三角网,因此 CLI 返回 exit 1,GUI 也弹 “unhandled file extension osgb”。CloudCompare 无法直接读取 OSGB 文件;前面提到的“File → Open OSGB → Edit → Mesh → Sample Points → Export LAS”前提是你先把 OSGB 转成 CloudCompare 能识别的格式(如 OBJ、PLY)。否则就会弹出 ”
(3)方案三: 完全开源的 OSGB → LAS 方案,使用 OpenSceneGraph 工具。我下载 OpenSceneGraph 工具,又费了很大的劲。
2.安装依赖 主要就是借助了 osgconv.exe 工具,这个工具也让我找了很久,在windows上的版本OpenSceneGraph-3.6.5-VC2022-64-2025-04.7z,反正不太好下载,下载之后,然后配置到环境变量中就可以了,linux安装如下步骤:
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 yum install gcc yum install gcc-c++ libstdc++-devel yum groupinstall "Development Tools" yum list mesa* yum install -y mesa* yum install -y freeglut* yum install -y *glew* cd OpenSceneGraphcmake . make make install ln -s ./bin/osgconv /usr/local/bin/osgconvexport PATH="${PATH} :/APP/osgb/openscenegraph-master/bin/" export LD_LIBRARY_PATH="${LD_LIBRARY_PATH} :/APP/osgb/openscenegraph-master/lib/" source /etp/profile
2.Osgb转Obj 经过不断的折腾,终于把分级的osgb合并成了 obj。
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 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 import osimport subprocessimport globimport reIN_ROOT = r"D:\zlc\earthwork\before" OUT_DIR = r"D:\zlc\earthwork\single2" OSGCONV = r"C:\Soft\OpenSceneGraph-3.6.5\bin\osgconv.exe" OSG_PLUGIN_PATH = r"C:\Soft\OpenSceneGraph-3.6.5\bin\osgPlugins-3.6.5" BATCH_SIZE = 10 TEMP_PREFIX = "temp_merge_" FINAL_OUTPUT = "merged.obj" def find_leaf_osgb_files (root_dir ): """查找所有包含几何数据的 .osgb 文件(L18~L22)""" pattern = os.path.join(root_dir, "**" , "*.osgb" ) all_files = glob.glob(pattern, recursive=True ) valid_files = [] for f in all_files: fname = os.path.basename(f) if 'root.osgb' in fname.lower(): continue if re.fullmatch(r'tile_\+\d+_\+\d+\.osgb' , fname, re.IGNORECASE): continue match = re.match (r'tile_\+\d+_\+\d+_l(\d+)_(0+)\.osgb' , fname, re.IGNORECASE) if match : level = int (match .group(1 )) zeros = match .group(2 ) if level <= 17 and zeros == '0' : continue if level >= 18 : pass else : continue level_match = re.search(r'_l(\d+)_' , fname, re.IGNORECASE) if level_match: level = int (level_match.group(1 )) if level >= 18 : valid_files.append(f) continue valid_files.sort(key=lambda x: x.lower()) return valid_files def run_osgconv (args, env, cwd ): """执行 osgconv 命令""" try : print (f"执行命令: {' ' .join(args)} " ) result = subprocess.run( args, env=env, cwd=cwd, check=True , capture_output=True , text=True , encoding='utf-8' ) print ("stdout:" , result.stdout.strip()) return True except subprocess.CalledProcessError as e: print (f"❌ 命令执行失败:{e.cmd} " ) print (f"错误输出:{e.stderr} " ) return False def main (): print ("� 正在检查环境..." ) if not os.path.exists(OSGCONV): print (f"❌ 错误:未找到 osgconv.exe!\n路径:{OSGCONV} " ) return if not os.path.exists(OSG_PLUGIN_PATH): print (f"❌ 错误:未找到 OSG 插件目录!\n路径:{OSG_PLUGIN_PATH} " ) return env = os.environ.copy() env['OSG_PLUGIN_PATH' ] = OSG_PLUGIN_PATH osgconv_dir = os.path.dirname(OSGCONV) env['PATH' ] = osgconv_dir + ';' + env.get('PATH' , '' ) os.makedirs(OUT_DIR, exist_ok=True ) print (f"� 已创建输出目录:{OUT_DIR} " ) print ("� 正在扫描 .osgb 文件..." ) leaf_files = find_leaf_osgb_files(IN_ROOT) if not leaf_files: print ("❌ 错误:未找到任何符合条件的 .osgb 文件!" ) return print (f"✅ 找到 {len (leaf_files)} 个 .osgb 文件,开始分批合并..." ) intermediate_objs = [] for i in range (0 , len (leaf_files), BATCH_SIZE): start_idx = i + 1 end_idx = min (i + BATCH_SIZE, len (leaf_files)) temp_obj = f"{TEMP_PREFIX} {start_idx:04d} .obj" print (f"� 合并第 {start_idx} ~ {end_idx} 个文件 → {temp_obj} " ) cmd = [ OSGCONV, "-O" , "OutputTextureFiles" ] cmd.extend(leaf_files[i:end_idx]) cmd.append(temp_obj) success = run_osgconv(cmd, env=env, cwd=OUT_DIR) if not success: print (f"❌ 合并失败:{temp_obj} " ) return else : print (f"✅ 成功生成:{temp_obj} " ) intermediate_objs.append(temp_obj) if len (intermediate_objs) == 1 : final_path = os.path.join(OUT_DIR, FINAL_OUTPUT) os.replace(os.path.join(OUT_DIR, intermediate_objs[0 ]), final_path) print (f"� 单批次完成,已重命名为:{FINAL_OUTPUT} " ) else : print (f"� 正在合并所有中间文件为 {FINAL_OUTPUT} ..." ) final_cmd = [ OSGCONV, "-O" , "OutputTextureFiles" ] final_cmd.extend(intermediate_objs) final_cmd.append(FINAL_OUTPUT) success = run_osgconv(final_cmd, env=env, cwd=OUT_DIR) if not success: print (f"❌ 最终合并失败!" ) return print (f"� === 成功生成 {FINAL_OUTPUT} === �" ) if __name__ == "__main__" : main()
3.Obj转Ply 将obj转为ply,也就是提取点云,有多种方法,一种是使用 CloudCompare ,一种是使用 MeshLab。 (1)CloudCompare 将obj加载进入 CloudCompare 里面,然后找到工具栏上的 “Sample Point On a Mesh”,生成点云数据之后,然后再选择File,保存导出就好了。
4.Ply转Dem 使用 CloudCompare 进行 Ply 转为 Dem,需要用到工具栏上的 “Convert a cloud to 2D raster” 工具,工具里面还要点击 Update grid 才能导出Dem。
5.计算土方量 获取到了Dem之后,就可以计算土方量了,两期DEM进行叠加,计算一个差值。
6.可视化 可视化这部分,后来老板提出一个三维可视化的概念:能不能实现在三维中,对挖方或者填方的地方进行选中,然后计算这部分的数值?这让我一度崩溃,我觉得这个需求不合理,但是就是没有可靠的证据能证明这个事情。所以我大量的查找资料,什么变化监测,3dtiles分区,点云聚类之类的,但是最后还是无果。我问过有些人,他们说能做,能选中变化区域,可是我始终没看到过实际的效果和例子。
(1)热力图 其实用二维好实现,就是把DEM做成一个热力图的形式,然后高的地方用红色,低的地方用蓝色等等,但是
(2)三维面片化 另外一种就是针对生成的 diff_result.tif 直接进行面片化,也就是把 dem 进行三维展示。打开 CloudCompare 选中 Dem -> Edit -> Mesh -> Delaunay 2.5D(XY Plane),可以将Dem进行三维化。
7.变化检测 1 2 3 4 conda install -c conda-forge python-pdal laspy conda install "blas=*=openblas" numpy scipy --force-reinstall
8.植被区域问题 (1)变化区域 过滤掉0.2米以内的数据
(1)联通区域 将Dem差值进行联通,如果联通区域内的面积较小,那么需要忽略
(2)狭长区域 如果联通区域较为狭长,需要忽略
(3)坡度统计 如果联通区域内的坡度都较为陡峭,有多个峰谷,也需要去掉
(4)空洞统计 如果联通区域内,面积和空洞的比率较大,也需要过滤掉。
问题 (1)returned non-zero exit status 3221226505 使用 osgb转为 las 的时候,出现了这个问题,其实关键问题是 PotreeConverter 不支持 osgb,让我弄了很久,kimi 的大模型还真是扯淡,这么低级的错误都能犯。
1 2 3 4 5 6 7 File "D:\zlc\earthwork\scripts\osgb2las.py", line 20, in <module> osgb_folder_to_las(osgb_root, out_las) File "D:\zlc\earthwork\scripts\osgb2las.py", line 15, in osgb_folder_to_las subprocess.run(cmd, check=True) File "C:\Soft\anaconda3\envs\yolo11\Lib\subprocess.py", line 571, in run raise CalledProcessError(retcode, process.args, subprocess.CalledProcessError: Command '['D:\\zlc\\earthwork\\scripts\\..\\tools\\PotreeConverter.exe', '-i', 'D:\\zlc\\earthwork\\before', '-o', 'D:\\zlc\\earthwork\\output', '--output-format', 'las', '-l', '1', '--generate-page', '0']' returned non-zero exit status 3221226505.
(2) DLL load failed while importing _base: 找不到指定的程序 无法使用 conda 进行 rasterio 安装,我遇到的问题就是使用 rasterio 的时候,如果用 conda 进行安装的时候,总是会报,找不到指定程序的问题,最后我只能是用 pip 安装 rasterio。
1 2 3 4 5 File "D:\zlc\earthwork\scripts\calculare_earthwork.py" , line 3, in <module> import rasterio File "C:\Soft\anaconda3\envs\earthwork\Lib\site-packages\rasterio\__init__.py" , line 25, in <module> from rasterio._base import DatasetBase ImportError: DLL load failed while importing _base: 找不到指定的程序。
【尝试方案】
1 2 3 4 5 pip install rasterio conda install -c conda-forge gdal
(3)ImportError: DLL load failed while importing pyexpat: 操作系统无法运行 %1。 另外还有一个问题,那就是安装了 matplotlib之后,总是报错:ImportError: DLL load failed while importing pyexpat: 操作系统无法运行 %1。
【解决方案】
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 pip uninstall matplotlib conda install -c conda-forge matplotlib pip uninstall matplotlib conda install -c conda-forge matplotlib conda deactivate conda env remove -n earthwork conda create -n earthwork python=3.11 conda activate earthwork conda config --env --add channels conda-forge conda config --env --set channel_priority strict conda install -c conda-forge rasterio matplotlib numpy pillow
(4)Intel oneMKL FATAL ERROR: Cannot load mkl_intel_thread.2.dll. 在运行的时候,出现了一个 Intel MKL 库 问题。
【解决方案】 解决方案就是重新安装 numpy
1 2 3 4 pip uninstall numpy conda install "blas=*=openblas" numpy --force-reinstall