
来源:第四届 3D 视觉创新应用竞赛,邓俊成 相机型号:Orbbec Gemini 2 支持设备:Jetson Nano、KUKA 六轴机械臂 GitHub:Measure_Security-in-Robot-Operation-Area
1. 项目概览:不是普通监控,是会“量距离”的安全哨兵 👀
机器人作业区域三维视觉安防系统面向工业机器人工作站的人机协作安全问题,核心目标是:在不依赖传统物理围栏的情况下,通过 3D 视觉实时判断人员或异物是否进入危险区域,并联动报警与机器人控制。
与常见 2D 摄像头不同,这套系统不只“看见画面”,还会计算目标的三维空间坐标。也就是说,它不满足于知道“有人在图里”,还要知道“这个人离机械臂有多近、是否跨进了危险区域”。这位安全员眼神不花,还自带尺子,夜班也不太抱怨。
| 维度 | 系统信息 |
|---|---|
| 应用对象 | 机器人作业区域安全监控 |
| 视觉传感器 | Orbbec Gemini 2 RGB-D 相机 |
| 计算平台 | Jetson Nano |
| 执行对象 | KUKA 六轴机械臂 |
| 开发环境 | Ubuntu、Qt Creator、C++ |
| 核心算法 | YOLOv8 姿态检测、MOG2 异物检测、三维区域碰撞检测 |
| 主要能力 | 3D 坐标计算、虚拟围栏、分级预警、机器人联动 |
2. 为什么要做这件事:传统围栏并不总是优雅 🏭
工业机器人速度快、负载大、动作路径复杂。传统防护手段当然有效,但在柔性制造、临时调线、多品种小批量生产场景下,它们经常显得不够灵活。
| 传统方案 | 主要问题 | 3D 视觉方案的改进 |
|---|---|---|
| 物理围栏 | 占空间,改造成本高 | 用虚拟区域替代固定隔离 |
| 安全光栅 | 安装面受限,易误触发 | 可设定任意形状监测区域 |
| 安全地毯 | 易老化,维护麻烦 | 非接触检测,部署更轻量 |
| 2D 摄像监控 | 缺少深度信息 | 直接判断三维空间入侵 |
该系统的价值在于:在保证安全的同时,尽量不把产线“围成迷宫”。通过 3D 视觉建立虚拟围栏,系统可以对不同区域设置不同防护等级,例如外围区域触发黄色预警,核心危险区触发红色报警并降低或停止机械臂速度。
3. 系统架构:相机看、算法算、机械臂听指挥 ⚙️
系统采用分层架构:
| 层级 | 组成 | 作用 |
|---|---|---|
| 硬件层 | Gemini 2、Jetson Nano、KUKA、显示器、报警灯 | 采集、计算、执行、提示 |
| 算法层 | YOLOv8、MOG2、坐标变换、区域判断 | 识别目标并判断风险 |
| 应用层 | Qt 界面、区域设置、日志、报警联动 | 人机交互与安全响应 |
系统的数据流可以概括为:
RGB-D 相机采集
↓
彩色图 + 深度图对齐
↓
人体关键点 / 异物轮廓检测
↓
二维像素点反算三维坐标
↓
转换到监测平面坐标系
↓
判断是否进入虚拟围栏
↓
界面提示 + 报警 + KUKA 速度控制

4. 工作流程:每一帧都在做安全体检 🩺

这套流程的关键并不是“识别一个人”这么简单,而是把目标从图像空间拉回真实空间,再判断它与机器人工作区域的几何关系。换句话说,系统不是在屏幕上画红框吓唬人,而是在算空间里的实际边界。
5. 关键技术一:RGB-D 采集与三维坐标反算 📷
Gemini 2 提供彩色图与深度图。项目中的 camera3d.cpp 使用 Orbbec SDK 建立数据管道,启用彩色流和深度流,并设置深度到彩色的对齐模式。
下面是根据 code/SafetySystem/src/camera3d.cpp 精简整理的核心逻辑:
auto colorProfiles = pipe.getStreamProfileList(OB_SENSOR_COLOR);
auto colorProfile = colorProfiles->getVideoStreamProfile(
640, 480, OB_FORMAT_RGB, 30
);
config->enableStream(colorProfile);
auto depthProfiles = pipe.getStreamProfileList(OB_SENSOR_DEPTH);
auto depthProfile = depthProfiles->getVideoStreamProfile(
640, 0, OB_FORMAT_Y16, 30
);
config->enableStream(depthProfile);
config->setAlignMode(ALIGN_D2C_HW_MODE);
pipe.start(config);
这段代码完成三件事:
- 打开彩色流,获得可用于检测的 RGB 图像。
- 打开深度流,获得每个像素对应的距离信息。
- 设置 D2C 对齐,使深度像素能和彩图检测结果对应起来。
当检测算法给出某个像素点 (u, v) 后,系统会用相机内参和深度值计算三维点。项目中的核心公式如下:
cv::Point3f camera3d::Get3DPosition(cv::Point p)
{
float intr[4];
GetColorCamIntrMat(intr);
float fx = intr[0];
float fy = intr[1];
float cx = intr[2];
float cy = intr[3];
cv::Point3f pt;
pt.z = depth_img_.at<uint16_t>(p) * 1.0f;
pt.x = (p.x - cx) / fx * pt.z;
pt.y = (p.y - cy) / fy * pt.z;
return pt;
}
其中:
| 参数 | 含义 |
|---|---|
fx, fy |
相机在 x、y 方向的焦距 |
cx, cy |
相机主点坐标 |
pt.z |
像素点对应的深度 |
pt.x, pt.y |
反投影得到的空间坐标 |
这一步是系统从“看图识别”升级为“空间安防”的关键。没有深度,虚拟围栏就只能在屏幕里装装样子;有了深度,它才真正站进车间。
6. 关键技术二:人体关键点检测,让系统知道“谁的脚迈进来了” 🧍
系统在“仅人体防护”模式下使用 YOLOv8 姿态检测。相比只检测人体框,姿态关键点能提供更细粒度的信息,例如脚踝、膝盖、肩部等位置。对于安全监测而言,这比单纯的矩形框更有价值:因为真正越界的可能是脚、手或身体的一部分,而不是整个检测框。
项目中的 yolov8.cpp 使用 TensorRT engine 加载姿态模型,并提取 17 个关键点:
void Yolov8::initize()
{
cudaSetDevice(0);
const std::string engine_file_path =
"/home/sdpt/Desktop/YOLOv8-TensorRT/csrc/jetson/pose/build/yolov8s-pose.engine";
yolov8_pose = new YOLOv8_pose(engine_file_path);
yolov8_pose->make_pipe(true);
}
std::vector<std::vector<cv::Point>> Yolov8::detect(cv::Mat& image)
{
cv::Size size = cv::Size{640, 640};
float score_thres = 0.8f;
float iou_thres = 0.65f;
yolov8_pose->copy_from_Mat(image, size);
yolov8_pose->infer();
yolov8_pose->postprocess(objs, score_thres, iou_thres, topk);
for (auto& obj : objs) {
std::vector<cv::Point> onePeople;
for (int k = 0; k < 17; k++) {
int kps_x = std::round(obj.kps[k * 3]);
int kps_y = std::round(obj.kps[k * 3 + 1]);
float kps_s = obj.kps[k * 3 + 2];
if (kps_s > 0.5f) {
onePeople.push_back(cv::Point(kps_x, kps_y));
}
}
result.push_back(onePeople);
}
return result;
}
这段逻辑的重点是:
| 处理环节 | 说明 |
|---|---|
| TensorRT 加速 | 适配 Jetson Nano,提升实时推理能力 |
| 置信度筛选 | 人体分数阈值为 0.8 |
| 关键点筛选 | 关键点置信度大于 0.5 才参与判断 |
| 输出结构 | 每个人对应一组关键点 |
这些关键点随后会被送入三维坐标计算模块。如果某个关键点进入危险区,系统就会触发对应状态。机械臂看到这里,大概会默默把速度收一收。
7. 关键技术三:人体加异物防护,用 MOG2 盯住“不该出现的东西” 📦
在“人体+异物防护”模式下,系统不仅检测人,也检测进入场景的其他物体。项目中的 objdetector.cpp 使用 OpenCV 的 MOG2 背景建模方法实现前景检测。
ObjDetector::ObjDetector()
{
back = cv::createBackgroundSubtractorMOG2();
kernel = cv::getStructuringElement(
cv::MORPH_ELLIPSE,
cv::Size(5, 5)
);
}
std::vector<std::vector<cv::Point>> ObjDetector::process(const cv::Mat &image)
{
cv::Mat img;
if (idx < 20) {
back->apply(image, img);
} else {
back->apply(image, img, 0);
}
cv::threshold(img, img, 240, 255, cv::THRESH_BINARY);
cv::morphologyEx(img, img_close, cv::MORPH_OPEN, kernel);
cv::findContours(img_close, contours, cv::RETR_EXTERNAL, cv::CHAIN_APPROX_SIMPLE);
for (const auto& cnt : contours) {
results.push_back(cnt);
}
idx++;
return results;
}
这段代码体现了一个朴素但实用的思路:
- 前 20 帧用于建立背景模型。
- 后续帧固定背景学习率,突出新出现的前景目标。
- 通过二值化和形态学开运算去除噪声。
- 提取前景轮廓点,送入区域判断模块。
MOG2 的好处是对背景变化有一定适应性,适合车间这类光照、人员和设备状态可能轻微变化的场景。它不是“看一眼就下结论”,而是先认识环境,再判断谁突然闯进来了。
8. 关键技术四:三维虚拟围栏与碰撞检测 🚧

项目中最有特色的部分,是把用户在界面上绘制的二维区域,结合深度信息转换为三维区域。系统支持两级区域:
| 区域 | 视觉颜色 | 系统状态 | 控制逻辑 |
|---|---|---|---|
| 一级危险区 | 红色 | 危险 | 机器人速度降为 0 |
| 二级预警区 | 黄色 | 警告 | 机器人低速运行 |
| 区域外 | 绿色 | 安全 | 机器人正常运行 |
在 maincontroller.cpp 中,系统循环执行检测、三维反投影、坐标变换和区域判断:
camera_->Get();
cv::Mat colorImg = camera_->color_img_.clone();
cv::Mat depthImg = camera_->depth_img_.clone();
if (renti_wuti == 0) {
result = y1.detect(colorImg);
} else if (renti_wuti == 1) {
result = detector.process(colorImg);
}
for (auto target : result) {
for (auto p2 : target) {
cv::Point3f p3 = camera_->Get3DPosition(p2);
Transform3D(p3, matrixW2P_, p3);
if (IsContain<cv::Point3f>(range_points3D_, p3)) {
human_contained = 1;
break;
} else if (IsContain<cv::Point3f>(range_points3D_2_, p3)) {
human_contained = 2;
}
}
}
emit HumanTrigger(human_contained);
这段逻辑可以翻译成更直观的伪代码:
for 每一帧图像:
获取彩色图和深度图
if 当前模式是人体防护:
检测人体关键点
else:
检测前景异物轮廓
for 每个检测点:
像素点 + 深度值 -> 三维坐标
三维坐标 -> 监测平面坐标系
if 点在红色危险区:
输出 危险
else if 点在黄色预警区:
输出 警告
else:
输出 安全
区域包含关系采用类似射线法的多边形包含判断。项目中的 IsContain 模板函数只关心点在多边形投影内外,因此计算量较小,适合实时循环。
template <class T>
bool IsContain(std::vector<T> &points, T &testp)
{
bool iscontain = false;
size_t count = points.size();
for (size_t i = 0, j = count - 1; i < count; j = i++) {
bool crossY = (points[j].y > testp.y) != (points[i].y > testp.y);
if (crossY) {
float crossX =
(points[i].x - points[j].x) /
(points[i].y - points[j].y) *
(testp.y - points[j].y) + points[j].x;
if (testp.x < crossX) {
iscontain = !iscontain;
}
}
}
return iscontain;
}
需要注意的是,这里的“三维碰撞检测”并不是对复杂网格体做高成本几何求交,而是先把监测区域转化为平面坐标系下的多边形边界,再对人体关键点或异物轮廓点进行快速包含判断。这种做法在工业安防中很实用:速度快、解释性强、便于调参。
9. 关键技术五:从安全状态到机器人动作 🦾
当 MainController 发出 HumanTrigger(status) 后,Qt 主界面会根据状态更新报警界面,并通过 KUKA 控制接口改变机器人速度。

项目中的 AlarmAction 展示了分级控制逻辑:
void MainWindow::AlarmAction()
{
while (is_alarming_) {
if (xinghao == 1) {
Kuka->MoveLFunc(0.0);
emit AlarmReady(
"QLabel{background-color:rgb(255,0,0);}",
"危险"
);
}
if (xinghao == 2) {
Kuka->MoveLFunc(10.0);
emit AlarmReady(
"QLabel{background-color:rgb(255,255,0);}",
"警告"
);
}
usleep(150 * 1000);
}
emit AlarmReady(
"QLabel{background-color:rgb(0,255,0);}",
"安全"
);
if (xinghao == 0) {
Kuka->MoveLFunc(50.0);
}
}
| 状态值 | 显示状态 | 控制动作 |
|---|---|---|
0 |
安全 | MoveLFunc(50.0) |
1 |
危险 | MoveLFunc(0.0) |
2 |
警告 | MoveLFunc(10.0) |
这是一种直观的安全策略:离得远,正常干活;进入预警区,先慢下来;进入危险区,立刻停住。系统没有试图用一句“请注意安全”来感化机械臂,而是直接把控制量写进去了,比较务实。
KUKA 通信部分采用 TCP/IP 与 XML 格式数据。KuKaRealTimeDriveImpl.cpp 中,上位机作为服务器监听连接;KuKaMessage.cpp 负责封装和解析机器人状态数据。
bool KuKaRealTimeDriveImpl::Start()
{
QString qIp(_ip.c_str());
connect(_Server, &QTcpServer::newConnection,
this, &KuKaRealTimeDriveImpl::RequireConnect);
if (!_Server->listen(QHostAddress(qIp), _Port)) {
_isConnected = false;
Q_EMIT robotConnectFail();
return false;
}
return true;
}
通信配置文件 config.xml 中给出了默认网络参数:
<Config>
<Ip>192.168.1.101</Ip>
<Port>10001</Port>
</Config>
10. 人机交互:区域可以画,模式可以切,状态一眼能看懂 🖥️

系统的 Qt 界面承担四类任务:
| 功能 | 说明 |
|---|---|
| 图像显示 | 展示彩色图、深度图、检测结果 |
| 区域绘制 | 鼠标点击设定虚拟围栏顶点 |
| 模式切换 | 支持人体防护、人体加异物防护 |
| 报警展示 | 显示安全、警告、危险状态 |
区域绘制逻辑大致如下:
左键点击:
读取当前像素点
获取该点深度值
保存 2D 点和 3D 点
右键结束:
将区域点写入 config.xml
启用监测启动按钮
这种交互方式的优势是部署快。现场人员不需要重新安装实体围栏,只需在画面中沿着设备工作区点选边界,即可完成虚拟区域配置。对于产线改造、临时演示、实验室验证,都比较友好。
11. 测试结果:准确率和速度都要讲证据 📊
根据项目 PPT 中的测试说明,系统分别在“仅人体防护”和“人体+异物防护”模式下进行测试,测试区域包括 L 形、I 形、正方形,测试地点覆盖实验室和车间,测试方向包括正向、左侧向、右侧向。
| 测试模式 | 区域形状 | 准确率 | 响应时间 |
|---|---|---|---|
| 仅人体防护 | L 形、I 形、正方形 | 99.3% | 34.5 ms – 36.5 ms |
| 人体+异物防护 | L 形、I 形、正方形 | 99.0% | 35.8 ms – 37.8 ms |
| 指标 | 项目给出的目标或表现 |
|---|---|
| 最大覆盖空间 | 8 m x 6 m x 3 m |
| 定位精度 | 2 cm |
| 帧率 | 30 FPS |
| 区域配置耗时 | 小于 1 h |
| 识别率 | 约 99% |
这些结果说明,系统具备较好的实时性。按 30 FPS 计算,每帧处理窗口约 33 ms,项目测试中的响应时间接近这一量级,符合实时安防监控的基本要求。
12. 与传统 2D 监控的差异:多了一个维度,少了很多误会 🧠
| 对比项 | 2D 监控 | 3D 视觉安防 |
|---|---|---|
| 信息类型 | 平面图像 | 彩色图、深度图、空间坐标 |
| 区域判断 | 依赖画面位置 | 基于真实三维位置 |
| 光照适应 | 受光照影响较大 | 微光环境下仍可工作 |
| 误报控制 | 难区分远近关系 | 可结合距离与区域判断 |
| 联动能力 | 多用于告警 | 可直接控制机器人速度 |
2D 监控容易出现“看起来靠近,实际很远”或“画面上没压线,空间里已越界”的问题。3D 视觉通过深度信息补上了这个短板,使安全判断从“图像猜测”变成“空间计算”。
13. 创新点与学术价值 ✨
| 创新点 | 技术意义 |
|---|---|
| 3D 虚拟围栏 | 用软件区域替代固定物理隔离 |
| 分级安全区域 | 支持警告区和危险区的不同策略 |
| 姿态关键点检测 | 比人体框更精细地判断局部越界 |
| 异物检测模式 | 扩展到工具、物料等非人体目标 |
| 机器人联动控制 | 形成感知、判断、执行闭环 |
从学术角度看,该项目把 RGB-D 感知、深度学习检测、几何计算和机器人通信集成为一个闭环系统。它不只是一个算法 demo,而是一个面向工业安全场景的原型验证系统。
更重要的是,它的判断链条具有较好的可解释性:
检测到目标
-> 取得目标点
-> 计算三维坐标
-> 判断是否进入区域
-> 输出安全等级
-> 控制机械臂速度
每一步都有明确的数据输入和输出,便于调试、验证和工程落地。
14. 可扩展方向:这位安全员还能继续进修 🎓
| 方向 | 可行改进 |
|---|---|
| 多相机融合 | 消除遮挡,扩大覆盖范围 |
| 任意曲面区域 | 支持曲线、球形、不规则三维区域 |
| 行为预测 | 提前判断人员运动趋势 |
| 多传感器融合 | 融合红外、声音、力觉信号 |
| 安全认证 | 对接工业安全标准与现场评估 |
| 数据闭环 | 建立误报、漏报样本回流机制 |
目前系统已经支持多边形立体监控区域。后续如果加入多相机标定与融合,系统可覆盖更大范围,并缓解单视角遮挡问题。如果进一步加入行为预测模型,则可以在人员真正进入危险区前进行提前预警。
15. 总结:把“别靠近机械臂”变成可计算、可执行的规则 ✅
机器人作业区域三维视觉安防系统的核心价值,是把工业现场的安全边界数字化、空间化和自动化。它使用 Gemini 2 获取深度信息,在 Jetson Nano 上完成检测与计算,通过 Qt 界面呈现状态,并联动 KUKA 机器人控制。
简而言之,它做了三件很关键的事:
- 看得见:通过 RGB-D 相机获取彩色与深度信息。
- 算得准:通过关键点、轮廓和三维坐标判断入侵。
- 反应快:通过报警与机器人速度控制形成闭环。
在柔性制造、人机协作、产线频繁调整的背景下,这类 3D 视觉虚拟围栏系统具有明显应用潜力。它不是要完全取代所有传统安全装置,而是为工业安全提供一种更灵活、更智能、更容易扩展的新方案。机械臂继续干活,人也更安心,这就挺好。