Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

findHomography returns bad homography and ouliers in the inlier mask #25546

Open
4 tasks done
cdeln opened this issue May 6, 2024 · 2 comments
Open
4 tasks done

findHomography returns bad homography and ouliers in the inlier mask #25546

cdeln opened this issue May 6, 2024 · 2 comments
Labels
bug category: calib3d confirmed There is stable reproducer / investigation complete
Milestone

Comments

@cdeln
Copy link

cdeln commented May 6, 2024

System Information

OpenCV python version: 4.9.0.80
Operating System / Platform: Ubuntu 23.10
Python version: 3.10.14

Detailed description

findHomography returns a bad homography and an inlier mask with outliers.
The RANSAC reprojection threshold is set to 5 pixels, but checking the reprojection error manually afterwards using the returned homography and inlier mask gives a maximum error around 410 pixels (i.e. the inlier mask contains outliers).

Steps to reproduce

Put the source_points.json and the target_points.json files in your current working directory and run the following script

import json

import cv2 as cv
import numpy as np


# Load source and target points from JSON
with open('source_points.json', 'r') as f:
    source_points = np.array(json.load(f))

with open('target_points.json', 'r') as f:
    target_points = np.array(json.load(f))

# Estimate homography from source to target using RANSAC with a specified point to point distance threshold
# Use the "index with None trick" to unsqueeze one axis to fit OpenCV shape requirements
point_to_point_distance_threshold = 5
homography, mask = cv.findHomography(source_points[:, None, :], target_points[:, None, :], cv.RANSAC, point_to_point_distance_threshold)

# Extract the points that passed in the RANSAC step using the mask
# These points should be within the point to point distance threshold specified earlier
mask = mask.astype(bool).squeeze()
predicted_points = cv.perspectiveTransform(source_points[:, None, :], homography).squeeze(1)
point_to_point_distances = np.linalg.norm(predicted_points[mask] - target_points[mask], axis=-1)

# The maximum error is around 410 pixels, which is way bigger than the specified threshold of 5 pixels
assert point_to_point_distances.max() <= point_to_point_distance_threshold, point_to_point_distances.max()

Issue submission checklist

  • I report the issue, it's not a question
  • I checked the problem with documentation, FAQ, open issues, forum.opencv.org, Stack Overflow, etc and have not found any solution
  • I updated to the latest OpenCV version and the issue is still there
  • There is reproducer code and related data files (videos, images, onnx, etc)
@cdeln cdeln added the bug label May 6, 2024
@asmorkalov asmorkalov added the confirmed There is stable reproducer / investigation complete label May 16, 2024
@asmorkalov
Copy link
Contributor

Reproduced the issue with current OpenCV 4.x (f2d6527). As workaround I could recommend USAC algorithm. See cv.USAC_DEFAULT option as example. It converges well for your case.

@asmorkalov asmorkalov added this to the 4.11.0 milestone May 16, 2024
@cdeln
Copy link
Author

cdeln commented May 23, 2024

Thanks @asmorkalov for your suggested workaround.

Please note that USAC is not documented as a supported method for findHomography.

Just to clarify, this is not a convergence issue, but a logical bug in findHomography. It returns an inlier mask with elements set to True for outlier correspondences. Converging or not, this is not the expected behavior of that interface.

This is just repro code, in the prod code that the issue was found in I already check the mask for convergence (mask contains at least 4 inliers) and handle the non-converging case (less than 4 inliers). In this repo code the mask has 29/65 elements set to True, that is, it has logically converged to a solution, which is not correct as shown by the post-hoc check (that I added as a workaround in my prod code as well, in addition to checking the mask).

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
bug category: calib3d confirmed There is stable reproducer / investigation complete
Projects
None yet
Development

No branches or pull requests

2 participants