Given the following figure taken from the Calib3Dd docs:
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:
@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