# cv2.fisheye.undistortPoints with fisheye camera is not working

**URL:** <https://forum.opencv.org/t/cv2-fisheye-undistortpoints-with-fisheye-camera-is-not-working/24344>\
**Category:** Python\
**Tags:** calib3d, fisheye\
**Created:** [January 31, 2026, 9:32pm UTC](https://forum.opencv.org/t/cv2-fisheye-undistortpoints-with-fisheye-camera-is-not-working/24344 "2026-01-31T21:32:53Z")\
**Posts on this page:** 4\
**Page:** 1

<div class="post-metadata">

**Author:** ![NMO](https://sea2.discourse-cdn.com/flex020/user_avatar/forum.opencv.org/nmo/32/4493_2.png) [@NMO](https://forum.opencv.org/u/NMO)\
**Post date:** [January 31, 2026, 9:32pm UTC](https://forum.opencv.org/t/cv2-fisheye-undistortpoints-with-fisheye-camera-is-not-working/24344/1 "2026-01-31T21:32:53Z")

</div>

I want to to estimate the motion of a monocular camera with a fisheye lens. The camera is a Raspberry Pi cam with 222° fisheye lens. The image resolution is 640x480.

I calibrated it using `cv2.fisheye.calibrate()`. I undistorted some images using  
`cv2.fisheye.undistortImage(image, K, D, Knew=K)`. The undistorted images look good.

I use this code to estimate R and t:

```python
def lift_pixels_to_normalized(calib: datatypes.FisheyeCalib, pts_px: np.ndarray) → np.ndarray:
    """
    pts_px: Nx2 float32/float64 pixel coordinates.
    Returns Nx2 normalized coordinates on z=1 plane (i.e., rays ~ [x,y,1]).
    This does NOT undistort the image, only the point measurements.
    """
    pts = pts_px.reshape(-1, 1, 2).astype(np.float64)
    # P is identity => output in normalized camera coordinates (no K re-application).
    pts_norm = cv2.fisheye.undistortPoints(pts, calib.K, calib.D, P=np.eye(3))
    return pts_norm.reshape(-1, 2)

def estimate_motion_from_fisheye(calib: datatypes.FisheyeCalib, pts0_px: np.ndarray, pts1_px: np.ndarray):
    """
    Returns (R, t, inlier_mask) where R is 3x3, t is 3x1 (unknown scale), mask is Nx1 uint8.
    Uses normalized coordinates from fisheye undistortPoints.
    """
    pts0_n = lift_pixels_to_normalized(calib, pts0_px)
    pts1_n = lift_pixels_to_normalized(calib, pts1_px)

    # findEssentialMat expects points as Nx2; if focal=1, pp=(0,0), points must be normalized.
    # threshold is in normalized units (roughly "radians-ish" small angle). Tune if needed.
    E, mask = cv2.findEssentialMat(
        pts0_n, pts1_n,
        focal=1.0, pp=(0.0, 0.0),
        method=cv2.RANSAC,
        prob=0.999,
        threshold=1e-3
    )
    if E is None or mask is None:
        return None, None, None

    # recoverPose also accepts normalized points with focal=1, pp=(0,0)
    _, R, t, mask_pose = cv2.recoverPose(E, pts0_n, pts1_n, focal=1, pp=(0, 0), mask=mask)
    return R, t, mask_pose

```

The calibration matrix:

```auto
FisheyeCalib(
    K=array([[240.67924447, 0. , 307.96438101],
             [0. , 240.58890106, 220.2128137],
             [0. , 0. , 1.]]),
    D=array([[-0.02361354],
             [-0.02081853],
             [0.01779144],
             [-0.00738871]]))

```

Calling

```auto
lift_pixels_to_normalized(calib, np.array([[561.9933471679688, 30.114423751831055]]))

```

returns `array([[-1000000., -1000000.]]` which is totally wrong. This is not a valid point on the image plane.

---

<div class="post-metadata">

**Author:** ![crackwitz](https://sea2.discourse-cdn.com/flex020/user_avatar/forum.opencv.org/crackwitz/32/14_2.png) [@crackwitz](https://forum.opencv.org/u/crackwitz)\
**Post date:** [February 1, 2026, 2:52pm UTC](https://forum.opencv.org/t/cv2-fisheye-undistortpoints-with-fisheye-camera-is-not-working/24344/2 "2026-02-01T14:52:44Z")

</div>

> [@NMO](#):
>
> returns `array([[-1000000., -1000000.]]` which is totally wrong

and implausibly round. what’s going on with that?

---

<div class="post-metadata">

**Author:** ![NMO](https://sea2.discourse-cdn.com/flex020/user_avatar/forum.opencv.org/nmo/32/4493_2.png) [@NMO](https://forum.opencv.org/u/NMO)\
**Post date:** [February 15, 2026, 10:03am UTC](https://forum.opencv.org/t/cv2-fisheye-undistortpoints-with-fisheye-camera-is-not-working/24344/3 "2026-02-15T10:03:08Z")

</div>

I suppose it comes from here: [opencv/modules/calib3d/src/fisheye.cpp at 4.x · opencv/opencv · GitHub](https://github.com/opencv/opencv/blob/4.x/modules/calib3d/src/fisheye.cpp)

I found an answer here: [OpenCV Fisheye Calibration FOV 220](https://forum.opencv.org/t/opencv-fisheye-calibration-fov-220/5276). @crackwitz the answer is from you. 😉

---

<div class="post-metadata">

**Author:** ![crackwitz](https://sea2.discourse-cdn.com/flex020/user_avatar/forum.opencv.org/crackwitz/32/14_2.png) [@crackwitz](https://forum.opencv.org/u/crackwitz)\
**Post date:** [February 15, 2026, 3:42pm UTC](https://forum.opencv.org/t/cv2-fisheye-undistortpoints-with-fisheye-camera-is-not-working/24344/4 "2026-02-15T15:42:26Z")

</div>

> `-1000000.0`

so it’s the else-branch of that condition

either “theta flipped” or it’s some iteration with an epsilon criterium that failed to converge.

if you can, you should step into the library code and observe what’s going on in there.
