Ask Your Question

Revision history [back]

Having Trouble Calibrating Stereo Fisheye/Undistorting Image

Hello everyone,

I've been struggling with figuring out how to properly calibrate and undistort a stereo image taken from two identical fisheye cameras. I think the issue has something to do with my program for calibration since when I run undistortImage() with the matrices obtained from the calibration program I get an image that is a small spec in the upper left corner and the rest of the image is black. Here is the code for obtaining the calibration matrices:

#include <iostream>
#include <vector>
#include <string>

#include <opencv2/core.hpp>
#include <opencv2/videoio.hpp>
#include <opencv2/calib3d.hpp>
#include <opencv2/imgproc.hpp>
#include <opencv2/highgui.hpp>

#define NUM_CAL 1
#define CHESS_ROW 9
#define CHESS_COL 6
#define SQUARE_SIZE_CM 0.023

using namespace std;
using namespace cv;

uint_fast8_t i;
Mat frame0[NUM_CAL], frame1[NUM_CAL];
vector<vector<Point2f>> imagePoints0, imagePoints1;
vector<Point2f> chessCorners0[NUM_CAL], chessCorners1[NUM_CAL];
vector<vector<Point2d>> leftPoints, rightPoints;
vector<vector<Point3d>> objectPoints;
Size chessSize(CHESS_COL, CHESS_ROW);


int main(int argc, char **argv)
{
    // Create matrix representing the chessboard corners
    vector<Point3d> obj;
    for(i = 0; i < CHESS_ROW; ++i )
    {
        for(uint_fast8_t j = 0; j < CHESS_COL; ++j )
        {
            obj.push_back(Point3d(double((float)j * SQUARE_SIZE_CM), double( (float)i * SQUARE_SIZE_CM ), 0));
        }
    }

    // Turn on cameras
    VideoCapture cam0(0), cam1(2);
    cam0.open(0,cv::CAP_V4L2);
    cam1.open(2,cv::CAP_V4L2);
    if(cam0.isOpened() == false) puts("No left camera found.  Please check connection \n");
    if(cam1.isOpened() == false) puts("No right camera found.  Please check connection \n");

    // Get calibration images and store them to RAM
    for(i = 0; i < NUM_CAL; ++i)
    {
        puts("Press enter to take a calibration picture \n");
        cin.get();
        cam0 >> frame0[i];
        cam1 >> frame1[i];
    }

    // Further refine corner points and store in intermediate matrix
    for(i = 0; i < NUM_CAL; ++i)
    {
        bool found1, found2;
        found1 = findChessboardCorners(frame0[i], chessSize, chessCorners0[i], CALIB_CB_ADAPTIVE_THRESH + CALIB_CB_NORMALIZE_IMAGE + CALIB_CB_FILTER_QUADS);
        found2 = findChessboardCorners(frame1[i], chessSize, chessCorners1[i], CALIB_CB_ADAPTIVE_THRESH + CALIB_CB_NORMALIZE_IMAGE + CALIB_CB_FILTER_QUADS);
        if((found1 == false) || (found2 == false)) puts("Not all corners found \n");
        cvtColor(frame0[i], frame0[i], CV_BGR2GRAY);
        cvtColor(frame1[i], frame1[i], CV_BGR2GRAY);
        cornerSubPix(frame0[i], chessCorners0[i], Size(1, 1), Size(-1, -1), TermCriteria(TermCriteria::COUNT+TermCriteria::EPS, 30, 0.01));
        cornerSubPix(frame1[i], chessCorners1[i], Size(1, 1), Size(-1, -1), TermCriteria(TermCriteria::COUNT+TermCriteria::EPS, 30, 0.01));
        drawChessboardCorners(frame0[i], chessSize, chessCorners0[i], found1);
        drawChessboardCorners(frame1[i], chessSize, chessCorners1[i], found2);
        // namedWindow("Image", WINDOW_AUTOSIZE);
        // imshow("Image", obj);
        // waitKey(0);
        imagePoints0.push_back(chessCorners0[i]);
        imagePoints1.push_back(chessCorners1[i]);
        objectPoints.push_back(obj);
    }

    // Finalize creation of the left and right calibration matrices
    // for(i = 0; i < imagePoints1.size(); ++i)
    for(i = 0; i < NUM_CAL; ++i)
    {
        long unsigned int j;
        vector<Point2d> v0, v1;
        for(j = 0; j < imagePoints1[i].size(); ++j)
        {
            v0.push_back(Point2d((double)imagePoints0[i][j].x, (double)imagePoints0[i][j].y));
            v1.push_back(Point2d((double)imagePoints1[i][j].x, (double)imagePoints1[i][j].y));
        }
        leftPoints.push_back(v0);
        rightPoints.push_back(v1);
    }

    // Begin actual calibration!
    printf("Calculating... \n");
    // Size newSize(0,0);
    // Matx33d K1, K2, R;
    // Vec3d T;
    // Vec4d D1, D2;
    Mat K1, K2, R, T, D1, D2;
    Mat R1, R2, P1, P2, Q;
    int flag = 0;
    flag |= fisheye::CALIB_RECOMPUTE_EXTRINSIC;
    flag |= fisheye::CALIB_CHECK_COND;
    flag |= fisheye::CALIB_FIX_SKEW;
    // flag |= fisheye::CALIB_FIX_K1;
    // flag |= fisheye::CALIB_FIX_K2;
    // flag |= fisheye::CALIB_FIX_K3;
    // flag |= fisheye::CALIB_FIX_K4;
    fisheye::stereoCalibrate(objectPoints, leftPoints, rightPoints, K1, D1, K2, D2, frame1[0].size(), R, T, flag, TermCriteria(TermCriteria::COUNT+TermCriteria::EPS, 100, 0.01));
    fisheye::stereoRectify(K1, D1, K2, D2, frame1[0].size(), R, T, R1, R2, P1, P2, Q, CV_CALIB_ZERO_DISPARITY, frame1[0].size(), 0.0, 1.0);
    printf("Calculations completed.  Saving results to file... \n");

    // Save results to file
    cv::FileStorage fs1("/home/lukefischer/OpenCV/calibration_output.yml", cv::FileStorage::WRITE);
    fs1 << "K1" << K1;
    fs1 << "K2" << K2;
    fs1 << "D1" << D1;
    fs1 << "D2" << D2;
    fs1 << "R" << R;
    fs1 << "T" << T;
    fs1 << "R1" << R1;
    fs1 << "R2" << R2;
    fs1 << "P1" << P1;
    fs1 << "P2" << P2;
    fs1 << "Q" << Q;
    printf("Results saved to file.  Calibration is complete.  \n");

    return 0;
}

I am really at a loss at this point.

Thanks in advance, Luke