Path: blob/master/Depth-Perception-Using-Stereo-Camera/cpp/obstacle_avoidance.cpp
3142 views
#include <opencv2/opencv.hpp>1#include <opencv2/calib3d/calib3d.hpp>2#include <opencv2/highgui/highgui.hpp>3#include <opencv2/imgproc/imgproc.hpp>4#include <stdio.h>5#include <iostream>6#include "opencv2/imgcodecs.hpp"7#include <iomanip>89// initialize values for StereoSGBM parameters10int numDisparities = 8;11int blockSize = 5;12int preFilterType = 1;13int preFilterSize = 1;14int preFilterCap = 31;15int minDisparity = 0;16int textureThreshold = 10;17int uniquenessRatio = 15;18int speckleRange = 0;19int speckleWindowSize = 0;20int disp12MaxDiff = -1;21float M = 0.0;222324cv::Mat imgL;25cv::Mat imgR;26cv::Mat imgL_gray;27cv::Mat imgR_gray;28cv::Mat disp, disparity, depth_map;29cv::Mat output_canvas;3031// These parameters can vary according to the setup32float max_depth = 400.0; //maximum distance the setup can measure (in cm)33float min_depth = 50.0; //minimum distance the setup can measure (in cm)34float depth_thresh = 100.0; // Threshold for SAFE distance (in cm)3536// function to sort contours from largest to smallest37bool compareContourAreas ( std::vector<cv::Point> contour1, std::vector<cv::Point> contour2 ) {38double i = fabs( cv::contourArea(cv::Mat(contour1)) );39double j = fabs( cv::contourArea(cv::Mat(contour2)) );40return ( i > j );41}4243void obstacle_avoid()44{45cv::Mat mask, mean, stddev, mask2;4647// Mask to segment regions with depth less than safe distance48cv::inRange(depth_map, 10, depth_thresh, mask);49double s = (cv::sum(mask)[0])/255.0;50double img_area = double(mask.rows * mask.cols);5152std::vector<std::vector<cv::Point>> contours;53std::vector<cv::Vec4i> hierarchy;5455// Check if a significantly large obstacle is present and filter out smaller noisy regions56if (s > 0.01*img_area)57{58// finding conoturs in the generated mask59cv::findContours(mask, contours, hierarchy, cv::RETR_TREE, cv::CHAIN_APPROX_SIMPLE);6061// sorting contours from largest to smallest62std::sort(contours.begin(), contours.end(), compareContourAreas);6364// extracting the largest contour65std::vector<cv::Point> cnt = contours[0];6667// Check if detected contour is significantly large (to avoid multiple tiny regions)68double cnt_area = fabs( cv::contourArea(cv::Mat(cnt)));69if (cnt_area > 0.01*img_area)70{71cv::Rect box;7273// Finding the bounding rectangle for the largest contour74box = cv::boundingRect(cnt);7576// finding average depth of region represented by the largest contour77mask2 = mask*0;78cv::drawContours(mask2, contours, 0, (255), -1);7980// Calculating the average depth of the object closer than the safe distance81cv::meanStdDev(depth_map, mean, stddev, mask2);8283// Printing the warning text with object distance84char text[10];85std::sprintf(text, "%.2f cm",mean.at<double>(0,0));8687cv::putText(output_canvas, "WARNING!", cv::Point2f(box.x + 5, box.y-40), 1, 2, cv::Scalar(0,0,255), 2, 2);88cv::putText(output_canvas, "Object at", cv::Point2f(box.x + 5, box.y), 1, 2, cv::Scalar(0,0,255), 2, 2);89cv::putText(output_canvas, text, cv::Point2f(box.x + 5, box.y+40), 1, 2, cv::Scalar(0,0,255), 2, 2);9091}92}93else94{95// Printing SAFE if no obstacle is closer than the safe distance96cv::putText(output_canvas, "SAFE!", cv::Point2f(200,200),1,2,cv::Scalar(0,255,0),2,2);97}9899100// Displaying the output of the obstacle avoidance system101cv::imshow("output_canvas",output_canvas);102}103104int main()105{106// Creating an object of StereoBM algorithm107cv::Ptr<cv::StereoBM> stereo = cv::StereoBM::create();108109// Reading the stored the StereoBM parameters110cv::FileStorage cv_file = cv::FileStorage("../data/depth_estimation_params_cpp.xml", cv::FileStorage::READ);111cv_file["numDisparities"] >> numDisparities;112cv_file["blockSize"] >> blockSize;113cv_file["preFilterType"] >> preFilterType;114cv_file["preFilterSize"] >> preFilterSize;115cv_file["preFilterCap"] >> preFilterCap;116cv_file["minDisparity"] >> minDisparity;117cv_file["textureThreshold"] >> textureThreshold;118cv_file["uniquenessRatio"] >> uniquenessRatio;119cv_file["speckleRange"] >> speckleRange;120cv_file["speckleWindowSize"] >> speckleWindowSize;121cv_file["disp12MaxDiff"] >> disp12MaxDiff;122cv_file["M"] >> M;123124// updating the parameter values of the StereoBM algorithm125stereo->setNumDisparities(numDisparities);126stereo->setBlockSize(blockSize);127stereo->setPreFilterType(preFilterType);128stereo->setPreFilterSize(preFilterSize);129stereo->setPreFilterCap(preFilterCap);130stereo->setTextureThreshold(textureThreshold);131stereo->setUniquenessRatio(uniquenessRatio);132stereo->setSpeckleRange(speckleRange);133stereo->setSpeckleWindowSize(speckleWindowSize);134stereo->setDisp12MaxDiff(disp12MaxDiff);135stereo->setMinDisparity(minDisparity);136137//Initialize variables to store the maps for stereo rectification138cv::Mat Left_Stereo_Map1, Left_Stereo_Map2;139cv::Mat Right_Stereo_Map1, Right_Stereo_Map2;140141// Reading the mapping values for stereo image rectification142cv::FileStorage cv_file2 = cv::FileStorage("../data/stereo_rectify_maps.xml", cv::FileStorage::READ);143cv_file2["Left_Stereo_Map_x"] >> Left_Stereo_Map1;144cv_file2["Left_Stereo_Map_y"] >> Left_Stereo_Map2;145cv_file2["Right_Stereo_Map_x"] >> Right_Stereo_Map1;146cv_file2["Right_Stereo_Map_y"] >> Right_Stereo_Map2;147cv_file2.release();148149// Check for left and right camera IDs150// These values can change depending on the system151int CamL_id{2}; // Camera ID for left camera152int CamR_id{0}; // Camera ID for right camera153154cv::VideoCapture camL(CamL_id), camR(CamR_id);155156// Check if left camera is attched157if (!camL.isOpened())158{159std::cout << "Could not open camera with index : " << CamL_id << std::endl;160return -1;161}162163// Check if right camera is attached164if (!camL.isOpened())165{166std::cout << "Could not open camera with index : " << CamL_id << std::endl;167return -1;168}169170cv::namedWindow("disparity",cv::WINDOW_NORMAL);171cv::resizeWindow("disparity",600,600);172173while (true)174{175// Capturing and storing left and right camera images176camL >> imgL;177camR >> imgR;178179// copy left image to display text message for the obstacle avoidance system180imgL.copyTo(output_canvas);181182// Converting images to grayscale183cv::cvtColor(imgL, imgL_gray, cv::COLOR_BGR2GRAY);184cv::cvtColor(imgR, imgR_gray, cv::COLOR_BGR2GRAY);185186// Initialize matrix for rectified stero images187cv::Mat Left_nice, Right_nice;188189// Applying stereo image rectification on the left image190cv::remap(imgL_gray,191Left_nice,192Left_Stereo_Map1,193Left_Stereo_Map2,194cv::INTER_LANCZOS4,195cv::BORDER_CONSTANT,1960);197// Applying stereo image rectification on the right image198cv::remap(imgR_gray,199Right_nice,200Right_Stereo_Map1,201Right_Stereo_Map2,202cv::INTER_LANCZOS4,203cv::BORDER_CONSTANT,2040);205206// Calculating disparith using the StereoBM algorithm207stereo->compute(Left_nice,Right_nice,disp);208209// NOTE: compute returns a 16bit signed single channel image,210// CV_16S containing a disparity map scaled by 16. Hence it211// is essential to convert it to CV_16S and scale it down 16 times.212213// Converting disparity values to CV_32F from CV_16S214disp.convertTo(disparity,CV_32F, 1.0);215216// Scaling down the disparity values and normalizing them217disparity = (disparity/(float)16.0 - (float)minDisparity)/((float)numDisparities);218219// Calculating disparity to depth map using the following equation220// || depth = M * (1/disparity) ||221depth_map = (float)M/disparity;222223// Updating the output of the obstacle avoidance system224obstacle_avoid();225226// Displaying the disparity map227cv::imshow("disparity",disparity);228229// Close window using esc key230if (cv::waitKey(1) == 27) break;231232}233234return 0;235}236237238