-
-
Notifications
You must be signed in to change notification settings - Fork 2.4k
Description
Description:
While going through the tests for the estimate functionality of Transforms, I noticed a problem with the test for the degenerate transforms.
The test (at https://github.com/scikit-image/scikit-image/blob/main/skimage/transform/tests/test_geometric.py#L943)) has this:
tform = AffineTransform()
assert not tform.estimate(src, dst)
# Prior to gh-6207, the above would set the parameters as the identity.
assert np.all(np.isnan(tform.params))However, this is accidentally using a bug in the scikit-image code, whereby tform = AffineTransform() (a 2D identity transform) gets estimated with 3D points. Because this is a 2D transform, and the tform has a 3x3 identity matrix, the code at https://github.com/scikit-image/scikit-image/blob/main/skimage/transform/_geometric.py#L1097 tells the estimation routine to use the wrong subset of the 4x4 matrix parameters that estimate is working on (at https://github.com/scikit-image/scikit-image/blob/main/skimage/transform/_geometric.py#L878). For this incorrect subset, the generated A matrix does lead to the test passing (V[-1, -1] is very close to zero). However, if you prevent this incorrect subset by starting with a 3D identity transform (tform = AffineTransform.identity(3)), with, therefore, a 4x4 identity transformation matrix, the test does not generate V[-1, -1] close to 0 (it's in the region of 0.5), and the test fails.
I think the test is incorrect. I'm afraid I didn't understand the explanation of the test:
# if the last element of the vector corresponding to the smallest
# singular value is close to zero, this implies a degenerate case
# because it is a rank-defective transform, which would map points
# to a line rather than a plane.because I did not know why that was the correct test for the rank-defective transform.
V comes from:
_, _, V = np.linalg.svd(A)Failing to understand that logic, and to make the fixed (AffineTransform.identity(3)) version of the test pass, I also check the generated H matrix for rank deficiency:
if np.isclose(np.linalg.det(H), 0):
self.params = np.full((d + 1, d + 1), np.nan)
return Falsebut I'm not confident that is the right test.
@cv3d - I think this is your code, from #3926? Could you explain more? What is the correct test for the correct initial (3D) transform?
Way to reproduce:
No response