views:

254

answers:

2

I am making a simple calibration program in C++ using OpenCV. Everything goes fine until I actually try to call CVCalibrateCamera2. At this point, I get one of several errors:

If the number of images which I am using is equal to 4 (which is the number of points being drawn from each image:

OpenCV Error: Sizes of input arguments do not match (Both matrices must have the same number of points) in unknown function, file ......\src\cv\cvfundam.cpp, line 870

If the number of images is below 20:

OpenCV Error: Bad argument (The total number of matrix elements is not divisible by the new number of rows) in unknown function, file ......\src\cxcore\cxarray.cpp, line 2749

Otherwise, if the number of image is 20 or above:

OpenCV Error: Unsupported format or combination of formats (Invalid matrix type) in unknown function, file ......\src\cxcore\cxarray.cpp, line 117

I have checked the arguments for CVCalibrateCamera2 many times, and I am certain that they are of the correct dimensions relative to one another. It seems like somewhere the program is trying to reshape a matrix based on the number of images, but I can't figure out where or why. Any ideas? I am using Eclipse Galileo, MINGW 5.1.6, and OpenCV 2.1.

A: 

Update:

This is the code which calls CVCalibrateCamera2():

void calibrate(CvMat * object_points, CvMat * image_points, CvMat * intrinsicsMatrix, CvMat * distortionVector){
    const int point_count = object_points->rows;
    const int image_count = image_points->rows / point_count;
    CvMat * const full_object_points = cvCreateMat(image_count * point_count, 3, CV_32FC1);
    CvMat * const point_counts = cvCreateMat(image_count, 1, CV_32SC1);
    for (int i = 0; i < image_count; i++){
        CV_MAT_ELEM(*point_counts, float, i, 0) = point_count;
        for (int j = 0; j < point_count; j++){
            for (int k = 0; k < 3; k++){
                CV_MAT_ELEM(*full_object_points, float, i * point_count + j, k) = CV_MAT_ELEM(*object_points, float, j, k);
            }
        }
}
cvCalibrateCamera2(full_object_points, image_points, point_counts, cvSize(1, 1), intrinsicsMatrix, distortionVector, NULL, NULL, 0);
}

And this is the piece which collects the point values and passes them to the above function:

int main(){
    const float points [] [2] = {{0, 0}, {1, 0}, {2, 0}, {3, 0}};

    const int image_count = 5;
    const int point_count = sizeof (points) / sizeof(points[1]);

    CvMat * const object_points = cvCreateMat(point_count, 3, CV_32FC1);
    for (int i = 0; i < point_count; i++){
        CV_MAT_ELEM(*object_points, float, i, 0) = points[i][0];
        CV_MAT_ELEM(*object_points, float, i, 1) = points[i][1];
        CV_MAT_ELEM(*object_points, float, i, 2) = 0;
    }

    CvMat * const image_points = cvCreateMat(image_count * point_count, 2, CV_32FC1);
    collectPoints(setup, image_count, point_count, image_points); // See below about this

    CvMat * const intrinsicsMatrix = cvCreateMat(3, 3, CV_32FC1);

    CvMat * const distortionVector = cvCreateMat(5, 1, CV_32FC1);

    calibrate(object_points, image_points, intrinsicsMatrix, distortionVector);
}

In the above code, collectPoints() is a function making use of a third party library (gl.tter's WiiYourself wiimote library, if it matters). The code is below, but the important thing is that the points returned have values ranging from -.5 to .5.

void collectPoints(wiimote_setup & setup, const int image_count, const int point_count, CvMat * const image_points){
    image_points->rows = image_count * point_count;
    image_points->cols = 2;

    bool A_pressed = false;
    for (int i = 0; i < image_count; i++){
        while (true){
            setup.remote.RefreshState();
            if (setup.remote.Button.A()){
                if (!A_pressed){
                    for (int j = 0; j < point_count; j++){
                        wiimote_state::ir::dot & dot = setup.remote.IR.Dot[j];
                        CV_MAT_ELEM(*image_points, float, i * point_count + j, 0) = .5 - dot.X;
                        CV_MAT_ELEM(*image_points, float, i * point_count + j, 1) = .5 - dot.Y;
                        cout << dot.X <<", " << dot.Y << "\n";
                    }
                    cout << "\n";
                    cout.flush();
                    A_pressed = true;
                    break;
                }
            } else{
                A_pressed = false;
            }
        }
    }
}
tlayton
A: 

I am not 100% sure about this, but I don't think your object points can be collinear. In your code, you have

const float points [] [2] = {{0, 0}, {1, 0}, {2, 0}, {3, 0}};

These points are all on the same line (the x-axis). I think the object points must define a plane for cvCalibrateCamera2 to work. This might explain the errors you are seeing.

As far as I know, the OpenCV calibration routines were designed mostly for use with the checkerboard pattern (or some other planar set of object points), I don't know if the same algorithms will work in your situation.

bde