264 lines
		
	
	
		
			8.3 KiB
		
	
	
	
		
			C++
		
	
	
	
	
	
			
		
		
	
	
			264 lines
		
	
	
		
			8.3 KiB
		
	
	
	
		
			C++
		
	
	
	
	
	
/*
 | 
						|
 *  stereo_match.cpp
 | 
						|
 *  calibration
 | 
						|
 *
 | 
						|
 *  Created by Victor  Eruhimov on 1/18/10.
 | 
						|
 *  Copyright 2010 Argus Corp. All rights reserved.
 | 
						|
 *
 | 
						|
 */
 | 
						|
 | 
						|
#include <cv.h>
 | 
						|
#include <highgui.h>
 | 
						|
#include <stdio.h>
 | 
						|
 | 
						|
using namespace cv;
 | 
						|
 | 
						|
void saveXYZ(const char* filename, const Mat& mat)
 | 
						|
{
 | 
						|
    const double max_z = 1.0e4;
 | 
						|
    FILE* fp = fopen(filename, "wt");
 | 
						|
    for(int y = 0; y < mat.rows; y++)
 | 
						|
    {
 | 
						|
        for(int x = 0; x < mat.cols; x++)
 | 
						|
        {
 | 
						|
            Vec3f point = mat.at<Vec3f>(y, x);
 | 
						|
            if(fabs(point[2] - max_z) < FLT_EPSILON || fabs(point[2]) > max_z) continue;
 | 
						|
            fprintf(fp, "%f %f %f\n", point[0], point[1], point[2]);
 | 
						|
        }
 | 
						|
    }
 | 
						|
    fclose(fp);
 | 
						|
}
 | 
						|
 | 
						|
void print_help()
 | 
						|
{
 | 
						|
    printf("Usage: stereo_match <left_image> <right_image> [--algorithm=bm|sgbm|hh] [--blocksize=<block_size>]\n"
 | 
						|
           "[--max-disparity=<max_disparity>] [-i <intrinsic_filename>] [-e <extrinsic_filename>]\n"
 | 
						|
           "[--no-display] [-o <disparity_image>] [-p <point_cloud_file>]\n");
 | 
						|
}
 | 
						|
 | 
						|
int main(int argc, char** argv)
 | 
						|
{
 | 
						|
    const char* algorithm_opt = "--algorithm=";
 | 
						|
    const char* maxdisp_opt = "--max-disparity=";
 | 
						|
    const char* blocksize_opt = "--blocksize=";
 | 
						|
    const char* nodisplay_opt = "--no-display=";
 | 
						|
    
 | 
						|
    if(argc < 3)
 | 
						|
    {
 | 
						|
        print_help();
 | 
						|
        return 0;
 | 
						|
    }
 | 
						|
    const char* img1_filename = 0;
 | 
						|
    const char* img2_filename = 0;
 | 
						|
    const char* intrinsic_filename = 0;
 | 
						|
    const char* extrinsic_filename = 0;
 | 
						|
    const char* disparity_filename = 0;
 | 
						|
    const char* point_cloud_filename = 0;
 | 
						|
    
 | 
						|
    enum { STEREO_BM=0, STEREO_SGBM=1, STEREO_HH=2 };
 | 
						|
    int alg = STEREO_SGBM;
 | 
						|
    int SADWindowSize = 0, numberOfDisparities = 0;
 | 
						|
    bool no_display = false;
 | 
						|
    
 | 
						|
    StereoBM bm;
 | 
						|
    StereoSGBM sgbm;
 | 
						|
    
 | 
						|
    for( int i = 1; i < argc; i++ )
 | 
						|
    {
 | 
						|
        if( argv[i][0] != '-' )
 | 
						|
        {
 | 
						|
            if( !img1_filename )
 | 
						|
                img1_filename = argv[i];
 | 
						|
            else
 | 
						|
                img2_filename = argv[i];
 | 
						|
        }
 | 
						|
        else if( strncmp(argv[i], algorithm_opt, strlen(algorithm_opt)) == 0 )
 | 
						|
        {
 | 
						|
            char* _alg = argv[i] + strlen(algorithm_opt);
 | 
						|
            alg = strcmp(_alg, "bm") == 0 ? STEREO_BM :
 | 
						|
                  strcmp(_alg, "sgbm") == 0 ? STEREO_SGBM :
 | 
						|
                  strcmp(_alg, "hh") == 0 ? STEREO_HH : -1;
 | 
						|
            if( alg < 0 )
 | 
						|
            {
 | 
						|
                printf("Command-line parameter error: Unknown stereo algorithm\n\n");
 | 
						|
                print_help();
 | 
						|
                return -1;
 | 
						|
            }
 | 
						|
        }
 | 
						|
        else if( strncmp(argv[i], maxdisp_opt, strlen(maxdisp_opt)) == 0 )
 | 
						|
        {
 | 
						|
            if( sscanf( argv[i] + strlen(maxdisp_opt), "%d", &numberOfDisparities ) != 1 ||
 | 
						|
                numberOfDisparities < 1 || numberOfDisparities % 16 != 0 )
 | 
						|
            {
 | 
						|
                printf("Command-line parameter error: The max disparity (--maxdisparity=<...>) must be a positive integer divisible by 16\n");
 | 
						|
                print_help();
 | 
						|
                return -1;
 | 
						|
            }
 | 
						|
        }
 | 
						|
        else if( strncmp(argv[i], blocksize_opt, strlen(blocksize_opt)) == 0 )
 | 
						|
        {
 | 
						|
            if( sscanf( argv[i] + strlen(blocksize_opt), "%d", &SADWindowSize ) != 1 ||
 | 
						|
                SADWindowSize < 1 || SADWindowSize % 2 != 1 )
 | 
						|
            {
 | 
						|
                printf("Command-line parameter error: The block size (--blocksize=<...>) must be a positive odd number\n");
 | 
						|
                return -1;
 | 
						|
            }
 | 
						|
        }
 | 
						|
        else if( strcmp(argv[i], nodisplay_opt) == 0 )
 | 
						|
            no_display = true;
 | 
						|
        else if( strcmp(argv[i], "-i" ) == 0 )
 | 
						|
            intrinsic_filename = argv[++i];
 | 
						|
        else if( strcmp(argv[i], "-e" ) == 0 )
 | 
						|
            extrinsic_filename = argv[++i];
 | 
						|
        else if( strcmp(argv[i], "-o" ) == 0 )
 | 
						|
            disparity_filename = argv[++i];
 | 
						|
        else if( strcmp(argv[i], "-p" ) == 0 )
 | 
						|
            point_cloud_filename = argv[++i];
 | 
						|
        else
 | 
						|
        {
 | 
						|
            printf("Command-line parameter error: unknown option %s\n", argv[i]);
 | 
						|
            return -1;
 | 
						|
        }
 | 
						|
    }
 | 
						|
    
 | 
						|
    if( !img1_filename || !img2_filename )
 | 
						|
    {
 | 
						|
        printf("Command-line parameter error: both left and right images must be specified\n");
 | 
						|
        return -1;
 | 
						|
    }
 | 
						|
    
 | 
						|
    if( (intrinsic_filename != 0) ^ (extrinsic_filename != 0) )
 | 
						|
    {
 | 
						|
        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");
 | 
						|
        return -1;
 | 
						|
    }
 | 
						|
    
 | 
						|
    if( extrinsic_filename == 0 && point_cloud_filename )
 | 
						|
    {
 | 
						|
        printf("Command-line parameter error: extrinsic and intrinsic parameters must be specified to compute the point cloud\n");
 | 
						|
        return -1;
 | 
						|
    }
 | 
						|
    
 | 
						|
    int color_mode = alg == STEREO_BM ? 0 : -1;
 | 
						|
    Mat img1 = imread(img1_filename, color_mode);
 | 
						|
    Mat img2 = imread(img2_filename, color_mode);
 | 
						|
    Size img_size = img1.size();
 | 
						|
    
 | 
						|
    Rect roi1, roi2;
 | 
						|
    Mat Q;
 | 
						|
    
 | 
						|
    if( intrinsic_filename )
 | 
						|
    {
 | 
						|
        // reading intrinsic parameters
 | 
						|
        FileStorage fs(intrinsic_filename, CV_STORAGE_READ);
 | 
						|
        if(!fs.isOpened())
 | 
						|
        {
 | 
						|
            printf("Failed to open file %s\n", intrinsic_filename);
 | 
						|
            return -1;
 | 
						|
        }
 | 
						|
        
 | 
						|
        Mat M1, D1, M2, D2;
 | 
						|
        fs["M1"] >> M1;
 | 
						|
        fs["D1"] >> D1;
 | 
						|
        fs["M2"] >> M2;
 | 
						|
        fs["D2"] >> D2;
 | 
						|
        
 | 
						|
        fs.open(extrinsic_filename, CV_STORAGE_READ);
 | 
						|
        if(!fs.isOpened())
 | 
						|
        {
 | 
						|
            printf("Failed to open file %s\n", extrinsic_filename);
 | 
						|
            return -1;
 | 
						|
        }
 | 
						|
        
 | 
						|
        Mat R, T, R1, P1, R2, P2;
 | 
						|
        fs["R"] >> R;
 | 
						|
        fs["T"] >> T;
 | 
						|
        
 | 
						|
        stereoRectify( M1, D1, M2, D2, img_size, R, T, R1, R2, P1, P2, Q, -1, img_size, &roi1, &roi2 );
 | 
						|
        
 | 
						|
        Mat map11, map12, map21, map22;
 | 
						|
        initUndistortRectifyMap(M1, D1, R1, P1, img_size, CV_16SC2, map11, map12);
 | 
						|
        initUndistortRectifyMap(M2, D2, R2, P2, img_size, CV_16SC2, map21, map22);
 | 
						|
        
 | 
						|
        Mat img1r, img2r;
 | 
						|
        remap(img1, img1r, map11, map12, INTER_LINEAR);
 | 
						|
        remap(img2, img2r, map21, map22, INTER_LINEAR);
 | 
						|
        
 | 
						|
        img1 = img1r;
 | 
						|
        img2 = img2r;
 | 
						|
    }
 | 
						|
    
 | 
						|
    numberOfDisparities = numberOfDisparities > 0 ? numberOfDisparities : img_size.width/8;
 | 
						|
    
 | 
						|
    bm.state->roi1 = roi1;
 | 
						|
    bm.state->roi2 = roi2;
 | 
						|
    bm.state->preFilterCap = 31;
 | 
						|
    bm.state->SADWindowSize = SADWindowSize > 0 ? SADWindowSize : 9;
 | 
						|
    bm.state->minDisparity = 0;
 | 
						|
    bm.state->numberOfDisparities = numberOfDisparities;
 | 
						|
    bm.state->textureThreshold = 10;
 | 
						|
    bm.state->uniquenessRatio = 15;
 | 
						|
    bm.state->speckleWindowSize = 100;
 | 
						|
    bm.state->speckleRange = 32;
 | 
						|
    bm.state->disp12MaxDiff = 1;
 | 
						|
    
 | 
						|
    sgbm.preFilterCap = 63;
 | 
						|
    sgbm.SADWindowSize = SADWindowSize > 0 ? SADWindowSize : 3;
 | 
						|
    
 | 
						|
    int cn = img1.channels();
 | 
						|
    
 | 
						|
    sgbm.P1 = 8*cn*sgbm.SADWindowSize*sgbm.SADWindowSize;
 | 
						|
    sgbm.P2 = 32*cn*sgbm.SADWindowSize*sgbm.SADWindowSize;
 | 
						|
    sgbm.minDisparity = 0;
 | 
						|
    sgbm.numberOfDisparities = numberOfDisparities;
 | 
						|
    sgbm.uniquenessRatio = 10;
 | 
						|
    sgbm.speckleWindowSize = bm.state->speckleWindowSize;
 | 
						|
    sgbm.speckleRange = bm.state->speckleRange;
 | 
						|
    sgbm.disp12MaxDiff = 1;
 | 
						|
    sgbm.fullDP = alg == STEREO_HH;
 | 
						|
    
 | 
						|
    Mat disp, disp8;
 | 
						|
    //Mat img1p, img2p, dispp;
 | 
						|
    //copyMakeBorder(img1, img1p, 0, 0, numberOfDisparities, 0, IPL_BORDER_REPLICATE);
 | 
						|
    //copyMakeBorder(img2, img2p, 0, 0, numberOfDisparities, 0, IPL_BORDER_REPLICATE);
 | 
						|
    
 | 
						|
    int64 t = getTickCount();
 | 
						|
    if( alg == STEREO_BM )
 | 
						|
        bm(img1, img2, disp);
 | 
						|
    else
 | 
						|
        sgbm(img1, img2, disp);
 | 
						|
    t = getTickCount() - t;
 | 
						|
    printf("Time elapsed: %fms\n", t*1000/getTickFrequency());
 | 
						|
 | 
						|
    //disp = dispp.colRange(numberOfDisparities, img1p.cols);
 | 
						|
    disp.convertTo(disp8, CV_8U, 255/(numberOfDisparities*16.));
 | 
						|
    if( !no_display )
 | 
						|
    {
 | 
						|
        namedWindow("left", 1);
 | 
						|
        imshow("left", img1);
 | 
						|
        namedWindow("right", 1);
 | 
						|
        imshow("right", img2);
 | 
						|
        namedWindow("disparity", 0);
 | 
						|
        imshow("disparity", disp8);
 | 
						|
        printf("press any key to continue...");
 | 
						|
        fflush(stdout);
 | 
						|
        waitKey();
 | 
						|
        printf("\n");
 | 
						|
    }
 | 
						|
    
 | 
						|
    if(disparity_filename)
 | 
						|
        imwrite(disparity_filename, disp8);
 | 
						|
    
 | 
						|
    if(point_cloud_filename)
 | 
						|
    {
 | 
						|
        printf("storing the point cloud...");
 | 
						|
        fflush(stdout);
 | 
						|
        Mat xyz;
 | 
						|
        reprojectImageTo3D(disp, xyz, Q, true);
 | 
						|
        saveXYZ(point_cloud_filename, xyz);
 | 
						|
        printf("\n");
 | 
						|
    }
 | 
						|
    
 | 
						|
    return 0;
 | 
						|
}
 |