Home | History | Annotate | Download | only in cpp
      1 /*
      2  *  stereo_match.cpp
      3  *  calibration
      4  *
      5  *  Created by Victor  Eruhimov on 1/18/10.
      6  *  Copyright 2010 Argus Corp. All rights reserved.
      7  *
      8  */
      9 
     10 #include "opencv2/calib3d/calib3d.hpp"
     11 #include "opencv2/imgproc/imgproc.hpp"
     12 #include "opencv2/imgcodecs.hpp"
     13 #include "opencv2/highgui/highgui.hpp"
     14 #include "opencv2/core/utility.hpp"
     15 
     16 #include <stdio.h>
     17 
     18 using namespace cv;
     19 
     20 static void print_help()
     21 {
     22     printf("\nDemo stereo matching converting L and R images into disparity and point clouds\n");
     23     printf("\nUsage: stereo_match <left_image> <right_image> [--algorithm=bm|sgbm|hh] [--blocksize=<block_size>]\n"
     24            "[--max-disparity=<max_disparity>] [--scale=scale_factor>] [-i <intrinsic_filename>] [-e <extrinsic_filename>]\n"
     25            "[--no-display] [-o <disparity_image>] [-p <point_cloud_file>]\n");
     26 }
     27 
     28 static void saveXYZ(const char* filename, const Mat& mat)
     29 {
     30     const double max_z = 1.0e4;
     31     FILE* fp = fopen(filename, "wt");
     32     for(int y = 0; y < mat.rows; y++)
     33     {
     34         for(int x = 0; x < mat.cols; x++)
     35         {
     36             Vec3f point = mat.at<Vec3f>(y, x);
     37             if(fabs(point[2] - max_z) < FLT_EPSILON || fabs(point[2]) > max_z) continue;
     38             fprintf(fp, "%f %f %f\n", point[0], point[1], point[2]);
     39         }
     40     }
     41     fclose(fp);
     42 }
     43 
     44 int main(int argc, char** argv)
     45 {
     46     const char* algorithm_opt = "--algorithm=";
     47     const char* maxdisp_opt = "--max-disparity=";
     48     const char* blocksize_opt = "--blocksize=";
     49     const char* nodisplay_opt = "--no-display";
     50     const char* scale_opt = "--scale=";
     51 
     52     if(argc < 3)
     53     {
     54         print_help();
     55         return 0;
     56     }
     57     const char* img1_filename = 0;
     58     const char* img2_filename = 0;
     59     const char* intrinsic_filename = 0;
     60     const char* extrinsic_filename = 0;
     61     const char* disparity_filename = 0;
     62     const char* point_cloud_filename = 0;
     63 
     64     enum { STEREO_BM=0, STEREO_SGBM=1, STEREO_HH=2, STEREO_VAR=3 };
     65     int alg = STEREO_SGBM;
     66     int SADWindowSize = 0, numberOfDisparities = 0;
     67     bool no_display = false;
     68     float scale = 1.f;
     69 
     70     Ptr<StereoBM> bm = StereoBM::create(16,9);
     71     Ptr<StereoSGBM> sgbm = StereoSGBM::create(0,16,3);
     72 
     73     for( int i = 1; i < argc; i++ )
     74     {
     75         if( argv[i][0] != '-' )
     76         {
     77             if( !img1_filename )
     78                 img1_filename = argv[i];
     79             else
     80                 img2_filename = argv[i];
     81         }
     82         else if( strncmp(argv[i], algorithm_opt, strlen(algorithm_opt)) == 0 )
     83         {
     84             char* _alg = argv[i] + strlen(algorithm_opt);
     85             alg = strcmp(_alg, "bm") == 0 ? STEREO_BM :
     86                   strcmp(_alg, "sgbm") == 0 ? STEREO_SGBM :
     87                   strcmp(_alg, "hh") == 0 ? STEREO_HH :
     88                   strcmp(_alg, "var") == 0 ? STEREO_VAR : -1;
     89             if( alg < 0 )
     90             {
     91                 printf("Command-line parameter error: Unknown stereo algorithm\n\n");
     92                 print_help();
     93                 return -1;
     94             }
     95         }
     96         else if( strncmp(argv[i], maxdisp_opt, strlen(maxdisp_opt)) == 0 )
     97         {
     98             if( sscanf( argv[i] + strlen(maxdisp_opt), "%d", &numberOfDisparities ) != 1 ||
     99                 numberOfDisparities < 1 || numberOfDisparities % 16 != 0 )
    100             {
    101                 printf("Command-line parameter error: The max disparity (--maxdisparity=<...>) must be a positive integer divisible by 16\n");
    102                 print_help();
    103                 return -1;
    104             }
    105         }
    106         else if( strncmp(argv[i], blocksize_opt, strlen(blocksize_opt)) == 0 )
    107         {
    108             if( sscanf( argv[i] + strlen(blocksize_opt), "%d", &SADWindowSize ) != 1 ||
    109                 SADWindowSize < 1 || SADWindowSize % 2 != 1 )
    110             {
    111                 printf("Command-line parameter error: The block size (--blocksize=<...>) must be a positive odd number\n");
    112                 return -1;
    113             }
    114         }
    115         else if( strncmp(argv[i], scale_opt, strlen(scale_opt)) == 0 )
    116         {
    117             if( sscanf( argv[i] + strlen(scale_opt), "%f", &scale ) != 1 || scale < 0 )
    118             {
    119                 printf("Command-line parameter error: The scale factor (--scale=<...>) must be a positive floating-point number\n");
    120                 return -1;
    121             }
    122         }
    123         else if( strcmp(argv[i], nodisplay_opt) == 0 )
    124             no_display = true;
    125         else if( strcmp(argv[i], "-i" ) == 0 )
    126             intrinsic_filename = argv[++i];
    127         else if( strcmp(argv[i], "-e" ) == 0 )
    128             extrinsic_filename = argv[++i];
    129         else if( strcmp(argv[i], "-o" ) == 0 )
    130             disparity_filename = argv[++i];
    131         else if( strcmp(argv[i], "-p" ) == 0 )
    132             point_cloud_filename = argv[++i];
    133         else
    134         {
    135             printf("Command-line parameter error: unknown option %s\n", argv[i]);
    136             return -1;
    137         }
    138     }
    139 
    140     if( !img1_filename || !img2_filename )
    141     {
    142         printf("Command-line parameter error: both left and right images must be specified\n");
    143         return -1;
    144     }
    145 
    146     if( (intrinsic_filename != 0) ^ (extrinsic_filename != 0) )
    147     {
    148         printf("Command-line parameter error: either both intrinsic and extrinsic parameters must be specified, or none of them (when the stereo pair is already rectified)\n");
    149         return -1;
    150     }
    151 
    152     if( extrinsic_filename == 0 && point_cloud_filename )
    153     {
    154         printf("Command-line parameter error: extrinsic and intrinsic parameters must be specified to compute the point cloud\n");
    155         return -1;
    156     }
    157 
    158     int color_mode = alg == STEREO_BM ? 0 : -1;
    159     Mat img1 = imread(img1_filename, color_mode);
    160     Mat img2 = imread(img2_filename, color_mode);
    161 
    162     if (img1.empty())
    163     {
    164         printf("Command-line parameter error: could not load the first input image file\n");
    165         return -1;
    166     }
    167     if (img2.empty())
    168     {
    169         printf("Command-line parameter error: could not load the second input image file\n");
    170         return -1;
    171     }
    172 
    173     if (scale != 1.f)
    174     {
    175         Mat temp1, temp2;
    176         int method = scale < 1 ? INTER_AREA : INTER_CUBIC;
    177         resize(img1, temp1, Size(), scale, scale, method);
    178         img1 = temp1;
    179         resize(img2, temp2, Size(), scale, scale, method);
    180         img2 = temp2;
    181     }
    182 
    183     Size img_size = img1.size();
    184 
    185     Rect roi1, roi2;
    186     Mat Q;
    187 
    188     if( intrinsic_filename )
    189     {
    190         // reading intrinsic parameters
    191         FileStorage fs(intrinsic_filename, FileStorage::READ);
    192         if(!fs.isOpened())
    193         {
    194             printf("Failed to open file %s\n", intrinsic_filename);
    195             return -1;
    196         }
    197 
    198         Mat M1, D1, M2, D2;
    199         fs["M1"] >> M1;
    200         fs["D1"] >> D1;
    201         fs["M2"] >> M2;
    202         fs["D2"] >> D2;
    203 
    204         M1 *= scale;
    205         M2 *= scale;
    206 
    207         fs.open(extrinsic_filename, FileStorage::READ);
    208         if(!fs.isOpened())
    209         {
    210             printf("Failed to open file %s\n", extrinsic_filename);
    211             return -1;
    212         }
    213 
    214         Mat R, T, R1, P1, R2, P2;
    215         fs["R"] >> R;
    216         fs["T"] >> T;
    217 
    218         stereoRectify( M1, D1, M2, D2, img_size, R, T, R1, R2, P1, P2, Q, CALIB_ZERO_DISPARITY, -1, img_size, &roi1, &roi2 );
    219 
    220         Mat map11, map12, map21, map22;
    221         initUndistortRectifyMap(M1, D1, R1, P1, img_size, CV_16SC2, map11, map12);
    222         initUndistortRectifyMap(M2, D2, R2, P2, img_size, CV_16SC2, map21, map22);
    223 
    224         Mat img1r, img2r;
    225         remap(img1, img1r, map11, map12, INTER_LINEAR);
    226         remap(img2, img2r, map21, map22, INTER_LINEAR);
    227 
    228         img1 = img1r;
    229         img2 = img2r;
    230     }
    231 
    232     numberOfDisparities = numberOfDisparities > 0 ? numberOfDisparities : ((img_size.width/8) + 15) & -16;
    233 
    234     bm->setROI1(roi1);
    235     bm->setROI2(roi2);
    236     bm->setPreFilterCap(31);
    237     bm->setBlockSize(SADWindowSize > 0 ? SADWindowSize : 9);
    238     bm->setMinDisparity(0);
    239     bm->setNumDisparities(numberOfDisparities);
    240     bm->setTextureThreshold(10);
    241     bm->setUniquenessRatio(15);
    242     bm->setSpeckleWindowSize(100);
    243     bm->setSpeckleRange(32);
    244     bm->setDisp12MaxDiff(1);
    245 
    246     sgbm->setPreFilterCap(63);
    247     int sgbmWinSize = SADWindowSize > 0 ? SADWindowSize : 3;
    248     sgbm->setBlockSize(sgbmWinSize);
    249 
    250     int cn = img1.channels();
    251 
    252     sgbm->setP1(8*cn*sgbmWinSize*sgbmWinSize);
    253     sgbm->setP2(32*cn*sgbmWinSize*sgbmWinSize);
    254     sgbm->setMinDisparity(0);
    255     sgbm->setNumDisparities(numberOfDisparities);
    256     sgbm->setUniquenessRatio(10);
    257     sgbm->setSpeckleWindowSize(100);
    258     sgbm->setSpeckleRange(32);
    259     sgbm->setDisp12MaxDiff(1);
    260     sgbm->setMode(alg == STEREO_HH ? StereoSGBM::MODE_HH : StereoSGBM::MODE_SGBM);
    261 
    262     Mat disp, disp8;
    263     //Mat img1p, img2p, dispp;
    264     //copyMakeBorder(img1, img1p, 0, 0, numberOfDisparities, 0, IPL_BORDER_REPLICATE);
    265     //copyMakeBorder(img2, img2p, 0, 0, numberOfDisparities, 0, IPL_BORDER_REPLICATE);
    266 
    267     int64 t = getTickCount();
    268     if( alg == STEREO_BM )
    269         bm->compute(img1, img2, disp);
    270     else if( alg == STEREO_SGBM || alg == STEREO_HH )
    271         sgbm->compute(img1, img2, disp);
    272     t = getTickCount() - t;
    273     printf("Time elapsed: %fms\n", t*1000/getTickFrequency());
    274 
    275     //disp = dispp.colRange(numberOfDisparities, img1p.cols);
    276     if( alg != STEREO_VAR )
    277         disp.convertTo(disp8, CV_8U, 255/(numberOfDisparities*16.));
    278     else
    279         disp.convertTo(disp8, CV_8U);
    280     if( !no_display )
    281     {
    282         namedWindow("left", 1);
    283         imshow("left", img1);
    284         namedWindow("right", 1);
    285         imshow("right", img2);
    286         namedWindow("disparity", 0);
    287         imshow("disparity", disp8);
    288         printf("press any key to continue...");
    289         fflush(stdout);
    290         waitKey();
    291         printf("\n");
    292     }
    293 
    294     if(disparity_filename)
    295         imwrite(disparity_filename, disp8);
    296 
    297     if(point_cloud_filename)
    298     {
    299         printf("storing the point cloud...");
    300         fflush(stdout);
    301         Mat xyz;
    302         reprojectImageTo3D(disp, xyz, Q, true);
    303         saveXYZ(point_cloud_filename, xyz);
    304         printf("\n");
    305     }
    306 
    307     return 0;
    308 }
    309