# Converting from image coordinates to camera coordinates using undistortPoints

**URL:** <https://forum.opencv.org/t/converting-from-image-coordinates-to-camera-coordinates-using-undistortpoints/15469>\
**Category:** Android/Java\
**Tags:** calib3d\
**Created:** [November 10, 2023, 11:39am UTC](https://forum.opencv.org/t/converting-from-image-coordinates-to-camera-coordinates-using-undistortpoints/15469 "2023-11-10T11:39:47Z")\
**Posts on this page:** 3\
**Page:** 1

<div class="post-metadata">

**Author:** ![vatbub](https://avatars.discourse-cdn.com/v4/letter/v/6de8d8/32.png) [@vatbub](https://forum.opencv.org/u/vatbub)\
**Post date:** [November 10, 2023, 11:39am UTC](https://forum.opencv.org/t/converting-from-image-coordinates-to-camera-coordinates-using-undistortpoints/15469/1 "2023-11-10T11:39:47Z")

</div>

Given the following figure taken from the Calib3Dd docs:  
 ![pinhole_camera_model](https://us1.discourse-cdn.com/flex020/uploads/opencv/original/2X/8/8250189d56d8a0aca2b04bca3c04960360e5b8d3.png)

I want to convert pixel coordinates that I measured in the image (u, v) into coordinates relative to the principal point (x, y). If I understand the figure correctly, OpenCV does not flip the y-axis, as some other SFM packages do, so, the x- and y-axis of the image plane point in the same direction as the u- and the v-axis. As a result, converting between (u, v) and (x, y) coordinates should merely be a matter of subtracting (c\_x, c\_y) (ignoring all distortions).

For concreteness, here’s a numerical example:

c\_x = 5.0  
c\_y = 5.0  
(u, v) = (8.22, 1.3)

Assuming my understanding is correct, I would expect  
(x, y) = (u, v) - (c\_x, c\_y) = (8.22, 1.3) - (5, 5) = (3.22, -3.7)

And according to my understanding of the docs of Calib3d, `undistortPoints` or `undistortImagePoints`would be the go-to functions for this task. However, when I do the following:

```kotlin
@Test
fun undistortImagePointsGeogebraExample() = manageResources {
    val intrinsics = CameraIntrinsics(
        CameraMatrix(
            focalLength = Point(3.0, 3.0),
            opticalCenter = Point(5.0, 5.0)
        ),
        DistortionCoefficients.default // All zeros or null
    )

    val observedPoint = Point(8.22, 1.3)
    val expectedUndistortedPoint = Point(3.22, -3.7)

    val dst = MatOfPoint2f().closeLater()
    Calib3d.undistortPoints(
        listOf(observedPoint).toMat2f().closeLater(),
        dst,
        intrinsics.cameraMatrix.toCameraMatrix().closeLater(),
        intrinsics.distortionCoefficients.toMat().closeLater()
    )

    val actualUndistortedPoint = dst.toArray()
        .first()
        .toDataPoint()

    assertEquals(expectedUndistortedPoint, actualUndistortedPoint)
}

```

`actualUndistortedPoint` evaluates to `Point(x=1.0733333826065063, y=-1.2333333492279053)`

If I replace `undistortPoints` with `undistortImagePoints` in the above test, I get `Point(x=8.220000267028809, y=1.2999999523162842)` instead.

Now, I already heard multiple times that `undistortPoints` returns normalized coordinates and one should use `undistortImagePoints` instead. However, since `undistortImagePoints` basically returned the same coordinates that I entered, I am wondering whether `undistortImagePoints` merely removes image distortion (which is non-existant in this case as I supplied all-zero distortion coefficients) and the coordinates still have their origin in the top-left corner.

Also, given that `undistortPoints` returned a negative y-coordinate, I am wondering whether the normalized-coordinate thing is really the only difference between the two functions.

My question therefore is whether my reasoning is correct and if so, my usage of `undistortImagePoints` is correct.  
Thanks and cheers 🙂

---

<div class="post-metadata">

**Author:** ![vatbub](https://avatars.discourse-cdn.com/v4/letter/v/6de8d8/32.png) [@vatbub](https://forum.opencv.org/u/vatbub)\
**Post date:** [November 10, 2023, 11:45am UTC](https://forum.opencv.org/t/converting-from-image-coordinates-to-camera-coordinates-using-undistortpoints/15469/2 "2023-11-10T11:45:21Z")

</div>

Note that the euclidean norm of `(x=1.0733333826065063, y=-1.2333333492279053)` is `1.6349788073657858` and not 1, so, calling those coordinates “normalized” is confusing to me.

Also, (1.0733333826065063, - 1.2333333492279053) \* 3 is approximately equal to my expected result, indicating that `undistortPoints` may be the better way to go, in which case an additional question is how this scale factor can be determined reliably ( or how I can get rid of it).

---

<div class="post-metadata">

**Author:** ![vatbub](https://avatars.discourse-cdn.com/v4/letter/v/6de8d8/32.png) [@vatbub](https://forum.opencv.org/u/vatbub)\
**Post date:** [November 10, 2023, 11:59am UTC](https://forum.opencv.org/t/converting-from-image-coordinates-to-camera-coordinates-using-undistortpoints/15469/3 "2023-11-10T11:59:52Z")

</div>

I ended up finding the solution in plain sight: Yes, my understanding is correct and `undistortPoints` is the way to go. The term “normalized” may be confusing here, as it means in this case that the coordinates are scaled by the focal length. So, given that I specified an arbitrary focal length of f\_x = f\_y = 3.0 in my code, my numerical example actually looks like this:

(x, y) = (u, v) - (c\_x, c\_y) = (8.22, 1.3) - (5, 5) = (3.22, -3.7) = (1.0733333826065063, -1.2333333492279053) \* (f\_x, f\_y)
