基于深度摄像头的障碍物检测(realsense+opencv)

原文链接

前几天老大给了个任务,让我帮slam组写一个基于深度摄像头的障碍物检测,捣鼓了两天弄出来了,效果还不错,就在这里记一下了。

代码的核心思路是首先通过二值化,将一米之外的安全距离置零不考虑,然后通过开运算去除掉一些噪点(这个后来发现不一定有必要),在求出所有障碍物的凸包,这个时候要计算面积,当面积小于一定的阈值的时候不予考虑,最终输出障碍物的凸包坐标。

//find_obstacle函数是获取深度图障碍物的函数,返回值是每个障碍物凸包的坐标,参数一depth是realsense返回的深度图(ushort型),
//参数二thresh和参数三max_thresh,是二值化的参数,参数四是凸包的最小有效面积,小于这个面积的障碍物可以视为噪点。
//函数首先筛选掉距离大于安全距离的点,然后进行阀值化和开运算减少一下噪点,用findContours得到轮廓图,最后用convexHull得到每个障碍物的凸包,最后返回坐标

//mask_depth函数是对深度图二值化,第一个参数image是原图,第二个参数th是目标图,第三个参数throld是最大距离,单位是mm,大于这个距离
//即为安全,不用考虑。

#include <iostream>
#include <opencv2/core/core.hpp>
#include <opencv2/highgui/highgui.hpp>
#include "RSWrapper.h"
#include "opencv2/imgproc/imgproc.hpp"

using namespace std;
using namespace cv;
void mask_depth(Mat &image,Mat& th,int throld=1000)
{
    int nr = image.rows; // number of rows 
    int nc = image.cols; // number of columns 
    for (int i = 0; i<nr; i++)
    {

        for (int j = 0; j<nc; j++) 
        {
            if (image.at<ushort>(i, j)>throld)
            th.at<ushort>(i, j) = 0;
        }
    }
}

vector<vector<Point> > find_obstacle(Mat &depth, int thresh = 20, int max_thresh = 255, int area = 500)
{
    Mat dep;
    depth.copyTo(dep);
    mask_depth(depth, dep, 1000);
    dep.convertTo(dep, CV_8UC1, 1.0 / 16);
    //imshow("color", color);
    imshow("depth", dep);
    Mat element = getStructuringElement(MORPH_RECT, Size(15, 15));//核的大小可适当调整
    Mat out;
    //进行开操作
    morphologyEx(dep, out, MORPH_OPEN, element);
    //dilate(dhc, out, element);

    //显示效果图
    imshow("opencv", out);
    Mat src_copy = dep.clone();
    Mat threshold_output;
    vector<vector<Point> > contours;
    vector<Vec4i> hierarchy;
    RNG rng(12345);
    // 对图像进行二值化
    threshold(dep, threshold_output, thresh, 255, CV_THRESH_BINARY);
    //mask_depth(src, threshold_output);
    // 寻找轮廓
    findContours(threshold_output, contours, hierarchy, CV_RETR_TREE, CV_CHAIN_APPROX_SIMPLE, Point(0, 0));

    // 对每个轮廓计算其凸包
    vector<vector<Point> >hull(contours.size());
    vector<vector<Point> > result;
    for (int i = 0; i < contours.size(); i++)
    {
        convexHull(Mat(contours[i]), hull[i], false);
    }

    // 绘出轮廓及其凸包
    Mat drawing = Mat::zeros(threshold_output.size(), CV_8UC3);
    for (int i = 0; i< contours.size(); i++)
    {
        if (contourArea(contours[i]) < area)//面积小于area的凸包,可忽略
        continue;
        result.push_back(hull[i]);
        Scalar color = Scalar(rng.uniform(0, 255), rng.uniform(0, 255), rng.uniform(0, 255));
    drawContours(drawing, contours, i, color, 1, 8, vector<Vec4i>(), 0, Point());
    drawContours(drawing, hull, i, color, 1, 8, vector<Vec4i>(), 0, Point());
    }
    imshow("contours", drawing);
    return result;
}


int main(int argc, char* argv[])
{
    Mat dhc;
    Mat dep;
    int idxImageRes = 1, idxFrameRate = 30;
    RSWrapper depthCam(idxImageRes, idxImageRes, idxFrameRate, idxFrameRate);
    if (!depthCam.init())
    {
    std::cerr << "Init. RealSense Failure!" << std::endl;
    return -1;
    }

    while (true)
    {
        //Get RGB-D Images
        cv::Mat color, depth;
        bool ret = depthCam.capture(color, depth);
        if (!ret) 
        {
            std::cerr << "Get realsense camera data failure!" << std::endl;
            break;
        }
        vector<vector<Point> > result;
        result = find_obstacle(depth, 20, 255, 500);
        if (cvWaitKey(1) == 27)
        break;
    }

    depthCam.release();
}

改进算法,去除地面阴影

在前文得到视差图和三维坐标的基础上,首先对地面干扰区域和行进路径以外区域进行去除。以下是地面干扰区域的去除方法,行进路径以外区域我采用的是机器人行进过程中设定一定的视角,去除视角之外的区域,通过行进路径以外物体距相机中心在x轴和z轴上的距离来就算角度。 

参考论文“基于双目立体视觉的移动机器人障碍物检测技术研究”

然后对处理后的视差图进行二值化分割,大致提取到障碍物。由于立体匹配过程中一些物体文理较弱的区域未匹配,导致一个物体可能被分割成几部分,所以对图像再进行闭运算,然后再求出所有障碍物的凸包,这个时候要计算面积,当面积小于一定的阈值的时候不予考虑,最终输出障碍物的凸包坐标。 
以下是实现过程: 

视差图→三维测距 

去除行进路径以外区域→去除地面干扰区域→二值化分割 

è¿éåå¾çæè¿°

闭运算→求凸包 

è¿éåå¾çæè¿°

### D435i 设备用于障碍物检测的方法 #### 使用YOLOv5与Realsense D435i相融合的方式 针对D435i设备进行障碍物识别的一种高效方法是结合深度学习框架YOLOv5以及英特尔RealSense系列中的D435i摄像头。此组合不仅能够提供高质量的RGB图像流,还能同步输出深度信息,有助于更精准地定位和分类障碍物[^1]。 具体来说,在`yolov5_d435i_detection`开源项目里实现了上述思路。该项目依赖PyTorch库构建,并特别设计用来处理由D435i捕获的数据。它能够在保持较高准确性的同时实时运行,适用于诸如机器人导航或辅助驾驶等应用场景中快速响应的需求。当执行目标检测任务时,除了给出边界框外,还会报告这些对象在摄像机坐标系内的三维位置参数,这对于理解周围环境至关重要。 ```python from ultralytics import YOLO import pyrealsense2 as rs import numpy as np def detect_obstacles(): model = YOLO('path/to/model') # 加载预训练好的YOLOv5模型 pipeline = rs.pipeline() config = rs.config() config.enable_stream(rs.stream.depth, 640, 480, rs.format.z16, 30) config.enable_stream(rs.stream.color, 640, 480, rs.format.bgr8, 30) profile = pipeline.start(config) try: while True: frames = pipeline.wait_for_frames() depth_frame = frames.get_depth_frame() color_frame = frames.get_color_frame() if not depth_frame or not color_frame: continue depth_image = np.asanyarray(depth_frame.get_data()) color_image = np.asanyarray(color_frame.get_data()) results = model.predict(source=color_image, stream=True) for result in results: boxes = result.boxes.cpu().numpy() for box in boxes: x_min, y_min, x_max, y_max = map(int, box.xyxy[0]) # 获取中心点深度值 center_x = (x_min + x_max) / 2 center_y = (y_min + y_max) / 2 distance = depth_frame.get_distance(center_x, center_y) print(f"Detected object at ({center_x}, {center_y}) with distance: {distance}") finally: pipeline.stop() ``` 该代码片段展示了如何集成YOLOv5与Intel RealSense SDK以实现基本的对象检测逻辑。注意这里的depth_frame提供了每个像素对应的物理距离测量值;color_frame则包含了彩色视频帧。两者共同作用可以使得程序既能看到物体的样子又能知道它们离相机有多远。 #### 结合其他传感技术提升性能 尽管单独使用视觉传感器已经可以获得不错的成果,但在某些复杂环境下可能仍需借助额外的信息源来增强系统的鲁棒性和可靠性。例如,考虑到毫米波雷达可以在恶劣天气条件下工作良好并且不受光照条件影响的特点,将其与基于视觉的目标检测系统相结合是一个不错的选择[^2]。通过引入如CFAR这样的高级信号处理机制,还可以进一步优化雷达数据的质量,减少不必要的报警次数,提高整体的安全保障水平。 另外,对于无人车而言,激光雷达同样是非常重要的组成部分之一。其优势在于能够生成精确的三维地图表示,帮助车辆更好地理解和适应周围的动态情况。尤其是在高速行驶状态下,这种类型的传感器显得尤为重要,因为它允许系统提前做出反应,避免潜在的风险事件发生[^3]。 综上所述,虽然单靠D435i即可完成初步的障碍物探测任务,但如果追求更高的精度和稳定性,则建议考虑多模态感知策略,即将多种不同类型的感觉器官有机结合起来,形成互补效应,从而达到最佳效果。
评论 21
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值