/*1IMPORTANT: READ BEFORE DOWNLOADING, COPYING, INSTALLING OR USING.23By downloading, copying, installing or using the software you agree to this license.4If you do not agree to this license, do not download, install,5copy or use the software.678BSD 3-Clause License910Copyright (C) 2014, Olexa Bilaniuk, Hamid Bazargani & Robert Laganiere, all rights reserved.1112Redistribution and use in source and binary forms, with or without modification,13are permitted provided that the following conditions are met:1415* Redistribution's of source code must retain the above copyright notice,16this list of conditions and the following disclaimer.1718* Redistribution's in binary form must reproduce the above copyright notice,19this list of conditions and the following disclaimer in the documentation20and/or other materials provided with the distribution.2122* The name of the copyright holders may not be used to endorse or promote products23derived from this software without specific prior written permission.2425This software is provided by the copyright holders and contributors "as is" and26any express or implied warranties, including, but not limited to, the implied27warranties of merchantability and fitness for a particular purpose are disclaimed.28In no event shall the Intel Corporation or contributors be liable for any direct,29indirect, incidental, special, exemplary, or consequential damages30(including, but not limited to, procurement of substitute goods or services;31loss of use, data, or profits; or business interruption) however caused32and on any theory of liability, whether in contract, strict liability,33or tort (including negligence or otherwise) arising in any way out of34the use of this software, even if advised of the possibility of such damage.35*/3637/**38* Bilaniuk, Olexa, Hamid Bazargani, and Robert Laganiere. "Fast Target39* Recognition on Mobile Devices: Revisiting Gaussian Elimination for the40* Estimation of Planar Homographies." In Computer Vision and Pattern41* Recognition Workshops (CVPRW), 2014 IEEE Conference on, pp. 119-125.42* IEEE, 2014.43*/4445/* Includes */46#include "precomp.hpp"47#include <opencv2/core.hpp>48#include <stdlib.h>49#include <stdio.h>50#include <string.h>51#include <stddef.h>52#include <limits.h>53#include <float.h>54#include <math.h>55#include <vector>56#include "rho.h"575859606162/* For the sake of cv:: namespace ONLY: */63namespace cv{/* For C support, replace with extern "C" { */646566/* Constants */67const int MEM_ALIGN = 32;68const size_t HSIZE = (3*3*sizeof(float));69const double MIN_DELTA_CHNG = 0.1;70// const double CHI_STAT = 2.706;71const double CHI_SQ = 1.645;72// const double RLO = 0.25;73// const double RHI = 0.75;74const int MAXLEVMARQITERS = 100;75const int SMPL_SIZE = 4; /* 4 points required per model */76const int SPRT_T_M = 25; /* Guessing 25 match evlauations / 1 model generation */77const int SPRT_M_S = 1; /* 1 model per sample */78const double SPRT_EPSILON = 0.1; /* No explanation */79const double SPRT_DELTA = 0.01; /* No explanation */80const double LM_GAIN_LO = 0.25; /* See sacLMGain(). */81const double LM_GAIN_HI = 0.75; /* See sacLMGain(). */828384/* Data Structures */8586/**87* Base Struct for RHO algorithm.88*89* A RHO estimator has initialization, finalization, capacity, seeding and90* homography-estimation APIs that must be implemented.91*/9293struct RHO_HEST{94/* This is a virtual base class; It should have a virtual destructor. */95virtual ~RHO_HEST(){}9697/* External Interface Methods */9899/**100* Initialization work.101*102* @return 0 if initialization is unsuccessful; non-zero otherwise.103*/104105virtual inline int initialize(void){return 1;}106107108/**109* Finalization work.110*/111112virtual inline void finalize(void){}113114/**115* Ensure that the estimator context's internal table for the non-randomness116* criterion is at least of the given size, and uses the given beta. The table117* should be larger than the maximum number of matches fed into the estimator.118*119* A value of N of 0 requests deallocation of the table.120*121* @param [in] N If 0, deallocate internal table. If > 0, ensure that the122* internal table is of at least this size, reallocating if123* necessary.124* @param [in] beta The beta-factor to use within the table.125* @return 0 if unsuccessful; non-zero otherwise.126*/127128virtual inline int ensureCapacity(unsigned N, double beta){129CV_UNUSED(N);130CV_UNUSED(beta);131132return 1;133}134135136/**137* Generates a random double uniformly distributed in the range [0, 1).138*139* The default implementation uses the xorshift128+ algorithm from140* Sebastiano Vigna. Further scramblings of Marsaglia's xorshift generators.141* CoRR, abs/1402.6246, 2014.142* http://vigna.di.unimi.it/ftp/papers/xorshiftplus.pdf143*144* Source roughly as given in145* http://en.wikipedia.org/wiki/Xorshift#Xorshift.2B146*/147148virtual inline double fastRandom(void){149uint64_t x = prng.s[0];150uint64_t y = prng.s[1];151x ^= x << 23; // a152x ^= x >> 17; // b153x ^= y ^ (y >> 26); // c154prng.s[0] = y;155prng.s[1] = x;156uint64_t s = x + y;157158return s * 5.421010862427522e-20;/* 2^-64 */159}160161162/**163* Seeds the context's PRNG.164*165* @param [in] seed A 64-bit unsigned integer seed.166*/167168virtual inline void fastSeed(uint64_t seed){169int i;170171prng.s[0] = seed;172prng.s[1] = ~seed;/* Guarantees one of the elements will be non-zero. */173174/**175* Escape from zero-land (see xorshift128+ paper). Approximately 20176* iterations required according to the graph.177*/178179for(i=0;i<20;i++){180fastRandom();181}182}183184185/**186* Estimates the homography using the given context, matches and parameters to187* PROSAC.188*189* @param [in] src The pointer to the source points of the matches.190* Cannot be NULL.191* @param [in] dst The pointer to the destination points of the matches.192* Cannot be NULL.193* @param [out] inl The pointer to the output mask of inlier matches.194* May be NULL.195* @param [in] N The number of matches.196* @param [in] maxD The maximum distance.197* @param [in] maxI The maximum number of PROSAC iterations.198* @param [in] rConvg The RANSAC convergence parameter.199* @param [in] cfd The required confidence in the solution.200* @param [in] minInl The minimum required number of inliers.201* @param [in] beta The beta-parameter for the non-randomness criterion.202* @param [in] flags A union of flags to control the estimation.203* @param [in] guessH An extrinsic guess at the solution H, or NULL if204* none provided.205* @param [out] finalH The final estimation of H, or the zero matrix if206* the minimum number of inliers was not met.207* Cannot be NULL.208* @return The number of inliers if the minimum number of209* inliers for acceptance was reached; 0 otherwise.210*/211212virtual unsigned rhoHest(const float* src, /* Source points */213const float* dst, /* Destination points */214char* inl, /* Inlier mask */215unsigned N, /* = src.length = dst.length = inl.length */216float maxD, /* Works: 3.0 */217unsigned maxI, /* Works: 2000 */218unsigned rConvg, /* Works: 2000 */219double cfd, /* Works: 0.995 */220unsigned minInl, /* Minimum: 4 */221double beta, /* Works: 0.35 */222unsigned flags, /* Works: 0 */223const float* guessH, /* Extrinsic guess, NULL if none provided */224float* finalH) = 0; /* Final result. */225226227228/* PRNG XORshift128+ */229struct{230uint64_t s[2]; /* PRNG state */231} prng;232};233234235236/**237* Generic C implementation of RHO algorithm.238*/239240struct RHO_HEST_REFC : RHO_HEST{241/**242* Virtual Arguments.243*244* Exactly the same as at function call, except:245* - minInl is enforced to be >= 4.246*/247248struct{249const float* src;250const float* dst;251char* inl;252unsigned N;253float maxD;254unsigned maxI;255unsigned rConvg;256double cfd;257unsigned minInl;258double beta;259unsigned flags;260const float* guessH;261float* finalH;262} arg;263264/* PROSAC Control */265struct{266unsigned i; /* Iteration Number */267unsigned phNum; /* Phase Number */268unsigned phEndI; /* Phase End Iteration */269double phEndFpI; /* Phase floating-point End Iteration */270unsigned phMax; /* Termination phase number */271unsigned phNumInl; /* Number of inliers for termination phase */272unsigned numModels; /* Number of models tested */273unsigned* smpl; /* Sample of match indexes */274} ctrl;275276/* Current model being tested */277struct{278float* pkdPts; /* Packed points */279float* H; /* Homography */280char* inl; /* Mask of inliers */281unsigned numInl; /* Number of inliers */282} curr;283284/* Best model (so far) */285struct{286float* H; /* Homography */287char* inl; /* Mask of inliers */288unsigned numInl; /* Number of inliers */289} best;290291/* Non-randomness criterion */292struct{293std::vector<unsigned> tbl; /* Non-Randomness: Table */294unsigned size; /* Non-Randomness: Size */295double beta; /* Non-Randomness: Beta */296} nr;297298/* SPRT Evaluator */299struct{300double t_M; /* t_M */301double m_S; /* m_S */302double epsilon; /* Epsilon */303double delta; /* delta */304double A; /* SPRT Threshold */305unsigned Ntested; /* Number of points tested */306unsigned Ntestedtotal; /* Number of points tested in total */307int good; /* Good/bad flag */308double lambdaAccept; /* Accept multiplier */309double lambdaReject; /* Reject multiplier */310} eval;311312/* Levenberg-Marquardt Refinement */313struct{314float (* JtJ)[8]; /* JtJ matrix */315float (* tmp1)[8]; /* Temporary 1 */316float* Jte; /* Jte vector */317} lm;318319/* Memory Management */320struct{321cv::Mat perObj;322cv::Mat perRun;323} mem;324325/* Initialized? */326int initialized;327328329/* Empty constructors and destructors */330public:331RHO_HEST_REFC();332private: /* Forbid copying. */333RHO_HEST_REFC(const RHO_HEST_REFC&);334public:335~RHO_HEST_REFC();336337/* Methods to implement external interface */338inline int initialize(void) CV_OVERRIDE;339inline void finalize(void) CV_OVERRIDE;340inline int ensureCapacity(unsigned N, double beta) CV_OVERRIDE;341unsigned rhoHest(const float* src, /* Source points */342const float* dst, /* Destination points */343char* inl, /* Inlier mask */344unsigned N, /* = src.length = dst.length = inl.length */345float maxD, /* Works: 3.0 */346unsigned maxI, /* Works: 2000 */347unsigned rConvg, /* Works: 2000 */348double cfd, /* Works: 0.995 */349unsigned minInl, /* Minimum: 4 */350double beta, /* Works: 0.35 */351unsigned flags, /* Works: 0 */352const float* guessH, /* Extrinsic guess, NULL if none provided */353float* finalH /* Final result. */354) CV_OVERRIDE;355356357358/* Methods to implement internals */359inline void allocatePerObj(void);360inline void allocatePerRun(void);361inline void deallocatePerRun(void);362inline void deallocatePerObj(void);363inline int initRun(void);364inline void finiRun(void);365inline int haveExtrinsicGuess(void);366inline int hypothesize(void);367inline int verify(void);368inline int isNREnabled(void);369inline int isRefineEnabled(void);370inline int isFinalRefineEnabled(void);371inline int PROSACPhaseEndReached(void);372inline void PROSACGoToNextPhase(void);373inline void getPROSACSample(void);374inline void rndSmpl(unsigned sampleSize,375unsigned* currentSample,376unsigned dataSetSize);377inline int isSampleDegenerate(void);378inline void generateModel(void);379inline int isModelDegenerate(void);380inline void evaluateModelSPRT(void);381inline void updateSPRT(void);382inline void designSPRTTest(void);383inline int isBestModel(void);384inline int isBestModelGoodEnough(void);385inline void saveBestModel(void);386inline void nStarOptimize(void);387inline void updateBounds(void);388inline void outputModel(void);389inline void outputZeroH(void);390inline int canRefine(void);391inline void refine(void);392};393394395396397/**398* Prototypes for purely-computational code.399*/400401static inline void sacInitNonRand (double beta,402unsigned start,403unsigned N,404unsigned* nonRandMinInl);405static inline double sacInitPEndFpI (const unsigned ransacConvg,406const unsigned n,407const unsigned s);408static inline unsigned sacCalcIterBound (double confidence,409double inlierRate,410unsigned sampleSize,411unsigned maxIterBound);412static inline void hFuncRefC (float* packedPoints, float* H);413static inline void sacCalcJacobianErrors(const float* H,414const float* src,415const float* dst,416const char* inl,417unsigned N,418float (* JtJ)[8],419float* Jte,420float* Sp);421static inline float sacLMGain (const float* dH,422const float* Jte,423const float S,424const float newS,425const float lambda);426static inline int sacChol8x8Damped (const float (*A)[8],427float lambda,428float (*L)[8]);429static inline void sacTRInv8x8 (const float (*L)[8],430float (*M)[8]);431static inline void sacTRISolve8x8 (const float (*L)[8],432const float* Jte,433float* dH);434static inline void sacSub8x1 (float* Hout,435const float* H,436const float* dH);437438439440/* Functions */441442/**443* External access to context constructor.444*445* @return A pointer to the context if successful; NULL if an error occurred.446*/447448Ptr<RHO_HEST> rhoInit(void){449/* Select an optimized implementation of RHO here. */450451#if 1452/**453* For now, only the generic C implementation is available. In the future,454* SSE2/AVX/AVX2/FMA/NEON versions may be added, and they will be selected455* depending on cv::checkHardwareSupport()'s return values.456*/457458Ptr<RHO_HEST> p = Ptr<RHO_HEST>(new RHO_HEST_REFC);459#endif460461/* Initialize it. */462if(p){463if(!p->initialize()){464p.release();465}466}467468/* Return it. */469return p;470}471472473/**474* External access to non-randomness table resize.475*/476477int rhoEnsureCapacity(Ptr<RHO_HEST> p, unsigned N, double beta){478return p->ensureCapacity(N, beta);479}480481482/**483* Seeds the internal PRNG with the given seed.484*/485486void rhoSeed(Ptr<RHO_HEST> p, uint64_t seed){487p->fastSeed(seed);488}489490491/**492* Estimates the homography using the given context, matches and parameters to493* PROSAC.494*495* @param [in/out] p The context to use for homography estimation. Must496* be already initialized. Cannot be NULL.497* @param [in] src The pointer to the source points of the matches.498* Must be aligned to 4 bytes. Cannot be NULL.499* @param [in] dst The pointer to the destination points of the matches.500* Must be aligned to 16 bytes. Cannot be NULL.501* @param [out] inl The pointer to the output mask of inlier matches.502* Must be aligned to 16 bytes. May be NULL.503* @param [in] N The number of matches.504* @param [in] maxD The maximum distance.505* @param [in] maxI The maximum number of PROSAC iterations.506* @param [in] rConvg The RANSAC convergence parameter.507* @param [in] cfd The required confidence in the solution.508* @param [in] minInl The minimum required number of inliers.509* @param [in] beta The beta-parameter for the non-randomness criterion.510* @param [in] flags A union of flags to control the estimation.511* @param [in] guessH An extrinsic guess at the solution H, or NULL if512* none provided.513* @param [out] finalH The final estimation of H, or the zero matrix if514* the minimum number of inliers was not met.515* Cannot be NULL.516* @return The number of inliers if the minimum number of517* inliers for acceptance was reached; 0 otherwise.518*/519520unsigned rhoHest(Ptr<RHO_HEST> p, /* Homography estimation context. */521const float* src, /* Source points */522const float* dst, /* Destination points */523char* inl, /* Inlier mask */524unsigned N, /* = src.length = dst.length = inl.length */525float maxD, /* Works: 3.0 */526unsigned maxI, /* Works: 2000 */527unsigned rConvg, /* Works: 2000 */528double cfd, /* Works: 0.995 */529unsigned minInl, /* Minimum: 4 */530double beta, /* Works: 0.35 */531unsigned flags, /* Works: 0 */532const float* guessH, /* Extrinsic guess, NULL if none provided */533float* finalH){ /* Final result. */534return p->rhoHest(src, dst, inl, N, maxD, maxI, rConvg, cfd, minInl, beta,535flags, guessH, finalH);536}537538539540541542543544545546547548549/*********************** RHO_HEST_REFC implementation **********************/550551/**552* Constructor for RHO_HEST_REFC.553*554* Does nothing. True initialization is done by initialize().555*/556557RHO_HEST_REFC::RHO_HEST_REFC() : initialized(0){558arg.src = 0;559arg.dst = 0;560arg.inl = 0;561arg.N = 0;562arg.maxD = 0;563arg.maxI = 0;564arg.rConvg = 0;565arg.cfd = 0;566arg.minInl = 0;567arg.beta = 0;568arg.flags = 0;569arg.guessH = 0;570arg.finalH = 0;571572ctrl.i = 0;573ctrl.phNum = 0;574ctrl.phEndI = 0;575ctrl.phEndFpI = 0;576ctrl.phMax = 0;577ctrl.phNumInl = 0;578ctrl.numModels = 0;579ctrl.smpl = 0;580581curr.pkdPts = 0;582curr.H = 0;583curr.inl = 0;584curr.numInl = 0;585586best.H = 0;587best.inl = 0;588best.numInl = 0;589590nr.size = 0;591nr.beta = 0;592593eval.t_M = 0;594eval.m_S = 0;595eval.epsilon = 0;596eval.delta = 0;597eval.A = 0;598eval.Ntested = 0;599eval.Ntestedtotal = 0;600eval.good = 0;601eval.lambdaAccept = 0;602eval.lambdaReject = 0;603604lm.JtJ = 0;605lm.tmp1 = 0;606lm.Jte = 0;607}608609/**610* Private copy constructor for RHO_HEST_REFC. Disabled.611*/612613RHO_HEST_REFC::RHO_HEST_REFC(const RHO_HEST_REFC&) : initialized(0){614615}616617/**618* Destructor for RHO_HEST_REFC.619*/620621RHO_HEST_REFC::~RHO_HEST_REFC(){622if(initialized){623finalize();624}625}626627628629/**630* Initialize the estimator context, by allocating the aligned buffers631* internally needed.632*633* Currently there are 5 per-estimator buffers:634* - The buffer of m indexes representing a sample635* - The buffer of 16 floats representing m matches (x,y) -> (X,Y).636* - The buffer for the current homography637* - The buffer for the best-so-far homography638* - Optionally, the non-randomness criterion table639*640* Returns 0 if unsuccessful and non-0 otherwise.641*/642643inline int RHO_HEST_REFC::initialize(void){644initialized = 0;645646647allocatePerObj();648649curr.inl = NULL;650curr.numInl = 0;651652best.inl = NULL;653best.numInl = 0;654655nr.size = 0;656nr.beta = 0.0;657658659fastSeed((uint64_t)~0);660661662int areAllAllocsSuccessful = !mem.perObj.empty();663664if(!areAllAllocsSuccessful){665finalize();666}else{667initialized = 1;668}669670return areAllAllocsSuccessful;671}672673/**674* Finalize.675*676* Finalize the estimator context, by freeing the aligned buffers used677* internally.678*/679680inline void RHO_HEST_REFC::finalize(void){681if(initialized){682deallocatePerObj();683684initialized = 0;685}686}687688/**689* Ensure that the estimator context's internal table for non-randomness690* criterion is at least of the given size, and uses the given beta. The table691* should be larger than the maximum number of matches fed into the estimator.692*693* A value of N of 0 requests deallocation of the table.694*695* @param [in] N If 0, deallocate internal table. If > 0, ensure that the696* internal table is of at least this size, reallocating if697* necessary.698* @param [in] beta The beta-factor to use within the table.699* @return 0 if unsuccessful; non-zero otherwise.700*701* Reads: nr.*702* Writes: nr.*703*/704705inline int RHO_HEST_REFC::ensureCapacity(unsigned N, double beta){706if(N == 0){707/* Clear. */708nr.tbl.clear();709nr.size = 0;710}else if(nr.beta != beta){711/* Beta changed. Redo all the work. */712nr.tbl.resize(N);713nr.beta = beta;714sacInitNonRand(nr.beta, 0, N, &nr.tbl[0]);715nr.size = N;716}else if(N > nr.size){717/* Work is partially done. Do rest of it. */718nr.tbl.resize(N);719sacInitNonRand(nr.beta, nr.size, N, &nr.tbl[nr.size]);720nr.size = N;721}else{722/* Work is already done. Do nothing. */723}724725return 1;726}727728729/**730* Estimates the homography using the given context, matches and parameters to731* PROSAC.732*733* @param [in] src The pointer to the source points of the matches.734* Must be aligned to 4 bytes. Cannot be NULL.735* @param [in] dst The pointer to the destination points of the matches.736* Must be aligned to 4 bytes. Cannot be NULL.737* @param [out] inl The pointer to the output mask of inlier matches.738* Must be aligned to 4 bytes. May be NULL.739* @param [in] N The number of matches.740* @param [in] maxD The maximum distance.741* @param [in] maxI The maximum number of PROSAC iterations.742* @param [in] rConvg The RANSAC convergence parameter.743* @param [in] cfd The required confidence in the solution.744* @param [in] minInl The minimum required number of inliers.745* @param [in] beta The beta-parameter for the non-randomness criterion.746* @param [in] flags A union of flags to control the estimation.747* @param [in] guessH An extrinsic guess at the solution H, or NULL if748* none provided.749* @param [out] finalH The final estimation of H, or the zero matrix if750* the minimum number of inliers was not met.751* Cannot be NULL.752* @return The number of inliers if the minimum number of753* inliers for acceptance was reached; 0 otherwise.754*/755756unsigned RHO_HEST_REFC::rhoHest(const float* src, /* Source points */757const float* dst, /* Destination points */758char* inl, /* Inlier mask */759unsigned N, /* = src.length = dst.length = inl.length */760float maxD, /* Works: 3.0 */761unsigned maxI, /* Works: 2000 */762unsigned rConvg, /* Works: 2000 */763double cfd, /* Works: 0.995 */764unsigned minInl, /* Minimum: 4 */765double beta, /* Works: 0.35 */766unsigned flags, /* Works: 0 */767const float* guessH, /* Extrinsic guess, NULL if none provided */768float* finalH){ /* Final result. */769770/**771* Setup772*/773774arg.src = src;775arg.dst = dst;776arg.inl = inl;777arg.N = N;778arg.maxD = maxD;779arg.maxI = maxI;780arg.rConvg = rConvg;781arg.cfd = cfd;782arg.minInl = minInl;783arg.beta = beta;784arg.flags = flags;785arg.guessH = guessH;786arg.finalH = finalH;787if(!initRun()){788outputZeroH();789finiRun();790return 0;791}792793/**794* Extrinsic Guess795*/796797if(haveExtrinsicGuess()){798verify();799}800801802/**803* PROSAC Loop804*/805806for(ctrl.i=0; ctrl.i < arg.maxI || ctrl.i < 100; ctrl.i++){807hypothesize() && verify();808}809810811/**812* Teardown813*/814815if(isFinalRefineEnabled() && canRefine()){816refine();817}818819outputModel();820finiRun();821return isBestModelGoodEnough() ? best.numInl : 0;822}823824825/**826* Allocate per-object dynamic storage.827*828* This includes aligned, fixed-size internal buffers, but excludes any buffers829* whose size cannot be determined ahead-of-time (before the number of matches830* is known).831*832* All buffer memory is allocated in one single shot, and all pointers are833* initialized.834*/835836inline void RHO_HEST_REFC::allocatePerObj(void){837/* We have known sizes */838size_t ctrl_smpl_sz = SMPL_SIZE*sizeof(*ctrl.smpl);839size_t curr_pkdPts_sz = SMPL_SIZE*2*2*sizeof(*curr.pkdPts);840size_t curr_H_sz = HSIZE;841size_t best_H_sz = HSIZE;842size_t lm_JtJ_sz = 8*8*sizeof(float);843size_t lm_tmp1_sz = 8*8*sizeof(float);844size_t lm_Jte_sz = 1*8*sizeof(float);845846/* We compute offsets */847size_t total = 0;848#define MK_OFFSET(v) \849size_t v ## _of = total; \850total = alignSize(v ## _of + v ## _sz, MEM_ALIGN)851852MK_OFFSET(ctrl_smpl);853MK_OFFSET(curr_pkdPts);854MK_OFFSET(curr_H);855MK_OFFSET(best_H);856MK_OFFSET(lm_JtJ);857MK_OFFSET(lm_tmp1);858MK_OFFSET(lm_Jte);859860#undef MK_OFFSET861862/* Allocate dynamic memory managed by cv::Mat */863mem.perObj.create(1, (int)(total + MEM_ALIGN), CV_8UC1);864865/* Extract aligned pointer */866unsigned char* ptr = alignPtr(mem.perObj.data, MEM_ALIGN);867868/* Assign pointers */869ctrl.smpl = (unsigned*) (ptr + ctrl_smpl_of);870curr.pkdPts = (float*) (ptr + curr_pkdPts_of);871curr.H = (float*) (ptr + curr_H_of);872best.H = (float*) (ptr + best_H_of);873lm.JtJ = (float(*)[8])(ptr + lm_JtJ_of);874lm.tmp1 = (float(*)[8])(ptr + lm_tmp1_of);875lm.Jte = (float*) (ptr + lm_Jte_of);876}877878879/**880* Allocate per-run dynamic storage.881*882* This includes storage that is proportional to the number of points, such as883* the inlier mask.884*/885886inline void RHO_HEST_REFC::allocatePerRun(void){887/* We have known sizes */888size_t best_inl_sz = arg.N;889size_t curr_inl_sz = arg.N;890891/* We compute offsets */892size_t total = 0;893#define MK_OFFSET(v) \894size_t v ## _of = total; \895total = alignSize(v ## _of + v ## _sz, MEM_ALIGN)896897MK_OFFSET(best_inl);898MK_OFFSET(curr_inl);899900#undef MK_OFFSET901902/* Allocate dynamic memory managed by cv::Mat */903mem.perRun.create(1, (int)(total + MEM_ALIGN), CV_8UC1);904905/* Extract aligned pointer */906unsigned char* ptr = alignPtr(mem.perRun.data, MEM_ALIGN);907908/* Assign pointers */909best.inl = (char*)(ptr + best_inl_of);910curr.inl = (char*)(ptr + curr_inl_of);911}912913914/**915* Deallocate per-run dynamic storage.916*917* Undoes the work by allocatePerRun().918*/919920inline void RHO_HEST_REFC::deallocatePerRun(void){921best.inl = NULL;922curr.inl = NULL;923924mem.perRun.release();925}926927928/**929* Deallocate per-object dynamic storage.930*931* Undoes the work by allocatePerObj().932*/933934inline void RHO_HEST_REFC::deallocatePerObj(void){935ctrl.smpl = NULL;936curr.pkdPts = NULL;937curr.H = NULL;938best.H = NULL;939lm.JtJ = NULL;940lm.tmp1 = NULL;941lm.Jte = NULL;942943mem.perObj.release();944}945946947/**948* Initialize SAC for a run given its arguments.949*950* Performs sanity-checks and memory allocations. Also initializes the state.951*952* @returns 0 if per-run initialization failed at any point; non-zero953* otherwise.954*955* Reads: arg.*, nr.*956* Writes: curr.*, best.*, ctrl.*, eval.*957*/958959inline int RHO_HEST_REFC::initRun(void){960/**961* Sanitize arguments.962*963* Runs zeroth because these are easy-to-check errors and unambiguously964* mean something or other.965*/966967if(!arg.src || !arg.dst){968/* Arguments src or dst are insane, must be != NULL */969return 0;970}971if(arg.N < (unsigned)SMPL_SIZE){972/* Argument N is insane, must be >= 4. */973return 0;974}975if(arg.maxD < 0){976/* Argument maxD is insane, must be >= 0. */977return 0;978}979if(arg.cfd < 0 || arg.cfd > 1){980/* Argument cfd is insane, must be in [0, 1]. */981return 0;982}983/* Clamp minInl to 4 or higher. */984arg.minInl = arg.minInl < (unsigned)SMPL_SIZE ? SMPL_SIZE : arg.minInl;985if(isNREnabled() && (arg.beta <= 0 || arg.beta >= 1)){986/* Argument beta is insane, must be in (0, 1). */987return 0;988}989if(!arg.finalH){990/* Argument finalH is insane, must be != NULL */991return 0;992}993994/**995* Optional NR setup.996*997* Runs first because it is decoupled from most other things (*) and if it998* fails, it is easy to recover from.999*1000* (*) The only things this code depends on is the flags argument, the nr.*1001* substruct and the sanity-checked N and beta arguments from above.1002*/10031004if(isNREnabled() && !ensureCapacity(arg.N, arg.beta)){1005return 0;1006}10071008/**1009* Inlier mask alloc.1010*1011* Runs second because we want to quit as fast as possible if we can't even1012* allocate the two masks.1013*/10141015allocatePerRun();10161017memset(best.inl, 0, arg.N);1018memset(curr.inl, 0, arg.N);10191020/**1021* Reset scalar per-run state.1022*1023* Runs third because there's no point in resetting/calculating a large1024* number of fields if something in the above junk failed.1025*/10261027ctrl.i = 0;1028ctrl.phNum = SMPL_SIZE;1029ctrl.phEndI = 1;1030ctrl.phEndFpI = sacInitPEndFpI(arg.rConvg, arg.N, SMPL_SIZE);1031ctrl.phMax = arg.N;1032ctrl.phNumInl = 0;1033ctrl.numModels = 0;10341035if(haveExtrinsicGuess()){1036memcpy(curr.H, arg.guessH, HSIZE);1037}else{1038memset(curr.H, 0, HSIZE);1039}1040curr.numInl = 0;10411042memset(best.H, 0, HSIZE);1043best.numInl = 0;10441045eval.Ntested = 0;1046eval.Ntestedtotal = 0;1047eval.good = 1;1048eval.t_M = SPRT_T_M;1049eval.m_S = SPRT_M_S;1050eval.epsilon = SPRT_EPSILON;1051eval.delta = SPRT_DELTA;1052designSPRTTest();10531054return 1;1055}10561057/**1058* Finalize SAC run.1059*1060* Deallocates per-run allocatable resources. Currently this consists only of1061* the best and current inlier masks, which are equal in size to p->arg.N1062* bytes.1063*1064* Reads: arg.bestInl, curr.inl, best.inl1065* Writes: curr.inl, best.inl1066*/10671068inline void RHO_HEST_REFC::finiRun(void){1069deallocatePerRun();1070}10711072/**1073* Hypothesize a model.1074*1075* Selects randomly a sample (within the rules of PROSAC) and generates a1076* new current model, and applies degeneracy tests to it.1077*1078* @returns 0 if hypothesized model could be rejected early as degenerate, and1079* non-zero otherwise.1080*/10811082inline int RHO_HEST_REFC::hypothesize(void){1083if(PROSACPhaseEndReached()){1084PROSACGoToNextPhase();1085}10861087getPROSACSample();1088if(isSampleDegenerate()){1089return 0;1090}10911092generateModel();1093if(isModelDegenerate()){1094return 0;1095}10961097return 1;1098}10991100/**1101* Verify the hypothesized model.1102*1103* Given the current model, evaluate its quality. If it is better than1104* everything before, save as new best model (and possibly refine it).1105*1106* Returns 1.1107*/11081109inline int RHO_HEST_REFC::verify(void){1110evaluateModelSPRT();1111updateSPRT();11121113if(isBestModel()){1114saveBestModel();11151116if(isRefineEnabled() && canRefine()){1117refine();1118}11191120updateBounds();11211122if(isNREnabled()){1123nStarOptimize();1124}1125}11261127return 1;1128}11291130/**1131* Check whether extrinsic guess was provided or not.1132*1133* @return Zero if no extrinsic guess was provided; non-zero otherwiseEE.1134*/11351136inline int RHO_HEST_REFC::haveExtrinsicGuess(void){1137return !!arg.guessH;1138}11391140/**1141* Check whether non-randomness criterion is enabled.1142*1143* @return Zero if non-randomness criterion disabled; non-zero if not.1144*/11451146inline int RHO_HEST_REFC::isNREnabled(void){1147return arg.flags & RHO_FLAG_ENABLE_NR;1148}11491150/**1151* Check whether best-model-so-far refinement is enabled.1152*1153* @return Zero if best-model-so-far refinement disabled; non-zero if not.1154*/11551156inline int RHO_HEST_REFC::isRefineEnabled(void){1157return arg.flags & RHO_FLAG_ENABLE_REFINEMENT;1158}11591160/**1161* Check whether final-model refinement is enabled.1162*1163* @return Zero if final-model refinement disabled; non-zero if not.1164*/11651166inline int RHO_HEST_REFC::isFinalRefineEnabled(void){1167return arg.flags & RHO_FLAG_ENABLE_FINAL_REFINEMENT;1168}11691170/**1171* Computes whether the end of the current PROSAC phase has been reached. At1172* PROSAC phase phNum, only matches [0, phNum) are sampled from.1173*1174* Reads (direct): ctrl.i, ctrl.phEndI, ctrl.phNum, ctrl.phMax1175* Reads (callees): None.1176* Writes (direct): None.1177* Writes (callees): None.1178*/11791180inline int RHO_HEST_REFC::PROSACPhaseEndReached(void){1181return ctrl.i >= ctrl.phEndI && ctrl.phNum < ctrl.phMax;1182}11831184/**1185* Updates unconditionally the necessary fields to move to the next PROSAC1186* stage.1187*1188* Not idempotent.1189*1190* Reads (direct): ctrl.phNum, ctrl.phEndFpI, ctrl.phEndI1191* Reads (callees): None.1192* Writes (direct): ctrl.phNum, ctrl.phEndFpI, ctrl.phEndI1193* Writes (callees): None.1194*/11951196inline void RHO_HEST_REFC::PROSACGoToNextPhase(void){1197double next;11981199ctrl.phNum++;1200next = (ctrl.phEndFpI * ctrl.phNum)/(ctrl.phNum - SMPL_SIZE);1201ctrl.phEndI += (unsigned)ceil(next - ctrl.phEndFpI);1202ctrl.phEndFpI = next;1203}12041205/**1206* Get a sample according to PROSAC rules. Namely:1207* - If we're past the phase end interaction, select randomly 4 out of the first1208* phNum matches.1209* - Otherwise, select match phNum-1 and select randomly the 3 others out of1210* the first phNum-1 matches.1211*1212* Reads (direct): ctrl.i, ctrl.phEndI, ctrl.phNum1213* Reads (callees): prng.s1214* Writes (direct): ctrl.smpl1215* Writes (callees): prng.s1216*/12171218inline void RHO_HEST_REFC::getPROSACSample(void){1219if(ctrl.i > ctrl.phEndI){1220/* FIXME: Dubious. Review. */1221rndSmpl(4, ctrl.smpl, ctrl.phNum);/* Used to be phMax */1222}else{1223rndSmpl(3, ctrl.smpl, ctrl.phNum-1);1224ctrl.smpl[3] = ctrl.phNum-1;1225}1226}12271228/**1229* Choose, without repetition, sampleSize integers in the range [0, numDataPoints).1230*1231* Reads (direct): None.1232* Reads (callees): prng.s1233* Writes (direct): None.1234* Writes (callees): prng.s1235*/12361237inline void RHO_HEST_REFC::rndSmpl(unsigned sampleSize,1238unsigned* currentSample,1239unsigned dataSetSize){1240/**1241* If sampleSize is very close to dataSetSize, we use selection sampling.1242* Otherwise we use the naive sampling technique wherein we select random1243* indexes until sampleSize of them are distinct.1244*/12451246if(sampleSize*2>dataSetSize){1247/**1248* Selection Sampling:1249*1250* Algorithm S (Selection sampling technique). To select n records at random from a set of N, where 0 < n <= N.1251* S1. [Initialize.] Set t = 0, m = 0. (During this algorithm, m represents the number of records selected so far,1252* and t is the total number of input records that we have dealt with.)1253* S2. [Generate U.] Generate a random number U, uniformly distributed between zero and one.1254* S3. [Test.] If (N - t)U >= n - m, go to step S5.1255* S4. [Select.] Select the next record for the sample, and increase m and t by 1. If m < n, go to step S2;1256* otherwise the sample is complete and the algorithm terminates.1257* S5. [Skip.] Skip the next record (do not include it in the sample), increase t by 1, and go back to step S2.1258*1259* Replaced m with i and t with j in the below code.1260*/12611262unsigned i=0,j=0;12631264for(i=0;i<sampleSize;j++){1265double U=fastRandom();1266if((dataSetSize-j)*U < (sampleSize-i)){1267currentSample[i++]=j;1268}1269}1270}else{1271/**1272* Naive sampling technique. Generate indexes until sampleSize of them are distinct.1273*/12741275unsigned i, j;1276for(i=0;i<sampleSize;i++){1277int inList;12781279do{1280currentSample[i] = (unsigned)(dataSetSize*fastRandom());12811282inList=0;1283for(j=0;j<i;j++){1284if(currentSample[i] == currentSample[j]){1285inList=1;1286break;1287}1288}1289}while(inList);1290}1291}1292}12931294/**1295* Checks whether the *sample* is degenerate prior to model generation.1296* - First, the extremely cheap numerical degeneracy test is run, which weeds1297* out bad samples to the optimized GE implementation.1298* - Second, the geometrical degeneracy test is run, which weeds out most other1299* bad samples.1300*1301* Reads (direct): ctrl.smpl, arg.src, arg.dst1302* Reads (callees): None.1303* Writes (direct): curr.pkdPts1304* Writes (callees): None.1305*/13061307inline int RHO_HEST_REFC::isSampleDegenerate(void){1308unsigned i0 = ctrl.smpl[0], i1 = ctrl.smpl[1], i2 = ctrl.smpl[2], i3 = ctrl.smpl[3];1309typedef struct{float x,y;} MyPt2f;1310MyPt2f* pkdPts = (MyPt2f*)curr.pkdPts, *src = (MyPt2f*)arg.src, *dst = (MyPt2f*)arg.dst;13111312/**1313* Pack the matches selected by the SAC algorithm.1314* Must be packed points[0:7] = {srcx0, srcy0, srcx1, srcy1, srcx2, srcy2, srcx3, srcy3}1315* points[8:15] = {dstx0, dsty0, dstx1, dsty1, dstx2, dsty2, dstx3, dsty3}1316* Gather 4 points into the vector1317*/13181319pkdPts[0] = src[i0];1320pkdPts[1] = src[i1];1321pkdPts[2] = src[i2];1322pkdPts[3] = src[i3];1323pkdPts[4] = dst[i0];1324pkdPts[5] = dst[i1];1325pkdPts[6] = dst[i2];1326pkdPts[7] = dst[i3];13271328/**1329* If the matches' source points have common x and y coordinates, abort.1330*/13311332if(pkdPts[0].x == pkdPts[1].x || pkdPts[1].x == pkdPts[2].x ||1333pkdPts[2].x == pkdPts[3].x || pkdPts[0].x == pkdPts[2].x ||1334pkdPts[1].x == pkdPts[3].x || pkdPts[0].x == pkdPts[3].x ||1335pkdPts[0].y == pkdPts[1].y || pkdPts[1].y == pkdPts[2].y ||1336pkdPts[2].y == pkdPts[3].y || pkdPts[0].y == pkdPts[2].y ||1337pkdPts[1].y == pkdPts[3].y || pkdPts[0].y == pkdPts[3].y){1338return 1;1339}13401341/* If the matches do not satisfy the strong geometric constraint, abort. */1342/* (0 x 1) * 2 */1343float cross0s0 = pkdPts[0].y-pkdPts[1].y;1344float cross0s1 = pkdPts[1].x-pkdPts[0].x;1345float cross0s2 = pkdPts[0].x*pkdPts[1].y-pkdPts[0].y*pkdPts[1].x;1346float dots0 = cross0s0*pkdPts[2].x + cross0s1*pkdPts[2].y + cross0s2;1347float cross0d0 = pkdPts[4].y-pkdPts[5].y;1348float cross0d1 = pkdPts[5].x-pkdPts[4].x;1349float cross0d2 = pkdPts[4].x*pkdPts[5].y-pkdPts[4].y*pkdPts[5].x;1350float dotd0 = cross0d0*pkdPts[6].x + cross0d1*pkdPts[6].y + cross0d2;1351if(((int)dots0^(int)dotd0) < 0){1352return 1;1353}1354/* (0 x 1) * 3 */1355float cross1s0 = cross0s0;1356float cross1s1 = cross0s1;1357float cross1s2 = cross0s2;1358float dots1 = cross1s0*pkdPts[3].x + cross1s1*pkdPts[3].y + cross1s2;1359float cross1d0 = cross0d0;1360float cross1d1 = cross0d1;1361float cross1d2 = cross0d2;1362float dotd1 = cross1d0*pkdPts[7].x + cross1d1*pkdPts[7].y + cross1d2;1363if(((int)dots1^(int)dotd1) < 0){1364return 1;1365}1366/* (2 x 3) * 0 */1367float cross2s0 = pkdPts[2].y-pkdPts[3].y;1368float cross2s1 = pkdPts[3].x-pkdPts[2].x;1369float cross2s2 = pkdPts[2].x*pkdPts[3].y-pkdPts[2].y*pkdPts[3].x;1370float dots2 = cross2s0*pkdPts[0].x + cross2s1*pkdPts[0].y + cross2s2;1371float cross2d0 = pkdPts[6].y-pkdPts[7].y;1372float cross2d1 = pkdPts[7].x-pkdPts[6].x;1373float cross2d2 = pkdPts[6].x*pkdPts[7].y-pkdPts[6].y*pkdPts[7].x;1374float dotd2 = cross2d0*pkdPts[4].x + cross2d1*pkdPts[4].y + cross2d2;1375if(((int)dots2^(int)dotd2) < 0){1376return 1;1377}1378/* (2 x 3) * 1 */1379float cross3s0 = cross2s0;1380float cross3s1 = cross2s1;1381float cross3s2 = cross2s2;1382float dots3 = cross3s0*pkdPts[1].x + cross3s1*pkdPts[1].y + cross3s2;1383float cross3d0 = cross2d0;1384float cross3d1 = cross2d1;1385float cross3d2 = cross2d2;1386float dotd3 = cross3d0*pkdPts[5].x + cross3d1*pkdPts[5].y + cross3d2;1387if(((int)dots3^(int)dotd3) < 0){1388return 1;1389}13901391/* Otherwise, accept */1392return 0;1393}13941395/**1396* Compute homography of matches in gathered, packed sample and output the1397* current homography.1398*1399* Reads (direct): None.1400* Reads (callees): curr.pkdPts1401* Writes (direct): None.1402* Writes (callees): curr.H1403*/14041405inline void RHO_HEST_REFC::generateModel(void){1406hFuncRefC(curr.pkdPts, curr.H);1407}14081409/**1410* Checks whether the model is itself degenerate.1411* - One test: All elements of the homography are added, and if the result is1412* NaN the homography is rejected.1413*1414* Reads (direct): curr.H1415* Reads (callees): None.1416* Writes (direct): None.1417* Writes (callees): None.1418*/14191420inline int RHO_HEST_REFC::isModelDegenerate(void){1421int degenerate;1422float* H = curr.H;1423float f=H[0]+H[1]+H[2]+H[3]+H[4]+H[5]+H[6]+H[7];14241425/* degenerate = isnan(f); */1426/* degenerate = f!=f;// Only NaN is not equal to itself. */1427degenerate = cvIsNaN(f);1428/* degenerate = 0; */142914301431return degenerate;1432}14331434/**1435* Evaluates the current model using SPRT for early exiting.1436*1437* Reads (direct): arg.maxD, arg.src, arg.dst, arg.N, curr.inl, curr.H,1438* ctrl.numModels, eval.Ntestedtotal, eval.lambdaAccept,1439* eval.lambdaReject, eval.A1440* Reads (callees): None.1441* Writes (direct): ctrl.numModels, curr.numInl, eval.Ntested, eval.good,1442* eval.Ntestedtotal1443* Writes (callees): None.1444*/14451446inline void RHO_HEST_REFC::evaluateModelSPRT(void){1447unsigned i;1448unsigned isInlier;1449double lambda = 1.0;1450float distSq = arg.maxD*arg.maxD;1451const float* src = arg.src;1452const float* dst = arg.dst;1453char* inl = curr.inl;1454const float* H = curr.H;145514561457ctrl.numModels++;14581459curr.numInl = 0;1460eval.Ntested = 0;1461eval.good = 1;146214631464/* SCALAR */1465for(i=0;i<arg.N && eval.good;i++){1466/* Backproject */1467float x=src[i*2],y=src[i*2+1];1468float X=dst[i*2],Y=dst[i*2+1];14691470float reprojX=H[0]*x+H[1]*y+H[2]; /* ( X_1 ) ( H_11 H_12 H_13 ) (x_1) */1471float reprojY=H[3]*x+H[4]*y+H[5]; /* ( X_2 ) = ( H_21 H_22 H_23 ) (x_2) */1472float reprojZ=H[6]*x+H[7]*y+1.0f; /* ( X_3 ) ( H_31 H_32 H_33=1.0 ) (x_3 = 1.0) */14731474/* reproj is in homogeneous coordinates. To bring back to "regular" coordinates, divide by Z. */1475reprojX/=reprojZ;1476reprojY/=reprojZ;14771478/* Compute distance */1479reprojX-=X;1480reprojY-=Y;1481reprojX*=reprojX;1482reprojY*=reprojY;1483float reprojDist = reprojX+reprojY;14841485/* ... */1486isInlier = reprojDist <= distSq;1487curr.numInl += isInlier;1488*inl++ = (char)isInlier;148914901491/* SPRT */1492lambda *= isInlier ? eval.lambdaAccept : eval.lambdaReject;1493eval.good = lambda <= eval.A;1494/* If !good, the threshold A was exceeded, so we're rejecting */1495}149614971498eval.Ntested = i;1499eval.Ntestedtotal += i;1500}15011502/**1503* Update either the delta or epsilon SPRT parameters, depending on the events1504* that transpired in the previous evaluation.1505*1506* Reads (direct): eval.good, curr.numInl, arg.N, eval.Ntested, eval.delta1507* Reads (callees): eval.delta, eval.epsilon, eval.t_M, eval.m_S1508* Writes (direct): eval.epsilon, eval.delta1509* Writes (callees): eval.A, eval.lambdaReject, eval.lambdaAccept1510*/15111512inline void RHO_HEST_REFC::updateSPRT(void){1513if(eval.good){1514if(isBestModel()){1515eval.epsilon = (double)curr.numInl/arg.N;1516designSPRTTest();1517}1518}else{1519double newDelta = (double)curr.numInl/eval.Ntested;15201521if(newDelta > 0){1522double relChange = fabs(eval.delta - newDelta)/ eval.delta;1523if(relChange > MIN_DELTA_CHNG){1524eval.delta = newDelta;1525designSPRTTest();1526}1527}1528}1529}15301531/**1532* Numerically compute threshold A from the estimated delta, epsilon, t_M and1533* m_S values.1534*1535* Epsilon: Denotes the probability that a randomly chosen data point is1536* consistent with a good model.1537* Delta: Denotes the probability that a randomly chosen data point is1538* consistent with a bad model.1539* t_M: Time needed to instantiate a model hypotheses given a sample.1540* (Computing model parameters from a sample takes the same time1541* as verification of t_M data points)1542* m_S: The number of models that are verified per sample.1543*/15441545static inline double sacDesignSPRTTest(double delta, double epsilon, double t_M, double m_S){1546double An, C, K, prevAn;1547unsigned i;15481549/**1550* Randomized RANSAC with Sequential Probability Ratio Test, ICCV 20051551* Eq (2)1552*/15531554C = (1-delta) * log((1-delta)/(1-epsilon)) +1555delta * log( delta / epsilon );15561557/**1558* Randomized RANSAC with Sequential Probability Ratio Test, ICCV 20051559* Eq (6)1560* K = K_1/K_2 + 1 = (t_M*C)/m_S + 11561*/15621563K = t_M*C/m_S + 1;15641565/**1566* Randomized RANSAC with Sequential Probability Ratio Test, ICCV 20051567* Paragraph below Eq (6)1568*1569* A* = lim_{n -> infty} A_n, where1570* A_0 = K1/K2 + 1 and1571* A_{n+1} = K1/K2 + 1 + log(A_n)1572* The series converges fast, typically within four iterations.1573*/15741575An = K;1576i = 0;15771578do{1579prevAn = An;1580An = K + log(An);1581}while((An-prevAn > 1.5e-8) && (++i < 10));15821583/**1584* Return A = An_stopping, with n_stopping < 101585*/15861587return An;1588}15891590/**1591* Design the SPRT test. Shorthand for1592* A = sprt(delta, epsilon, t_M, m_S);1593*1594* Idempotent.1595*1596* Reads (direct): eval.delta, eval.epsilon, eval.t_M, eval.m_S1597* Reads (callees): None.1598* Writes (direct): eval.A, eval.lambdaReject, eval.lambdaAccept.1599* Writes (callees): None.1600*/16011602inline void RHO_HEST_REFC::designSPRTTest(void){1603eval.A = sacDesignSPRTTest(eval.delta, eval.epsilon, eval.t_M, eval.m_S);1604eval.lambdaReject = ((1.0 - eval.delta) / (1.0 - eval.epsilon));1605eval.lambdaAccept = (( eval.delta ) / ( eval.epsilon ));1606}16071608/**1609* Return whether the current model is the best model so far.1610*1611* @return Non-zero if this is the model with the most inliers seen so far;1612* 0 otherwise.1613*1614* Reads (direct): curr.numInl, best.numInl1615* Reads (callees): None.1616* Writes (direct): None.1617* Writes (callees): None.1618*/16191620inline int RHO_HEST_REFC::isBestModel(void){1621return curr.numInl > best.numInl;1622}16231624/**1625* Returns whether the current-best model is good enough to be an1626* acceptable best model, by checking whether it meets the minimum1627* number of inliers.1628*1629* @return Non-zero if the current model is "good enough" to save;1630* 0 otherwise.1631*1632* Reads (direct): best.numInl, arg.minInl1633* Reads (callees): None.1634* Writes (direct): None.1635* Writes (callees): None.1636*/16371638inline int RHO_HEST_REFC::isBestModelGoodEnough(void){1639return best.numInl >= arg.minInl;1640}16411642/**1643* Make current model new best model by swapping the homography, inlier mask1644* and count of inliers between the current and best models.1645*1646* Reads (direct): curr.H, curr.inl, curr.numInl,1647* best.H, best.inl, best.numInl1648* Reads (callees): None.1649* Writes (direct): curr.H, curr.inl, curr.numInl,1650* best.H, best.inl, best.numInl1651* Writes (callees): None.1652*/16531654inline void RHO_HEST_REFC::saveBestModel(void){1655float* H = curr.H;1656char* inl = curr.inl;1657unsigned numInl = curr.numInl;16581659curr.H = best.H;1660curr.inl = best.inl;1661curr.numInl = best.numInl;16621663best.H = H;1664best.inl = inl;1665best.numInl = numInl;1666}16671668/**1669* Compute NR table entries [start, N) for given beta.1670*/16711672static inline void sacInitNonRand(double beta,1673unsigned start,1674unsigned N,1675unsigned* nonRandMinInl){1676unsigned n = SMPL_SIZE+1 > start ? SMPL_SIZE+1 : start;1677double beta_beta1_sq_chi = sqrt(beta*(1.0-beta)) * CHI_SQ;16781679for(; n < N; n++){1680double mu = n * beta;1681double sigma = sqrt((double)n)* beta_beta1_sq_chi;1682unsigned i_min = (unsigned)ceil(SMPL_SIZE + mu + sigma);16831684nonRandMinInl[n] = i_min;1685}1686}16871688/**1689* Optimize the stopping criterion to account for the non-randomness criterion1690* of PROSAC.1691*1692* Reads (direct): arg.N, best.numInl, nr.tbl, arg.inl, ctrl.phMax,1693* ctrl.phNumInl, arg.cfd, arg.maxI1694* Reads (callees): None.1695* Writes (direct): arg.maxI, ctrl.phMax, ctrl.phNumInl1696* Writes (callees): None.1697*/16981699inline void RHO_HEST_REFC::nStarOptimize(void){1700unsigned min_sample_length = 10*2; /*(N * INLIERS_RATIO) */1701unsigned best_n = arg.N;1702unsigned test_n = best_n;1703unsigned bestNumInl = best.numInl;1704unsigned testNumInl = bestNumInl;17051706for(;test_n > min_sample_length && testNumInl;test_n--){1707if(testNumInl*best_n > bestNumInl*test_n){1708if(testNumInl < nr.tbl[test_n]){1709break;1710}1711best_n = test_n;1712bestNumInl = testNumInl;1713}1714testNumInl -= !!best.inl[test_n-1];1715}17161717if(bestNumInl*ctrl.phMax > ctrl.phNumInl*best_n){1718ctrl.phMax = best_n;1719ctrl.phNumInl = bestNumInl;1720arg.maxI = sacCalcIterBound(arg.cfd,1721(double)ctrl.phNumInl/ctrl.phMax,1722SMPL_SIZE,1723arg.maxI);1724}1725}17261727/**1728* Classic RANSAC iteration bound based on largest # of inliers.1729*1730* Reads (direct): arg.maxI, arg.cfd, best.numInl, arg.N1731* Reads (callees): None.1732* Writes (direct): arg.maxI1733* Writes (callees): None.1734*/17351736inline void RHO_HEST_REFC::updateBounds(void){1737arg.maxI = sacCalcIterBound(arg.cfd,1738(double)best.numInl/arg.N,1739SMPL_SIZE,1740arg.maxI);1741}17421743/**1744* Output the best model so far to the output argument.1745*1746* Reads (direct): arg.finalH, best.H, arg.inl, best.inl, arg.N1747* Reads (callees): arg.finalH, arg.inl, arg.N1748* Writes (direct): arg.finalH, arg.inl1749* Writes (callees): arg.finalH, arg.inl1750*/17511752inline void RHO_HEST_REFC::outputModel(void){1753if(isBestModelGoodEnough()){1754memcpy(arg.finalH, best.H, HSIZE);1755if(arg.inl){1756memcpy(arg.inl, best.inl, arg.N);1757}1758}else{1759outputZeroH();1760}1761}17621763/**1764* Output a zeroed H to the output argument.1765*1766* Reads (direct): arg.finalH, arg.inl, arg.N1767* Reads (callees): None.1768* Writes (direct): arg.finalH, arg.inl1769* Writes (callees): None.1770*/17711772inline void RHO_HEST_REFC::outputZeroH(void){1773if(arg.finalH){1774memset(arg.finalH, 0, HSIZE);1775}1776if(arg.inl){1777memset(arg.inl, 0, arg.N);1778}1779}17801781/**1782* Compute the real-valued number of samples per phase, given the RANSAC convergence speed,1783* data set size and sample size.1784*/17851786static inline double sacInitPEndFpI(const unsigned ransacConvg,1787const unsigned n,1788const unsigned s){1789double numer=1, denom=1;17901791unsigned i;1792for(i=0;i<s;i++){1793numer *= s-i;1794denom *= n-i;1795}17961797return ransacConvg*numer/denom;1798}17991800/**1801* Estimate the number of iterations required based on the requested confidence,1802* proportion of inliers in the best model so far and sample size.1803*1804* Clamp return value at maxIterationBound.1805*/18061807static inline unsigned sacCalcIterBound(double confidence,1808double inlierRate,1809unsigned sampleSize,1810unsigned maxIterBound){1811unsigned retVal;18121813/**1814* Formula chosen from http://en.wikipedia.org/wiki/RANSAC#The_parameters :1815*1816* \[ k = \frac{\log{(1-confidence)}}{\log{(1-inlierRate**sampleSize)}} \]1817*/18181819double atLeastOneOutlierProbability = 1.-pow(inlierRate, (double)sampleSize);18201821/**1822* There are two special cases: When argument to log() is 0 and when it is 1.1823* Each has a special meaning.1824*/18251826if(atLeastOneOutlierProbability>=1.){1827/**1828* A certainty of picking at least one outlier means that we will need1829* an infinite amount of iterations in order to find a correct solution.1830*/18311832retVal = maxIterBound;1833}else if(atLeastOneOutlierProbability<=0.){1834/**1835* The certainty of NOT picking an outlier means that only 1 iteration1836* is needed to find a solution.1837*/18381839retVal = 1;1840}else{1841/**1842* Since 1-confidence (the probability of the model being based on at1843* least one outlier in the data) is equal to1844* (1-inlierRate**sampleSize)**numIterations (the probability of picking1845* at least one outlier in numIterations samples), we can isolate1846* numIterations (the return value) into1847*/18481849retVal = (unsigned)ceil(log(1.-confidence)/log(atLeastOneOutlierProbability));1850}18511852/**1853* Clamp to maxIterationBound.1854*/18551856return retVal <= maxIterBound ? retVal : maxIterBound;1857}185818591860/**1861* Given 4 matches, computes the homography that relates them using Gaussian1862* Elimination. The row operations are as given in the paper.1863*1864* TODO: Clean this up. The code is hideous, and might even conceal sign bugs1865* (specifically relating to whether the last column should be negated,1866* or not).1867*/18681869static void hFuncRefC(float* packedPoints,/* Source (four x,y float coordinates) points followed by1870destination (four x,y float coordinates) points, aligned by 32 bytes */1871float* H){ /* Homography (three 16-byte aligned rows of 3 floats) */1872float x0=*packedPoints++;1873float y0=*packedPoints++;1874float x1=*packedPoints++;1875float y1=*packedPoints++;1876float x2=*packedPoints++;1877float y2=*packedPoints++;1878float x3=*packedPoints++;1879float y3=*packedPoints++;1880float X0=*packedPoints++;1881float Y0=*packedPoints++;1882float X1=*packedPoints++;1883float Y1=*packedPoints++;1884float X2=*packedPoints++;1885float Y2=*packedPoints++;1886float X3=*packedPoints++;1887float Y3=*packedPoints++;18881889float x0X0=x0*X0, x1X1=x1*X1, x2X2=x2*X2, x3X3=x3*X3;1890float x0Y0=x0*Y0, x1Y1=x1*Y1, x2Y2=x2*Y2, x3Y3=x3*Y3;1891float y0X0=y0*X0, y1X1=y1*X1, y2X2=y2*X2, y3X3=y3*X3;1892float y0Y0=y0*Y0, y1Y1=y1*Y1, y2Y2=y2*Y2, y3Y3=y3*Y3;189318941895/**1896* [0] [1] Hidden Prec1897* x0 y0 1 x11898* x1 y1 1 x11899* x2 y2 1 x11900* x3 y3 1 x11901*1902* Eliminate ones in column 2 and 5.1903* R(0)-=R(2)1904* R(1)-=R(2)1905* R(3)-=R(2)1906*1907* [0] [1] Hidden Prec1908* x0-x2 y0-y2 0 x1+11909* x1-x2 y1-y2 0 x1+11910* x2 y2 1 x11911* x3-x2 y3-y2 0 x1+11912*1913* Eliminate column 0 of rows 1 and 31914* R(1)=(x0-x2)*R(1)-(x1-x2)*R(0), y1'=(y1-y2)(x0-x2)-(x1-x2)(y0-y2)1915* R(3)=(x0-x2)*R(3)-(x3-x2)*R(0), y3'=(y3-y2)(x0-x2)-(x3-x2)(y0-y2)1916*1917* [0] [1] Hidden Prec1918* x0-x2 y0-y2 0 x1+11919* 0 y1' 0 x2+31920* x2 y2 1 x11921* 0 y3' 0 x2+31922*1923* Eliminate column 1 of rows 0 and 31924* R(3)=y1'*R(3)-y3'*R(1)1925* R(0)=y1'*R(0)-(y0-y2)*R(1)1926*1927* [0] [1] Hidden Prec1928* x0' 0 0 x3+51929* 0 y1' 0 x2+31930* x2 y2 1 x11931* 0 0 0 x4+71932*1933* Eliminate columns 0 and 1 of row 21934* R(0)/=x0'1935* R(1)/=y1'1936* R(2)-= (x2*R(0) + y2*R(1))1937*1938* [0] [1] Hidden Prec1939* 1 0 0 x6+101940* 0 1 0 x4+61941* 0 0 1 x4+71942* 0 0 0 x4+71943*/19441945/**1946* Eliminate ones in column 2 and 5.1947* R(0)-=R(2)1948* R(1)-=R(2)1949* R(3)-=R(2)1950*/19511952/*float minor[4][2] = {{x0-x2,y0-y2},1953{x1-x2,y1-y2},1954{x2 ,y2 },1955{x3-x2,y3-y2}};*/1956/*float major[8][3] = {{x2X2-x0X0,y2X2-y0X0,(X0-X2)},1957{x2X2-x1X1,y2X2-y1X1,(X1-X2)},1958{-x2X2 ,-y2X2 ,(X2 )},1959{x2X2-x3X3,y2X2-y3X3,(X3-X2)},1960{x2Y2-x0Y0,y2Y2-y0Y0,(Y0-Y2)},1961{x2Y2-x1Y1,y2Y2-y1Y1,(Y1-Y2)},1962{-x2Y2 ,-y2Y2 ,(Y2 )},1963{x2Y2-x3Y3,y2Y2-y3Y3,(Y3-Y2)}};*/1964float minor[2][4] = {{x0-x2,x1-x2,x2 ,x3-x2},1965{y0-y2,y1-y2,y2 ,y3-y2}};1966float major[3][8] = {{x2X2-x0X0,x2X2-x1X1,-x2X2 ,x2X2-x3X3,x2Y2-x0Y0,x2Y2-x1Y1,-x2Y2 ,x2Y2-x3Y3},1967{y2X2-y0X0,y2X2-y1X1,-y2X2 ,y2X2-y3X3,y2Y2-y0Y0,y2Y2-y1Y1,-y2Y2 ,y2Y2-y3Y3},1968{ (X0-X2) , (X1-X2) , (X2 ) , (X3-X2) , (Y0-Y2) , (Y1-Y2) , (Y2 ) , (Y3-Y2) }};19691970/**1971* int i;1972* for(i=0;i<8;i++) major[2][i]=-major[2][i];1973* Eliminate column 0 of rows 1 and 31974* R(1)=(x0-x2)*R(1)-(x1-x2)*R(0), y1'=(y1-y2)(x0-x2)-(x1-x2)(y0-y2)1975* R(3)=(x0-x2)*R(3)-(x3-x2)*R(0), y3'=(y3-y2)(x0-x2)-(x3-x2)(y0-y2)1976*/19771978float scalar1=minor[0][0], scalar2=minor[0][1];1979minor[1][1]=minor[1][1]*scalar1-minor[1][0]*scalar2;19801981major[0][1]=major[0][1]*scalar1-major[0][0]*scalar2;1982major[1][1]=major[1][1]*scalar1-major[1][0]*scalar2;1983major[2][1]=major[2][1]*scalar1-major[2][0]*scalar2;19841985major[0][5]=major[0][5]*scalar1-major[0][4]*scalar2;1986major[1][5]=major[1][5]*scalar1-major[1][4]*scalar2;1987major[2][5]=major[2][5]*scalar1-major[2][4]*scalar2;19881989scalar2=minor[0][3];1990minor[1][3]=minor[1][3]*scalar1-minor[1][0]*scalar2;19911992major[0][3]=major[0][3]*scalar1-major[0][0]*scalar2;1993major[1][3]=major[1][3]*scalar1-major[1][0]*scalar2;1994major[2][3]=major[2][3]*scalar1-major[2][0]*scalar2;19951996major[0][7]=major[0][7]*scalar1-major[0][4]*scalar2;1997major[1][7]=major[1][7]*scalar1-major[1][4]*scalar2;1998major[2][7]=major[2][7]*scalar1-major[2][4]*scalar2;19992000/**2001* Eliminate column 1 of rows 0 and 32002* R(3)=y1'*R(3)-y3'*R(1)2003* R(0)=y1'*R(0)-(y0-y2)*R(1)2004*/20052006scalar1=minor[1][1];scalar2=minor[1][3];2007major[0][3]=major[0][3]*scalar1-major[0][1]*scalar2;2008major[1][3]=major[1][3]*scalar1-major[1][1]*scalar2;2009major[2][3]=major[2][3]*scalar1-major[2][1]*scalar2;20102011major[0][7]=major[0][7]*scalar1-major[0][5]*scalar2;2012major[1][7]=major[1][7]*scalar1-major[1][5]*scalar2;2013major[2][7]=major[2][7]*scalar1-major[2][5]*scalar2;20142015scalar2=minor[1][0];2016minor[0][0]=minor[0][0]*scalar1-minor[0][1]*scalar2;20172018major[0][0]=major[0][0]*scalar1-major[0][1]*scalar2;2019major[1][0]=major[1][0]*scalar1-major[1][1]*scalar2;2020major[2][0]=major[2][0]*scalar1-major[2][1]*scalar2;20212022major[0][4]=major[0][4]*scalar1-major[0][5]*scalar2;2023major[1][4]=major[1][4]*scalar1-major[1][5]*scalar2;2024major[2][4]=major[2][4]*scalar1-major[2][5]*scalar2;20252026/**2027* Eliminate columns 0 and 1 of row 22028* R(0)/=x0'2029* R(1)/=y1'2030* R(2)-= (x2*R(0) + y2*R(1))2031*/20322033scalar1=1.0f/minor[0][0];2034major[0][0]*=scalar1;2035major[1][0]*=scalar1;2036major[2][0]*=scalar1;2037major[0][4]*=scalar1;2038major[1][4]*=scalar1;2039major[2][4]*=scalar1;20402041scalar1=1.0f/minor[1][1];2042major[0][1]*=scalar1;2043major[1][1]*=scalar1;2044major[2][1]*=scalar1;2045major[0][5]*=scalar1;2046major[1][5]*=scalar1;2047major[2][5]*=scalar1;204820492050scalar1=minor[0][2];scalar2=minor[1][2];2051major[0][2]-=major[0][0]*scalar1+major[0][1]*scalar2;2052major[1][2]-=major[1][0]*scalar1+major[1][1]*scalar2;2053major[2][2]-=major[2][0]*scalar1+major[2][1]*scalar2;20542055major[0][6]-=major[0][4]*scalar1+major[0][5]*scalar2;2056major[1][6]-=major[1][4]*scalar1+major[1][5]*scalar2;2057major[2][6]-=major[2][4]*scalar1+major[2][5]*scalar2;20582059/* Only major matters now. R(3) and R(7) correspond to the hollowed-out rows. */2060scalar1=major[0][7];2061major[1][7]/=scalar1;2062major[2][7]/=scalar1;20632064scalar1=major[0][0];major[1][0]-=scalar1*major[1][7];major[2][0]-=scalar1*major[2][7];2065scalar1=major[0][1];major[1][1]-=scalar1*major[1][7];major[2][1]-=scalar1*major[2][7];2066scalar1=major[0][2];major[1][2]-=scalar1*major[1][7];major[2][2]-=scalar1*major[2][7];2067scalar1=major[0][3];major[1][3]-=scalar1*major[1][7];major[2][3]-=scalar1*major[2][7];2068scalar1=major[0][4];major[1][4]-=scalar1*major[1][7];major[2][4]-=scalar1*major[2][7];2069scalar1=major[0][5];major[1][5]-=scalar1*major[1][7];major[2][5]-=scalar1*major[2][7];2070scalar1=major[0][6];major[1][6]-=scalar1*major[1][7];major[2][6]-=scalar1*major[2][7];207120722073/* One column left (Two in fact, but the last one is the homography) */2074scalar1=major[1][3];20752076major[2][3]/=scalar1;2077scalar1=major[1][0];major[2][0]-=scalar1*major[2][3];2078scalar1=major[1][1];major[2][1]-=scalar1*major[2][3];2079scalar1=major[1][2];major[2][2]-=scalar1*major[2][3];2080scalar1=major[1][4];major[2][4]-=scalar1*major[2][3];2081scalar1=major[1][5];major[2][5]-=scalar1*major[2][3];2082scalar1=major[1][6];major[2][6]-=scalar1*major[2][3];2083scalar1=major[1][7];major[2][7]-=scalar1*major[2][3];208420852086/* Homography is done. */2087H[0]=major[2][0];2088H[1]=major[2][1];2089H[2]=major[2][2];20902091H[3]=major[2][4];2092H[4]=major[2][5];2093H[5]=major[2][6];20942095H[6]=major[2][7];2096H[7]=major[2][3];2097H[8]=1.0;2098}209921002101/**2102* Returns whether refinement is possible.2103*2104* NB This is separate from whether it is *enabled*.2105*2106* @return 0 if refinement isn't possible, non-zero otherwise.2107*2108* Reads (direct): best.numInl2109* Reads (callees): None.2110* Writes (direct): None.2111* Writes (callees): None.2112*/21132114inline int RHO_HEST_REFC::canRefine(void){2115/**2116* If we only have 4 matches, GE's result is already optimal and cannot2117* be refined any further.2118*/21192120return best.numInl > (unsigned)SMPL_SIZE;2121}212221232124/**2125* Refines the best-so-far homography (p->best.H).2126*2127* Reads (direct): best.H, arg.src, arg.dst, best.inl, arg.N, lm.JtJ,2128* lm.Jte, lm.tmp12129* Reads (callees): None.2130* Writes (direct): best.H, lm.JtJ, lm.Jte, lm.tmp12131* Writes (callees): None.2132*/21332134inline void RHO_HEST_REFC::refine(void){2135int i;2136float S, newS; /* Sum of squared errors */2137float gain; /* Gain-parameter. */2138float L = 100.0f;/* Lambda of LevMarq */2139float dH[8], newH[8];21402141/**2142* Iteratively refine the homography.2143*/2144/* Find initial conditions */2145sacCalcJacobianErrors(best.H, arg.src, arg.dst, best.inl, arg.N,2146lm.JtJ, lm.Jte, &S);21472148/*Levenberg-Marquardt Loop.*/2149for(i=0;i<MAXLEVMARQITERS;i++){2150/**2151* Attempt a step given current state2152* - Jacobian-x-Jacobian (JtJ)2153* - Jacobian-x-error (Jte)2154* - Sum of squared errors (S)2155* and current parameter2156* - Lambda (L)2157* .2158*2159* This is done by solving the system of equations2160* Ax = b2161* where A (JtJ) and b (Jte) are sourced from our current state, and2162* the solution x becomes a step (dH) that is applied to best.H in2163* order to compute a candidate homography (newH).2164*2165* The system above is solved by Cholesky decomposition of a2166* sufficently-damped JtJ into a lower-triangular matrix (and its2167* transpose), whose inverse is then computed. This inverse (and its2168* transpose) then multiply Jte in order to find dH.2169*/21702171while(!sacChol8x8Damped(lm.JtJ, L, lm.tmp1)){2172L *= 2.0f;2173}2174sacTRInv8x8 (lm.tmp1, lm.tmp1);2175sacTRISolve8x8(lm.tmp1, lm.Jte, dH);2176sacSub8x1 (newH, best.H, dH);2177sacCalcJacobianErrors(newH, arg.src, arg.dst, best.inl, arg.N,2178NULL, NULL, &newS);2179gain = sacLMGain(dH, lm.Jte, S, newS, L);2180/*printf("Lambda: %12.6f S: %12.6f newS: %12.6f Gain: %12.6f\n",2181L, S, newS, gain);*/21822183/**2184* If the gain is positive (i.e., the new Sum of Square Errors (newS)2185* corresponding to newH is lower than the previous one (S) ), save2186* the current state and accept the new step dH.2187*2188* If the gain is below LM_GAIN_LO, damp more (increase L), even if the2189* gain was positive. If the gain is above LM_GAIN_HI, damp less2190* (decrease L). Otherwise the gain is left unchanged.2191*/21922193if(gain < LM_GAIN_LO){2194L *= 8;2195if(L>1000.0f/FLT_EPSILON){2196break;/* FIXME: Most naive termination criterion imaginable. */2197}2198}else if(gain > LM_GAIN_HI){2199L *= 0.5;2200}22012202if(gain > 0){2203S = newS;2204memcpy(best.H, newH, sizeof(newH));2205sacCalcJacobianErrors(best.H, arg.src, arg.dst, best.inl, arg.N,2206lm.JtJ, lm.Jte, &S);2207}2208}2209}221022112212/**2213* Compute directly the JtJ, Jte and sum-of-squared-error for a given2214* homography and set of inliers.2215*2216* This is possible because the product of J and its transpose as well as with2217* the error and the sum-of-squared-error can all be computed additively2218* (match-by-match), as one would intuitively expect; All matches make2219* contributions to the error independently of each other.2220*2221* What this allows is a constant-space implementation of Lev-Marq that can2222* nevertheless be vectorized if need be.2223*/22242225static inline void sacCalcJacobianErrors(const float* H,2226const float* src,2227const float* dst,2228const char* inl,2229unsigned N,2230float (* JtJ)[8],2231float* Jte,2232float* Sp){2233unsigned i;2234float S;22352236/* Zero out JtJ, Jte and S */2237if(JtJ){memset(JtJ, 0, 8*8*sizeof(float));}2238if(Jte){memset(Jte, 0, 8*1*sizeof(float));}2239S = 0.0f;22402241/* Additively compute JtJ and Jte */2242for(i=0;i<N;i++){2243/* Skip outliers */2244if(!inl[i]){2245continue;2246}22472248/**2249* Otherwise, compute additively the upper triangular matrix JtJ and2250* the Jtd vector within the following formula:2251*2252* LaTeX:2253* (J^{T}J + \lambda \diag( J^{T}J )) \beta = J^{T}[ y - f(\Beta) ]2254* Simplified ASCII:2255* (JtJ + L*diag(JtJ)) beta = Jt e, where e (error) is y-f(Beta).2256*2257* For this we need to calculate2258* 1) The 2D error (e) of the homography on the current point i2259* using the current parameters Beta.2260* 2) The derivatives (J) of the error on the current point i under2261* perturbations of the current parameters Beta.2262* Accumulate products of the error times the derivative to Jte, and2263* products of the derivatives to JtJ.2264*/22652266/* Compute Squared Error */2267float x = src[2*i+0];2268float y = src[2*i+1];2269float X = dst[2*i+0];2270float Y = dst[2*i+1];2271float W = (H[6]*x + H[7]*y + 1.0f);2272float iW = fabs(W) > FLT_EPSILON ? 1.0f/W : 0;22732274float reprojX = (H[0]*x + H[1]*y + H[2]) * iW;2275float reprojY = (H[3]*x + H[4]*y + H[5]) * iW;22762277float eX = reprojX - X;2278float eY = reprojY - Y;2279float e = eX*eX + eY*eY;2280S += e;22812282/* Compute Jacobian */2283if(JtJ || Jte){2284float dxh11 = x * iW;2285float dxh12 = y * iW;2286float dxh13 = iW;2287/*float dxh21 = 0.0f;*/2288/*float dxh22 = 0.0f;*/2289/*float dxh23 = 0.0f;*/2290float dxh31 = -reprojX*x * iW;2291float dxh32 = -reprojX*y * iW;22922293/*float dyh11 = 0.0f;*/2294/*float dyh12 = 0.0f;*/2295/*float dyh13 = 0.0f;*/2296float dyh21 = x * iW;2297float dyh22 = y * iW;2298float dyh23 = iW;2299float dyh31 = -reprojY*x * iW;2300float dyh32 = -reprojY*y * iW;23012302/* Update Jte: X Y */2303if(Jte){2304Jte[0] += eX *dxh11 ;/* +0 */2305Jte[1] += eX *dxh12 ;/* +0 */2306Jte[2] += eX *dxh13 ;/* +0 */2307Jte[3] += eY *dyh21;/* 0+ */2308Jte[4] += eY *dyh22;/* 0+ */2309Jte[5] += eY *dyh23;/* 0+ */2310Jte[6] += eX *dxh31 + eY *dyh31;/* + */2311Jte[7] += eX *dxh32 + eY *dyh32;/* + */2312}23132314/* Update JtJ: X Y */2315if(JtJ){2316JtJ[0][0] += dxh11*dxh11 ;/* +0 */23172318JtJ[1][0] += dxh11*dxh12 ;/* +0 */2319JtJ[1][1] += dxh12*dxh12 ;/* +0 */23202321JtJ[2][0] += dxh11*dxh13 ;/* +0 */2322JtJ[2][1] += dxh12*dxh13 ;/* +0 */2323JtJ[2][2] += dxh13*dxh13 ;/* +0 */23242325/*JtJ[3][0] += ; 0+0 */2326/*JtJ[3][1] += ; 0+0 */2327/*JtJ[3][2] += ; 0+0 */2328JtJ[3][3] += dyh21*dyh21;/* 0+ */23292330/*JtJ[4][0] += ; 0+0 */2331/*JtJ[4][1] += ; 0+0 */2332/*JtJ[4][2] += ; 0+0 */2333JtJ[4][3] += dyh21*dyh22;/* 0+ */2334JtJ[4][4] += dyh22*dyh22;/* 0+ */23352336/*JtJ[5][0] += ; 0+0 */2337/*JtJ[5][1] += ; 0+0 */2338/*JtJ[5][2] += ; 0+0 */2339JtJ[5][3] += dyh21*dyh23;/* 0+ */2340JtJ[5][4] += dyh22*dyh23;/* 0+ */2341JtJ[5][5] += dyh23*dyh23;/* 0+ */23422343JtJ[6][0] += dxh11*dxh31 ;/* +0 */2344JtJ[6][1] += dxh12*dxh31 ;/* +0 */2345JtJ[6][2] += dxh13*dxh31 ;/* +0 */2346JtJ[6][3] += dyh21*dyh31;/* 0+ */2347JtJ[6][4] += dyh22*dyh31;/* 0+ */2348JtJ[6][5] += dyh23*dyh31;/* 0+ */2349JtJ[6][6] += dxh31*dxh31 + dyh31*dyh31;/* + */23502351JtJ[7][0] += dxh11*dxh32 ;/* +0 */2352JtJ[7][1] += dxh12*dxh32 ;/* +0 */2353JtJ[7][2] += dxh13*dxh32 ;/* +0 */2354JtJ[7][3] += dyh21*dyh32;/* 0+ */2355JtJ[7][4] += dyh22*dyh32;/* 0+ */2356JtJ[7][5] += dyh23*dyh32;/* 0+ */2357JtJ[7][6] += dxh31*dxh32 + dyh31*dyh32;/* + */2358JtJ[7][7] += dxh32*dxh32 + dyh32*dyh32;/* + */2359}2360}2361}23622363if(Sp){*Sp = S;}2364}236523662367/**2368* Compute the Levenberg-Marquardt "gain" obtained by the given step dH.2369*2370* Drawn from http://www2.imm.dtu.dk/documents/ftp/tr99/tr05_99.pdf.2371*/23722373static inline float sacLMGain(const float* dH,2374const float* Jte,2375const float S,2376const float newS,2377const float lambda){2378float dS = S-newS;2379float dL = 0;2380int i;23812382/* Compute h^t h... */2383for(i=0;i<8;i++){2384dL += dH[i]*dH[i];2385}2386/* Compute mu * h^t h... */2387dL *= lambda;2388/* Subtract h^t F'... */2389for(i=0;i<8;i++){2390dL += dH[i]*Jte[i];/* += as opposed to -=, since dH we compute is2391opposite sign. */2392}2393/* Multiply by 1/2... */2394dL *= 0.5;23952396/* Return gain as S-newS / L0 - LH. */2397return fabs(dL) < FLT_EPSILON ? dS : dS / dL;2398}239924002401/**2402* Cholesky decomposition on 8x8 real positive-definite matrix defined by its2403* lower-triangular half. Outputs L, the lower triangular part of the2404* decomposition.2405*2406* A and L can overlap fully (in-place) or not at all, but may not partially2407* overlap.2408*2409* For damping, the diagonal elements are scaled by 1.0 + lambda.2410*2411* Returns zero if decomposition unsuccessful, and non-zero otherwise.2412*2413* Source: http://en.wikipedia.org/wiki/Cholesky_decomposition#2414* The_Cholesky.E2.80.93Banachiewicz_and_Cholesky.E2.80.93Crout_algorithms2415*/24162417static inline int sacChol8x8Damped(const float (*A)[8],2418float lambda,2419float (*L)[8]){2420const int N = 8;2421int i, j, k;2422float lambdap1 = lambda + 1.0f;2423float x;24242425for(i=0;i<N;i++){/* Row */2426/* Pre-diagonal elements */2427for(j=0;j<i;j++){2428x = A[i][j]; /* Aij */2429for(k=0;k<j;k++){2430x -= L[i][k] * L[j][k];/* - Sum_{k=0..j-1} Lik*Ljk */2431}2432L[i][j] = x / L[j][j]; /* Lij = ... / Ljj */2433}24342435/* Diagonal element */2436{j = i;2437x = A[j][j] * lambdap1; /* Ajj */2438for(k=0;k<j;k++){2439x -= L[j][k] * L[j][k];/* - Sum_{k=0..j-1} Ljk^2 */2440}2441if(x<0){2442return 0;2443}2444L[j][j] = sqrtf(x); /* Ljj = sqrt( ... ) */2445}2446}24472448return 1;2449}245024512452/**2453* Invert lower-triangular 8x8 matrix L into lower-triangular matrix M.2454*2455* L and M can overlap fully (in-place) or not at all, but may not partially2456* overlap.2457*2458* Uses formulation from2459* http://www.cs.berkeley.edu/~knight/knight_math221_poster.pdf2460* , adjusted for the fact that A^T^-1 = A^-1^T. Thus:2461*2462* U11 U12 U11^-1 -U11^-1*U12*U22^-12463* ->2464* 0 U22 0 U22^-12465*2466* Becomes2467*2468* L11 0 L11^-1 02469* ->2470* L21 L22 -L22^-1*L21*L11^-1 L22^-12471*2472* Since2473*2474* ( -L11^T^-1*L21^T*L22^T^-1 )^T = -L22^T^-1^T*L21^T^T*L11^T^-1^T2475* = -L22^T^T^-1*L21^T^T*L11^T^T^-12476* = -L22^-1*L21*L11^-12477*/24782479static inline void sacTRInv8x8(const float (*L)[8],2480float (*M)[8]){2481float s[2][2], t[2][2];2482float u[4][4], v[4][4];24832484/*2485L00 0 0 0 0 0 0 02486L10 L11 0 0 0 0 0 02487L20 L21 L22 0 0 0 0 02488L30 L31 L32 L33 0 0 0 02489L40 L41 L42 L43 L44 0 0 02490L50 L51 L52 L53 L54 L55 0 02491L60 L61 L62 L63 L64 L65 L66 02492L70 L71 L72 L73 L74 L75 L76 L772493*/24942495/* Invert 4*2 1x1 matrices; Starts recursion. */2496M[0][0] = 1.0f/L[0][0];2497M[1][1] = 1.0f/L[1][1];2498M[2][2] = 1.0f/L[2][2];2499M[3][3] = 1.0f/L[3][3];2500M[4][4] = 1.0f/L[4][4];2501M[5][5] = 1.0f/L[5][5];2502M[6][6] = 1.0f/L[6][6];2503M[7][7] = 1.0f/L[7][7];25042505/*2506M00 0 0 0 0 0 0 02507L10 M11 0 0 0 0 0 02508L20 L21 M22 0 0 0 0 02509L30 L31 L32 M33 0 0 0 02510L40 L41 L42 L43 M44 0 0 02511L50 L51 L52 L53 L54 M55 0 02512L60 L61 L62 L63 L64 L65 M66 02513L70 L71 L72 L73 L74 L75 L76 M772514*/25152516/* 4*2 Matrix products of 1x1 matrices */2517M[1][0] = -M[1][1]*L[1][0]*M[0][0];2518M[3][2] = -M[3][3]*L[3][2]*M[2][2];2519M[5][4] = -M[5][5]*L[5][4]*M[4][4];2520M[7][6] = -M[7][7]*L[7][6]*M[6][6];25212522/*2523M00 0 0 0 0 0 0 02524M10 M11 0 0 0 0 0 02525L20 L21 M22 0 0 0 0 02526L30 L31 M32 M33 0 0 0 02527L40 L41 L42 L43 M44 0 0 02528L50 L51 L52 L53 M54 M55 0 02529L60 L61 L62 L63 L64 L65 M66 02530L70 L71 L72 L73 L74 L75 M76 M772531*/25322533/* 2*2 Matrix products of 2x2 matrices */25342535/*2536(M22 0 ) (L20 L21) (M00 0 )2537- (M32 M33) x (L30 L31) x (M10 M11)2538*/25392540s[0][0] = M[2][2]*L[2][0];2541s[0][1] = M[2][2]*L[2][1];2542s[1][0] = M[3][2]*L[2][0]+M[3][3]*L[3][0];2543s[1][1] = M[3][2]*L[2][1]+M[3][3]*L[3][1];25442545t[0][0] = s[0][0]*M[0][0]+s[0][1]*M[1][0];2546t[0][1] = s[0][1]*M[1][1];2547t[1][0] = s[1][0]*M[0][0]+s[1][1]*M[1][0];2548t[1][1] = s[1][1]*M[1][1];25492550M[2][0] = -t[0][0];2551M[2][1] = -t[0][1];2552M[3][0] = -t[1][0];2553M[3][1] = -t[1][1];25542555/*2556(M66 0 ) (L64 L65) (M44 0 )2557- (L76 M77) x (L74 L75) x (M54 M55)2558*/25592560s[0][0] = M[6][6]*L[6][4];2561s[0][1] = M[6][6]*L[6][5];2562s[1][0] = M[7][6]*L[6][4]+M[7][7]*L[7][4];2563s[1][1] = M[7][6]*L[6][5]+M[7][7]*L[7][5];25642565t[0][0] = s[0][0]*M[4][4]+s[0][1]*M[5][4];2566t[0][1] = s[0][1]*M[5][5];2567t[1][0] = s[1][0]*M[4][4]+s[1][1]*M[5][4];2568t[1][1] = s[1][1]*M[5][5];25692570M[6][4] = -t[0][0];2571M[6][5] = -t[0][1];2572M[7][4] = -t[1][0];2573M[7][5] = -t[1][1];25742575/*2576M00 0 0 0 0 0 0 02577M10 M11 0 0 0 0 0 02578M20 M21 M22 0 0 0 0 02579M30 M31 M32 M33 0 0 0 02580L40 L41 L42 L43 M44 0 0 02581L50 L51 L52 L53 M54 M55 0 02582L60 L61 L62 L63 M64 M65 M66 02583L70 L71 L72 L73 M74 M75 M76 M772584*/25852586/* 1*2 Matrix products of 4x4 matrices */25872588/*2589(M44 0 0 0 ) (L40 L41 L42 L43) (M00 0 0 0 )2590(M54 M55 0 0 ) (L50 L51 L52 L53) (M10 M11 0 0 )2591(M64 M65 M66 0 ) (L60 L61 L62 L63) (M20 M21 M22 0 )2592- (M74 M75 M76 M77) x (L70 L71 L72 L73) x (M30 M31 M32 M33)2593*/25942595u[0][0] = M[4][4]*L[4][0];2596u[0][1] = M[4][4]*L[4][1];2597u[0][2] = M[4][4]*L[4][2];2598u[0][3] = M[4][4]*L[4][3];2599u[1][0] = M[5][4]*L[4][0]+M[5][5]*L[5][0];2600u[1][1] = M[5][4]*L[4][1]+M[5][5]*L[5][1];2601u[1][2] = M[5][4]*L[4][2]+M[5][5]*L[5][2];2602u[1][3] = M[5][4]*L[4][3]+M[5][5]*L[5][3];2603u[2][0] = M[6][4]*L[4][0]+M[6][5]*L[5][0]+M[6][6]*L[6][0];2604u[2][1] = M[6][4]*L[4][1]+M[6][5]*L[5][1]+M[6][6]*L[6][1];2605u[2][2] = M[6][4]*L[4][2]+M[6][5]*L[5][2]+M[6][6]*L[6][2];2606u[2][3] = M[6][4]*L[4][3]+M[6][5]*L[5][3]+M[6][6]*L[6][3];2607u[3][0] = M[7][4]*L[4][0]+M[7][5]*L[5][0]+M[7][6]*L[6][0]+M[7][7]*L[7][0];2608u[3][1] = M[7][4]*L[4][1]+M[7][5]*L[5][1]+M[7][6]*L[6][1]+M[7][7]*L[7][1];2609u[3][2] = M[7][4]*L[4][2]+M[7][5]*L[5][2]+M[7][6]*L[6][2]+M[7][7]*L[7][2];2610u[3][3] = M[7][4]*L[4][3]+M[7][5]*L[5][3]+M[7][6]*L[6][3]+M[7][7]*L[7][3];26112612v[0][0] = u[0][0]*M[0][0]+u[0][1]*M[1][0]+u[0][2]*M[2][0]+u[0][3]*M[3][0];2613v[0][1] = u[0][1]*M[1][1]+u[0][2]*M[2][1]+u[0][3]*M[3][1];2614v[0][2] = u[0][2]*M[2][2]+u[0][3]*M[3][2];2615v[0][3] = u[0][3]*M[3][3];2616v[1][0] = u[1][0]*M[0][0]+u[1][1]*M[1][0]+u[1][2]*M[2][0]+u[1][3]*M[3][0];2617v[1][1] = u[1][1]*M[1][1]+u[1][2]*M[2][1]+u[1][3]*M[3][1];2618v[1][2] = u[1][2]*M[2][2]+u[1][3]*M[3][2];2619v[1][3] = u[1][3]*M[3][3];2620v[2][0] = u[2][0]*M[0][0]+u[2][1]*M[1][0]+u[2][2]*M[2][0]+u[2][3]*M[3][0];2621v[2][1] = u[2][1]*M[1][1]+u[2][2]*M[2][1]+u[2][3]*M[3][1];2622v[2][2] = u[2][2]*M[2][2]+u[2][3]*M[3][2];2623v[2][3] = u[2][3]*M[3][3];2624v[3][0] = u[3][0]*M[0][0]+u[3][1]*M[1][0]+u[3][2]*M[2][0]+u[3][3]*M[3][0];2625v[3][1] = u[3][1]*M[1][1]+u[3][2]*M[2][1]+u[3][3]*M[3][1];2626v[3][2] = u[3][2]*M[2][2]+u[3][3]*M[3][2];2627v[3][3] = u[3][3]*M[3][3];26282629M[4][0] = -v[0][0];2630M[4][1] = -v[0][1];2631M[4][2] = -v[0][2];2632M[4][3] = -v[0][3];2633M[5][0] = -v[1][0];2634M[5][1] = -v[1][1];2635M[5][2] = -v[1][2];2636M[5][3] = -v[1][3];2637M[6][0] = -v[2][0];2638M[6][1] = -v[2][1];2639M[6][2] = -v[2][2];2640M[6][3] = -v[2][3];2641M[7][0] = -v[3][0];2642M[7][1] = -v[3][1];2643M[7][2] = -v[3][2];2644M[7][3] = -v[3][3];26452646/*2647M00 0 0 0 0 0 0 02648M10 M11 0 0 0 0 0 02649M20 M21 M22 0 0 0 0 02650M30 M31 M32 M33 0 0 0 02651M40 M41 M42 M43 M44 0 0 02652M50 M51 M52 M53 M54 M55 0 02653M60 M61 M62 M63 M64 M65 M66 02654M70 M71 M72 M73 M74 M75 M76 M772655*/2656}265726582659/**2660* Solves dH = inv(JtJ) Jte. The argument lower-triangular matrix is the2661* inverse of L as produced by the Cholesky decomposition LL^T of the matrix2662* JtJ; Thus the operation performed here is a left-multiplication of a vector2663* by two triangular matrices. The math is below:2664*2665* JtJ = LL^T2666* Linv = L^-12667* (JtJ)^-1 = (LL^T)^-12668* = (L^T^-1)(Linv)2669* = (Linv^T)(Linv)2670* dH = ((JtJ)^-1) (Jte)2671* = (Linv^T)(Linv) (Jte)2672*2673* where J is nx8, Jt is 8xn, JtJ is 8x8 PD, e is nx1, Jte is 8x1, L is lower2674* triangular 8x8 and dH is 8x1.2675*/26762677static inline void sacTRISolve8x8(const float (*L)[8],2678const float* Jte,2679float* dH){2680float t[8];26812682t[0] = L[0][0]*Jte[0];2683t[1] = L[1][0]*Jte[0]+L[1][1]*Jte[1];2684t[2] = L[2][0]*Jte[0]+L[2][1]*Jte[1]+L[2][2]*Jte[2];2685t[3] = L[3][0]*Jte[0]+L[3][1]*Jte[1]+L[3][2]*Jte[2]+L[3][3]*Jte[3];2686t[4] = L[4][0]*Jte[0]+L[4][1]*Jte[1]+L[4][2]*Jte[2]+L[4][3]*Jte[3]+L[4][4]*Jte[4];2687t[5] = L[5][0]*Jte[0]+L[5][1]*Jte[1]+L[5][2]*Jte[2]+L[5][3]*Jte[3]+L[5][4]*Jte[4]+L[5][5]*Jte[5];2688t[6] = L[6][0]*Jte[0]+L[6][1]*Jte[1]+L[6][2]*Jte[2]+L[6][3]*Jte[3]+L[6][4]*Jte[4]+L[6][5]*Jte[5]+L[6][6]*Jte[6];2689t[7] = L[7][0]*Jte[0]+L[7][1]*Jte[1]+L[7][2]*Jte[2]+L[7][3]*Jte[3]+L[7][4]*Jte[4]+L[7][5]*Jte[5]+L[7][6]*Jte[6]+L[7][7]*Jte[7];269026912692dH[0] = L[0][0]*t[0]+L[1][0]*t[1]+L[2][0]*t[2]+L[3][0]*t[3]+L[4][0]*t[4]+L[5][0]*t[5]+L[6][0]*t[6]+L[7][0]*t[7];2693dH[1] = L[1][1]*t[1]+L[2][1]*t[2]+L[3][1]*t[3]+L[4][1]*t[4]+L[5][1]*t[5]+L[6][1]*t[6]+L[7][1]*t[7];2694dH[2] = L[2][2]*t[2]+L[3][2]*t[3]+L[4][2]*t[4]+L[5][2]*t[5]+L[6][2]*t[6]+L[7][2]*t[7];2695dH[3] = L[3][3]*t[3]+L[4][3]*t[4]+L[5][3]*t[5]+L[6][3]*t[6]+L[7][3]*t[7];2696dH[4] = L[4][4]*t[4]+L[5][4]*t[5]+L[6][4]*t[6]+L[7][4]*t[7];2697dH[5] = L[5][5]*t[5]+L[6][5]*t[6]+L[7][5]*t[7];2698dH[6] = L[6][6]*t[6]+L[7][6]*t[7];2699dH[7] = L[7][7]*t[7];2700}270127022703/**2704* Subtract dH from H.2705*/27062707static inline void sacSub8x1(float* Hout, const float* H, const float* dH){2708Hout[0] = H[0] - dH[0];2709Hout[1] = H[1] - dH[1];2710Hout[2] = H[2] - dH[2];2711Hout[3] = H[3] - dH[3];2712Hout[4] = H[4] - dH[4];2713Hout[5] = H[5] - dH[5];2714Hout[6] = H[6] - dH[6];2715Hout[7] = H[7] - dH[7];2716}271727182719/* End namespace cv */2720}272127222723