Ask Your Question
0

use opencv to calibrate camera problem

asked 2013-06-28 17:06:07 -0600

updated 2013-06-28 17:10:18 -0600

Hi,

I am trying to write a program for fixing camera distortion. I studied the sample code from opencv and also looked at some tutorials online. However, I was having trouble with the calibrateCamera function call. The version of opencv I am using is 2.4.5.

Here is the code that I have:

    #include "stdafx.h"
    #include <cv.h>
    #include <highgui.h>
    using namespace cv;
    using namespace std;


int _tmain(int argc, _TCHAR* argv[])
{
    int numBoards = 0;
    int numCornersHor;
    int numCornersVer;

    printf("Enter number of corners along width: ");
    scanf("%d", &numCornersHor);
    printf("Enter number of corners along height: ");
    scanf("%d", &numCornersVer);
    printf("Enter number of boards: ");
    scanf("%d", &numBoards);

    int numSquares = numCornersHor * numCornersVer;
    Size board_sz = Size(numCornersHor, numCornersVer);

    /* Chessboard images that will be used to calibrate the camera */
    vector<string> imageList(10);
    imageList[0] = "chessboard1.jpg";
    imageList[1] = "chessboard2.jpg";
    imageList[2] = "chessboard3.jpg";
    imageList[3] = "chessboard4.jpg";
    imageList[4] = "chessboard5.jpg";
    imageList[5] = "chessboard6.jpg";
    imageList[6] = "chessboard7.jpg";
    imageList[7] = "chessboard8.jpg";
    imageList[8] = "chessboard9.jpg";
    imageList[9] = "chessboard10.jpg";

    /* physical position of the corners (in 3D space) */
    vector<vector<Point3f>> object_points(1); 
    /* location of corners in the image (in 2D space) */
    vector<vector<Point2f>> image_points;
    /* corners in the current chessboard image */
    vector<Point2f> corners;
    /* ??? */
    int successes = 0;

    Mat image;
    Mat gray_image;

    for (int index = 0; index < numSquares; index++)
    {
        object_points[0].push_back(Point3f(float(index/numCornersHor), float(index % numCornersHor), 0.0f));
    }

    while(successes < numBoards)
    {
        image = imread(imageList[successes], CV_LOAD_IMAGE_COLOR);
        /* convert image into a grayscale image */
        cvtColor(image, gray_image, CV_BGR2GRAY);

        bool found = findChessboardCorners(image, board_sz, corners, CV_CALIB_CB_ADAPTIVE_THRESH | CV_CALIB_CB_FILTER_QUADS);

        if (found)
        {
            cornerSubPix(gray_image, corners, Size(11, 11), Size(-1, -1), TermCriteria(CV_TERMCRIT_EPS | CV_TERMCRIT_ITER, 30, 0.1));
            drawChessboardCorners(gray_image, board_sz, corners, found);
            image_points.push_back(corners);
            successes++;
        } 
    }

    object_points.resize(image_points.size(), object_points[0]); 

    Mat intrinsic = Mat(3, 3, CV_32FC1);
    Mat distCoeffs;
    vector<Mat> rvecs;
    vector<Mat> tvecs;

    intrinsic.ptr<float>(0)[0]= 1;
    intrinsic.ptr<float>(1)[1] = 1;
    calibrateCamera(object_points, image_points, image.size(), intrinsic, 
        distCoeffs, rvecs, tvecs);

    return 0;
}

I keep getting errors from opencv on this particular line from function collectCalibrationData:

for( i = 0; i < nimages; i++ )
{
     ni = objectPoints.getMat(i).checkVector(3, CV_32F);
     CV_Assert( ni >= 0 );
     total += ni;
}

The program fails the assertion every single time.

I don't know what is wrong with my object_points declaration. Could anyone explain to me why and how to fix it? I have been spending a long time on this and not getting any where. Thank you very much.

edit retag flag offensive close merge delete

2 answers

Sort by » oldest newest most voted
0

answered 2015-10-27 03:09:17 -0600

I met the same issue, too. In my case, there is a bug to convert vector< vector < Point3f > > to InputArrayOfArrays. You may run the following sample code to check it in your system.

using namespace std;
using namespace cv;

/** @function main */
int main( void )
{   
    vector<Point3f> objectPoints_tmp(54);
    objectPoints_tmp.clear();

    for( int i = 0; i < 9; ++i )
        for( int j = 0; j < 6; ++j )
            objectPoints_tmp.push_back(Point3f(j*50, i*50, 0.0f));

    vector<vector<Point3f> > objectPoints(7, objectPoints_tmp); 
    InputArrayOfArrays OBJPOINT = objectPoints; std::cout << (int) OBJPOINT.total() << std::endl;  

    for( int i = 0; i < 7; ++i )
        std::cout << OBJPOINT.getMat(i).checkVector(3, CV_32F) << std::endl;  

    waitKey(0);
    return 0;
}

Normally, it should print out

7
54
54
54
54
54
54
54

In my NG case, it prints out random numbers.

I guess that the opencv lib is not fit with my system(win7 x64 + vs2012). After rebuild opencv myself, it may work now. You may google keyword "Win7x64 VS2012 OpenCV CMake TBB".

edit flag offensive delete link more
0

answered 2013-06-29 01:36:22 -0600

berak gravatar image

updated 2013-06-29 02:48:46 -0600

you only got 1 vector of objectPoints,

 vector<vector<Point3f>> object_points(1);

but it needs to be the same size as your imagepoints ( 10 in the end), one object_point vector per corner vector.

also, i think, your calculation of the object_points is wrong, that'll never make an artificial chessboard.

so, try this instead:

/* physical position of the corners (in 3D space) */
vector<vector<Point3f> > object_points;
/* location of corners in the image (in 2D space) */
vector<vector<Point2f>> image_points;
/* corners in the current chessboard image */
vector<Point2f> corners;
/* ??? */
int successes = 0;

Mat image;
Mat gray_image;

const float squareSize = 1.f;  // Set this to your actual square size

vector<Point3f> model;
for( int j = 0; j < numCornersHor; j++ )
    for( int k = 0; k < numCornersVer; k++ )
        model.push_back(Point3f(float(j)*squareSize, float(k)*squareSize, 0));

for( int i = 0; i < numBoards; i++ )
{
    image = imread(imageList[i], CV_LOAD_IMAGE_COLOR);
    /* convert image into a grayscale image */
    cvtColor(image, gray_image, CV_BGR2GRAY);

    bool found = findChessboardCorners(image, board_sz, corners, CV_CALIB_CB_ADAPTIVE_THRESH | CV_CALIB_CB_FILTER_QUADS);

    if (found)
    {
        cornerSubPix(gray_image, corners, Size(11, 11), Size(-1, -1), TermCriteria(CV_TERMCRIT_EPS | CV_TERMCRIT_ITER, 30, 0.1));
        drawChessboardCorners(gray_image, board_sz, corners, found);
        image_points.push_back(corners);
        object_points.push_back(model);
        successes++;
    } 
}
edit flag offensive delete link more

Comments

Hi. Thank you for your suggestions. I tried them. However, I am getting the same assertion error.

I don't understand how OpenCV is doing the conversion from 2d vector to a matrix. Doesn't the assertion check whether the matrix created has 3 columns and each element has a float type? If so, how can the object_points fail the assertion? I am really confused.

richardfrommars gravatar imagerichardfrommars ( 2013-06-29 01:51:16 -0600 )edit

gosh, numBoards is 0 in your code, i assumed, it would be 10 ;)

also, what is this for ?

object_points.resize(image_points.size(), object_points[0]);

the assertion checks whether each of the 10 required matrices has 3 columns and each element has a float type, and in your 1st version, that wa only true for the first

berak gravatar imageberak ( 2013-06-29 02:03:02 -0600 )edit

bah, i had objectPoints instead of object_points, check, if it used the right one for the calculation !

berak gravatar imageberak ( 2013-06-29 02:19:40 -0600 )edit

there's another flaw in your code, if it does not find a chessboard in the image, successes will never get increased, and it will loop forever checking the very same image ..

berak gravatar imageberak ( 2013-06-29 02:22:57 -0600 )edit

Did you solve your problem richardfrommars?

ahof1704 gravatar imageahof1704 ( 2013-07-19 11:43:03 -0600 )edit

Question Tools

Stats

Asked: 2013-06-28 17:06:07 -0600

Seen: 2,062 times

Last updated: Jul 19 '13