Opencv-contrib-python Assertion error

System information (version)
  • OpenCV => 4.5.5
  • Python => 3.9
  • Operating System / Platform => Windows 64 Bit
  • Compiler => Visual Studio 2019
Detailed description

When trying to calibrate a wide FOV camera using opencv-contrib-python the omnidir.calibrate() results in Assertion error (-215):
"OpenCV(4.5.5) D:\a\opencv-python\opencv-python\opencv_contrib\modules\ccalib\src\omnidir.cpp:854: error: (-215:Assertion failed) !objectPoints.empty() && objectPoints.type() == CV_64FC3 in function 'cv::omnidir::internal::computeJacobian'"

Additional description:
shape of objectpoints: (8, 1, 150, 3)
size of objectpoints: 3600
type of objectpoints: dtype=np.float64

Steps to reproduce
import cv2
assert cv2.__version__[0] >= '3', 'The fisheye module requires opencv version >= 3.0.0'
import numpy as np
import os
import glob
import matplotlib.pyplot as plt

# Globals
image_path = 'C:/Users/FJOHAN86/source/repos/Camera_calibration/Checkboard/'
#output_path = '../fisheye_images/output/'
image_extension = 'jpg'
image_size = (4032  , 3024)
checkerboard_size = (10,15)
subpixel_criteria = (cv2.TERM_CRITERIA_EPS+cv2.TERM_CRITERIA_MAX_ITER, 300, 0.1)
fisheye_calibration_flags = cv2.fisheye.CALIB_RECOMPUTE_EXTRINSIC+cv2.fisheye.CALIB_CHECK_COND+cv2.fisheye.CALIB_FIX_SKEW
omnidir_calibration_flags = cv2.omnidir.CALIB_USE_GUESS + cv2.omnidir.CALIB_FIX_SKEW + cv2.omnidir.CALIB_FIX_CENTER + cv2.omnidir.CALIB_FIX_XI
draw_chessboard_marked_images = False

def getObjectAndImagePoints(imagePath, imageExtension, checkerboardSize, subpixelCriteria, drawChessboardMarkedImages):
    objp = np.zeros((1, checkerboardSize[0]*checkerboardSize[1], 3), np.float32)
    objp[0,:,:2] = np.mgrid[0:checkerboardSize[0], 0:checkerboardSize[1], ].T.reshape(-1, 2)
    _img_shape = None
    objpoints = [] # 3d point in real world space
    imgpoints = [] # 2d points in image plane.
 
    images = glob.glob(imagePath + '*.' + imageExtension)
    for fname in images:
        img = cv2.imread(fname)
        if _img_shape == None:
            _img_shape = img.shape[:2]
        else:
            assert _img_shape == img.shape[:2], "All images must share the same size."
        gray = cv2.cvtColor(img,cv2.COLOR_BGR2GRAY)
        # Find the chess board corners
        ret, corners = cv2.findChessboardCorners(gray, checkerboardSize, cv2.CALIB_CB_ADAPTIVE_THRESH+cv2.CALIB_CB_FAST_CHECK+cv2.CALIB_CB_NORMALIZE_IMAGE)
        print('Nr of corners ' + str(corners.shape))
 
        # If found, add object points, image points (after refining them)
        if ret == True:
            corners = cv2.cornerSubPix(gray, corners, (11,11), (-1,-1), subpixelCriteria)
            corners = corners.reshape((150,2)) # This is necessary only for omnidirectional calibration
            imgpoints.append(corners)
            objpoints.append(objp)
 
            if drawChessboardMarkedImages:
                gray2 = gray
                cv2.drawChessboardCorners(gray2, checkerboardSize, corners, ret)
                cv2.imwrite(os.path.splitext(fname)[0] + '_' + 'CHESSCORNERS.png', gray2)
    return (objpoints, imgpoints)
 
 
def getOmnidirectionalCalibrationParams(objectpoints, imagepoints, calibration_flag, subpixel_criteria):
    K = np.zeros((3,3))
    D = np.zeros((1,4))
    xi = np.array([])
    idx = np.array([])
    no_images = len(imagepoints)
    no_points = len(imagepoints[0])
    
    #objectpoints = np.reshape(objectpoints, (no_images, 1, no_points, 3))
    objectpoints = np.array(objectpoints,dtype=np.float64).reshape(no_images, 1, no_points, 3)
    #imagepoints = np.reshape(imagepoints, (no_images, 1, no_points, 2))
    imagepoints = np.array(imagepoints,dtype=np.float64).reshape(no_images, 1, no_points, 2)
    print('shape of objectpoints ' + str(objectpoints.shape))
    print('shape of imagepoints ' + str(imagepoints.shape))
    
    print("size of objectpoints " + str(objectpoints.size))
    print("size of imagepoints " + str(imagepoints.size))
    ret, K, xi, D, rvecs, tvecs, idx = cv2.omnidir.calibrate(objectpoints, imagepoints,image_size , K, xi, D, calibration_flag, subpixel_criteria)
    
    return ret, K, xi, D, rvecs, tvecs, idx
 

# Find camera calibration parameters
objectpoints, imagepoints = getObjectAndImagePoints(image_path, image_extension, checkerboard_size, subpixel_criteria, draw_chessboard_marked_images)
         
ret, K, xi, D, rvecs, tvecs, idx = getOmnidirectionalCalibrationParams(objectpoints, imagepoints, omnidir_calibration_flags, subpixel_criteria)
 
print("Found " + str(len(imagepoints)) + " valid images for calibration")
print("K = np.array(" + str(K.tolist()) + ")")
print("D = np.array(" + str(D.tolist()) + ")")
print("xi = np.array(" + str(xi.tolist()) + ")")

Reproduce

input dump:

load inputs:

file = open('inputsDump.txt', 'rb')
objectpoints, imagepoints, image_size, K, xi, D, calibration_flag, subpixel_criteria = pickle.load(file)

ret, K, xi, D, rvecs, tvecs, idx = cv2.omnidir.calibrate(objectpoints, imagepoints,image_size , K, xi, D, calibration_flag, subpixel_criteria)

related: Cv2.omnidir.calibrate() error

It seems to be a bug in opencv-contrib: cv2.omnidir.calibrate - Assertion error(-215) - Python · Issue #3161 · opencv/opencv_contrib · GitHub

Please if someone has a fix/ other solution for calibrating cameras with large FOV~190 degrees, let me know :slight_smile: