Source code for xrprimer.calibration.sview_fisheye_calibrator

import logging
from typing import List, Union

import cv2
import numpy as np

from xrprimer.data_structure.camera import FisheyeCameraParameter
from .base_calibrator import BaseCalibrator


[docs]class SviewFisheyeDistortionCalibrator(BaseCalibrator): """Single-view distortion calibrator for distorted fisheye camera. It takes an init intrinsic, fix it and calibrate distortion coefficients. """ def __init__(self, chessboard_width: int, chessboard_height: int, logger: Union[None, str, logging.Logger] = None) -> None: """Initialization for SviewFisheyeDistortionCalibrator class. Args: chessboard_width (int): How many internal corners along the horizontal edge of the chessboard. chessboard_height (int): How many internal corners along the vertical edge of the chessboard. logger (Union[None, str, logging.Logger], optional): Logger for logging. If None, root logger will be selected. Defaults to None. """ BaseCalibrator.__init__(self, logger=logger) self.chessboard_width = chessboard_width self.chessboard_height = chessboard_height
[docs] def calibrate( self, frames: List[str], fisheye_param: FisheyeCameraParameter, ) -> FisheyeCameraParameter: """Calibrate FisheyeCameraParameter with a chessboard. It takes intrinsics from fisheye_param, calibrates only distortion coefficients on undistorted frames. Args: frames (List[str]): A list of distorted image paths. fisheye_param (FisheyeCameraParameter): An instance of FisheyeCameraParameter. Intrinsic matrix is necessary for calibration, and the input instance will not be modified. Returns: FisheyeCameraParameter: An instance of FisheyeCameraParameter. Distortion coefficients are the only difference from input. """ if len(frames) <= 0: self.logger.error('Frames are necessary for fisheye distortion' + ' calibration.') raise ValueError # termination criteria criteria = (cv2.TERM_CRITERIA_EPS + cv2.TERM_CRITERIA_MAX_ITER, 30, 0.001) # prepare object points in (x, y, 0), # like (0,0,0), (1,0,0), (2,0,0), ... sframe_obj_points = np.zeros( (self.chessboard_width * self.chessboard_height, 3), np.float32) sframe_obj_points[:, :2] = np.mgrid[ 0:self.chessboard_width, 0:self.chessboard_height].T.reshape(-1, 2) mframe_obj_points = [] # 3d point in real world space mframe_img_points = [] # 2d points in image plane. for _, frame_path in enumerate(frames): img = cv2.imread(frame_path) if len(img.shape) == 3 and img.shape[-1] == 3: img = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY) height, width = img.shape # Find the chess board corners pattern_found, corners = cv2.findChessboardCorners( img, (self.chessboard_width, self.chessboard_height), None) # If found, add object points, image points (after refining them) if pattern_found: mframe_obj_points.append(sframe_obj_points.copy()) better_conners = cv2.cornerSubPix(img, corners, (11, 11), (-1, -1), criteria) mframe_img_points.append(better_conners) # use preset-intrinsic and fix fx, fy, cx, cy calib_flags = cv2.CALIB_USE_INTRINSIC_GUESS + \ cv2.CALIB_FIX_PRINCIPAL_POINT + \ cv2.CALIB_FIX_FOCAL_LENGTH _, _, dist_coeff, _, _ = cv2.calibrateCamera( objectPoints=mframe_obj_points, imagePoints=mframe_img_points, imageSize=(width, height), cameraMatrix=np.asarray(fisheye_param.get_intrinsic(3)), distCoeffs=None, flags=calib_flags) ret_fisheye_param = fisheye_param.clone() dist_coeff = dist_coeff.tolist()[0] ret_fisheye_param.set_dist_coeff( dist_coeff_k=dist_coeff[:2] + dist_coeff[-1:], dist_coeff_p=dist_coeff[2:4]) return ret_fisheye_param