3D 点云体积测量:货物堆方量检测实战
3D 点云体积测量货物堆方量检测实战1. 堆方量概念堆方量Bulk Volume ├── 定义松散货物堆放的体积 ├── 应用矿石、粮食、煤炭、砂石 ├── 测量传统人工测量 vs 视觉测量 └── 精度要求±3%商业结算 视觉测量优势 ├── 非接触式不影响堆放 ├── 实时性秒级测量 ├── 高精度±1-2% └── 自动化减少人工2. 深度相机点云采集#!/usr/bin/env python3pointcloud_capture.py - 点云采集importcv2importnumpyasnpimportopen3daso3dimportpyrealsense2asrsclassPointCloudCapture:点云采集器def__init__(self):self.pipeliners.pipeline()configrs.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_tors.stream.color self.alignrs.align(align_to)# 获取内参profileself.pipeline.get_active_profile()self.intrinsicsprofile.get_stream(rs.stream.color).as_video_stream_profile().get_intrinsics()defcapture_pointcloud(self):采集一帧点云framesself.pipeline.wait_for_frames()alignedself.align.process(frames)depth_framealigned.get_depth_frame()color_framealigned.get_color_frame()# 创建点云pcrs.pointcloud()pc.map_to(color_frame)pointspc.calculate(depth_frame)# 转 Open3D 格式verticesnp.asanyarray(points.get_vertices()).view(np.float32).reshape(-1,3)colorsnp.asanyarray(color_frame.get_data()).reshape(-1,3)/255.0pcdo3d.geometry.PointCloud()pcd.pointso3d.utility.Vector3dVector(vertices)pcd.colorso3d.utility.Vector3dVector(colors)returnpcddefcapture_multi_view(self,num_views4):多视角采集pcds[]foriinrange(num_views):print(f采集视角{i1}/{num_views}...)input(调整相机位置后按 Enter...)pcdself.capture_pointcloud()pcds.append(pcd)# 多视角融合mergedself._merge_pointclouds(pcds)returnmergeddef_merge_pointclouds(self,pcds):多视角点云融合iflen(pcds)1:returnpcds[0]# ICP 配准mergedpcds[0]foriinrange(1,len(pcds)):rego3d.pipelines.registration.registration_icp(pcds[i],merged,0.02,np.eye(4),o3d.pipelines.registration.TransformationEstimationPointToPoint())pcds[i].transform(reg.transformation)mergedpcds[i]# 降采样mergedmerged.voxel_down_sample(voxel_size0.01)returnmergedif__name____main__:capturePointCloudCapture()pcdcapture.capture_pointcloud()# 保存点云o3d.io.write_point_cloud(stockpile.pcd,pcd)print(f点云点数:{len(pcd.points)})3. 体积计算算法#!/usr/bin/env python3volume_calc.py - 点云体积计算importnumpyasnpimportopen3daso3dclassVolumeCalculator:体积计算器def__init__(self):passdefcalculate_volume_convex_hull(self,pcd):凸包体积hull,_pcd.compute_convex_hull()volumehull.get_volume()returnvolumedefcalculate_volume_alpha_shape(self,pcd,alpha0.05):Alpha Shape 体积更精确mesho3d.geometry.TriangleMesh.create_from_point_cloud_alpha_shape(pcd,alpha)volumemesh.get_volume()returnvolumedefcalculate_volume_voxel(self,pcd,voxel_size0.01):体素化体积# 体素化voxel_grido3d.geometry.VoxelGrid.create_from_point_cloud(pcd,voxel_size)voxelsvoxel_grid.get_voxels()# 体积 体素数 × 体素体积voxel_volumevoxel_size**3total_volumelen(voxels)*voxel_volumereturntotal_volumedefcalculate_volume_height_map(self,pcd,grid_size0.05):高度图体积pointsnp.asarray(pcd.points)# 创建网格x_min,y_minpoints[:,0].min(),points[:,1].min()x_max,y_maxpoints[:,0].max(),points[:,1].max()x_binsnp.arange(x_min,x_max,grid_size)y_binsnp.arange(y_min,y_max,grid_size)# 计算每个网格的最大高度height_mapnp.zeros((len(y_bins),len(x_bins)))forpointinpoints:x_idxint((point[0]-x_min)/grid_size)y_idxint((point[1]-y_min)/grid_size)if0x_idxlen(x_bins)and0y_idxlen(y_bins):height_map[y_idx,x_idx]max(height_map[y_idx,x_idx],point[2])# 计算底面高度取最小值或已知值base_heightpoints[:,2].min()# 体积 Σ(高度差 × 网格面积)height_diffheight_map-base_height volumenp.sum(height_diff[height_diff0])*grid_size**2returnvolume,height_mapdefcalculate_stockpile_volume(self,pcd,base_planeNone):计算堆料体积pointsnp.asarray(pcd.points)ifbase_planeisNone:# 自动检测底面RANSAC 平面拟合plane_model,inlierspcd.segment_plane(distance_threshold0.02,ransac_n3,num_iterations1000)base_heightnp.mean(points[inliers,2])else:base_heightbase_plane# 过滤底面以上的点above_basepoints[points[:,2]base_height0.01]# 计算体积高度图法pcd_aboveo3d.geometry.PointCloud()pcd_above.pointso3d.utility.Vector3dVector(above_base)volume,height_mapself.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__:# 加载点云pcdo3d.io.read_point_cloud(stockpile.pcd)calcVolumeCalculator()# 方法 1凸包vol_convexcalc.calculate_volume_convex_hull(pcd)print(f凸包体积:{vol_convex:.2f}m³)# 方法 2高度图resultcalc.calculate_stockpile_volume(pcd)print(f堆料体积:{result[volume]:.2f}m³)print(f最大高度:{result[max_height]:.2f}m)4. 精度校准#!/usr/bin/env python3calibration.py - 体积测量精度校准importnumpyasnpclassVolumeCalibrator:体积测量校准器def__init__(self):self.scale_factor1.0self.bias0.0defcalibrate(self,measured_volumes,reference_volumes):校准measurednp.array(measured_volumes)referencenp.array(reference_volumes)# 线性回归: reference scale * measured biasAnp.vstack([measured,np.ones(len(measured))]).T self.scale_factor,self.biasnp.linalg.lstsq(A,reference,rcondNone)[0]# 计算校准后误差calibratedself.scale_factor*measuredself.bias errorsnp.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_volumeself.bias# 校准示例calibratorVolumeCalibrator()# 已知体积的标定物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 python3realtime_stockpile.py - 实时堆方量监测importcv2importnumpyasnpimporttimeclassStockpileMonitor:堆方量监测器def__init__(self,camera,calculator):self.cameracamera self.calculatorcalculator self.history[]defmeasure_once(self):单次测量pcdself.camera.capture_pointcloud()resultself.calculator.calculate_stockpile_volume(pcd)self.history.append({time:time.time(),volume:result[volume],max_height:result[max_height],})returnresultdefget_trend(self,window10):获取趋势iflen(self.history)2:return0recentself.history[-window:]volumes[h[volume]forhinrecent]# 计算变化率iflen(volumes)2:rate(volumes[-1]-volumes[0])/len(volumes)returnratereturn0defrun(self,interval5):持续监测print(开始堆方量监测...)whileTrue:resultself.measure_once()trendself.get_trend()print(f体积:{result[volume]:.2f}m³ | f最大高度:{result[max_height]:.2f}m | f变化率:{trend:.2f}m³/次)time.sleep(interval)if__name____main__:cameraPointCloudCapture()calculatorVolumeCalculator()monitorStockpileMonitor(camera,calculator)monitor.run()总结方法精度速度适用场景凸包低快凸形物体Alpha Shape中中不规则形状高度图高快堆料/仓储体素化高慢复杂形状