
先说个实在话客流统计这个需求乍一听真不是什么大事。门口放个数人头的东西进一个加一出一个减一完事。但等你在真实门店里跑过一轮就会明白“数人”这两个字背后牵扯的是深度相机选型、空间标定、目标追踪、事件去重、消息投递这一整条链路。任何一个环节没做到位你给运营报出来的数字到了晚上盘点的时候都会被现实狠狠打脸。这篇文章我把做“3D视觉AI客流系统”的完整思路摊开聊一聊。从底层的Sensor Pipeline怎么把深度图变成人的坐标轨迹到上层的数据事件引擎怎么把轨迹变成“进门”“出门”“停留”这类业务事件。适合正在做智慧零售、门店数字化、楼宇安防相关系统的开发者也适合想评估技术方案的架构师看完基本可以直接拿去当系统设计底稿用。1. 为什么客流系统要盯着3D视觉做1.1 2D方案不够用的真实原因很多团队做客流统计第一反应是上2D摄像头加一个目标检测模型YOLO拉起来框住人就算一个人。但这个方案落地之后问题一个接一个。先说光照问题。2D画面的质量极度依赖现场光线逆光、暗光、地面反光、高光灯箱都会让检测器失灵。尤其门店入口这种地方经常是一边是室内灯一边是自然光亮度差好几个挡位2D检测在这种高动态范围场景下非常容易漏检。再说遮挡问题。客流高峰时人挨着人2D检测器在俯视角度下看到的是大片头顶和肩膀目标之间的边界非常模糊。如果用平视或斜视角度又会被前后遮挡严重干扰。检测框重叠率高的时候你根本分不清是两个人还是一群人。还有一个经常被忽略的点2D画面里没有身高信息。你没法区分一个背着包的大人和一个站在推车旁边的儿童没法判断这个人是在正常行走还是在蹲下系鞋带更没法把“人”和“购物车里的货物”精确分离开。运营想分析“小孩进店率”或者“弯腰挑选时长”2D方案很难给出可靠答案。隐私问题也越来越绕不过去。摄像头对着顾客从头拍到尾人脸、身形都会留下数据痕迹。在国内外的合规要求下采集原始RGB画面并传回云端本身就是一种风险。一旦客户问起来“你们存储的人脸数据在哪、怎么删”答不上来就是事故。1.2 3D视觉的工程优势到底体现在哪3D视觉方案的核心变化是把“从图像里认人”变成了“从几何结构里找目标”。这是两个完全不同的问题。深度相机返回的是一张深度图每个像素的值代表这个点到相机的距离。在顶部安装的场景下人头顶离相机最近所以深度图上人头顶的区域会形成一个明显的“凸起”或“凹陷”根据深度方向定义不同有所差异。这种几何特征比RGB纹理稳定得多光照变化不影响深度地面反光不影响深度穿什么颜色衣服也不影响深度。更实际的优势是脱敏。深度图本质上是一堆距离值不包含人脸纹理信息拿出去给客户看客户能接受合规压力也小。就算要做二次分析也只需要在边缘端保留目标的3D位置、速度、轨迹不需要保存任何可识别身份的图像。3D视觉还有一个隐藏价值支持“高度维度”的精细化判断。比如区分大人和小孩只需要看目标团的体积和高度判断一个人是否蹲下只需要看头部高度是否明显低于周围站立人群的头部平面判断购物车是否载人可以通过目标高度和运动模式来区分。这些都是2D方案很难做到的事情。1.3 传感器选型ToF、结构光、双目怎么定深度相机的选型是整个系统最容易被低估的一步。很多人以为“随便拿一款深度相机就能跑”结果现场的玻璃墙、黑色地面、自然光干扰直接把深度图打成筛子。三种主流方案的取舍我直接按下表对比方案原理典型测距优点主要限制ToF发射红外光测量反射时间差0.3m-8m帧率高、点云均匀、成本适中、暗光可用室外强光红外干扰大多台设备可能互相干扰结构光投射编码光斑根据形变计算深度0.3m-2m近距离精度极高功耗低距离受限环境光敏感黑色/反光表面效果差双目立体视觉双摄像头视差匹配0.2m-10m室外可用不主动发射光源支持远距离弱纹理场景效果差计算量大暗光需要补光客流系统绝大多数场景是室内天花板安装高度在2.8米到3.5米之间检测区域半径大约3到5米。我个人比较推荐ToF方案理由有两个第一工作距离正好覆盖这个区间第二顶部俯视时人头顶的反射率相对稳定ToF在这种几何场景下点云质量很扎实。结构光更适合近距离交互场景比如门禁闸机、自助收银台边上做一个1到2米内的人体识别。双目适合户外或半户外场景比如商业街入口、码头轮渡口这种遮挡少但红外光干扰大的地方但它对算力要求高边缘设备上跑实时视差计算会比较吃力。另一个容易忽略的点是相机的视场角和分辨率。安装高度越高地面覆盖范围越大但单位面积上的像素数会下降。一般来说水平视场角不低于90度的相机在3米高安装时能覆盖差不多20到40平米的区域。如果门店入口特别宽不要盲目买一台超广角相机更靠谱的做法是上两台相机做拼接每台负责一片区域重叠区控制在10%以内。2. Sensor Pipeline把深度图变成人的轨迹2.1 相机接入与数据对齐Sensor Pipeline的第一段是把深度相机接入到计算平台。大部分深度相机SDK都提供了类似“Pipeline”的封装你只需要启动数据流、读取帧、把数据扔给下游处理。以Python为例逻辑结构大概是这样的import depth_sdk as ds pipeline ds.Pipeline() config ds.Config() config.enable_stream(ds.Stream.DEPTH, 640, 480, 30) config.enable_stream(ds.Stream.ACCELEROMETER, ds.Stream.COLOR, 640, 480, 30) pipeline.start(config) while True: frames pipeline.wait_for_frames() depth_frame frames.get_depth_frame() color_frame frames.get_color_frame() # 交给预处理模块 process(depth_frame, color_frame)注意这段代码是伪码级别的演示不同厂商SDK接口会有差异但核心思路一模一样拿到深度帧拿到彩色帧然后带着时间戳一起往下游传。真正容易翻车的是“数据对齐”。深度图和彩色图是两套传感器物理位置不同、视场角不同、曝光时间不同直接拿彩色图像的检测结果去深度图上取距离会出现明显的错位。好的做法是使用SDK内置的深度-彩色对齐功能先把两路图像映射到同一坐标系下再做后续处理。还有一个必须处理的问题是时间戳同步。单相机场景还好多用一台相机的拼接场景如果两台设备时间基准不一致同一个人的坐标在两个相机画面里会有几十毫秒的跳变追踪轨迹会被拉成锯齿状。建议在采集层就用硬件同步或者PTP时间同步确保多相机帧间隔控制在5毫秒以内。2.2 深度图预处理数据不干净算法白搭深度图直接拿来跑检测是不行的。我见过太多初版系统检测准确率上不去最后发现根因在预处理。深度相机的原始数据有几种典型脏数据第一种是空洞。黑色吸光物体、透明玻璃、高反光表面都会导致红外光回不来或回来得太强深度图上对应的像素值直接变成0。人的头发如果是深黑色在某些相机上也会产生小范围空洞。第二种是飞点噪声。半透明物体、边缘轮廓、运动物体都会产生一些毫无规律的极近或极远点。第三种是运动拖影。预处理三板斧按顺序来先做距离裁剪。距离相机0.3米以内的点和超过6米的点直接置为无效只保留有效检测区间。这步看着简单但能大幅减少后续计算量。再做时域滤波。对同一像素位置的连续多帧取中值能有效干掉飞点噪声代价是会引入一点点延迟所以窗口一般不超过5帧。最后做空洞填充。对检测区域内的细小空洞用邻域插值补上对大空洞不要强行补因为那通常意味着真正的遮挡或反射盲区补出来也是错的。处理完之后深度图会干净很多。如果还想进一步压缩计算量可以把深度图下采样到320x240或160x120。对于人体检测和头部定位来说低分辨率完全够用关键是深度距离精度而不是像素多密。2.3 人员检测与空间定位顶部视角下的“找头顶”逻辑在顶部安装场景里检测人的方式跟平视场景完全不一样。不需要跑复杂的深度神经网络反而可以用一个简单且极其稳定的几何方法找局部极值点。先解释一下几何逻辑。相机向下安装地面是均匀平面深度值随着到相机距离变化是光滑的。当一个人站到画面里头顶距离相机比地面更近所以在深度图上头顶位置会形成一个局部的“凹陷”或“凸起”取决于你用的是“距离值”还是“视差值”。我们要做的就是扫描整张深度图找出这些偏离地面的局部极值区域。具体步骤可以这样拆估计地面模型。取连续若干帧深度图的中值作为背景深度图再用RANSAC拟合一个地面平面方程。这个步骤非常关键因为实际安装的相机不可能是绝对垂直向下的地面也不可能是绝对水平的必须拟合出一个真实的地面平面。计算高度图。把每个有效深度像素投影到3D空间用地面平面方程算出该点到地面的高度。高度值在5厘米到2.2米之间、连续面积达到一定阈值的区域就是候选目标团块。对候选团块做聚类和形态学处理。相邻的前景像素合并成一个个连通域再用尺寸、宽高比过滤掉异常团块。比如一个大纸箱的体积也可能很像一个人但纸箱的高度通常不会超过1.5米且长时间不动可以通过运动特征排除。计算目标底部中心坐标。取每个团块底部在地面上的中心投影点作为该人的平面位置坐标x, y团块的最高点作为高度h。这个坐标就是后续追踪和事件判定用的核心数据。这种几何检测方法的好处是功耗低、推理快纯CPU都能跑到30fps以上。但要注意它不适合人员密度极高的场景人贴人站成一片时团块会粘连定位精度急剧下降。这时候可以引入一个辅助的2D检测器先用轻量级人体检测模型比如YOLOv8n在彩色图上检出人体框再把检测框中心投影到深度图取框内深度中值作为距离从而得到每个目标的3D坐标。两条检测路径做一个置信度融合高密度场景的系统鲁棒性会好很多。2.4 空间标定像素到世界坐标的换算拿到相机坐标系下的3D坐标还不够业务上需要的是“世界坐标”。比如“距离门口2米”“在货架B前停留超过5秒”这些都必须建立在绝对的空间坐标上。坐标转换的数学原理不复杂。相机内参负责把像素坐标换算到相机坐标系公式如下X_c (u - cx) * Z / fx Y_c (v - cy) * Z / fy Z_c Z其中(u, v)是像素坐标(cx, cy)是主点坐标fx和fy是焦距Z是深度值。这一步把像素对齐到相机坐标系下的三维点。外参负责把相机坐标转到世界坐标用一个旋转矩阵R和平移向量t表示[X_w, Y_w, Z_w]^T R * [X_c, Y_c, Z_c]^T tR和t怎么来现场标定。推荐的做法是世界坐标直接定义在地面上以门口正中为原点门中线为Y轴平行于门面为X轴Z轴垂直向上。标定时拿一个棋盘格或带高精度标记的平面板在不同位置、不同朝向采集几组点然后交给OpenCV的solvePnP求解外参。如果不想搞复杂也可以直接在相机画面里把地面区域网格化用手动点击的方式标几个已知距离的点反推出地面平面方程和坐标映射关系。这里有一个现场技巧如果你准备安装的相机高度是3米最好先用激光水平仪在地面上打一个十字基准线再把基准线的落点标到相机画面里。这样标定出来的世界坐标和实际走线、卷尺量出来的距离基本能对上落差能控制在5厘米以内。标定完一定要做一次验证请一个人沿着已知路线走一圈看系统输出的轨迹跟实际路线是否重合偏差大就重新标。2.5 多目标追踪与轨迹输出检测模块每一帧都会输出一批人的坐标但这一帧里的“人”和下一帧里的“人”是不是同一个人需要追踪模块来回答。追踪的做法分三步第一步状态预测。每个跟踪目标用卡尔曼滤波器维护一个状态向量包含位置(x, y)、速度(vx, vy)每帧先用匀速运动模型预测目标下一帧可能出现的位置。第二步数据关联。新检测帧的目标位置和预测位置做匹配距离在阈值内就认为是同一个目标。多目标之间用匈牙利算法做全局最优匹配避免两个目标抢同一个检测框。如果上一帧匹配不上就新建一个候选轨迹连续多帧匹配不上轨迹置为丢失。第三步ID生命周期管理。一个轨迹的完整生命周期包括初始化、活跃、丢失、销毁。刚检测到但还没确认的阶段轨迹标记为候选连续3帧以上都能匹配到目标升级为活跃轨迹并分配永久track_id连续5到10帧匹配不到目标轨迹标记为丢失丢失状态保持超过设定阈值比如10秒就销毁释放ID。追踪模块最终输出的轨迹数据结构我习惯用统一的JSON格式传递下游{ track_id: trk_1032, positions: [ {t: 1710000000.10, x: 1.2, y: 0.8, h: 1.7}, {t: 1710000000.14, x: 1.3, y: 0.9, h: 1.7} ], start_time: 1710000000.00, end_time: 1710000008.50, avg_speed: 0.4, direction: 90 }到这一步Sensor Pipeline的任务就算完成了原始深度图像已经变成了一个带坐标、速度、时间戳的结构化轨迹流。3. 数据事件引擎轨迹怎么变成业务结果3.1 事件模型与字段设计轨迹数据本身是不能直接给业务看的。运营关心的是“上午10点有多少人进店”“收银台前排队超时了几次”“A区停留的平均时长是多少”。这些业务事实就是事件。事件模型的设计原则是事件是不可变事实只新增不修改不删除。业务分析全部基于事件流来聚合这样任何一个时间段的数据都能复盘任何一条聚合结果都能追溯到原始事件。我常用的最小事件字段集如下字段说明示例event_id全局唯一事件IDevt_0192_00001event_type事件类型ENTER / EXIT / REGION_ENTER / REGION_EXIT / QUEUE_TIMEOUTstore_id门店/区域编号ST-101camera_id相机编号CAM-01track_id触发事件的轨迹IDtrk_1032timestamp事件发生时间毫秒级UTC1710000000000region_id事件关联的区域region_doorposition事件发生时的世界坐标{x: 1.2, y: 0.8}duration_ms持续时间如停留时长0extra扩展字段保留给业务自定义{type: adult}实际输出到消息队列的事件JSON长这样{ event_id: evt_0192_00001, event_type: ENTER, store_id: ST-101, camera_id: CAM-01, track_id: trk_1032, timestamp: 1710000000000, region_id: region_door, position: {x: 1.2, y: 0.8}, duration_ms: 0 }设计字段时有一条经验宁可多带几个字段也不要让下游到处“补数据”。像store_id、camera_id这种维度字段在事件生成的时候直接打进去后面做任何聚合、分析、告警都不需要再关联主数据表省掉一大串join。3.2 区域规则绊线、热区、驻留时长事件引擎最核心的能力是把轨迹与业务规则做匹配。规则主要有三种绊线计数、热区进出、驻留时长。这三种规则都建立在“点与区域关系”的基础上。先看绊线。定义一个有向线段比如从A点到B点代表门店门口的中线方向定义为“从外到内”是正方向。一个轨迹点P从线段的一侧移到另一侧就触发一次跨越事件。判断点在线的哪一侧用向量叉积sign (P.x - A.x) * (B.y - A.y) - (P.y - A.y) * (B.x - A.x)sign为正是一侧为负是另一侧。当一帧轨迹的sign值从上一次的正变为负或反向且轨迹点在时间上没有跳变就说明发生了跨越。再结合跨越方向和绊线定义的正方向就能确定是“进入”还是“离开”。再看热区。定义地面上的一个多边形比如“试衣间区域”“收银台区域”。判断轨迹点是否在多边形内最常用的是射线法从点沿任意方向画一条射线统计与多边形相交的边数奇数则在多边形内偶数则在多边形外。这个算法实现简单运行效率高几十毫秒就能跑完一个区域的所有轨迹点判断。检测到轨迹点从“区域外”变为“区域内”触发REGION_ENTER事件从“区域内”变为“区域外”触发REGION_EXIT事件。出入两个事件的时间差就是这个人的区域驻留时长。区域驻留时长是热区分析的核心数据可以用来识别“试穿很久但没买单”或“在某个货架前反复徘徊”等深层的现场行为。还有一个经常被要求的功能是排队检测。做法是在收银台前定义一个“瓶颈区域”再结合轨迹的方向和停留状态判断是否有超过3个人在区域内连续停留超过1分钟。一旦触发就生成一条QUEUE_TIMEOUT事件业务端可以配置告警比如钉钉机器人推送或广播语音提示。3.3 事件去重与轨迹生命周期事件引擎在实际运行中最容易出的问题是重复事件和幽灵事件。重复事件怎么来的一个人跨越绊线的过程通常不止一帧而是一个连续的位移动过程大约会持续几帧到几十帧。如果不做状态管理轨迹每换一帧都可能触发一次“跨越”同一个进入动作被记成三四次进入事件数据整个报废。解决办法是给每条轨迹维护一个状态机。比如对“进入”这个动作轨迹状态分为“店外”“进入中”“店内”三种。只有当轨迹状态从“店外”变为“进入中”的那一帧才算一次进入事件之后无论轨迹怎么抖动只要没有离开过绊线范围状态都保持在“进入中”不会再触发新事件。等到轨迹状态变为“店内”整个进入动作才算闭环。轨迹生命周期同样需要严格管理。一条轨迹如果在两个事件之间长时间不更新状态就应该逐步降级。我常用的阈值参数是5秒内没有新位置更新轨迹标记为“暂停”事件引擎对暂停状态的轨迹不再做区域计算30秒后仍然没有恢复判定轨迹结束释放track_id。还有一种比较隐蔽的情况是“边界反复横跳”。一个人在门口探头看了一下又缩回去再伸头又缩回去。如果不做处理这种动作会被记成多次进入和离开。应对方式有两个一是给区域判断加迟滞进入和离开判定使用两条不同的边界线外侧线触发进入内侧线触发离开中间区域不触发任何事件二是给连续事件加最小间隔同一条轨迹触发进入事件后60秒内不允许再触发离开事件。具体用哪个策略取决于业务定义如果客户希望精确记录所有进出用迟滞方案如果客户希望记录“有效到访”用最小间隔方案更符合直觉。3.4 数据投递与存储架构事件引擎生成的每一批事件都要被快速可靠地送出实时链路同时落库供后续分析。投递架构我一般分为三层实时投递层。事件引擎把结构化事件序列化为JSON发布到消息队列。现场网络条件好的用Kafka网络条件一般的用MQTT。Kafka拉模式适合后端服务做流式消费吞吐量和可靠性都高MQTT推模式适合告警通知和移动端订阅延迟低且实现简单。如果是中小门店项目没有专职运维直接用EMQX这类开箱即用的MQTT Broker就够用。存储层。事件明细写入ClickHouse或PostgreSQL单表按天分区保留90天。区域实时计数和热区聚合结果写Redis供大屏和移动端低延迟查询。轨迹历史数据存到对象存储或低成本时序库平时不查出事复盘的时候再翻出来。对外接口层。数据服务封一层REST/WebSocket API给BI报表、店长端、总部驾驶舱使用。每条API都能追溯回事件比如“今日进店人数”就是统计event_typeENTER在当天的总量“当前店内人数”是维护当前净计数而非简单的累加。事件投递的伪码逻辑大概是这样def on_event(event): message json.dumps(event, ensure_asciiFalse) kafka_producer.send(store-events, message) redis.incr(fcounter:{event[store_id]}:{event[event_type]}:{today}) if event[event_type] QUEUE_TIMEOUT: webhook.notify(event)这里特别注意一点消息队列投递要做幂等处理。下游消费端断线重连后会重复拉取部分消息如果不做幂等报表数据就会偏大。最简单的做法是在事件表里给event_id加唯一约束重复插入直接忽略。4. 部署实战与现场调优4.1 安装位置、角度与光照要求系统跑得稳不稳从安装那一刻就决定了。很多现场问题参数调不好最后发现是安装方式不对。高度是第一优先级。室内客流场景相机安装高度建议在2.8米到3.5米之间。低于2.5米检测范围太小门口一过人就被拉成超大特写多人场景极易重叠高于4米地面像素分辨率严重下降儿童和小个子的头顶在深度图上可能只有一两个像素直接漏检。角度方面要尽量做到垂直向下实测经验是相机光轴与地面法线夹角不要超过20度。倾斜太大会导致头部轮廓拉长变形深度图中头顶的局部极值特征弱化检测精度下降。如果实在没有正上方的安装点倾斜超过30度时建议改用斜视检测模型并单独标定不要再依赖顶部极值方案。光照和地面材质要在进场时一并检查。深度相机受自然光中的红外分量干扰很大迎着窗户安装的相机在晴天中午会看到深度图上一片片闪烁噪声。解决办法是拉遮光帘或者在相机选型时选择带窄带滤光片的型号只允许相机自身发射波段的红外光进入传感器。地面材质方面黑色哑光地砖、镜面地砖、玻璃地面都是深度相机的死对头。黑色吸收红外光造成深度空洞镜面反射红外光造成边缘飞点。进场时发现这种地面要么换安装位置要么在预处理流程里对特定区域做掩膜把已知盲区直接遮挡掉不让检测算法在这些区域产生输出。4.2 关键参数和推荐值现场调试的时候下面这些参数是最常动的我给一个经验值范围但一定记着参数要基于现场数据来回调优参数推荐值说明检测距离范围0.5m - 6m小于0.5m的信噪比差大于6m的深度误差大地面高度范围0.1m - 2.2m低于0.1m视为地面噪声高于2.2m视为异常反射体最小目标面积0.05平方米对应成人头顶面积下限可过滤大部分飞点跟踪最大匹配距离0.5m目标在1秒内移动距离超过0.5m则不关联轨迹丢失判定帧数5帧超过5帧无更新则标记丢失轨迹结束超时10s超过10秒无更新则销毁轨迹进入事件最小间隔30s同一轨迹30秒内不重复触发同类型事件深度图分辨率320x240或640x480160x120建议只用于粗筛不适合精确定位调参顺序也有讲究。先调检测参数保证单帧输出的人数和实际相符再调追踪参数保证轨迹连续不漂移最后调事件规则参数保证业务计数准确。如果一上来就调事件去重等于在错误地基上盖楼效率极低。4.3 边缘部署的性能取舍客流系统通常跑在门店现场计算设备一般是Jetson系列或国产边缘盒子算力并不宽裕。要保证7x24小时稳定运行必须在性能上做取舍。深度图采集和预处理这一层建议固定帧率不要盲目追高。一般15fps就够用。人走路速度再快在15fps下相邻两帧的位移也就几十厘米完全满足追踪关联需求。把帧率从30fps压到15fpsCPU占用能下降一半以上。模型推理这层如果用了2D辅助检测器必须做模型压缩。YOLOv8n原版在Jetson Nano这种设备上跑不到实时用TensorRT转成FP16引擎再配合输入的动态尺寸批处理实测单路推理延迟可以压到20毫秒以内。检测频率也不用逐帧跑可以3帧跑一次检测中间两帧只做深度极值检测和追踪预测效果差不多算力开销小得多。多线程架构建议拆三个线程采集线程只管收帧和预处理算法线程负责检测和追踪事件线程处理规则判定和投递。线程之间用无锁队列传递数据避免互相阻塞。我见过很多性能问题不是算力不够而是所有活挤在一个线程里垃圾回收一卡整条管线全部停摆。分层解耦之后就算事件投递偶尔抖动采集和追踪仍然稳如老狗。5. 常见问题与排查经验5.1 高频故障速查表现象可能原因排查方法解决建议深度图出现大面积黑色空洞目标过近/过远黑色吸光材质玻璃高透切换相机参数看实时深度图调整安装高度对盲区做掩膜计数偏多检测到购物车、纸箱等假目标检查日志中目标团块尺寸增加高度/面积过滤开启运动检测计数偏少密集人流导致团块粘连拉高帧率看单帧可视化引入2D检测器做融合或调整安装角度轨迹频繁分裂帧率低或追踪匹配距离过小查看轨迹时间戳间隔降低帧率要求放宽匹配距离至0.8m进入事件重复上报事件状态机未生效检查轨迹状态日志补全状态机逻辑加入最小事件间隔逆光时段检测崩溃2D检测器受曝光影响查看该时段彩色图曝光参数锁定曝光或将主检测切换到深度几何路径多相机拼接处目标跳动相机时间戳不同步对比两路数据的时间偏移开启硬件同步或PTP时间同步事件延迟越来越大消息队列堆积检查消费端吞吐和网络消费者扩容消息批量拉取5.2 现场避坑手册我在不同门店现场踩过的坑总结几条典型的写在这里供你参考。第一条黑色地毯比想象中更致命。很多门店入口处会铺一块深色地垫吸灰又耐脏但对深度相机来说就是一块黑洞。人头一旦移动到地垫区域上方底部定位点会被吸进空洞边缘导致跟踪坐标上下跳动。处理方式是在地面平面估计时把地垫区域单独建模或者直接在检测阶段对地垫区域的高度置信度打折。第二条相机装在金属吊顶上要注意固定牢靠。我在一个项目里发现深度图偶尔整帧抖动查了半天才找到原因相机支架固定在回风口的轻钢龙骨上空调一开龙骨轻微振动相机跟着抖深度图整体偏移了十几厘米。后来换了独立的吊杆加装了橡胶减震垫问题才消失。现场安装时一定要测试空调运行状态下的画面稳定性。第三条玻璃门和镜面的影响会被低估。如果检测区域边缘有玻璃展柜或镜面柱子深度相机会在镜像位置产生鬼影目标。因为红外光打在玻璃上反射回来相机以为玻璃后面站着一个人。这种鬼影很难靠调参解决最好的办法是调整安装角度尽量让玻璃表面不垂直于相机视线。实在躲不开就在后处理里加一个“反射区域排除”把玻璃、镜子、不锈钢柱这些已知反射面的世界坐标块加入黑名单。第四条升级固件前一定要先做回归测试。有次我把相机固件从1.2升到1.4原本正常的检测精度突然下降了两成。原因是新版固件改变了深度图单位的精度策略低分辨率模式下的量化噪声变大。这类问题在文档里根本找不到只有靠回归测试才能兜住。最后说几句心里话这套系统从头到尾做下来我的体会是3D视觉也好AI模型也好数据事件引擎也好它们都不是最难的。最难的是把“现场物理世界的不确定性”和“业务逻辑的严谨性”之间的缝隙填平。Sensor Pipeline不干净数据事件引擎再精巧也是空中楼阁事件模型设计得再规范检测端漏检误检一样会把报表搅得无法直视。所以我现在做类似项目开场第一句话永远是先花一半时间把现场跑透把传感器和标定的事情做扎实再谈AI和高大上的数据平台。想清楚这件事客诉会少一半头发也能多留几根。