|
|
|
@ -158,7 +158,6 @@ struct RHO_HEST_REFC{ |
|
|
|
|
|
|
|
|
|
/* Levenberg-Marquardt Refinement */ |
|
|
|
|
struct{ |
|
|
|
|
float* ws; /* Levenberg-Marqhard Workspace */ |
|
|
|
|
float (* JtJ)[8]; /* JtJ matrix */ |
|
|
|
|
float (* tmp1)[8]; /* Temporary 1 */ |
|
|
|
|
float* Jte; /* Jte vector */ |
|
|
|
@ -169,8 +168,14 @@ struct RHO_HEST_REFC{ |
|
|
|
|
uint64_t s[2]; /* PRNG state */ |
|
|
|
|
} prng; |
|
|
|
|
|
|
|
|
|
/* Memory Management */ |
|
|
|
|
struct{ |
|
|
|
|
cv::Mat perObj; |
|
|
|
|
cv::Mat perRun; |
|
|
|
|
} mem; |
|
|
|
|
|
|
|
|
|
/* Initialized? */ |
|
|
|
|
int init; |
|
|
|
|
int initialized; |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/* Empty constructors and destructors */ |
|
|
|
@ -202,6 +207,10 @@ struct RHO_HEST_REFC{ |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/* Methods to implement internals */ |
|
|
|
|
inline void allocatePerObj(void); |
|
|
|
|
inline void allocatePerRun(void); |
|
|
|
|
inline void deallocatePerRun(void); |
|
|
|
|
inline void deallocatePerObj(void); |
|
|
|
|
inline int initRun(void); |
|
|
|
|
inline void finiRun(void); |
|
|
|
|
inline int haveExtrinsicGuess(void); |
|
|
|
@ -242,9 +251,6 @@ struct RHO_HEST_REFC{ |
|
|
|
|
* Prototypes for purely-computational code. |
|
|
|
|
*/ |
|
|
|
|
|
|
|
|
|
static inline void* almalloc(size_t nBytes); |
|
|
|
|
static inline void alfree (void* ptr); |
|
|
|
|
|
|
|
|
|
static inline void sacInitNonRand (double beta, |
|
|
|
|
unsigned start, |
|
|
|
|
unsigned N, |
|
|
|
@ -382,36 +388,6 @@ unsigned rhoRefC(RHO_HEST_REFC* p, /* Homography estimation context. */ |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* Allocate memory aligned to a boundary of MEMALIGN. |
|
|
|
|
*/ |
|
|
|
|
|
|
|
|
|
static inline void* almalloc(size_t nBytes){ |
|
|
|
|
if(nBytes){ |
|
|
|
|
unsigned char* ptr = (unsigned char*)malloc(MEM_ALIGN + nBytes); |
|
|
|
|
if(ptr){ |
|
|
|
|
unsigned char* adj = (unsigned char*)(((intptr_t)(ptr+MEM_ALIGN))&((intptr_t)(-MEM_ALIGN))); |
|
|
|
|
ptrdiff_t diff = adj - ptr; |
|
|
|
|
adj[-1] = (unsigned char)(diff - 1); |
|
|
|
|
return adj; |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
return NULL; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* Free aligned memory. |
|
|
|
|
* |
|
|
|
|
* If argument is NULL, do nothing in accordance with free() semantics. |
|
|
|
|
*/ |
|
|
|
|
|
|
|
|
|
static inline void alfree(void* ptr){ |
|
|
|
|
if(ptr){ |
|
|
|
|
unsigned char* cptr = (unsigned char*)ptr; |
|
|
|
|
free(cptr - (ptrdiff_t)cptr[-1] - 1); |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* Constructor for RHO_HEST_REFC. |
|
|
|
@ -419,7 +395,7 @@ static inline void alfree(void* ptr){ |
|
|
|
|
* Does nothing. True initialization is done by initialize(). |
|
|
|
|
*/ |
|
|
|
|
|
|
|
|
|
RHO_HEST_REFC::RHO_HEST_REFC() : init(0){ |
|
|
|
|
RHO_HEST_REFC::RHO_HEST_REFC() : initialized(0){ |
|
|
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
@ -427,7 +403,7 @@ RHO_HEST_REFC::RHO_HEST_REFC() : init(0){ |
|
|
|
|
* Private copy constructor for RHO_HEST_REFC. Disabled. |
|
|
|
|
*/ |
|
|
|
|
|
|
|
|
|
RHO_HEST_REFC::RHO_HEST_REFC(const RHO_HEST_REFC&) : init(0){ |
|
|
|
|
RHO_HEST_REFC::RHO_HEST_REFC(const RHO_HEST_REFC&) : initialized(0){ |
|
|
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
@ -436,7 +412,7 @@ RHO_HEST_REFC::RHO_HEST_REFC(const RHO_HEST_REFC&) : init(0){ |
|
|
|
|
*/ |
|
|
|
|
|
|
|
|
|
RHO_HEST_REFC::~RHO_HEST_REFC(){ |
|
|
|
|
if(init){ |
|
|
|
|
if(initialized){ |
|
|
|
|
finalize(); |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
@ -458,37 +434,30 @@ RHO_HEST_REFC::~RHO_HEST_REFC(){ |
|
|
|
|
*/ |
|
|
|
|
|
|
|
|
|
inline int RHO_HEST_REFC::initialize(void){ |
|
|
|
|
ctrl.smpl = (unsigned*)almalloc(SMPL_SIZE*sizeof(*ctrl.smpl)); |
|
|
|
|
initialized = 0; |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
allocatePerObj(); |
|
|
|
|
|
|
|
|
|
curr.pkdPts = (float*) almalloc(SMPL_SIZE*2*2*sizeof(*curr.pkdPts)); |
|
|
|
|
curr.H = (float*) almalloc(HSIZE); |
|
|
|
|
curr.inl = NULL; |
|
|
|
|
curr.numInl = 0; |
|
|
|
|
|
|
|
|
|
best.H = (float*) almalloc(HSIZE); |
|
|
|
|
best.inl = NULL; |
|
|
|
|
best.numInl = 0; |
|
|
|
|
|
|
|
|
|
nr.size = 0; |
|
|
|
|
nr.beta = 0.0; |
|
|
|
|
|
|
|
|
|
lm.ws = NULL; |
|
|
|
|
lm.JtJ = NULL; |
|
|
|
|
lm.tmp1 = NULL; |
|
|
|
|
lm.Jte = NULL; |
|
|
|
|
|
|
|
|
|
fastSeed((unsigned)cv::theRNG()); |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
int areAllAllocsSuccessful = ctrl.smpl && |
|
|
|
|
curr.H && |
|
|
|
|
best.H && |
|
|
|
|
curr.pkdPts; |
|
|
|
|
int areAllAllocsSuccessful = !mem.perObj.empty(); |
|
|
|
|
|
|
|
|
|
if(!areAllAllocsSuccessful){ |
|
|
|
|
finalize(); |
|
|
|
|
}else{ |
|
|
|
|
init = 1; |
|
|
|
|
initialized = 1; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
return areAllAllocsSuccessful; |
|
|
|
@ -502,15 +471,10 @@ inline int RHO_HEST_REFC::initialize(void){ |
|
|
|
|
*/ |
|
|
|
|
|
|
|
|
|
inline void RHO_HEST_REFC::finalize(void){ |
|
|
|
|
if(init){ |
|
|
|
|
alfree(ctrl.smpl); |
|
|
|
|
alfree(curr.H); |
|
|
|
|
alfree(best.H); |
|
|
|
|
alfree(curr.pkdPts); |
|
|
|
|
|
|
|
|
|
memset(this, 0, sizeof(*this)); |
|
|
|
|
if(initialized){ |
|
|
|
|
deallocatePerObj(); |
|
|
|
|
|
|
|
|
|
init = 0; |
|
|
|
|
initialized = 0; |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
|
|
|
|
@ -651,6 +615,128 @@ unsigned RHO_HEST_REFC::rhoRefC(const float* src, /* Source points */ |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* Allocate per-object dynamic storage. |
|
|
|
|
* |
|
|
|
|
* This includes aligned, fixed-size internal buffers, but excludes any buffers |
|
|
|
|
* whose size cannot be determined ahead-of-time (before the number of matches |
|
|
|
|
* is known). |
|
|
|
|
* |
|
|
|
|
* All buffer memory is allocated in one single shot, and all pointers are |
|
|
|
|
* initialized. |
|
|
|
|
*/ |
|
|
|
|
|
|
|
|
|
inline void RHO_HEST_REFC::allocatePerObj(void){ |
|
|
|
|
/* We have known sizes */ |
|
|
|
|
size_t ctrl_smpl_sz = SMPL_SIZE*sizeof(*ctrl.smpl); |
|
|
|
|
size_t curr_pkdPts_sz = SMPL_SIZE*2*2*sizeof(*curr.pkdPts); |
|
|
|
|
size_t curr_H_sz = HSIZE; |
|
|
|
|
size_t best_H_sz = HSIZE; |
|
|
|
|
size_t lm_JtJ_sz = 8*8*sizeof(float); |
|
|
|
|
size_t lm_tmp1_sz = 8*8*sizeof(float); |
|
|
|
|
size_t lm_Jte_sz = 1*8*sizeof(float); |
|
|
|
|
|
|
|
|
|
/* We compute offsets */ |
|
|
|
|
size_t total = 0; |
|
|
|
|
#define MK_OFFSET(v) \ |
|
|
|
|
size_t v ## _of = total; \
|
|
|
|
|
total = alignSize(v ## _of + v ## _sz, MEM_ALIGN) |
|
|
|
|
|
|
|
|
|
MK_OFFSET(ctrl_smpl); |
|
|
|
|
MK_OFFSET(curr_pkdPts); |
|
|
|
|
MK_OFFSET(curr_H); |
|
|
|
|
MK_OFFSET(best_H); |
|
|
|
|
MK_OFFSET(lm_JtJ); |
|
|
|
|
MK_OFFSET(lm_tmp1); |
|
|
|
|
MK_OFFSET(lm_Jte); |
|
|
|
|
|
|
|
|
|
#undef MK_OFFSET |
|
|
|
|
|
|
|
|
|
/* Allocate dynamic memory managed by cv::Mat */ |
|
|
|
|
mem.perObj.create(1, total + MEM_ALIGN, CV_8UC1); |
|
|
|
|
|
|
|
|
|
/* Extract aligned pointer */ |
|
|
|
|
unsigned char* ptr = alignPtr(mem.perObj.data, MEM_ALIGN); |
|
|
|
|
|
|
|
|
|
/* Assign pointers */ |
|
|
|
|
ctrl.smpl = (unsigned*) (ptr + ctrl_smpl_of); |
|
|
|
|
curr.pkdPts = (float*) (ptr + curr_pkdPts_of); |
|
|
|
|
curr.H = (float*) (ptr + curr_H_of); |
|
|
|
|
best.H = (float*) (ptr + best_H_of); |
|
|
|
|
lm.JtJ = (float(*)[8])(ptr + lm_JtJ_of); |
|
|
|
|
lm.tmp1 = (float(*)[8])(ptr + lm_tmp1_of); |
|
|
|
|
lm.Jte = (float*) (ptr + lm_Jte_of); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* Allocate per-run dynamic storage. |
|
|
|
|
* |
|
|
|
|
* This includes storage that is proportional to the number of points, such as |
|
|
|
|
* the inlier mask. |
|
|
|
|
*/ |
|
|
|
|
|
|
|
|
|
inline void RHO_HEST_REFC::allocatePerRun(void){ |
|
|
|
|
/* We have known sizes */ |
|
|
|
|
size_t best_inl_sz = arg.N; |
|
|
|
|
size_t curr_inl_sz = arg.N; |
|
|
|
|
|
|
|
|
|
/* We compute offsets */ |
|
|
|
|
size_t total = 0; |
|
|
|
|
#define MK_OFFSET(v) \ |
|
|
|
|
size_t v ## _of = total; \
|
|
|
|
|
total = alignSize(v ## _of + v ## _sz, MEM_ALIGN) |
|
|
|
|
|
|
|
|
|
MK_OFFSET(best_inl); |
|
|
|
|
MK_OFFSET(curr_inl); |
|
|
|
|
|
|
|
|
|
#undef MK_OFFSET |
|
|
|
|
|
|
|
|
|
/* Allocate dynamic memory managed by cv::Mat */ |
|
|
|
|
mem.perRun.create(1, total + MEM_ALIGN, CV_8UC1); |
|
|
|
|
|
|
|
|
|
/* Extract aligned pointer */ |
|
|
|
|
unsigned char* ptr = alignPtr(mem.perRun.data, MEM_ALIGN); |
|
|
|
|
|
|
|
|
|
/* Assign pointers */ |
|
|
|
|
best.inl = (char*)(ptr + best_inl_of); |
|
|
|
|
curr.inl = (char*)(ptr + curr_inl_of); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* Deallocate per-run dynamic storage. |
|
|
|
|
* |
|
|
|
|
* Undoes the work by allocatePerRun(). |
|
|
|
|
*/ |
|
|
|
|
|
|
|
|
|
inline void RHO_HEST_REFC::deallocatePerRun(void){ |
|
|
|
|
best.inl = NULL; |
|
|
|
|
curr.inl = NULL; |
|
|
|
|
|
|
|
|
|
mem.perRun.release(); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* Deallocate per-object dynamic storage. |
|
|
|
|
* |
|
|
|
|
* Undoes the work by allocatePerObj(). |
|
|
|
|
*/ |
|
|
|
|
|
|
|
|
|
inline void RHO_HEST_REFC::deallocatePerObj(void){ |
|
|
|
|
ctrl.smpl = NULL; |
|
|
|
|
curr.pkdPts = NULL; |
|
|
|
|
curr.H = NULL; |
|
|
|
|
best.H = NULL; |
|
|
|
|
lm.JtJ = NULL; |
|
|
|
|
lm.tmp1 = NULL; |
|
|
|
|
lm.Jte = NULL; |
|
|
|
|
|
|
|
|
|
mem.perObj.release(); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* Initialize SAC for a run given its arguments. |
|
|
|
|
* |
|
|
|
@ -716,46 +802,18 @@ inline int RHO_HEST_REFC::initRun(void){ |
|
|
|
|
* Inlier mask alloc. |
|
|
|
|
* |
|
|
|
|
* Runs second because we want to quit as fast as possible if we can't even |
|
|
|
|
* allocate the up tp two masks. |
|
|
|
|
* |
|
|
|
|
* If the calling software wants an output mask, use buffer provided. If |
|
|
|
|
* not, allocate one anyways internally. |
|
|
|
|
* allocate the two masks. |
|
|
|
|
*/ |
|
|
|
|
|
|
|
|
|
best.inl = arg.inl ? arg.inl : (char*)almalloc(arg.N); |
|
|
|
|
curr.inl = (char*)almalloc(arg.N); |
|
|
|
|
|
|
|
|
|
if(!curr.inl || !best.inl){ |
|
|
|
|
return 0; |
|
|
|
|
} |
|
|
|
|
allocatePerRun(); |
|
|
|
|
|
|
|
|
|
memset(best.inl, 0, arg.N); |
|
|
|
|
memset(curr.inl, 0, arg.N); |
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* LevMarq workspace alloc. |
|
|
|
|
* |
|
|
|
|
* Runs third, consists only in a few conditional mallocs. If malloc fails |
|
|
|
|
* we wish to quit before doing any serious work. |
|
|
|
|
*/ |
|
|
|
|
|
|
|
|
|
if(isRefineEnabled() || isFinalRefineEnabled()){ |
|
|
|
|
lm.ws = (float*)almalloc(2*8*8*sizeof(float) + 1*8*sizeof(float)); |
|
|
|
|
if(!lm.ws){ |
|
|
|
|
return 0; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
lm.JtJ = (float(*)[8])(lm.ws + 0*8*8); |
|
|
|
|
lm.tmp1 = (float(*)[8])(lm.ws + 1*8*8); |
|
|
|
|
lm.Jte = (float*) (lm.ws + 2*8*8); |
|
|
|
|
}else{ |
|
|
|
|
lm.ws = NULL; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* Reset scalar per-run state. |
|
|
|
|
* |
|
|
|
|
* Runs fourth because there's no point in resetting/calculating a large |
|
|
|
|
* Runs third because there's no point in resetting/calculating a large |
|
|
|
|
* number of fields if something in the above junk failed. |
|
|
|
|
*/ |
|
|
|
|
|
|
|
|
@ -801,32 +859,7 @@ inline int RHO_HEST_REFC::initRun(void){ |
|
|
|
|
*/ |
|
|
|
|
|
|
|
|
|
inline void RHO_HEST_REFC::finiRun(void){ |
|
|
|
|
/**
|
|
|
|
|
* If no output inlier mask was required, free both (internal) masks. |
|
|
|
|
* Else if an (external) mask was provided as argument, find the other |
|
|
|
|
* (the internal one) and free it. |
|
|
|
|
*/ |
|
|
|
|
|
|
|
|
|
if(arg.inl){ |
|
|
|
|
if(arg.inl == best.inl){ |
|
|
|
|
alfree(curr.inl); |
|
|
|
|
}else{ |
|
|
|
|
alfree(best.inl); |
|
|
|
|
} |
|
|
|
|
}else{ |
|
|
|
|
alfree(best.inl); |
|
|
|
|
alfree(curr.inl); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
best.inl = NULL; |
|
|
|
|
curr.inl = NULL; |
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* ₣ree the Levenberg-Marquardt workspace. |
|
|
|
|
*/ |
|
|
|
|
|
|
|
|
|
alfree(lm.ws); |
|
|
|
|
lm.ws = NULL; |
|
|
|
|
deallocatePerRun(); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
@ -1464,9 +1497,9 @@ inline void RHO_HEST_REFC::nStarOptimize(void){ |
|
|
|
|
ctrl.phMax = best_n; |
|
|
|
|
ctrl.phNumInl = bestNumInl; |
|
|
|
|
arg.maxI = sacCalcIterBound(arg.cfd, |
|
|
|
|
(double)ctrl.phNumInl/ctrl.phMax, |
|
|
|
|
SMPL_SIZE, |
|
|
|
|
arg.maxI); |
|
|
|
|
(double)ctrl.phNumInl/ctrl.phMax, |
|
|
|
|
SMPL_SIZE, |
|
|
|
|
arg.maxI); |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
|
|
|
|
@ -1488,7 +1521,7 @@ inline void RHO_HEST_REFC::updateBounds(void){ |
|
|
|
|
inline void RHO_HEST_REFC::outputModel(void){ |
|
|
|
|
if(isBestModelGoodEnough()){ |
|
|
|
|
memcpy(arg.finalH, best.H, HSIZE); |
|
|
|
|
if(arg.inl && arg.inl != best.inl){ |
|
|
|
|
if(arg.inl){ |
|
|
|
|
memcpy(arg.inl, best.inl, arg.N); |
|
|
|
|
} |
|
|
|
|
}else{ |
|
|
|
@ -1501,8 +1534,12 @@ inline void RHO_HEST_REFC::outputModel(void){ |
|
|
|
|
*/ |
|
|
|
|
|
|
|
|
|
inline void RHO_HEST_REFC::outputZeroH(void){ |
|
|
|
|
memset(arg.finalH, 0, HSIZE); |
|
|
|
|
memset(arg.inl, 0, arg.N); |
|
|
|
|
if(arg.finalH){ |
|
|
|
|
memset(arg.finalH, 0, HSIZE); |
|
|
|
|
} |
|
|
|
|
if(arg.inl){ |
|
|
|
|
memset(arg.inl, 0, arg.N); |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|