Ask Your Question

Revision history [back]

click to hide/show revision 1
initial version

camera calibration focal length is wrong

So I'm sure this is my error, just not sure what I'm doing wrong. I had started a post about how my Aruco markers Z distance was off by a factor of 2... But then I realized that must point to my focal length in my camera matrix being wrong and here I am. I got the focal length from the datasheet and then calculated it from fx,fy and the pixel size. I was off by more than 2x.

I guess my cal approach is wrong. I wrote some python code to run cameraCalibrate, and I took 25 pictures of this chess board that I printed out. But one thing I didn't do was keep the distance from the chessboard to the camera constant in all those pictures. Could that have screwed me up?

Another thing I did was just printed out the chessboard pattern in the openCV examples. It didn't exactly fit the paper so I let it scale a little bit... Maybe that's wrong too.

This is my calibration code in python. It runs, finds the chess board, and draws all the markers on it. But... my focal length is still coming out wrong. I'm thinking the way I made my chessboard, and took pictures is wrong.

import numpy as np
from matplotlib import pyplot as plt
import cv2
import glob
import os
import sys
import math



CHESSBOARD_SIZE = (7, 7)
CHESSBOARD_OPTIONS = (cv2.CALIB_CB_ADAPTIVE_THRESH |
        cv2.CALIB_CB_NORMALIZE_IMAGE | cv2.CALIB_CB_FAST_CHECK)

OBJECT_POINT_ZERO = np.zeros((7*7,3), np.float32)
OBJECT_POINT_ZERO[:, :2] = np.mgrid[0:7,0:7].T.reshape(-1,2)

OPTIMIZE_ALPHA = 0.25

TERMINATION_CRITERIA = (cv2.TERM_CRITERIA_EPS | cv2.TERM_CRITERIA_MAX_ITER, 30,
        0.001)


REMAP_INTERPOLATION = cv2.INTER_LINEAR
DEPTH_VISUALIZATION_SCALE = 640

# 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)
objp = np.zeros((7*7,3), np.float32)
objp[:,:2] = np.mgrid[0:7,0:7].T.reshape(-1,2)

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


leftImageDir = 'show'
outputFile = 'output'

def readImagesAndFindChessboards(imageDirectory):
    print("Reading images at {0}".format(imageDirectory))
    imagePaths = glob.glob("{0}/*.jpg".format(imageDirectory))

    filenames = []
    objectPoints = []
    imagePoints = []
    imageSize = None

    for imagePath in sorted(imagePaths):
        image = cv2.imread(imagePath)
        grayImage = cv2.cvtColor(image, cv2.COLOR_BGR2GRAY)

        newSize = grayImage.shape[::-1]
        if imageSize != None and newSize != imageSize:
            raise ValueError(
                    "Calibration image at {0} is not the same size as the others"
                    .format(imagePath))
        imageSize = newSize

        hasCorners, corners = cv2.findChessboardCorners(grayImage,
                CHESSBOARD_SIZE, cv2.CALIB_CB_FAST_CHECK)

        if hasCorners:
            print("HAS corners")
            filenames.append(os.path.basename(imagePath))
            objectPoints.append(OBJECT_POINT_ZERO)
            cv2.cornerSubPix(grayImage, corners, (11, 11), (-1, -1),
                    TERMINATION_CRITERIA)
            imagePoints.append(corners)

        cv2.drawChessboardCorners(image, CHESSBOARD_SIZE, corners, hasCorners)
        cv2.imshow(imageDirectory, image)

        # Needed to draw the window
        cv2.waitKey(1)

    cv2.destroyWindow(imageDirectory)

    print("Found corners in {0} out of {1} images"
            .format(len(imagePoints), len(imagePaths)))

    return filenames, objectPoints, imagePoints, imageSize

(leftFilenames, leftObjectPoints, leftImagePoints, leftSize
        ) = readImagesAndFindChessboards(leftImageDir)

imageSize = leftSize

filenames = list(set(leftFilenames ))


filenames = sorted(filenames)


def getMatchingObjectAndImagePoints(requestedFilenames,
        allFilenames, objectPoints, imagePoints):

    requestedFilenameSet = set(requestedFilenames)
    requestedObjectPoints = []
    requestedImagePoints = []


    for index, filename in enumerate(allFilenames):
        if filename in requestedFilenameSet:
            requestedObjectPoints.append(objectPoints[index])
            requestedImagePoints.append(imagePoints[index])

    return requestedObjectPoints, requestedImagePoints

leftObjectPoints, leftImagePoints = getMatchingObjectAndImagePoints(filenames,
        leftFilenames, leftObjectPoints, leftImagePoints)
#rightObjectPoints, rightImagePoints = getMatchingObjectAndImagePoints(filenames,
#        rightFilenames, rightObjectPoints, rightImagePoints)

objectPoints = leftObjectPoints



print("Calibrating left camera...")

_, leftCameraMatrix, leftDistortionCoefficients, _, _ = cv2.calibrateCamera(
        objectPoints, leftImagePoints, imageSize, None, None)

print("Camera Matrix")
print(leftCameraMatrix)

print("Camera Distortion Coefficients")
print(leftDistortionCoefficients)

#notice how its almost exactly the same, imagine cv2 is the namespace for cv
#in C++, only difference is FILE_STORGE_WRITE is exposed directly in cv2
cv_file = cv2.FileStorage("rgb.yaml", cv2.FILE_STORAGE_WRITE)

cv_file.write("camMatrix", leftCameraMatrix)
cv_file.write("distortionCoefficients", leftDistortionCoefficients)

# note you *release* you don't close() a FileStorage object
cv_file.release()



cv2.waitKey(1)


cv2.destroyAllWindows()