[OpenCV] undistortPoints

3,950 views
Skip to first unread message

Michael Barz

unread,
Feb 19, 2014, 8:11:59 AM2/19/14
to pupil-...@googlegroups.com
Hello,

I calibrated my camera and want to undistort a set of points with the gathered intrinsic values (cameraMatrix and distortionCoeffs). After searching the openCV-Doku the best method for that task seems to be undistortPoints().

However, after several tries I could not succeed. I keep getting the following error:
cv2.error: /home/michael/workspace/opencv-2.4.8/modules/imgproc/src/undistort.cpp:282: error: (-215) CV_IS_MAT(_cameraMatrix) && _cameraMatrix->rows == 3 && _cameraMatrix->cols == 3 in function cvUndistortPoints

My initializations of the cameraMatrix (I called it K) and the coefficients are:
K = np.array([[776.65250589, 0, 645.53907335],
                   
[0, 770.65916345, 374.76352079],
                   
[0.0,0.0, 1.0]], dtype = np.float64)

dist_coef
= np.array([6.47285370e-02, -1.55334472e-01, -1.29510733e-03, 1.95433144e-05, 4.63095096e-02], dtype = np.float32)

The line for calling the function is:
cv2.undistortPoints(src, dst, K, dist_coef)
where src is a list with 2D points and dst is None.

Maybe someone sees something I missed.... hopefully.
Any idea?

Thanks!
Michael

Moritz Kassner

unread,
Feb 19, 2014, 4:13:10 PM2/19/14
to pupil-...@googlegroups.com
Hi,

this function did not work for us as well when we had to use it so we wrote our own:


def undistort_point(pt, K, dist_coeffs):
# see link for reference on the equation
u, v = pt
k1,k2,p1,p2, k3 = dist_coeffs


u0 = K[0,2] # cx
v0 = K[1,2] # cy
fx = K[0,0]
fy = K[1,1]

_fx = 1.0/fx
_fy = 1.0/fy
y = (v - v0)*_fy
x = (u - u0)*_fx


r = np.sqrt(x**2 + y**2)
u_undistort = (x * (1+ (k1*r**2) + (k2*r**4) + (k3*r**6))) + 2*p1*x*y + p2*(r**2 + 2*x**2)
v_undistort = (y * (1+ (k1*r**2) + (k2*r**4) + (k3*r**6))) + 2*p2*y*x + p1*(r**2 + 2*y**2)

x_undistort = fx*u_undistort+ u0
y_undistort = fy*v_undistort+ v0

return x_undistort[0], y_undistort[0]


(this may be this most helpful answer I have given so far in this forum :-) )

best,

Moritz




--
You received this message because you are subscribed to the Google Groups "pupil-discuss" group.
To unsubscribe from this group and stop receiving emails from it, send an email to pupil-discus...@googlegroups.com.
To post to this group, send email to pupil-...@googlegroups.com.
To view this discussion on the web visit https://groups.google.com/d/msgid/pupil-discuss/fe32548a-1833-4d01-a34d-8f7b28a65d0f%40googlegroups.com.
For more options, visit https://groups.google.com/groups/opt_out.

Michael Barz

unread,
Feb 20, 2014, 4:47:33 AM2/20/14
to pupil-...@googlegroups.com, moritz...@googlemail.com
Hey,

thank you very much! I didn't really expect ready to use code snippets ;)
I'll definitely try your function.

Meanwhile I was not inactive. I want to share my alternative approach for completeness:

I start with K and dist_coeff as defined above. Then I compute maps for remapping as used with OpenCV remap() on init:
newCameraMatrix, _ = cv2.getOptimalNewCameraMatrix(self.K, self.dist_coef, fieldcam_res, 1, fieldcam_res, 0)
self.map1, self.map2 = cv2.initUndistortRectifyMap(self.K, self.dist_coef, np.identity(3), newCameraMatrix, fieldcam_res, cv2.CV_16SC2)

I further use map1 to gather an undistorted point:
point = point.reshape(2)
res
.append(self.map1[point[1]][point[0]])

It is not really defined what these maps are for, regarding that remap is used for mono and stereo cameras and theres only little documentation. But finally I found out, that initUndistortRectifyMap returns map1 which contains the undistorted pixel position for each original pixel position. What map2 is good for I didn't find out till now...
X and Y are swapped due to the row major numpy array.

Hope this helps outhers, cause I spent at least one day to find out. And now they can find two solutions on one page ;)

Kind regards,
Michael

Michael Barz

unread,
Feb 20, 2014, 5:05:11 AM2/20/14
to pupil-...@googlegroups.com, moritz...@googlemail.com
As an addition, a comparison for points on a rectangle:

Original rect:
[[[  950.83978271   290.43954468]]
 
[[  950.43261719   345.45806885]]
 
[[ 1007.75939941   344.32891846]]
 
[[ 1008.68023682   288.5925293 ]]]

My approach (using map1):
[[ 965  286]
 
[ 965  344]
 
[1025  343]
 
[1026  284]]

And Moritz' approach:
[[  952.97440459   289.68448081]
 
[  952.44679391   345.10943655]
 
[ 1010.41879156   343.88709266]
 
[ 1011.4226513    287.71192094]]

Kind regards,
Michael

Moritz Kassner

unread,
Feb 20, 2014, 5:15:55 AM2/20/14
to Michael Barz, pupil-...@googlegroups.com
Wait so my snippet is not performing correctly? The difference does not come from rounding to ints.

any thoughts?

m




Michael Barz

unread,
Feb 20, 2014, 6:01:56 AM2/20/14
to pupil-...@googlegroups.com, Michael Barz, moritz...@googlemail.com
Hi,

I'm not sure, but I think I read somewhere, that undistortPoints undistorts points, but does no rectification. And am I right, that your function reimplements undistort points?
The other method however does. This could be the difference.

Or it could be caused by the newCameraMatrix, which I compute and which differs a bit from the original camera matrix.

But independent from that, I think I'll use my approach, since I have to do an array look up per point only. With your approach I'll have to compute several things with python which is a bit slower....

Another thing to be mentioned: You can also compute the maps as float maps, when replacing the CV_16SC2 with a corresponding float type.

Kind regards,
Michael

Michael Barz

unread,
Feb 20, 2014, 6:42:22 AM2/20/14
to pupil-...@googlegroups.com, Michael Barz, moritz...@googlemail.com
I just conducted the following test:
First I made a copy of the frame and remapped it with map1 and map2 as defined above.
Then I computed my stuff (detect rects) with the original image and undistorted the results with your an my method.
Finally I drew first the undistorted image, then the rects on it.
I assumed that the rectangles I undistorted would match the ones in the new image. But the undistorted rectangles grew in the opposite direction as the image. (for both approaches)
The remapping of the frame yielded an image which has a similar shape than the following one I found on the web: http://i.stack.imgur.com/UU6t0.png

Now I'm unsure, if my mapping is correct. There are two cases I can imagine:
  • The mapping I do, corresponds to the remapped image, if I'd resize it, such that the black borders disappear, or
  • The mapping must be done the other way round. In this case, map1 would not give me the pixel position of the undistorted image, but rather the pixel coordinates of the distorted image, which have to be copied to the new undistorted image.

Seems that I didn't found a solution yet... any ideas?


Kind regards,

Michael

Michael Barz

unread,
Feb 20, 2014, 7:25:20 AM2/20/14
to pupil-...@googlegroups.com, Michael Barz, moritz...@googlemail.com
Hmm... seems if I was right with the error for my approach:

The function actually builds the maps for the inverse mapping algorithm that is used by remap() . That is, for each pixel (u, v) in the destination (corrected and rectified) image, the function computes the corresponding coordinates in the source image (that is, in the original image from camera).


Reply all
Reply to author
Forward
0 new messages