OpenCV 2.3 camera calibration

camera-calibration, computer-vision, matlab, opencv, vision

Solution

First off, your camera matrix is wrong. If you read the documentation, it should look like:

fx  0 cx
 0 fy cy
 0  0  1

If you look at yours, you've got it the wrong way round:

fx  0  0
 0 fy  0
cx cy  1

So first, set `camera_matrix` to `camera_matrix.T` (or change how you construct `camera_matrix`. Remember that `camera_matrix[i,j]` is row `i`, column `j`).

camera_matrix = camera_matrix.T

Next, I ran your code and I see that "can't seem to get it to work" means the following error (by the way - always say what you mean by "can't seem to get it to work" in your questions - if it's an error, post the error. If it runs but gives you weirdo numbers, say so):

OpenCV Error: Assertion failed (ni >= 0) in collectCalibrationData, file /home/cha66i/Downloads/OpenCV-2.3.1/modules/calib3d/src/calibration.cpp, line 3161
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
cv2.error: /home/cha66i/Downloads/OpenCV-2.3.1/modules/calib3d/src/calibration.cpp:3161: error: (-215) ni >= 0 in function collectCalibrationData

I then read the documentation (very useful by the way) and noticed that `obj_points` and `img_points` have to be vectors of vectors, because it is possible to feed in sets of object/image points for multiple images of the same chessboard(/calibration points).

Hence:

cv2.calibrateCamera([obj_points], [img_points],size, camera_matrix, dist_coefs)

What? I still get the same error?!

Then, I had a look at the OpenCV python2 samples (in the folder `OpenCV-2.x.x/samples/python2`), and noticed a `calibration.py` showing me how to use the calibration functions (never underestimate the samples, they're often better than the documentation!).

I tried to run `calibration.py` but it doesn't run because it doesn't supply the `camera_matrix` and `distCoeffs` arguments, which are necessary. So I modified it to feed in a dummy `camera_matrix` and `distCoeffs`, and hey, it works!

The only difference I can see between my `obj_points`/`img_points` and theirs, is that theirs has `dtype=float32`, while mine doesn't.

So, I change my `obj_points` and `img_points` to also have dtype float32 (the python2 interface to OpenCV is funny like that; often functions don't work when matrices don't have a `dtype`):

obj_points = obj_points.astype('float32')
img_points = img_points.astype('float32')

Then I try again:

>>> cv2.calibrateCamera([obj_points], [img_points],size, camera_matrix, dist_coefs)
OpenCV Error: Bad argument 
(For non-planar calibration rigs the initial intrinsic matrix must be specified) 
in cvCalibrateCamera2, file ....

What?! A different error at least. But I did supply an initial intrinsic matrix!

So I go back to the documentation, and notice the `flags` parameter:

flags – Different flags that may be zero or a combination of the following values:

`CV_CALIB_USE_INTRINSIC_GUESS` cameraMatrix contains valid initial values of fx, fy, cx, cy that are optimized further

...

Aha, so I have to tell the function explicitly to use the initial guesses I provided:

cv2.calibrateCamera([obj_points], [img_points],size, camera_matrix.T, dist_coefs,
                    flags=cv2.CALIB_USE_INTRINSIC_GUESS)

Hurrah! It works!

(Moral of the story - read the OpenCV documentation carefully, and use the newest version (i.e. on opencv.itseez.com) if you're using the Python `cv2` interface. Also, consult the examples in the `samples/python2` directory to supplement the documentation. With these two things you should be able to work out most problems.)

Problem

I'm trying to use `OpenCV 2.3` python bindings to calibrate a camera. I've used the data below in matlab and the calibration worked, but I can't seem to get it to work in OpenCV. The camera matrix I setup as an initial guess is very close to the answer calculated from the matlab toolbox. ``` import cv2 import numpy as np obj_points = [[-9.7,3.0,4.5],[-11.1,0.5,3.1],[-8.5,0.9,2.4],[-5.8,4.4,2.7],[-4.8,1.5,0.2],[-6.7,-1.6,-0.4],[-8.7,-3.3,-0.6],[-4.3,-1.2,-2.4],[-12.4,-2.3,0.9], [-14.1,-3.8,-0.6],[-18.9,2.9,2.9],[-14.6,2.3,4.6],[-16.0,0.8,3.0],[-18.9,-0.1,0.3], [-16.3,-1.7,0.5],[-18.6,-2.7,-2.2]] img_points = [[993.0,623.0],[942.0,705.0],[1023.0,720.0],[1116.0,645.0],[1136.0,764.0],[1071.0,847.0],[1003.0,885.0],[1142.0,887.0],[886.0,816.0],[827.0,883.0],[710.0,636.0],[837.0,621.0],[789.0,688.0],[699.0,759.0],[768.0,800.0],[697.0,873.0]] obj_points = np.array(obj_points) img_points = np.array(img_points) w = 1680 h = 1050 size = (w,h) camera_matrix = np.zeros((3, 3)) camera_matrix[0,0]= 2200.0 camera_matrix[1,1]= 2200.0 camera_matrix[2,2]=1.0 camera_matrix[2,0]=750.0 camera_matrix[2,1]=750.0 dist_coefs = np.zeros(4) results = cv2.calibrateCamera(obj_points, img_points,size, camera_matrix, dist_coefs) ```

Original source