Ask Your Question

Chessboard and Circle calibration provide radically different results

asked 2016-02-24 08:34:52 -0600

wweaver gravatar image

updated 2016-02-24 09:34:47 -0600

I have a 35mm nominal focal length camera that I'm trying to calibrate using a PyQt front end I'm building onto OpenCV's python library. It finds and displays matched points. Everything works except for the returns on cv2.calibrateCamera() when using a 4 x 11 asymmetric circle grid and cv2.findCirclesGrid().

Using a 6 x 9 chessboard pattern, I obtain a focal length (converted to mm) of 35.8 mm. I'd accept this for now with the 35mm lens I'm using. When I use the same camera/lens and a circle grid pattern I obtain a focal length of 505.9 mm. This is clearly wrong. The k and p coefficients are also enormous. What am I missing? See code below.

Edited down to show only relevant bits. Some variables are defined elsewhere.

# termination criteria
criteria = (cv2.TERM_CRITERIA_EPS + cv2.TERM_CRITERIA_MAX_ITER, 30, 0.001)

# prepare object points, like (0,0,0), (1,0,0), (2,0,0) ....,(6,5,0)
params = []
def objParams (grid):
    if grid == "Checkerboard":
        param1 = np.zeros((6 * 9, 3), np.float32)
        param2 = np.mgrid[0:9,0:6].T.reshape(-1,2)
    elif grid == "Circle Grid":
        param1 = np.zeros((4 * 11, 3), np.float32)
        param2 = np.mgrid[0:4,0:11].T.reshape(-1,2)
objp = params[0]
objp[:, :2] = params[1]

# Arrays to store object points and image points from all the images.
objpoints = []  # 3d point in real world space
imgpoints = []  # 2d points in image plane.

images = glob.glob(folder + '/*.jpg')
i = 0
for fname in images:
    img = cv2.imread(fname)
    smimg = cv2.resize(img, (0, 0), fx=scaleTo, fy=scaleTo)
    gray = cv2.cvtColor(smimg, cv2.COLOR_BGR2GRAY)
    # step counter
    i += 1
    # Find the chess board corners
    if pattern == 'Checkerboard':
        print("Now finding corners on image " + str(i) + ".")
        ret, corners = cv2.findChessboardCorners(gray, (9, 6), None)
        # If found, add object points, image points
        if ret == True:
            print("Corners found on image " + str(i) + ".")
            print("Drawing corners on image " + str(i) + ".")
            # Draw and display the corners
            cv2.drawChessboardCorners(smimg, (9, 6), corners, ret)
            if saveMarked == True:
                cv2.imwrite(os.path.join(outfolder, os.path.basename(fname)), smimg)
            cv2.imshow(os.path.basename(fname), smimg)
    elif pattern == 'Circle Grid':
        print("Now finding circles on image " + str(i) + ".")
        ret, circles = cv2.findCirclesGrid(gray, (4,11), flags = cv2.CALIB_CB_ASYMMETRIC_GRID)
        # If found, add object points, image points
        if ret == True:
            print("Circles found on image " + str(i) + ".")
            # Draw and display the circles
            cv2.drawChessboardCorners(smimg, (4, 11), circles, ret)
            if saveMarked == True:
                cv2.imwrite(os.path.join(outfolder, os.path.basename(fname)), smimg)
            cv2.imshow(os.path.basename(fname), smimg)

ret, mtx, dist, rvecs, tvecs = cv2.calibrateCamera(objpoints, imgpoints, gray.shape[::-1], paramMtx, None, None)

EDIT: Here are the outputs as well as my pretty print statements:

Chessboard ... (more)

edit retag flag offensive close merge delete


How many images did you use for the calibration process ?

I know only the basics with Python, so maybe I missed the information, how did you construct your object point ? For asymetric grid, the formula is different as you can see it here:

Also, I don't see in your code if you have supply the real square size ? Otherwise, you will be dependent of a scale factor.

You can look at this tutorial for C++: Camera Calibration with OpenCV.

Eduardo gravatar imageEduardo ( 2016-02-24 10:44:52 -0600 )edit

I used 35 images for each pattern. I think you are correct that the object point vectors aren't being constructed correctly. I only know the basics of C++ so I'm having trouble translating that. The arrays are set up in the objParams() function near the top as 0's. Values are appended to these arrays following the check on whether or not points were found, if ret == True: I'm pretty much building on this tutorial (which didn't work initially, for the record), but it's a little light on details. I'm not quite sure how I should construct an object point array for asymmetric circles.

As for the square size, I'm just scaling it for now

wweaver gravatar imagewweaver ( 2016-02-24 12:38:30 -0600 )edit

1 answer

Sort by ยป oldest newest most voted

answered 2019-06-17 10:50:44 -0600

SlackChameleon gravatar image

updated 2019-06-18 09:51:45 -0600

I'm posting this as a late answer, for folks coming from Google.

The problem is almost certainly that your object points are incorrect. What you've done is symmetric grid (like a chessboard) which assumes the same number of grid points per row. The asymmetric pattern doesn't. This code is adapted from the C++ source. It's worth plotting your object points to double check that it actually looks like your pattern:

objectPoints= []
grid_size = 0.03 # 3cm, or whatever
rows, cols = 4, 11

for i in range(cols):
    for j in range(rows):
        objectPoints.append( (i*grid_size, (2*j + i%2)*grid_size, 0) )

objectPoints= np.array(objectPoints).astype('float32')

scatter(objectPoints[:,0], objectPoints[:,1])

Note that the rows are staggered in the pattern, that's where the asymmetry comes from. The grid_size is the x-spacing between the circles. The loop plots a 4x11 grid, but shifts alternate columns down by grid_size. Here's a plot of the pattern as generated:

asymmetric pattern

edit flag offensive delete link more

Question Tools

1 follower


Asked: 2016-02-24 08:34:52 -0600

Seen: 5,608 times

Last updated: Jun 18 '19