This is basically an
image matching process, which looks for corresponding matches on
points in the image set.

It's actually a two
step process – an initial run through looks for likely matches (the
“putative” matches) which uses one of a set of possible matching
algorithms. Following this then the possible matches are run through
a geometric filter which should discard outliers (unreliable)
matches.

Once again this
isn't something you really need to understand the behind the scenes detail to use –
there are a couple of default values which determine the thresholds
for flagging a match and determining the outliers, but otherwise the
API is fairly opaque.

However the Region
information must be used to determine which of the Scalar or Binary
geometric matcheroptions are available.

**First – Load the image information**
Run through the view
list, get the file names and push to a list of names and sizes

**Next– The matchers**
Then we create a
matcher to process the image information. This is of the base type
openMVG::Matcher_Regions_AllInMemory
and which is one of the derived matcher types which matches
the region we used (scalar or binary).

We pass in a
distance ratio, used to determine the threshold for discarding
spurious points: A higher value is stricter (from the Nearest Neighbour distance matching code; the "Ratio between best and second best matches must be superior to [the] given threshold")

Since we used the
default AKAZE earlier we can simply assign an ANN_L2 matcher to it.

On the successful
load then we use openMVG::exhaustivePairs()
to generate all the pair values (type openMVG::Pair_Set),
and then we run the Match function, and the output is set of matches we drop to a file using the
PairedIndMatchToStream()
call.

**Next: Geometric Filter**
The geometric filter
process takes a maximum residual error value, the complete list of
potential (putative) matches alongside a geometric model fitting
function. It then generates an output set of matches that fit the
model to within the residual error.

There are three
available solvers, which are used to generate a target model to
filter points against:

- GeometricFilter_FMatrix_AC AContrario Fundamental matrix solver
- GeometricFilter_EMatrix_AC AContrario Essential matrix solver
- GeometricFilter_HMatrix_AC AContrario Homography matrix solver

So, for the
Fundamental Matrix solver then we pass it the list of putative match
pairs, and using these points then the geometric filter estimates
the fundamental matrix and removes outliers from the set of matches.
Following this we save the final matches to a file using
PairedIndMatchToStream().

Although there's
some fiddly detail hiding behind this model, we can simply pass in
the filter reference and the maximum residual error that is used to
discard outliers; a lower value here discards more points (but too
high a value will include outliers and cause problems when bundle
adjusting).

There's some more
information on using fundamental matrix and a-contrario estimation at
http://www.loria.fr/~sur/articles/noury07fundamental.pdf

A simple MWE using
some default values from the sample code is:

void ImageList::computeMatches()

{

float fDistRatio = 0.6f;

openMVG::matching::PairWiseMatches map_PutativesMatches;

std::vector<std::string> vec_fileNames;

std::vector<std::pair<size_t, size_t> > vec_imagesSize;

for (openMVG::sfm::Views::const_iterator iter = _sfm_data.GetViews().begin(); iter != _sfm_data.GetViews().end(); ++iter)

{

const openMVG::sfm::View * v = iter->second.get();

vec_fileNames.push_back(stlplus::create_filespec(_sfm_data.s_root_path, v->s_Img_path));

vec_imagesSize.push_back( std::make_pair( v->ui_width, v->ui_height) );

}

std::unique_ptr<openMVG::Matcher_Regions_AllInMemory> collectionMatcher;

collectionMatcher.reset(new openMVG::Matcher_Regions_AllInMemory(fDistRatio, openMVG::ANN_L2));

if (collectionMatcher->loadData(_regionsType, vec_fileNames, getDirectory()))

{

openMVG::Pair_Set pairs;

pairs = openMVG::exhaustivePairs(_sfm_data.GetViews().size());

collectionMatcher->Match(vec_fileNames, pairs, map_PutativesMatches);

std::ofstream file(_matches_full);

if (file.is_open())

PairedIndMatchToStream(map_PutativesMatches, file);

file.close();

}

std::shared_ptr<openMVG::sfm::Features_Provider> feats_provider = std::make_shared<openMVG::sfm::Features_Provider>();

if (!feats_provider->load(_sfm_data, getDirectory(), _regionsType))

return;

openMVG::PairWiseMatches map_GeometricMatches;

ImageCollectionGeometricFilter collectionGeomFilter(feats_provider.get());

const double maxResidualError = 1.0;

collectionGeomFilter.Filter(

GeometricFilter_FMatrix_AC(maxResidualError),

map_PutativesMatches,

map_GeometricMatches,

vec_imagesSize);

std::ofstream file (_matches_filtered);

if (file.is_open())

PairedIndMatchToStream(map_GeometricMatches, file);

file.close();

}