当前位置: 首页 > news >正文

3D 点云体积测量:货物堆方量检测实战

3D 点云体积测量:货物堆方量检测实战

1. 堆方量概念

堆方量(Bulk Volume): ├── 定义:松散货物堆放的体积 ├── 应用:矿石、粮食、煤炭、砂石 ├── 测量:传统人工测量 vs 视觉测量 └── 精度要求:±3%(商业结算) 视觉测量优势: ├── 非接触式:不影响堆放 ├── 实时性:秒级测量 ├── 高精度:±1-2% └── 自动化:减少人工

2. 深度相机点云采集

#!/usr/bin/env python3"""pointcloud_capture.py - 点云采集"""importcv2importnumpyasnpimportopen3daso3dimportpyrealsense2asrsclassPointCloudCapture:"""点云采集器"""def__init__(self):self.pipeline=rs.pipeline()config=rs.config()config.enable_stream(rs.stream.depth,1280,720,rs.format.z16,30)config.enable_stream(rs.stream.color,1280,720,rs.format.bgr8,30)self.pipeline.start(config)align_to=rs.stream.color self.align=rs.align(align_to)# 获取内参profile=self.pipeline.get_active_profile()self.intrinsics=profile.get_stream(rs.stream.color).as_video_stream_profile().get_intrinsics()defcapture_pointcloud(self):"""采集一帧点云"""frames=self.pipeline.wait_for_frames()aligned=self.align.process(frames)depth_frame=aligned.get_depth_frame()color_frame=aligned.get_color_frame()# 创建点云pc=rs.pointcloud()pc.map_to(color_frame)points=pc.calculate(depth_frame)# 转 Open3D 格式vertices=np.asanyarray(points.get_vertices()).view(np.float32).reshape(-1,3)colors=np.asanyarray(color_frame.get_data()).reshape(-1,3)/255.0pcd=o3d.geometry.PointCloud()pcd.points=o3d.utility.Vector3dVector(vertices)pcd.colors=o3d.utility.Vector3dVector(colors)returnpcddefcapture_multi_view(self,num_views=4):"""多视角采集"""pcds=[]foriinrange(num_views):print(f"采集视角{i+1}/{num_views}...")input("调整相机位置后按 Enter...")pcd=self.capture_pointcloud()pcds.append(pcd)# 多视角融合merged=self._merge_pointclouds(pcds)returnmergeddef_merge_pointclouds(self,pcds):"""多视角点云融合"""iflen(pcds)==1:returnpcds[0]# ICP 配准merged=pcds[0]foriinrange(1,len(pcds)):reg=o3d.pipelines.registration.registration_icp(pcds[i],merged,0.02,np.eye(4),o3d.pipelines.registration.TransformationEstimationPointToPoint())pcds[i].transform(reg.transformation)merged+=pcds[i]# 降采样merged=merged.voxel_down_sample(voxel_size=0.01)returnmergedif__name__=="__main__":capture=PointCloudCapture()pcd=capture.capture_pointcloud()# 保存点云o3d.io.write_point_cloud("stockpile.pcd",pcd)print(f"点云点数:{len(pcd.points)}")

3. 体积计算算法

#!/usr/bin/env python3"""volume_calc.py - 点云体积计算"""importnumpyasnpimportopen3daso3dclassVolumeCalculator:"""体积计算器"""def__init__(self):passdefcalculate_volume_convex_hull(self,pcd):"""凸包体积"""hull,_=pcd.compute_convex_hull()volume=hull.get_volume()returnvolumedefcalculate_volume_alpha_shape(self,pcd,alpha=0.05):"""Alpha Shape 体积(更精确)"""mesh=o3d.geometry.TriangleMesh.create_from_point_cloud_alpha_shape(pcd,alpha)volume=mesh.get_volume()returnvolumedefcalculate_volume_voxel(self,pcd,voxel_size=0.01):"""体素化体积"""# 体素化voxel_grid=o3d.geometry.VoxelGrid.create_from_point_cloud(pcd,voxel_size)voxels=voxel_grid.get_voxels()# 体积 = 体素数 × 体素体积voxel_volume=voxel_size**3total_volume=len(voxels)*voxel_volumereturntotal_volumedefcalculate_volume_height_map(self,pcd,grid_size=0.05):"""高度图体积"""points=np.asarray(pcd.points)# 创建网格x_min,y_min=points[:,0].min(),points[:,1].min()x_max,y_max=points[:,0].max(),points[:,1].max()x_bins=np.arange(x_min,x_max,grid_size)y_bins=np.arange(y_min,y_max,grid_size)# 计算每个网格的最大高度height_map=np.zeros((len(y_bins),len(x_bins)))forpointinpoints:x_idx=int((point[0]-x_min)/grid_size)y_idx=int((point[1]-y_min)/grid_size)if0<=x_idx<len(x_bins)and0<=y_idx<len(y_bins):height_map[y_idx,x_idx]=max(height_map[y_idx,x_idx],point[2])# 计算底面高度(取最小值或已知值)base_height=points[:,2].min()# 体积 = Σ(高度差 × 网格面积)height_diff=height_map-base_height volume=np.sum(height_diff[height_diff>0])*grid_size**2returnvolume,height_mapdefcalculate_stockpile_volume(self,pcd,base_plane=None):"""计算堆料体积"""points=np.asarray(pcd.points)ifbase_planeisNone:# 自动检测底面(RANSAC 平面拟合)plane_model,inliers=pcd.segment_plane(distance_threshold=0.02,ransac_n=3,num_iterations=1000)base_height=np.mean(points[inliers,2])else:base_height=base_plane# 过滤底面以上的点above_base=points[points[:,2]>base_height+0.01]# 计算体积(高度图法)pcd_above=o3d.geometry.PointCloud()pcd_above.points=o3d.utility.Vector3dVector(above_base)volume,height_map=self.calculate_volume_height_map(pcd_above)return{'volume':volume,'base_height':base_height,'max_height':above_base[:,2].max()-base_height,'height_map':height_map,}if__name__=="__main__":# 加载点云pcd=o3d.io.read_point_cloud("stockpile.pcd")calc=VolumeCalculator()# 方法 1:凸包vol_convex=calc.calculate_volume_convex_hull(pcd)print(f"凸包体积:{vol_convex:.2f}m³")# 方法 2:高度图result=calc.calculate_stockpile_volume(pcd)print(f"堆料体积:{result['volume']:.2f}m³")print(f"最大高度:{result['max_height']:.2f}m")

4. 精度校准

#!/usr/bin/env python3"""calibration.py - 体积测量精度校准"""importnumpyasnpclassVolumeCalibrator:"""体积测量校准器"""def__init__(self):self.scale_factor=1.0self.bias=0.0defcalibrate(self,measured_volumes,reference_volumes):"""校准"""measured=np.array(measured_volumes)reference=np.array(reference_volumes)# 线性回归: reference = scale * measured + biasA=np.vstack([measured,np.ones(len(measured))]).T self.scale_factor,self.bias=np.linalg.lstsq(A,reference,rcond=None)[0]# 计算校准后误差calibrated=self.scale_factor*measured+self.bias errors=np.abs(calibrated-reference)/reference*100print(f"校准系数: scale={self.scale_factor:.4f}, bias={self.bias:.4f}")print(f"校准前平均误差:{np.mean(np.abs(measured-reference)/reference*100):.2f}%")print(f"校准后平均误差:{np.mean(errors):.2f}%")defapply_calibration(self,measured_volume):"""应用校准"""returnself.scale_factor*measured_volume+self.bias# 校准示例calibrator=VolumeCalibrator()# 已知体积的标定物calibrator.calibrate(measured_volumes=[1.02,2.05,3.08,4.12,5.15],reference_volumes=[1.00,2.00,3.00,4.00,5.00])

5. 实时堆方量监测

#!/usr/bin/env python3"""realtime_stockpile.py - 实时堆方量监测"""importcv2importnumpyasnpimporttimeclassStockpileMonitor:"""堆方量监测器"""def__init__(self,camera,calculator):self.camera=camera self.calculator=calculator self.history=[]defmeasure_once(self):"""单次测量"""pcd=self.camera.capture_pointcloud()result=self.calculator.calculate_stockpile_volume(pcd)self.history.append({'time':time.time(),'volume':result['volume'],'max_height':result['max_height'],})returnresultdefget_trend(self,window=10):"""获取趋势"""iflen(self.history)<2:return0recent=self.history[-window:]volumes=[h['volume']forhinrecent]# 计算变化率iflen(volumes)>=2:rate=(volumes[-1]-volumes[0])/len(volumes)returnratereturn0defrun(self,interval=5):"""持续监测"""print("开始堆方量监测...")whileTrue:result=self.measure_once()trend=self.get_trend()print(f"体积:{result['volume']:.2f}m³ | "f"最大高度:{result['max_height']:.2f}m | "f"变化率:{trend:+.2f}m³/次")time.sleep(interval)if__name__=="__main__":camera=PointCloudCapture()calculator=VolumeCalculator()monitor=StockpileMonitor(camera,calculator)monitor.run()

总结

方法精度速度适用场景
凸包凸形物体
Alpha Shape不规则形状
高度图堆料/仓储
体素化复杂形状
http://www.gsyq.cn/news/1611898.html

相关文章:

  • 基于STM32单片机甲醛浓度检测有害气体空气质量智能家居系统成品1(设计源文件+万字报告+讲解)(支持资料、图片参考_相关定制)_
  • 企业级AI Agent平台架构设计与Spring Boot实现
  • 130多个 Home Assistant 插件,一个人维护的仓库
  • 离石 KTV 全套设备
  • 鸿蒙原生 ArkTS 布局深度解析:width / height 固定尺寸与百分比尺寸完全指南
  • 基于单片机人脸识别电子密码锁智能门禁指纹识别语音提醒防盗成品11(设计源文件+万字报告+讲解)(支持资料、图片参考_相关定制)_
  • DiffusionGemma 是什么:Google 为什么用扩散模型做文本生成
  • 全星 APQP——QMS 一体化平台:打通 QMS,AI 赋能研发数智化建设——上海全星数智平台
  • Mac 党转 Linux 必看:用 keyd 复刻你最熟悉的快捷键习惯
  • 无人机合速度和航捷转速度分量
  • OpenCV VideoCapture 类
  • 新店起店怎么查抖音小店对标数据?蝉妈妈拆解头部4要点
  • 专访大晓机器人王飞:世界模型是“进化型基础设施”
  • 基于51/STM32单片机温度控制系统 恒温箱 水温控制 温度采集 成品1(设计源文件+万字报告+讲解)(支持资料、图片参考_相关定制)_
  • 别再盲目试用了!AI编程助手采购决策树:按团队规模、语言栈、安全等级自动匹配最优组合(含SaaS/私有化/混合部署ROI计算表)
  • 公开课紧张到忘词?老教师都在用的3个临场应对方法
  • Dism++深度解析:现代化Windows系统维护架构与技术实现
  • 【VMware磁盘扩容终极指南】:20年运维专家亲授5种零宕机扩容方案,99%的人不知道第3种!
  • 2026年技术方向怎么选?机器视觉、PLC、AI大模型、嵌入式深度对比
  • 从H100的异步执行和线程块集群,聊聊如何榨干GPU的每一分算力
  • Python爬虫经典案例018:爬虫性能优化与调优——从慢到快的全面优化指南
  • VisualCppRedist AIO:终极Windows运行库一体化智能管理解决方案深度解析
  • 国家标准起草单位是什么?有什么价值?企业如何申请参与国标制定
  • 上门按摩APP小程序开发公司,获客新思路:酒店渠道为什么值得做
  • 如何在一部手机上实现工作与生活数据的完全隔离?
  • SIM 卡克隆工具指南:安全移动 SIM 卡数据
  • 如何利用多人协作在线表格提升团队效率?告别协作混乱与数据勒索
  • API受限下15种LLM幻觉抑制创新方法
  • Unreal Engine 5.7 C++ 完整说明(C++ 标准、内置库、第三方库、内存 GC)
  • 课堂时间总不够用?这5个环节压缩技巧让教学节奏更从容