14

I'm having trouble formatting the x,y list of points to pass to undistortPoints (opencv 2.4.1).

The error message is c++ specific and complains about the array of points not being of type CV_32FC2. Shouldn't I be able to pass in an Nx2 numpy array?

import cv2

camera_matrix = array(mat('1.3e+03, 0., 6.0e+02; 0., 1.3e+03, 4.8e+02; 0., 0., 1.'), dtype=float32)
dist_coeffs = array(mat('-2.4-01, 9.5e-02, -4.0e-04, 8.9e-05, 0.'), dtype=float32)

test = zeros((10,2), dtype=float32)

print test.shape, type(test)

xy_undistorted = cv2.undistortPoints(test, camera_matrix, dist_coeffs)

results in:

opencv/modules/imgproc/src/undistort.cpp:279: error: (-215) CV_IS_MAT(_src) && CV_IS_MAT(_dst) && (_src->rows == 1 || _src->cols == 1) && (_dst->rows == 1 || _dst->cols == 1) && _src->cols + _src->rows - 1 == _dst->rows + _dst->cols - 1 && (CV_MAT_TYPE(_src->type) == CV_32FC2 || CV_MAT_TYPE(_src->type) == CV_64FC2) && (CV_MAT_TYPE(_dst->type) == CV_32FC2 || CV_MAT_TYPE(_dst->type) == CV_64FC2) in function cvUndistortPoints

In samples/python2/video.py there is usage of projectPoints which takes an array and reshapes it (-1,3) resulting in an Nx3 array for that function, it seems like the same format should work here.

Lucas Walter
  • 942
  • 3
  • 10
  • 23

2 Answers2

13

I don't know much about camera calibration. But seeing your code and the error, I changed it as follows:

import cv2
import numpy as np
camera_matrix = np.array([[1.3e+03, 0., 6.0e+02], [0., 1.3e+03, 4.8e+02], [0., 0., 1.]], dtype=np.float32)
dist_coeffs = np.array([-2.4-01, 9.5e-02, -4.0e-04, 8.9e-05, 0.], dtype=np.float32)

test = np.zeros((10,1,2), dtype=np.float32)
xy_undistorted = cv2.undistortPoints(test, camera_matrix, dist_coeffs)

print xy_undistorted

Below is the result I got, Check if it is correct:

[[[ 0.0187303   0.01477836]]

 [[ 0.0187303   0.01477836]]

 [[ 0.0187303   0.01477836]]

 [[ 0.0187303   0.01477836]]

 [[ 0.0187303   0.01477836]]

 [[ 0.0187303   0.01477836]]

 [[ 0.0187303   0.01477836]]

 [[ 0.0187303   0.01477836]]

 [[ 0.0187303   0.01477836]]

 [[ 0.0187303   0.01477836]]]

What is the problem :

The error says, source should be having EITHER one row OR one column. And it should be of CV_32FC2 or CV_64FC2, means two channels and floating point. So make your src of shape (10,1,2) or (1,10,2). Both methods work and give same result ( I checked it myself ) . Only problem is, I don't know if it is correct, so check it yourself.

Abid Rahman K
  • 51,886
  • 31
  • 146
  • 157
  • My output (with real data instead of zeros) looks reasonable with a reshape(-1,1,2)- thanks for the insight that a third numpy array dimension are treated as channels. I'm not sure if that is obvious or documented anywhere, and it seems inconsistent with the projectPoints example. – Lucas Walter Jun 13 '12 at 18:36
2

I have tested Abid Rahman's method and it works well, but there are some issues to note.

calib = np.reshape(calib, [3, 3])
dist = np.array(kp_mat, dtype=np.float32)
newcameramtx, _ = cv2.getOptimalNewCameraMatrix(calib, dist, (w, h), 1, (w, h))
# undistort
dst = cv2.undistortPoints(pt, calib, dist, None, newcameramtx)
dst = np.squeeze(dst)

Note

  1. points should be shape [1,N,2] or [N,1,2], with coordinate [x,y]
  2. new camera matrix should be specified. Or the output will be normalized coordinate.
JeffQ
  • 94
  • 5