Skip to content

Simple Python script for testing the robust estimation of the fundamental matrix between two images with RANSAC and MAGSAC++ in OpenCV, and reproducibility across 100 runs.

License

Notifications You must be signed in to change notification settings

kerolex/test-robustfundamentalmat-opencv-python

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

19 Commits
 
 
 
 
 
 
 
 

Repository files navigation

Robust estimation of the fundamantal matrix with MAGSAC++ in OpenCV and Python - Testing

RANSAC-like fitting model methods used for different computer vision taks, such as 3D reconstruction, ego-motion estimation, image matching, etc., are based on sampling strategies that makes the output of the methods non-deterministic. Because of this, one should expect implementations of these methods in OpenCV to output different results when running multiple times on the same data and with the same paramters. But this is currently not happening, and running

F, status = cv2.findFundamentalMat(pts1, pts2, cv2.FM_RANSAC, ransacReprojThreshold, confidence, maxIters)

multiple times returns always the same fundamental matrix and number of inliers (FM_RANSAC can be replaced with any other USAC method). This is caused by a random seed initialised always to the same value in the OpenCV source code.

Therefore, STOP using this function!

Instead, start initialising the parameters of the struct UsacParams(), especially by randomly setting randomGeneratorState and the non-deterministic behaviour will be restored!

Table of Contents

  1. Setup
  2. Demo
  3. Arguments
  4. Known issues
  5. Enquiries, Question and Comments
  6. Reference
  7. Licence

Setup

  • Ubuntu 18.04 LTS
  • OpenCV: 4.5.5
  • Python: 3.10

Create a conda environment name USAC with py-opencv and tqdm packages:

conda create --name USAC
conda install -c conda-forge py-opencv
conda install -c conda-forge tqdm

Demo

From Linux terminal, run to activate the created conda environment and launch the testing Python script:

source run_USAC.sh

The script will run on two example images from the sequence Machine Hall 05 of the public EuRoC MAV Dataset located in data/EuR5.

Values of the arguments can be changed directly in the Python script or passed within the bash script.

The demo runs automatically the robust estimator MAGSAC++.

Arguments

  • n_runs: number of runs (default: 5)
  • min_num_inliers: minimum number of inliers to accept the estimated fundamental matrix (default: 15)
  • ransacReprojThreshold: maximum reprojection error allowed for RANSAC (default: 2.0)
  • conf: confidence for RANSAC (default: 0.99)
  • maxIters: maximum number of iterations for RANSAC (default: 1000)
  • max_n_kps: maximum number of keypoints to detect in an image (default: 1000)
  • dist_th: threshold on the Hamming distance for ORB features (default: 50)
  • snn_th: threshold for the Lowe's ratio test or Second Nearest Neighbour (default: 0.6)
  • feature: type of local image feature to use, for example SIFT or ORB (default: orb)
  • SACestimator: algorithm to use for robustly estimating the fundamental matrix, for example RANSAC or MAGSAC++ (default: MAGSAC++)

Known issues

The script returns the same fundamental matrix and number of inliers across the 100 runs without changing any value of the parameters. This behaviour is unexpected due to the sampling approach of the estimators (RANSAC, MAGSAC++). I posted a question on the OpenCV Forum to know more about this behaviour.

The behaviour is due to a random seed initialises always to zero when calling:

F, status = cv2.findFundamentalMat(pts1, pts2, cv2.USAC_MAGSAC, ransacReprojThreshold, confidence, maxIters)

or

F, status = cv2.findFundamentalMat(pts1, pts2, cv2.FM_RANSAC, ransacReprojThreshold, confidence, maxIters)

I would reccomend to avoid using the above functions. To fix the issue and folliwing the reply provided in OpenCV Forum, I would suggest using the following portions of code (here reported only for MAGSAC++):

def FindFundamentalMatMAGSACplusplus(pts1, pts2, ransacReprojThreshold, confidence, maxIters):
  usac_params = cv2.UsacParams()

  usac_params.randomGeneratorState = random.randint(0,1000000)
  usac_params.confidence = confidence
  usac_params.maxIterations = maxIters
  usac_params.loMethod = cv2.LOCAL_OPTIM_SIGMA
  usac_params.score = cv2.SCORE_METHOD_MAGSAC
  usac_params.threshold = ransacReprojThreshold
  # usac_params.isParallel = False # False is deafult
  usac_params.loIterations = 10
  usac_params.loSampleSize = 50
  usac_params.neighborsSearch = cv2.NEIGH_GRID
  usac_params.sampler = cv2.SAMPLING_UNIFORM

  F, status = cv2.findFundamentalMat(pts1, pts2, usac_params)

  return F, status

If you comment the line about setting the randomGenerateState, the code will generate the same output as the previous command:

F, status = cv2.findFundamentalMat(pts1, pts2, cv2.USAC_MAGSAC, ransacReprojThreshold, confidence, maxIters)

Setting the randomGenerateState to random integers will restore the standard non-deterministic behaviour of these estimators, providing different results for each run.

References

D. Barath, J. Noskova, M. Ivashechkin, J. Matas, MAGSAC++, a fast, reliable and accurate robust estimator, CVPR 2020
[paper] [code]

D. Mishkin, Evaluating OpenCV new RANSACs, Blog post [link]

The Python script is a personal adaption of codes taken from:

Enquiries, Question and Comments

If you have any further enquiries, question, or comments, please contact a.xompero@gmail.com If you would like to file a bug report or a feature request, use the Github issue tracker.

Licence

This work is licensed under the MIT License. To view a copy of this license, see LICENSE.

About

Simple Python script for testing the robust estimation of the fundamental matrix between two images with RANSAC and MAGSAC++ in OpenCV, and reproducibility across 100 runs.

Topics

Resources

License

Stars

Watchers

Forks