无法使用OpenCv undistortPoints方法取消扭曲点

时间:2018-08-29 11:02:27

标签: python c opencv computer-vision camera-calibration

我试图使用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配置文件的方式

如果能帮助我解决问题,我将不胜感激。谢谢!

2 个答案:

答案 0 :(得分:0)

如果我的理解正确,getOptimalNewCameraMatrix功能仅用于当您不希望使整个图像失真的同时出现黑边时(请参阅this问题),而不适用于您不失真的情况个别点。此外,P中的RundistortPoints仅用于立体视觉事物。

我会简化一下,只是说:

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

其中optical_camera_matrix是直接来自calibrateCamera函数的矩阵。只需确保points是一个1xN or Nx1 2-channel数组即可。

更新:

我意识到了问题所在。秘密就是这个website上的句子。

  

该函数还执行对projectPoints()的反向转换

据我了解(如果我错了,请纠正我)未失真的点已归一化。为了以像素为单位放回它们,只需执行以下操作(以伪代码):

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

我希望这会有所帮助!

答案 1 :(得分:0)

对于输出空间是归一化的情况,可以设置P=optic_camera_matrix。文档中写到“如果矩阵P是恒等或省略,dst将包含归一化点坐标”: http://amroamroamro.github.io/mexopencv/matlab/cv.undistortPoints.html