基于双目摄像头所拍摄的图像进行障碍物提取,主要分为一下四个步骤:

1.双目摄像头校正

2.视差图提取

3.删除无关干扰区域

4.提取障碍物轮廓,重心,大小等属性

一丶相机标定

相机标定有很多方法,光流自标定,棋盘格标定等,张正友标定法,网上可以了解一下,最后得出相机的一系列参数

/*
事先标定好的相机的参数
fx 0 cx
0 fy cy
0 0  1
*/
//MATLAB优化前
Mat cameraMatrixL = (Mat_<double>(3, 3) << 1440.07133, 0, 954.95752,0, 1440.87527, 537.00282,0, 0, 1);
Mat distCoeffL = (Mat_<double>(5, 1) << 0.00691, -0.00898, 0.00032, 0.00235, 0);Mat cameraMatrixR = (Mat_<double>(3, 3) << 1435.24677, 0, 1011.06019,0, 1435.19970, 545.11155,0, 0, 1);
Mat distCoeffR = (Mat_<double>(5, 1) << 0.01228, -0.02151, 0.00005, 0.00199, 0);Mat T = (Mat_<double>(3, 1) << -59.33860, -0.18628, -0.62481);//T平移向量
Mat rec = (Mat_<double>(3, 1) << 0.00484, -0.01154, 0.00018);//rec旋转向量
Mat R;//R 旋转矩阵

二丶视差图提取

上图中,两个光轴保持平行的相机对视场一点进行拍摄,O1,O2分别为两个相机的光心,两个相机之间的距离也就是基线为D,Z为场景目标与成像面之间的距离,f为两个相机的焦距,P1,P2分别为两个摄像机拍摄的图像中对应的两个像素点,在传感器上的坐标点分别为(x1,y1),(x2,y2),其中y1=y2。根据三角形的相似原理可知:

本文采用opencv中的sgbm算法,进行视差图提取,部分代码如下:

void stereo_match(Ptr<StereoSGBM> sgbm,Mat rectifyImageL,Mat rectifyImageR,Mat &disp8,Mat  &xyz)
{sgbm->setPreFilterCap(63);int sgbmWinSize = 5;//根据实际情况自己设定int NumDisparities = 416;//根据实际情况自己设定int UniquenessRatio = 6;//根据实际情况自己设定sgbm->setBlockSize(sgbmWinSize);int cn = rectifyImageL.channels();sgbm->setP1(8 * cn*sgbmWinSize*sgbmWinSize);sgbm->setP2(32 * cn*sgbmWinSize*sgbmWinSize);sgbm->setMinDisparity(0);sgbm->setNumDisparities(NumDisparities);sgbm->setUniquenessRatio(UniquenessRatio);sgbm->setSpeckleWindowSize(100);sgbm->setSpeckleRange(10);sgbm->setDisp12MaxDiff(1);sgbm->setMode(StereoSGBM::MODE_SGBM);Mat  disp,dispf;sgbm->compute(rectifyImageL, rectifyImageR, disp);//去黑边Mat img1p, img2p;copyMakeBorder(rectifyImageL, img1p, 0, 0, NumDisparities, 0, IPL_BORDER_REPLICATE);copyMakeBorder(rectifyImageR, img2p, 0, 0, NumDisparities, 0, IPL_BORDER_REPLICATE);dispf = disp.colRange(NumDisparities, img2p.cols - NumDisparities);dispf.convertTo(disp8, CV_8U, 255 / (NumDisparities *16.));imshow("disparity", disp8);}

并且在程序中对视差图进行了上色,程序如下:

/*给深度图上色*/
void GenerateFalseMap(cv::Mat &src, cv::Mat &disp)//视差图和彩色视差图
{// color map  float max_val = 255.0f;float map[8][4] = { { 0,0,0,114 },{ 0,0,1,185 },{ 1,0,0,114 },{ 1,0,1,174 },{ 0,1,0,114 },{ 0,1,1,185 },{ 1,1,0,114 },{ 1,1,1,0 } };float sum = 0;for (int i = 0; i < 8; i++)sum += map[i][3];float weights[8]; // relative   weights  float cumsum[8];  // cumulative weights  cumsum[0] = 0;for (int i = 0; i < 7; i++) {weights[i] = sum / map[i][3];cumsum[i + 1] = cumsum[i] + map[i][3] / sum;}int height_ = src.rows;int width_ = src.cols;// for all pixels do  for (int v = 0; v < height_; v++) {for (int u = 0; u < width_; u++) {// get normalized value  float val = std::min(std::max(src.data[v*width_ + u] / max_val, 0.0f), 1.0f);// find bin  int i;for (i = 0; i < 7; i++)if (val < cumsum[i + 1])break;// compute red/green/blue values  float   w = 1.0 - (val - cumsum[i])*weights[i];uchar r = (uchar)((w*map[i][0] + (1.0 - w)*map[i + 1][0]) * 255.0);uchar g = (uchar)((w*map[i][1] + (1.0 - w)*map[i + 1][1]) * 255.0);uchar b = (uchar)((w*map[i][2] + (1.0 - w)*map[i + 1][2]) * 255.0);//rgb内存连续存放  disp.data[v*width_ * 3 + 3 * u + 0] = b;disp.data[v*width_ * 3 + 3 * u + 1] = g;disp.data[v*width_ * 3 + 3 * u + 2] = r;}}
}

最终得到的视差图如下所示:

三丶干扰区域去除

在提取视差图之后,通过Opencv自带的reprojectionImageTo3D函数将视差图转化为实际距离,以双目摄像头为中心建立的世界坐标系。经过函数处理的x,y,z坐标值是以mm为单位的世界坐标系坐标。

1.行进路径外场景去除

以相机的左光心简历摄像机坐标系,也就是世界坐标系,x轴与行进路径水平,y与路面垂直,z指向前进方向,假设相机位于道路中间,道路的宽度为Q,双目摄像头之间的基线为T,则行进路线在世界坐标系的X坐标范围为:{-(Q/2-T/2),Q/2-T/2},示意图如下:

2.地面去除

设光心距离地面的高度为H,(x,y,z)实际空间中点p的三维坐标,则p点距地面的高度为:

h=H-y

设定一个阈值,就可以消除地面低于一定高度的物体了,包括地面,

注:我由于xyz坐标转换有点问题,效果不是很理想,就不放图了

四丶轮廓提取,高度等属性

opencv中常见的一些操作,可以自行查一下,我直接放一下程序。

//阈值化int threshValue = Otsu(result1);Mat local;threshold(result1, local, 20,255,CV_THRESH_BINARY);imshow("二值化", local);imwrite("thresholded.jpg", local);//计算凸包cout << "计算凸包和轮廓....." << endl;vector<vector<Point> > contours;vector<Vec4i> hierarchy;findContours(local, contours, hierarchy, CV_RETR_EXTERNAL, 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);}cout << "轮廓凸包绘制......" << endl;/// 绘出轮廓及其凸包Mat drawing = Mat::zeros(local.size(), CV_8UC3);for (int i = 0; i < contours.size(); i++){if (contourArea(contours[i]) < 500)//面积小于area的凸包,可忽略continue;result.push_back(hull[i]);Scalar color = Scalar(0,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);imwrite("contours.jpg", drawing);//计算每一个凸包的位置和高度(也就是物体高度和位置)cout << "计算物体位置....." << endl;Point pt[100000];Moments moment;//矩vector<Vec3f>Center;//创建保存物体重心的向量Vec3f Point3v;//三维坐标点for (int i = 0; i >= 0; i = hierarchy[i][0])//读取每一个轮廓求取重心{Mat temp(contours.at(i));Scalar color(0, 0, 255);moment = moments(temp, false);if (contourArea(contours[i]) < 500)//面积小于area的凸包,可忽略continue;if (moment.m00 != 0)//除数不能为0{pt[i].x = cvRound(moment.m10 / moment.m00);//计算重心横坐标pt[i].y = cvRound(moment.m01 / moment.m00);//计算重心纵坐标}//重心坐标Point3v = xyz.at<Vec3f>(pt[i].y, pt[i].x);Center.push_back(Point3v);//将重心坐标保存到Center向量中}//统计物体高度Point p1, p2;//分别是物体最高点和最低点的位置float height,width;//物体高度Vec3f point1,point2;//物体的最高点和最低点的实际高度vector<float>all_height;vector<float>all_width;for (int i = 0; i < result.size(); i++){sort(hull[i].begin(), hull[i].end(), sortRuleY);p1 = hull[i][0];p2 = hull[i][hull[i].size() - 1];point1 = xyz.at<Vec3f>(p1.y, p1.x);point2 = xyz.at<Vec3f>(p2.y, p2.x);height = abs(point1[1] - point2[1]);sort(hull[i].begin(), hull[i].end(), sortRuleX);p1 = hull[i][0];p2 = hull[i][hull[i].size() - 1];point1 = xyz.at<Vec3f>(p1.y, p1.x);point2 = xyz.at<Vec3f>(p2.y, p2.x);width = abs(point1[0] - point2[0]);all_height.push_back(height);all_width.push_back(width);}//输出物体的位置和高度if (all_height.size() == Center.size()&&all_height.size()!=0){for (int i = 0; i < Center.size(); i++){cout << "障碍物坐标:" << Center[i] << "  " << "障碍物高度:" << all_height[i] <<"障碍物宽度:"<<all_width[i]<< endl;}}else{cout << "位置和高度数量不一致或者大小全为0!" << endl;}

转载请注明:转载自:https://blog.csdn.net/weixin_38285131

基于双目摄像头SGBM视差图的障碍物提取相关推荐

  1. 基于双目摄像头的障碍物检测

    基于双目摄像头的障碍物检测 前言:关于双目摄像头的障碍物检测以及基于OpenCV的障碍物检测在CSDN以及博客园上都有几篇相关的文章.然而,相当一部分的关于障碍物检测的文章多偏向于理论,而有实践的文章 ...

  2. 论文精读-基于双目图像的视差估计方法研究以及实现

    基于双目图像的视差估计方法研究及实现 第一章 绪论 1.1 课题的研究背景与意义 1.2 双目视差估计的研究现状 1.2.1 传统立体匹配方法研究现状 1.2.2 统计学习方法研究现状 1.2.3 深 ...

  3. 双目立体视觉建立深度图_计算机视觉实验五 双目立体匹配获得视差图,深度图...

    完整源码链接 https://github.com/LamyaLi/cvLab 文章目录 一. 立体匹配的研究背景及意义 二. 立体匹配算法的基本实现思想 1.误差能量函数 2.基于最小平均误差能量的 ...

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

    原文链接 前几天老大给了个任务,让我帮slam组写一个基于深度摄像头的障碍物检测,捣鼓了两天弄出来了,效果还不错,就在这里记一下了. 代码的核心思路是首先通过二值化,将一米之外的安全距离置零不考虑,然 ...

  5. 双目立体视觉 II:块匹配视差图计算

    点击上方"3D视觉工坊",选择"星标" 干货第一时间送达 作者:Ali Yasin Eser 编译:ronghuaiyang(AI 公园) 导读 双目立体视觉的 ...

  6. 双目测距 视差图(不完善)

    博主INBC 删掉点云之后 效果 # -*- coding: utf-8 -*- import cv2 import numpy as np import stereoconfig_040_2 # 导 ...

  7. orb特征 稠密特征_一种基于ORB-SLAM2的双目三维稠密建图方法技术

    本发明专利技术公开了一种基于ORB‑SLAM2的双目稠密建图方法,涉及机器人同步定位与地图创建领域,该方法主要由跟踪线程.局部地图线程.闭环检测线程和稠密建图线程组成.其中稠密建图线程包含以下步骤:1 ...

  8. [Windows][C#][.NET][WPF]基于ArcFace2.0+红外双目摄像头的活体检测

    废话不多说 直接上图 这个是demo中用到的双目摄像头,一个是红外的,一个是正常的rgb摄像头 两个usb接口,在电脑上呈现两路摄像头通道 程序检测RGB输出图像,当检测到有人脸时,用RGB人脸的位置 ...

  9. 基于matlab的双目摄像头标定

    利用matlab对双目摄像头进行标定,本文使用的matlab版本为Matlab R2018b. (1)下载标定工具箱 网址:http://www.vision.caltech.edu/bouguetj ...

  10. 多传感器融合算法,单目测距、基于双目,长焦短焦,图像拼接,环视等

    标定:已知世界坐标系平面内的三维坐标和像素坐标,求解内参和外参: 本质矩阵和基本矩阵:已知内参和两幅图像中对应点的坐标,通过对极约束(八点法,尺度等价性,齐次坐标)求解相机的运动R和t(用到RANSA ...

最新文章

  1. 封装php连接数据库返回方法
  2. Voyage 联合创始人目击苹果无人车,推测其计算堆栈集成在传感器中
  3. 数据结构-荷兰国旗问题
  4. 多线程编程之一——问题提出
  5. 银行核心海量数据无损迁移:TDSQL数据库多源异构迁移方案
  6. (pytorch-深度学习系列)正向传播与反向传播-学习笔记
  7. Hive与Hadoop的调用关系
  8. windows如何添加本机dns记录_Mac的100个必备技巧,Windows的功能在Mac能用了
  9. CentOS6.x 下 LNMP环境搭建(二、安装 Nginx)
  10. iCloud5_Building and Running Your App
  11. Django知识总结
  12. 空号检测和手机在网状态查询的区别
  13. Java 兼容 百度 腾讯 高德 经纬度校验距离
  14. 2009中国IT界名人
  15. 固态硬盘安装Win7双系统
  16. cogs1570 KMP hash
  17. 开发APP的费用是多少?
  18. 【WIN10】关闭/开启休眠功能
  19. 社区产品如何搭建内容体系?看看懂球帝与虎扑如何做
  20. Canvas 文字对齐方式

热门文章

  1. GOOGLE登陆火星
  2. DSPE磷脂用作药用辅料具有乳化、药物增溶的作用;CAS:1069-79-0
  3. Vue H5微信分享功能实现
  4. 复函数图像怎么画_excel根据表格数据绘制函数图像-怎样用excel画函数图
  5. oracle 19c em,Oracle 19C EM
  6. 文件加密器 java_文件加密器: 使用Java Swing编写的文件加密工具,可批量加密电脑中的文件。兼容Windows和Linux。...
  7. Flask部署机器学习模型---基于线性回归模型的销售预测系统实现简易版代码
  8. PySpark+Prophet
  9. 机器学习实战读书笔记-朴素贝叶斯
  10. python cprofile_《Python高性能编程》——2.6 使用cProfile模块