当前位置: 首页 > 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.jsqmd.com/news/1099933/

相关文章:

  • operator-manager ClusterServiceVersion控制器:Operator部署与权限管理的核心技术
  • 企业级AI Agent平台架构设计与Spring Boot实现
  • MCP Python SDK:给大模型接入工具和数据的标准协议
  • 130多个 Home Assistant 插件,一个人维护的仓库
  • 盐城装修付款避坑的四个核心注意要点
  • 1500公里跑掉的21斤,我用15个月又长了回来——36岁,我决定重返跑步的江湖
  • 鸿蒙原生 ArkTS 布局深度解析:width / height 固定尺寸与百分比尺寸完全指南
  • 基于单片机人脸识别电子密码锁智能门禁指纹识别语音提醒防盗成品11(设计源文件+万字报告+讲解)(支持资料、图片参考_相关定制)_
  • 离石 KTV 全套设备
  • 2026年7月国内充值 GPT:为什么我不再建议只找低价渠道?
  • PHP+VUE医疗预约系统毕业设计:全栈开发实战与二次开发指南
  • 3步解锁加密音频:让您的QQ音乐文件在任何设备自由播放
  • 深度测评2026年AI论文工具:这几款让论文写作不再是难题
  • Python 入门:常用数据类型与程序结构详解(二)
  • 从Coze到Dify:手把手构建电商AI智能体工作流实战
  • 算法之旅-Hot100—字母异位词分组
  • DiffusionGemma 是什么:Google 为什么用扩散模型做文本生成
  • AI时代下的前端求生之路
  • 第一章Netty,如何处理客户端断开连接的事件
  • 最新量化验证,回测模拟实盘不是一件事
  • PHP+VUE医疗预约系统毕业设计:从环境搭建到核心业务实现全流程详解
  • 从Prompt到RAG:AI大模型应用开发全链路实战指南
  • 全星 APQP——QMS 一体化平台:打通 QMS,AI 赋能研发数智化建设——上海全星数智平台
  • Mac 党转 Linux 必看:用 keyd 复刻你最熟悉的快捷键习惯
  • Sa-Token:48,800+ Star 的背后让鉴权变得简单优雅
  • open harmony 项目实战:给语文学习 App 做一个高端精致的沉浸式界面
  • OpenCV VideoCapture 类
  • 无人机合速度和航捷转速度分量
  • 大数据志愿填报冲稳保如何搭配院校梯度
  • 龙芯3B6000服务器手动安装Docker 29.5.1实战指南