├── .gitignore ├── CMakeLists.txt ├── config.txt ├── README.md ├── StereoMatcher.h ├── main.cpp └── StereoMatcher.cpp /.gitignore: -------------------------------------------------------------------------------- 1 | *.pdf 2 | .idea/ 3 | cmake-build-debug/ -------------------------------------------------------------------------------- /CMakeLists.txt: -------------------------------------------------------------------------------- 1 | cmake_minimum_required(VERSION 3.7) 2 | project(Stereo_Matcher) 3 | find_package( OpenCV REQUIRED ) 4 | set(CMAKE_CXX_STANDARD 11) 5 | 6 | set(SOURCE_FILES main.cpp StereoMatcher.cpp StereoMatcher.h) 7 | add_executable(StereoMatcher ${SOURCE_FILES}) 8 | target_link_libraries( StereoMatcher ${OpenCV_LIBS} ) -------------------------------------------------------------------------------- /config.txt: -------------------------------------------------------------------------------- 1 | # BM Parameter 2 | BM_blockSize=21 3 | # 4 | # SGBM parameter 5 | SGBM_blockSize=11 6 | SGBM_P1=1600 7 | SGBM_P2=4200 8 | SGBM_disp12MaxDiff=1 9 | SGBM_preFilterCap=10 10 | SGBM_uniquenessRatio=5 11 | SGBM_speckleWindowSize=100 12 | SGBM_speckleRange=32 13 | SGBM_mode=cv::StereoSGBM::MODE_SGBM 14 | # 15 | # BP Parameters 16 | BP_iters=5 17 | BP_levels=5 18 | # 19 | # CSBP Parameters 20 | CSBP_iters=8 21 | CSBP_levels=4 22 | CSBP_nr_plane=4 23 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Stereo Matcher 2 | 3 | ## Description 4 | #### General Information 5 | The tool takes two rectified colorvideos of a stereo camera as input and calculates 6 | the according disparity map for every frame. The disparity map is displayed and written to 7 | an output file. 8 | 9 | There are 4 available stereo matching algorithms available in openCV 3.x and thus implemented 10 | here 11 | 12 | - Block Matching (BM) 13 | - Semi-Global Block Matching (SGBM) 14 | - Belief Propagation (BP) 15 | - Constant Space Belief Propagation (CSBP) 16 | 17 | The CUDA implementation of all algorithms is used, except for SGBM. 18 | The displayed disparity-maps are calculated by openCVs drawColorDisp, only the 19 | SGBM-created disparity maps are displayed in grayscale. 20 | 21 | 22 | #### Preprocesing 23 | 24 | All used frames are preprocessed using the following steps: 25 | 26 | - Convert to grayscale 27 | - Equalize intensity histogram 28 | - Gaussian Blur 29 | 30 | 31 | ## Dependencies 32 | OpenCV 3.x with CUDA enabled 33 | 34 | ## Usage 35 | 36 | StereoMatcher.out 'Input_Video_1' 'Input_Video_2' 'Output_Video' 'Algorithm' 37 | 38 | 'Algorithm' may be BM, SGBM, BP, CSBP, Default is BM 39 | 40 | A configuration file 'config.txt' must be located in the same folder as the executable, containing the 41 | parameters for the stereo matching algorithms. A template containing the parameter names and default 42 | values is provided. -------------------------------------------------------------------------------- /StereoMatcher.h: -------------------------------------------------------------------------------- 1 | #ifndef DISPARITYTESTS_STEREOMATCHER_H 2 | #define DISPARITYTESTS_STEREOMATCHER_H 3 | 4 | #include 5 | #include "opencv2/cudaarithm.hpp" 6 | #include "opencv2/cudaimgproc.hpp" 7 | #include 8 | #include 9 | 10 | class StereoMatcher { 11 | 12 | protected: 13 | // allocate all required gpu memory 14 | cv::cuda::GpuMat gpu_frame_1, gpu_frame_2, gpu_disp_map, gpu_colored_disp; 15 | // allocate all required memory 16 | cv::Mat frame_1, frame_2; // init frames 17 | cv::Mat disp_map, colored_disp_map; // init results 18 | int frame_w, frame_h, ndisp; 19 | double fps; 20 | std::map configValues; 21 | 22 | public: 23 | // Constructor 24 | StereoMatcher(int fr_w, int fr_h, int num_disp, double framerate) 25 | :frame_w(fr_w), frame_h(fr_h), ndisp(num_disp), fps(framerate){}; 26 | virtual ~StereoMatcher(){}; // deconstructor 27 | 28 | virtual void getStereoObj()=0; 29 | virtual void calcDisparityMap()=0; 30 | 31 | void setFrames(cv::Mat frame1, cv::Mat frame2); 32 | void preprocessFrame(cv::Mat& frame); 33 | cv::Mat getDispMap(); 34 | cv::Mat getColoredDispMap(); 35 | void readConfig(); 36 | }; 37 | 38 | 39 | class BM : public StereoMatcher 40 | { 41 | cv::Ptr stereo; 42 | public: 43 | // Constructor 44 | BM(int fr_w, int fr_h, int num_disp, double framerate) : StereoMatcher(fr_w, fr_h, num_disp, framerate){}; 45 | void getStereoObj(); 46 | void calcDisparityMap(); 47 | }; 48 | 49 | class SGBM : public StereoMatcher 50 | { 51 | cv::Ptr stereo; 52 | public: 53 | // Constructor 54 | SGBM(int fr_w, int fr_h, int num_disp, double framerate) : StereoMatcher(fr_w, fr_h, num_disp, framerate){}; 55 | 56 | void getStereoObj(); 57 | void calcDisparityMap(); 58 | }; 59 | 60 | class BP : public StereoMatcher 61 | { 62 | cv::Ptr stereo; 63 | public: 64 | // Constructor 65 | BP(int fr_w, int fr_h, int num_disp, double framerate) : StereoMatcher(fr_w, fr_h, num_disp, framerate){}; 66 | 67 | void getStereoObj(); 68 | void calcDisparityMap(); 69 | }; 70 | 71 | class CSBP : public StereoMatcher 72 | { 73 | cv::Ptr stereo; 74 | public: 75 | // Constructor 76 | CSBP(int fr_w, int fr_h, int num_disp, double framerate) : StereoMatcher(fr_w, fr_h, num_disp, framerate){}; 77 | 78 | void getStereoObj(); 79 | void calcDisparityMap(); 80 | }; 81 | 82 | #endif //DISPARITYTESTS_STEREOMATCHER_H 83 | -------------------------------------------------------------------------------- /main.cpp: -------------------------------------------------------------------------------- 1 | #include "StereoMatcher.h" 2 | #include 3 | 4 | int main(int argc, char** argv) { 5 | 6 | if (argc != 5) { 7 | std::cout<<"usage:StereoMatcher.out "<< std::endl; 8 | std::cout<<" may be BM, SGBM, BP, CSBP, Default is BM..."<< std::endl; 9 | return -1; 10 | } 11 | // create video captures for both input videos 12 | cv::VideoCapture cap_left(argv[1]); 13 | cv::VideoCapture cap_right(argv[2]); 14 | if (!cap_left.isOpened() || !cap_right.isOpened()) { 15 | std::cout<<"Could not open Video(s)!"< matcher; 36 | if (std::string(argv[4])=="SGBM"){matcher.reset(new SGBM(frame_w, frame_h, ndisp, fps));} 37 | else if (std::string(argv[4])=="BP"){matcher.reset(new BP(frame_w, frame_h, ndisp, fps));} 38 | else if (std::string(argv[4])=="CSBP"){matcher.reset(new CSBP(frame_w, frame_h, ndisp, fps));} 39 | else {matcher.reset(new BM(frame_w, frame_h, ndisp, fps));} 40 | 41 | matcher->readConfig(); // read configuration file 42 | matcher->getStereoObj(); // create Stereo Object 43 | 44 | while (cap_left.isOpened() && cap_right.isOpened()) //iterate over video frames 45 | { 46 | cap_left>>frame_1; // get frames from video capture 47 | cap_right>>frame_2; 48 | if (!frame_1.data || !frame_2.data) break; // break if one frame contains no data 49 | 50 | matcher->setFrames(frame_1, frame_2); 51 | matcher->calcDisparityMap(); 52 | // write disp map to video 53 | output_video.write(matcher->getDispMap()); 54 | 55 | // display colored disp map 56 | cv::imshow("Colored Disparity Map", matcher->getColoredDispMap()); 57 | cv::waitKey(1000/fps); //waitKey 58 | 59 | } 60 | cv::destroyWindow("Colored Disparity Map"); //destroy the window with the name, "MyWindow" 61 | 62 | cap_left.release(); // release video capture 63 | cap_right.release(); 64 | 65 | return 0; 66 | } 67 | 68 | -------------------------------------------------------------------------------- /StereoMatcher.cpp: -------------------------------------------------------------------------------- 1 | #include "StereoMatcher.h" 2 | 3 | // Function Definitions 4 | void StereoMatcher::setFrames(cv::Mat frame1, cv::Mat frame2){ 5 | frame_1 = frame1; 6 | frame_2 = frame2; 7 | } 8 | 9 | void StereoMatcher::preprocessFrame(cv::Mat& frame){ 10 | /* Preprocess a frame for stereo matching: 11 | * -convert color to gray 12 | * -equalize histogram 13 | * -gaussian blur 14 | */ 15 | cv::cvtColor(frame, frame, cv::COLOR_BGR2GRAY); 16 | cv::equalizeHist(frame, frame); 17 | cv::GaussianBlur(frame, frame, cv::Size (5,5), 0); 18 | } 19 | 20 | cv::Mat StereoMatcher::getDispMap(){ 21 | return disp_map; 22 | } 23 | 24 | cv::Mat StereoMatcher::getColoredDispMap(){ 25 | return colored_disp_map; 26 | } 27 | 28 | void BM::getStereoObj(){ 29 | int blockSize = std::stoi(configValues.at("BM_blockSize")); 30 | stereo = cv::cuda::createStereoBM(ndisp, blockSize); 31 | } 32 | 33 | void BM::calcDisparityMap(){ 34 | // preprocess frames 35 | StereoMatcher::preprocessFrame(frame_1); 36 | StereoMatcher::preprocessFrame(frame_2); 37 | 38 | // upload frames to gpu memory 39 | gpu_frame_1.upload(frame_1); 40 | gpu_frame_2.upload(frame_2); 41 | // compute disparity map using the stereoObj 42 | stereo->compute(gpu_frame_1, gpu_frame_2, gpu_disp_map); 43 | 44 | // refine Disparity Map with bilateral Filter 45 | cv::Ptr disp_filter = cv::cuda::createDisparityBilateralFilter(ndisp, 5, 1); 46 | disp_filter->apply(gpu_disp_map, gpu_frame_1, gpu_disp_map); 47 | 48 | // calc colored disparity map 49 | cv::cuda::drawColorDisp(gpu_disp_map, gpu_colored_disp, ndisp); 50 | // normalize the disparity map to uint8 51 | cv::cuda::normalize(gpu_disp_map, gpu_disp_map, 0, 255, cv::NORM_MINMAX, CV_8U); 52 | 53 | // download results from gpu memory 54 | gpu_disp_map.download(disp_map); 55 | gpu_colored_disp.download(colored_disp_map); 56 | } 57 | 58 | void SGBM::getStereoObj() { 59 | int blockSize = std::stoi(configValues.at("SGBM_blockSize")); 60 | int P1 = std::stoi(configValues.at("SGBM_P1")); 61 | int P2 = std::stoi(configValues.at("SGBM_P2")); 62 | int disp12MaxDiff = std::stoi(configValues.at("SGBM_disp12MaxDiff")); 63 | int preFilterCap = std::stoi(configValues.at("SGBM_preFilterCap")); 64 | int uniquenessRatio = std::stoi(configValues.at("SGBM_uniquenessRatio")); 65 | int speckleWindowSize = std::stoi(configValues.at("SGBM_speckleWindowSize")); 66 | int speckleRange = std::stoi(configValues.at("SGBM_speckleRange")); 67 | int mode = cv::StereoSGBM::MODE_SGBM; 68 | stereo = cv::StereoSGBM::create(0, ndisp, blockSize, P1, P2, disp12MaxDiff, 69 | preFilterCap, 70 | uniquenessRatio, speckleWindowSize, speckleRange, 71 | mode); 72 | } 73 | 74 | void SGBM::calcDisparityMap(){ 75 | // preprocess frames 76 | StereoMatcher::preprocessFrame(frame_1); 77 | StereoMatcher::preprocessFrame(frame_2); 78 | 79 | // compute disparity map using the stereoObj 80 | stereo->compute(frame_1, frame_2, disp_map); 81 | 82 | // normalize the disparity map to uint8 83 | cv::normalize(disp_map, disp_map, 0, 255, cv::NORM_MINMAX, CV_8U); 84 | // calc colored disparity map 85 | colored_disp_map = disp_map; 86 | } 87 | 88 | void BP::getStereoObj(){ 89 | //Create Stereo Matcher Object for cuda::StereoBeliefPropagation and return the pointer 90 | int iters = std::stoi(configValues.at("BP_iters")); 91 | int levels = std::stoi(configValues.at("BP_levels")); 92 | stereo = cv::cuda::createStereoBeliefPropagation(ndisp, iters, levels, CV_32F); 93 | stereo->estimateRecommendedParams(frame_w, frame_h, ndisp, iters, levels); 94 | } 95 | 96 | void BP::calcDisparityMap(){ 97 | // preprocess frames 98 | StereoMatcher::preprocessFrame(frame_1); 99 | StereoMatcher::preprocessFrame(frame_2); 100 | 101 | // upload frames to gpu memory 102 | gpu_frame_1.upload(frame_1); 103 | gpu_frame_2.upload(frame_2); 104 | // compute disparity map using the stereoObj 105 | stereo->compute(gpu_frame_1, gpu_frame_2, gpu_disp_map); 106 | 107 | // refine Disparity Map with bilateral Filter 108 | cv::Ptr disp_filter = cv::cuda::createDisparityBilateralFilter(ndisp, 5, 1); 109 | disp_filter->apply(gpu_disp_map, gpu_frame_1, gpu_disp_map); 110 | 111 | // calc colored disparity map 112 | cv::cuda::drawColorDisp(gpu_disp_map, gpu_colored_disp, ndisp); 113 | // normalize the disparity map to uint8 114 | cv::cuda::normalize(gpu_disp_map, gpu_disp_map, 0, 255, cv::NORM_MINMAX, CV_8U); 115 | 116 | // download results from gpu memory 117 | gpu_disp_map.download(disp_map); 118 | gpu_colored_disp.download(colored_disp_map); 119 | } 120 | 121 | void CSBP::getStereoObj(){ 122 | //Create Stereo Matcher Object for cuda::StereoConstantSpaceBP and return the pointer 123 | int iters = std::stoi(configValues.at(("CSBP_iters"))); 124 | int levels = std::stoi(configValues.at("CSBP_levels")); 125 | int nr_plane = std::stoi(configValues.at("CSBP_nr_plane")); 126 | stereo = cv::cuda::createStereoConstantSpaceBP(ndisp, iters, levels, nr_plane, CV_32F); 127 | stereo->estimateRecommendedParams(frame_w, frame_h, ndisp, iters, levels, nr_plane); 128 | } 129 | 130 | void CSBP::calcDisparityMap(){ 131 | // preprocess frames 132 | StereoMatcher::preprocessFrame(frame_1); 133 | StereoMatcher::preprocessFrame(frame_2); 134 | 135 | // upload frames to gpu memory 136 | gpu_frame_1.upload(frame_1); 137 | gpu_frame_2.upload(frame_2); 138 | // compute disparity map using the stereoObj 139 | stereo->compute(gpu_frame_1, gpu_frame_2, gpu_disp_map); 140 | 141 | // refine Disparity Map with bilateral Filter 142 | cv::Ptr disp_filter = cv::cuda::createDisparityBilateralFilter(ndisp, 5, 1); 143 | disp_filter->apply(gpu_disp_map, gpu_frame_1, gpu_disp_map); 144 | 145 | // calc colored disparity map 146 | cv::cuda::drawColorDisp(gpu_disp_map, gpu_colored_disp, ndisp); 147 | // normalize the disparity map to uint8 148 | cv::cuda::normalize(gpu_disp_map, gpu_disp_map, 0, 255, cv::NORM_MINMAX, CV_8U); 149 | 150 | // download results from gpu memory 151 | gpu_disp_map.download(disp_map); 152 | gpu_colored_disp.download(colored_disp_map); 153 | } 154 | 155 | void StereoMatcher::readConfig(){ 156 | // Read Config File and store key-value pairs as strings in configValues map 157 | std::ifstream fs; // open filestream 158 | fs.open ("./config.txt"); 159 | 160 | try 161 | { 162 | if (!fs) { 163 | throw 1; 164 | } 165 | // if file is opened, get key, value pairs, ignore # and / 166 | else { 167 | std::string line; 168 | while (std::getline(fs, line)) { 169 | std::istringstream is_line(line); 170 | std::string key; 171 | if (std::getline(is_line, key, '=')) { 172 | std::string value; 173 | if (key[0] == '#' || key[0] == '/') // check for comments in config file 174 | continue; 175 | 176 | if (std::getline(is_line, value)) { 177 | configValues[key] = value; 178 | } 179 | } 180 | } 181 | } 182 | fs.close(); // close filestream 183 | } 184 | catch (int e) 185 | { 186 | std::cout << "Could not open & read config.txt! Please check file and location. Terminating..." << std::endl; 187 | std::terminate(); 188 | } 189 | } --------------------------------------------------------------------------------