Skip to content

Undistort image without cropping #360

@LeviMays

Description

@LeviMays

I'm using cv2.undistort, but it crops the image. I'd like to have all the undistorted image, so that the undistorted size is bigger than the original one, like this:
image

See this post on stackoverflow, particularly the responses for Josep Bosch and andremkeller:
https://stackoverflow.com/questions/18742679/how-to-get-all-undistorted-image-with-opencv

I have tried to emulate the code andrewmkeller posted, using Python instead of C++, with some minor changes based on Josh Bosch's response. The result is the following:

  #!/usr/bin/env` python

  import cv2
  import numpy as np

  def loadUndistortedImage(fileName):
      # load image
      image = cv2.imread(fileName)
      #print(image)

      # set distortion coeff and intrinsic camera matrix (focal length, centerpoint offset, x-y skew)
      cameraMatrix = np.array([[894.96803896,0,470.38713516],[0,901.32629374,922.41232898], [0,0,1]])
      distCoeffs = np.array([[-0.340671222,0.110426603,-.000867987573,0.000189669273,-0.0160049526]])

      # setup enlargement and offset for new image
      y_shift = 60    #experiment with
      x_shift = 70    #experiment with    
      imageShape = image.shape  #image.size
      print(imageShape)
      imageSize = (int(imageShape[0])+2*y_shift, int(imageShape[1])+2*x_shift, 3)
      print(imageSize)
    
      # create a new camera matrix with the principal point offest according to the offset above
      newCameraMatrix, validPixROI = cv2.getOptimalNewCameraMatrix(cameraMatrix, distCoeffs, imageSize,
        1)
      #newCameraMatrix = cv2.getDefaultNewCameraMatrix(cameraMatrix, imageSize, True) # imageSize, True

      # create undistortion maps
      R = np.array([[1,0,0],[0,1,0],[0,0,1]])
      map1, map2 = cv2.initUndistortRectifyMap(cameraMatrix, distCoeffs, R, newCameraMatrix, imageSize,
        cv2.CV_16SC2)

      # remap
      outputImage = cv2.remap(image, map1, map2, INTER_LINEAR)
      #save output image as file with "FIX" appened to name - only works with .jpg files at the moment
      index = filename.find('.jpg')
      fixed_filename = filename[:index] +'_undistorted'+fileName[index:]
      cv2.imwrite(fixed_filename, outputImage)
      cv2.imshow('fix_img',outputImage)
      cv2.waitKey(0)
      return
    
  #Undistort the images, then save the restored images
  `loadUndistortedImage('./calib/WIN_20200626_11_29_16_Pro.jpg')

This seemed good to me, but then problems came up when trying to use cv2.getOptimalNewCameraMatrix or cv2.getDefaultNewCameraMatrix and cv2.initUndistortRectifyMap. I kept getting told that 'the argument takes exactly 2 arguments (3 given)' even though I am putting the parameters as specified in their documentation here: https://docs.opencv.org/2.4/modules/calib3d/doc/camera_calibration_and_3d_reconstruction.html https://docs.opencv.org/2.4/modules/imgproc/doc/geometric_transformations.html

I can remove the error from "...getDefault..." if I remove the optional params, but I'd rather not do that.

Stacktrace:

Traceback (most recent call last):
  File ".\main.py", line 46, in <module>
    loadUndistortedImage('./<image file name>.jpg')
  File ".\main.py", line 27, in loadUndistortedImage
    newCameraMatrix, validPixROI = cv2.getOptimalNewCameraMatrix(cameraMatrix, distCoeffs, imageSize, 1)
TypeError: function takes exactly 2 arguments (3 given)

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions