2
votes

I am doing camera calibration using opencv. I am using the same code given in "Cook book programming".

I am taking pictures from my smartphone of a chessboard. Then I am using opencv program to do camera calibration for me. Program worked for only one set of images when I have very large chess board. It does not work for other set of images and I get run time error "Assertion failed enter image description here

I dont know what going wrong in my code. The code is as follows:-

int main()
{
CameraCalibrator calibrateCam;
std::vector<std::string> filelist;
char buff[100];

for(int i=0;i<21;i++)
{
    sprintf(buff,"..\\Train\\3\\%d.jpg",i+1);
    filelist.push_back(buff);
}
cv::Size boardSize(4,3);
double calibrateError;
int success;
success = calibrateCam.addChessboardPoints(filelist,boardSize);
}

class CameraCalibrator{
public:
   std::vector<std::vector<cv::Point3f>> objectPoints;
   std::vector<std::vector<cv::Point2f>> imagePoints;
   //Square Lenght
   float squareLenght;
   //output Matrices
   cv::Mat cameraMatrix; //intrinsic
   cv::Mat distCoeffs;
   //flag to specify how calibration is done
   int flag;
   //used in image undistortion
   cv::Mat map1,map2;
   bool mustInitUndistort;
public:
    CameraCalibrator(): flag(0), squareLenght(36.0), mustInitUndistort(true){};
    int addChessboardPoints(const std::vector<std::string>& filelist,cv::Size& boardSize){
        std::vector<std::string>::const_iterator itImg;
        std::vector<cv::Point2f> imageCorners;
        std::vector<cv::Point3f> objectCorners;
        //initialize the chessboard corners in the chessboard reference frame
        //3d scene points
        for(int i = 0; i<boardSize.height; i++){
            for(int j=0;j<boardSize.width;j++){
                objectCorners.push_back(cv::Point3f(float(i)*squareLenght,float(j)*squareLenght,0.0f));
            }
        }
        //2D Image points:
        cv::Mat image; //to contain chessboard image
        int successes = 0;

        for(itImg=filelist.begin(); itImg!=filelist.end(); itImg++){
            image = cv::imread(*itImg,CV_LOAD_IMAGE_GRAYSCALE);
            std::cout<<*itImg<<"\n";

            bool found = cv::findChessboardCorners(image, boardSize, imageCorners);

            cv::drawChessboardCorners(image, boardSize, imageCorners, found);                      
            cv::cornerSubPix(image, imageCorners, cv::Size(5,5),cv::Size(-1,-1),
                cv::TermCriteria(cv::TermCriteria::MAX_ITER+cv::TermCriteria::EPS,30,0.1));
            //if we have a good board, add it to our data
            if(imageCorners.size() == boardSize.area()){
                addPoints(imageCorners,objectCorners);
                successes++;
            }
        }

        return successes;
    }
    void addPoints(const std::vector<cv::Point2f>& imageCorners,const std::vector<cv::Point3f>& objectCorners){
        //2D image point from one view
        imagePoints.push_back(imageCorners);
        //corresponding 3D scene points
        objectPoints.push_back(objectCorners);
    }
    double calibrate(cv::Size &imageSize){
        mustInitUndistort = true;
        std::vector<cv::Mat> rvecs,tvecs;
        return
            cv::calibrateCamera(objectPoints, //the 3D points
                imagePoints,
                imageSize, 
                cameraMatrix, //output camera matrix
                distCoeffs,
                rvecs,tvecs,
                flag);

    }
    void remap(const cv::Mat &image, cv::Mat &undistorted){
        std::cout << cameraMatrix;
        if(mustInitUndistort){ //called once per calibration
            cv::initUndistortRectifyMap(
                cameraMatrix,
                distCoeffs,
                cv::Mat(),
                cameraMatrix,
                image.size(),
                CV_32FC1,
                map1,map2);
            mustInitUndistort = false;
        }
        //apply mapping functions
        cv::remap(image,undistorted,map1,map2,cv::INTER_LINEAR);
    }
};

In camera calibration class, it opens the image successfully but it fails on findChessboardCorners line . . .

Plz help me in that. One sample chess board image is as follows. The algorithm fails on this very 1st image to find the corners . . . . :-enter image description here

1
You are not providing enough info yet. Does the algorithm fail in the above image? If not, you should post some images when the algorithm fails plus your actual calibration code, not just this part. Do you draw the detected points? Also, why do you have a red border around your black squares?Sassa
i have updated my answer. plz have a look and let me know. . .user1388142

1 Answers

2
votes

First, in cv::findChessboardCorners your boardSize is wrong, you define it as cv::Size boardSize(4,3); when it should be cv::Size boardSize(5,4); since your board has 5 inner corners per row and 4 corners per column.


Also, you should add a check in case corners are not found. In your code, after

bool found = cv::findChessboardCorners(image, boardSize, imageCorners);

you continue and call functions like cv::drawChessboardCorners and cv::cornerSubPix which will not work if there are no corners. This part should be:

for(itImg=filelist.begin(); itImg!=filelist.end(); itImg++)
{
    image = cv::imread(*itImg,CV_LOAD_IMAGE_GRAYSCALE);
    std::cout<<*itImg<<"\n";

    bool found = cv::findChessboardCorners(image, boardSize, imageCorners);

    if (found)  // continue only if corners have been found
    {
        cv::drawChessboardCorners(image, boardSize, imageCorners, found);                      
        cv::cornerSubPix(image, imageCorners, cv::Size(5,5),cv::Size(-1,-1), cv::TermCriteria(cv::TermCriteria::MAX_ITER+cv::TermCriteria::EPS,30,0.1));

        //if we have a good board, add it to our data
        if(imageCorners.size() == boardSize.area())
        {
            addPoints(imageCorners,objectCorners);
            successes++;
        }
    }
    else    // if no corners found
    {
        std::cout<<"No corners found in image"<<std::endl;

        // Do anything else you want here
    }
}


Also, why is there a red border around your black squares? I haven't looked at how exactly cv::findChessboardCorners detects the corners, but this could very possibly lead the algorithm to fail. Can you try with a new board without it? While we're at it, the light reflection on the upper corner could play some role too, since the intensity values there for black are a very light grey. Did you try your algorithm in the sample images provided by OpenCV?