基于双目摄像头SGBM视差图的障碍物提取
基于雙目攝像頭所拍攝的圖像進行障礙物提取,主要分為一下四個步驟:
1.雙目攝像頭校正
2.視差圖提取
3.刪除無關干擾區(qū)域
4.提取障礙物輪廓,重心,大小等屬性
一丶相機標定?
相機標定有很多方法,光流自標定,棋盤格標定等,張正友標定法,網上可以了解一下,最后得出相機的一系列參數(shù)
/* 事先標定好的相機的參數(shù) fx 0 cx 0 fy cy 0 0 1 */ //MATLAB優(yōu)化前 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內存連續(xù)存放 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;}} }?最終得到的視差圖如下所示:
三丶干擾區(qū)域去除
在提取視差圖之后,通過Opencv自帶的reprojectionImageTo3D函數(shù)將視差圖轉化為實際距離,以雙目攝像頭為中心建立的世界坐標系。經過函數(shù)處理的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;//創(chuàng)建保存物體重心的向量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)//除數(shù)不能為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向量中}//統(tǒng)計物體高度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 << "位置和高度數(shù)量不一致或者大小全為0!" << endl;}轉載請注明:轉載自:https://blog.csdn.net/weixin_38285131
?
?
總結
以上是生活随笔為你收集整理的基于双目摄像头SGBM视差图的障碍物提取的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: applet调用js:导入netscap
- 下一篇: ahri8.php,文件上传处理 - [