Невозможно отменить искажение точек с помощью метода OpenCv undistortPoints - PullRequest
0 голосов
/ 29 августа 2018

Я пытаюсь не искажать определенные точки изображения, используя метод «неискаженных точек» OpenCV, но безуспешно. Here an example where I undistort all the whole picture

Это будут мои коэффициенты неискаженности

  optic_camera_matrix: [[710.52285,  0.0,      882.14702],
                        [0.0,        713.9636, 638.8421],
                        [0.0,        0.0,      1.0]],

  distorsion_coeffs: [[-0.4176419401669212,
                                 0.15978235598732332,
                                 -8.299875092923166e-05,
                                 -0.001784191694247801,
                                 -0.027396621999692457]],

Несмотря на то, что я могу не искажать все изображение, чтобы оптимизировать время обработки камеры, если я не искажу только угловые точки (красные точки изображения):

distorted_border_points = np.array([[[584,1415],
                                        [576,457],
                                        [1956,415],
                                        [1996,1422],
                                        [1261,242],
                                        [1281,1594]]],np.float32)

undistorted_points =  cv2.undistortPoints(distorted_border_points, optic_camera_matrix, distorsion_coeffs)

Я получаю это взамен:

[[[ -6.40190065e-01   1.66883194e+00]
  [ -4.87006754e-01  -2.88225353e-01]
  [ -1.82562262e-01   3.74070629e-02]
  [ -5.28450182e-04  -3.51850584e-04]
  [  8.09574544e-01  -8.40054870e-01]
  [ -5.28259724e-02  -1.22379906e-01]]]

При построении они не выровнены по прямоугольнику, как на первом изображении.

Я полагаю, что коэффициенты неискаженности хорошо рассчитаны (так как неискаженность работает на первом изображении), но здесь я прилагаю код камеры

import glob
import cv2
import numpy as np
import os
import json
import numpy as np

directory = os.path.dirname(__file__)


def get_optic_calibration_parameters(device,config_folder=None):
    if config_folder is None:
        optic_calibration_path = directory + '/../config/' + \
            device + '/optic_calibration.json'
    else:
        optic_calibration_path = config_folder + device + '/optic_calibration.json'

    if not os.path.exists(optic_calibration_path):
        os.makedirs(optic_calibration_path[:-22])

    with open(optic_calibration_path) as optic_calibration_file:
        optic_calibration = json.load(optic_calibration_file)

    optic_camera_matrix = optic_calibration['optic_camera_matrix']
    distorsion_coeffs = optic_calibration['distorsion_coeffs']
    optic_resolution = optic_calibration['optic_resolution']

    return optic_camera_matrix, distorsion_coeffs, optic_resolution


def _save_calibration_parameters(camera_matrix, distorsion_coeffs, optic_resolution, device, config_folder=None):

    if config_folder is None:
        optic_calibration_path = directory + '/../config/' + \
            device + '/optic_calibration.json'
    else:
        optic_calibration_path = config_folder + device + '/optic_calibration.json'

    if not os.path.exists(optic_calibration_path):
        os.makedirs(optic_calibration_path[:-22])

    optic_calibration_parameters = {'optic_camera_matrix': camera_matrix.tolist(),
                                    'distorsion_coeffs': distorsion_coeffs.tolist(),
                                    'optic_resolution': optic_resolution}

    with open(optic_calibration_path, 'wb') as optic_calibration_file:
        json.dump(optic_calibration_parameters, optic_calibration_file)

    return


def _get_image_points(plot=False, dim=(4, 5), input_dir='calibration_samples',extension='jp'):
    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((dim[0] * dim[1], 3), np.float32)
    objp[:, :2] = np.mgrid[0:dim[1], 0:dim[0]].T.reshape(-1, 2)

    # 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(input_dir + '*.'+extension+'*')
    for fname in images:
        img = cv2.imread(fname)
        gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)

        # Find the chess board corners
        ret, corners = cv2.findChessboardCorners(gray, (dim[1], dim[0]), None)

        # If found, add object points, image points (after refining them)
        if ret == True:
            objpoints.append(objp)

            corners2 = cv2.cornerSubPix(
                gray, corners, (11, 11), (-1, -1), criteria)
            imgpoints.append(corners2)

            # Draw and display the corners
            if plot:
                img = cv2.drawChessboardCorners(
                    img, (dim[1], dim[0]), corners2, ret)
                cv2.imshow('img', img)
                cv2.waitKey(500)

    resolution = (img.shape[1], img.shape[0])

    return imgpoints, objpoints, resolution


def calibrate_camera(optic_resolution, imgpoints, objpoints, device, config_folder=None):

    _, camera_matrix, distorsion_coeffs, _, _ = cv2.calibrateCamera(
        objpoints, imgpoints, optic_resolution, None, None)

    _save_calibration_parameters(
        camera_matrix, distorsion_coeffs, optic_resolution, device, config_folder=config_folder)

    return

Для выполнения функции загружены разные изображения:

imgpoints, objpoints, optic_resolution = _get_image_points(plot=False, dim=(4,5), input_dir=calibration_samples)
_show_N_chessborders(N=3, dim=(4,5), input_dir=calibration_samples)
calibrate_camera(optic_resolution, imgpoints, objpoints,device, config_folder=config_folder)

И вот как я сохраняю файлы конфигурации json

Буду признателен, если кто-нибудь сможет помочь мне с решением. Спасибо!

1 Ответ

0 голосов
/ 29 августа 2018

Если я правильно понимаю, функция getOptimalNewCameraMatrix предназначена только для случаев, когда вы не хотите черных сторон при искажении всего изображения (см. этот вопрос), а не для случаев, когда вы не искажаете отдельные очки. Кроме того, кажется, что P и R в undistortPoints предназначены только для стереозрения.

Я бы упростил это и просто сказал:

undistorted_points =  cv2.undistortPoints(np.array(points), optical_camera_matrix, d) 

где optical_camera_matrix - матрица непосредственно из функции calibrateCamera. Просто убедитесь, что points является массивом 1xN or Nx1 2-channel.

UPDATE:

Я понял, в чем проблема. Секрет в предложении на этом сайте .

Также функция выполняет обратное преобразование в projectPoints ()

Насколько я понимаю (поправьте меня, если я ошибаюсь), неискаженные точки нормализуются. Чтобы вернуть их обратно в пиксельные единицы, просто сделайте следующее (в псевдокоде):

for each point in undistorted_points:
    point = point * focal_length + boresight

Надеюсь, это поможет!

...