4

I tried a camera calibration with python and opencv to find the camera matrix. I used the following code from this link

https://automaticaddison.com/how-to-perform-camera-calibration-using-opencv/

import cv2 # Import the OpenCV library to enable computer vision
import numpy as np # Import the NumPy scientific computing library
import glob # Used to get retrieve files that have a specified pattern
 
# Path to the image that you want to undistort
distorted_img_filename = r'C:\Users\uid20832\3.jpg'
 
# Chessboard dimensions
number_of_squares_X = 10 # Number of chessboard squares along the x-axis
number_of_squares_Y = 7  # Number of chessboard squares along the y-axis
nX = number_of_squares_X - 1 # Number of interior corners along x-axis
nY = number_of_squares_Y - 1 # Number of interior corners along y-axis
 
# Store vectors of 3D points for all chessboard images (world coordinate frame)
object_points = []
 
# Store vectors of 2D points for all chessboard images (camera coordinate frame)
image_points = []
 
# Set termination criteria. We stop either when an accuracy is reached or when
# we have finished a certain number of iterations.
criteria = (cv2.TERM_CRITERIA_EPS + cv2.TERM_CRITERIA_MAX_ITER, 30, 0.001)
 
# Define real world coordinates for points in the 3D coordinate frame
# Object points are (0,0,0), (1,0,0), (2,0,0) ...., (5,8,0)
object_points_3D = np.zeros((nX * nY, 3), np.float32)       
 
# These are the x and y coordinates                                              
object_points_3D[:,:2] = np.mgrid[0:nY, 0:nX].T.reshape(-1, 2) 
 
def main():
     
  # Get the file path for images in the current directory
  images = glob.glob(r'C:\Users\Kalibrierung\*.jpg')
     
  # Go through each chessboard image, one by one
  for image_file in images:
  
    # Load the image
    image = cv2.imread(image_file)  
 
    # Convert the image to grayscale
    gray = cv2.cvtColor(image, cv2.COLOR_BGR2GRAY)  
 
    # Find the corners on the chessboard
    success, corners = cv2.findChessboardCorners(gray, (nY, nX), None)
     
    # If the corners are found by the algorithm, draw them
    if success == True:
 
      # Append object points
      object_points.append(object_points_3D)
 
      # Find more exact corner pixels       
      corners_2 = cv2.cornerSubPix(gray, corners, (11,11), (-1,-1), criteria)       
       
            # Append image points
      image_points.append(corners)
 
      # Draw the corners
      cv2.drawChessboardCorners(image, (nY, nX), corners_2, success)
 
      # Display the image. Used for testing.
      #cv2.imshow("Image", image) 
     
      # Display the window for a short period. Used for testing.
      #cv2.waitKey(200) 
                                                                                                                     
  # Now take a distorted image and undistort it 
  distorted_image = cv2.imread(distorted_img_filename)
 
  # Perform camera calibration to return the camera matrix, distortion coefficients, rotation and translation vectors etc 
  ret, mtx, dist, rvecs, tvecs = cv2.calibrateCamera(object_points, 
                                                    image_points, 
                                                    gray.shape[::-1], 
                                                    None, 
                                                    None)

But I think I always get wrong parameters. My focal length is around 1750 in x and y direction from calibration. I think this couldnt be rigth, it is pretty much. The camera documentation says the focal lentgh is between 4-7 mm. But I am not sure, why it is so high from the calibration. Here are some of my photos for the calibration. Maybe something is wrong with them. I moved the chessboard under the camera in different directions, angles and high.

I was also wondering, why I dont need the size of the squares in the code. Can someone explains it to me or did I forgot this input somewhere?

enter image description here enter image description here enter image description here

Christoph Rackwitz
  • 11,317
  • 4
  • 27
  • 36
lkrss
  • 57
  • 1
  • 9

1 Answers1

12

Your misconception is about "focal length". It's an overloaded term.

  • "focal length" (unit mm) in the optical part: it describes the distance between the lens plane and image/sensor plane, assuming a focus to infinity
  • "focal length" (unit pixels) in the camera matrix: it describes a scale factor for mapping the real world to a picture of a certain resolution

1750 may very well be correct, if you have a high resolution picture (Full HD or something).

The calculation goes:

f [pixels] = (focal length [mm]) / (pixel pitch [µm / pixel])

(take care of the units and prefixes, 1 mm = 1000 µm)

Example: a Pixel 4a phone, which has 1.40 µm pixel pitch and 4.38 mm focal length, has f = ~3128.57 (= fx = fy).

Another example: A Pixel 4a has a diagonal Field of View of approximately 77.7 degrees, and a resolution of 4032 x 3024 pixels, so that's 5040 pixels diagonally. You can calculate:

f = (5040 / 2) / tan(~77.7° / 2)

f = ~3128.6 [pixels]

And that calculation you can apply to arbitrary cameras for which you know the field of view and picture size. Use horizontal FoV and horizontal resolution if the diagonal resolution is ambiguous. That can happen if the sensor isn't 16:9 but the video you take from it is cropped to 16:9... assuming the crop only crops vertically, and leaves the horizontal alone.


Why don't you need the size of the chessboard squares in this code? Because it only calibrates the intrinsic parameters (camera matrix and distortion coefficients). Those don't depend on the distance to the board or any other object in the scene.

If you were to calibrate extrinsic parameters, i.e. the distance of cameras in a stereo setup, then you would need to give the size of the squares.

Christoph Rackwitz
  • 11,317
  • 4
  • 27
  • 36
  • Thanks a lot. Your explanation helps me to know the difference between focal length in mm and pixels. My idea was to calculate the object size with the cameramatrix with px[cm]= z/fx (u - cx) and py[cm]= z/fy (v - cy). Z is the distance to my object measured by a sensor. So there I use the focal length in pixel, right? – lkrss Sep 13 '21 at 12:39
  • looks correct but I'm guessing because you don't explain the variables. take the size x_p [pixels], and the distance to the object z [meters], and calculate: x [m] = x_p [pixels] / fx [pixels] * z [m] – Christoph Rackwitz Sep 13 '21 at 14:37
  • Sorry, I forgot to explain the other variables. fx/fy is the focal length. U/V is the picture coordinates in pixel. And cx/cy is the camera main point from the calibration matrix. Can you explain what you mean with x_p? Is it my point in pixel? I think c_x/c_y is to convert from picture-koordinates to camera-koordinates?! But this is unneccessary to get the object size, right? – lkrss Sep 14 '21 at 10:18
  • 1
    you'd measure a length as a *difference* in pixels. absolute pixel coordinates don't matter in this situation. you could work with them, but then you have "absolute" positions in pixels or in meters, and anything you'd want to know the size of, you'd calculate a difference of those absolute positions, to get a length... play with the numbers. do a 2D sketch on graph paper and explore the math. – Christoph Rackwitz Sep 14 '21 at 14:16