/*M/////////////////////////////////////////////////////////////////////////////////////// // // IMPORTANT: READ BEFORE DOWNLOADING, COPYING, INSTALLING OR USING. // // By downloading, copying, installing or using the software you agree to this license. // If you do not agree to this license, do not download, install, // copy or use the software. // // // License Agreement // For Open Source Computer Vision Library // // Copyright (C) 2014, Biagio Montesano, all rights reserved. // Third party copyrights are property of their respective owners. // // Redistribution and use in source and binary forms, with or without modification, // are permitted provided that the following conditions are met: // // * Redistribution's of source code must retain the above copyright notice, // this list of conditions and the following disclaimer. // // * Redistribution's in binary form must reproduce the above copyright notice, // this list of conditions and the following disclaimer in the documentation // and/or other materials provided with the distribution. // // * The name of the copyright holders may not be used to endorse or promote products // derived from this software without specific prior written permission. // // This software is provided by the copyright holders and contributors "as is" and // any express or implied warranties, including, but not limited to, the implied // warranties of merchantability and fitness for a particular purpose are disclaimed. // In no event shall the Intel Corporation or contributors be liable for any direct, // indirect, incidental, special, exemplary, or consequential damages // (including, but not limited to, procurement of substitute goods or services; // loss of use, data, or profits; or business interruption) however caused // and on any theory of liability, whether in contract, strict liability, // or tort (including negligence or otherwise) arising in any way out of // the use of this software, even if advised of the possibility of such damage. // //M*/ #include "precomp.hpp" #define MAX_B 37 double ARRAY_RESIZE_FACTOR = 1.1; // minimum is 1.0 double ARRAY_RESIZE_ADD_FACTOR = 4; // minimum is 1 //using namespace cv; namespace cv { namespace line_descriptor { /* constructor */ BinaryDescriptorMatcher::BinaryDescriptorMatcher() { dataset = Ptr<Mihasher>(new Mihasher( 256, 32 )); nextAddedIndex = 0; numImages = 0; descrInDS = 0; } /* constructor with smart pointer */ Ptr<BinaryDescriptorMatcher> BinaryDescriptorMatcher::createBinaryDescriptorMatcher() { return Ptr < BinaryDescriptorMatcher > ( new BinaryDescriptorMatcher() ); } /* store new descriptors to be inserted in dataset */ void BinaryDescriptorMatcher::add( const std::vector<Mat>& descriptors ) { for ( size_t i = 0; i < descriptors.size(); i++ ) { descriptorsMat.push_back( descriptors[i] ); indexesMap.insert( std::pair<int, int>( nextAddedIndex, numImages ) ); nextAddedIndex += descriptors[i].rows; numImages++; } } /* store new descriptors into dataset */ void BinaryDescriptorMatcher::train() { if( !dataset ) dataset = Ptr<Mihasher>(new Mihasher( 256, 32 )); if( descriptorsMat.rows > 0 ) dataset->populate( descriptorsMat, descriptorsMat.rows, descriptorsMat.cols ); descrInDS = descriptorsMat.rows; descriptorsMat.release(); } /* clear dataset and internal data */ void BinaryDescriptorMatcher::clear() { descriptorsMat.release(); indexesMap.clear(); dataset.release(); nextAddedIndex = 0; numImages = 0; descrInDS = 0; } /* retrieve Hamming distances */ void BinaryDescriptorMatcher::checkKDistances( UINT32 * numres, int k, std::vector<int> & k_distances, int row, int string_length ) const { int k_to_found = k; UINT32 * numres_tmp = numres + ( ( string_length + 1 ) * row ); for ( int j = 0; j < ( string_length + 1 ) && k_to_found > 0; j++ ) { if( ( * ( numres_tmp + j ) ) > 0 ) { for ( int i = 0; i < (int) ( * ( numres_tmp + j ) ) && k_to_found > 0; i++ ) { k_distances.push_back( j ); k_to_found--; } } } } /* for every input descriptor, find the best matching one (from one image to a set) */ void BinaryDescriptorMatcher::match( const Mat& queryDescriptors, std::vector<DMatch>& matches, const std::vector<Mat>& masks ) { /* check data validity */ if( queryDescriptors.rows == 0 ) { std::cout << "Error: query descriptors'matrix is empty" << std::endl; return; } if( masks.size() != 0 && (int) masks.size() != numImages ) { std::cout << "Error: the number of images in dataset is " << numImages << " but match function received " << masks.size() << " masks. Program will be terminated" << std::endl; return; } /* add new descriptors to dataset, if needed */ train(); /* set number of requested matches to return for each query */ dataset->setK( 1 ); /* prepare structures for query */ UINT32 *results = new UINT32[queryDescriptors.rows]; UINT32 * numres = new UINT32[ ( 256 + 1 ) * ( queryDescriptors.rows )]; /* execute query */ dataset->batchquery( results, numres, queryDescriptors, queryDescriptors.rows, queryDescriptors.cols ); /* compose matches */ for ( int counter = 0; counter < queryDescriptors.rows; counter++ ) { /* create a map iterator */ std::map<int, int>::iterator itup; /* get info about original image of each returned descriptor */ itup = indexesMap.upper_bound( results[counter] - 1 ); itup--; /* data validity check */ if( !masks.empty() && ( masks[itup->second].rows != queryDescriptors.rows || masks[itup->second].cols != 1 ) ) { std::stringstream ss; ss << "Error: mask " << itup->second << " in knnMatch function " << "should have " << queryDescriptors.rows << " and " << "1 column. Program will be terminated"; //throw std::runtime_error( ss.str() ); } /* create a DMatch object if required by mask or if there is no mask at all */ else if( masks.empty() || masks[itup->second].at < uchar > ( counter ) != 0 ) { std::vector<int> k_distances; checkKDistances( numres, 1, k_distances, counter, 256 ); DMatch dm; dm.queryIdx = counter; dm.trainIdx = results[counter] - 1; dm.imgIdx = itup->second; dm.distance = (float) k_distances[0]; matches.push_back( dm ); } } /* delete data */ delete[] results; delete[] numres; } /* for every input descriptor, find the best matching one (for a pair of images) */ void BinaryDescriptorMatcher::match( const Mat& queryDescriptors, const Mat& trainDescriptors, std::vector<DMatch>& matches, const Mat& mask ) const { /* check data validity */ if( queryDescriptors.rows == 0 || trainDescriptors.rows == 0 ) { std::cout << "Error: descriptors matrices cannot be void" << std::endl; return; } if( !mask.empty() && ( mask.rows != queryDescriptors.rows && mask.cols != 1 ) ) { std::cout << "Error: input mask should have " << queryDescriptors.rows << " rows and 1 column. " << "Program will be terminated" << std::endl; return; } /* create a new mihasher object */ Mihasher *mh = new Mihasher( 256, 32 ); /* populate mihasher */ cv::Mat copy = trainDescriptors.clone(); mh->populate( copy, copy.rows, copy.cols ); mh->setK( 1 ); /* prepare structures for query */ UINT32 *results = new UINT32[queryDescriptors.rows]; UINT32 * numres = new UINT32[ ( 256 + 1 ) * ( queryDescriptors.rows )]; /* execute query */ mh->batchquery( results, numres, queryDescriptors, queryDescriptors.rows, queryDescriptors.cols ); /* compose matches */ for ( int counter = 0; counter < queryDescriptors.rows; counter++ ) { /* create a DMatch object if required by mask or if there is no mask at all */ if( mask.empty() || ( !mask.empty() && mask.at < uchar > ( counter ) != 0 ) ) { std::vector<int> k_distances; checkKDistances( numres, 1, k_distances, counter, 256 ); DMatch dm; dm.queryIdx = counter; dm.trainIdx = results[counter] - 1; dm.imgIdx = 0; dm.distance = (float) k_distances[0]; matches.push_back( dm ); } } /* delete data */ delete mh; delete[] results; delete[] numres; } /* for every input descriptor, find the best k matching descriptors (for a pair of images) */ void BinaryDescriptorMatcher::knnMatch( const Mat& queryDescriptors, const Mat& trainDescriptors, std::vector<std::vector<DMatch> >& matches, int k, const Mat& mask, bool compactResult ) const { /* check data validity */ if( queryDescriptors.rows == 0 || trainDescriptors.rows == 0 ) { std::cout << "Error: descriptors matrices cannot be void" << std::endl; return; } if( !mask.empty() && ( mask.rows != queryDescriptors.rows || mask.cols != 1 ) ) { std::cout << "Error: input mask should have " << queryDescriptors.rows << " rows and 1 column. " << "Program will be terminated" << std::endl; return; } /* create a new mihasher object */ Mihasher *mh = new Mihasher( 256, 32 ); /* populate mihasher */ cv::Mat copy = trainDescriptors.clone(); mh->populate( copy, copy.rows, copy.cols ); /* set K */ mh->setK( k ); /* prepare structures for query */ UINT32 *results = new UINT32[k * queryDescriptors.rows]; UINT32 * numres = new UINT32[ ( 256 + 1 ) * ( queryDescriptors.rows )]; /* execute query */ mh->batchquery( results, numres, queryDescriptors, queryDescriptors.rows, queryDescriptors.cols ); /* compose matches */ int index = 0; for ( int counter = 0; counter < queryDescriptors.rows; counter++ ) { /* initialize a vector of matches */ std::vector < DMatch > tempVec; /* chech whether query should be ignored */ if( !mask.empty() && mask.at < uchar > ( counter ) == 0 ) { /* if compact result is not requested, add an empty vector */ if( !compactResult ) matches.push_back( tempVec ); } /* query matches must be considered */ else { std::vector<int> k_distances; checkKDistances( numres, k, k_distances, counter, 256 ); for ( int j = index; j < index + k; j++ ) { DMatch dm; dm.queryIdx = counter; dm.trainIdx = results[j] - 1; dm.imgIdx = 0; dm.distance = (float) k_distances[j - index]; tempVec.push_back( dm ); } matches.push_back( tempVec ); } /* increment pointer */ index += k; } /* delete data */ delete mh; delete[] results; delete[] numres; } /* for every input descriptor, find the best k matching descriptors (from one image to a set) */ void BinaryDescriptorMatcher::knnMatch( const Mat& queryDescriptors, std::vector<std::vector<DMatch> >& matches, int k, const std::vector<Mat>& masks, bool compactResult ) { /* check data validity */ if( queryDescriptors.rows == 0 ) { std::cout << "Error: descriptors matrix cannot be void" << std::endl; return; } if( masks.size() != 0 && (int) masks.size() != numImages ) { std::cout << "Error: the number of images in dataset is " << numImages << " but knnMatch function received " << masks.size() << " masks. Program will be terminated" << std::endl; return; } /* add new descriptors to dataset, if needed */ train(); /* set number of requested matches to return for each query */ dataset->setK( k ); /* prepare structures for query */ UINT32 *results = new UINT32[k * queryDescriptors.rows]; UINT32 * numres = new UINT32[ ( 256 + 1 ) * ( queryDescriptors.rows )]; /* execute query */ dataset->batchquery( results, numres, queryDescriptors, queryDescriptors.rows, queryDescriptors.cols ); /* compose matches */ int index = 0; for ( int counter = 0; counter < queryDescriptors.rows; counter++ ) { /* create a void vector of matches */ std::vector < DMatch > tempVector; /* loop over k results returned for every query */ for ( int j = index; j < index + k; j++ ) { /* retrieve which image returned index refers to */ int currentIndex = results[j] - 1; std::map<int, int>::iterator itup; itup = indexesMap.upper_bound( currentIndex ); itup--; /* data validity check */ if( !masks.empty() && ( masks[itup->second].rows != queryDescriptors.rows || masks[itup->second].cols != 1 ) ) { std::cout << "Error: mask " << itup->second << " in knnMatch function " << "should have " << queryDescriptors.rows << " and " << "1 column. Program will be terminated" << std::endl; return; } /* decide if, according to relative mask, returned match should be considered */ else if( masks.size() == 0 || masks[itup->second].at < uchar > ( counter ) != 0 ) { std::vector<int> k_distances; checkKDistances( numres, k, k_distances, counter, 256 ); DMatch dm; dm.queryIdx = counter; dm.trainIdx = results[j] - 1; dm.imgIdx = itup->second; dm.distance = (float) k_distances[j - index]; tempVector.push_back( dm ); } } /* decide whether temporary vector should be saved */ if( ( tempVector.size() == 0 && !compactResult ) || tempVector.size() > 0 ) matches.push_back( tempVector ); /* increment pointer */ index += k; } /* delete data */ delete[] results; delete[] numres; } /* for every input desciptor, find all the ones falling in a certaing matching radius (for a pair of images) */ void BinaryDescriptorMatcher::radiusMatch( const Mat& queryDescriptors, const Mat& trainDescriptors, std::vector<std::vector<DMatch> >& matches, float maxDistance, const Mat& mask, bool compactResult ) const { /* check data validity */ if( queryDescriptors.rows == 0 || trainDescriptors.rows == 0 ) { std::cout << "Error: descriptors matrices cannot be void" << std::endl; return; } if( !mask.empty() && ( mask.rows != queryDescriptors.rows && mask.cols != 1 ) ) { std::cout << "Error: input mask should have " << queryDescriptors.rows << " rows and 1 column. " << "Program will be terminated" << std::endl; return; } /* create a new Mihasher */ Mihasher* mh = new Mihasher( 256, 32 ); /* populate Mihasher */ //Mat copy = queryDescriptors.clone(); Mat copy = trainDescriptors.clone(); mh->populate( copy, copy.rows, copy.cols ); /* set K */ mh->setK( trainDescriptors.rows ); /* prepare structures for query */ UINT32 *results = new UINT32[trainDescriptors.rows * queryDescriptors.rows]; UINT32 * numres = new UINT32[ ( 256 + 1 ) * ( queryDescriptors.rows )]; /* execute query */ mh->batchquery( results, numres, queryDescriptors, queryDescriptors.rows, queryDescriptors.cols ); /* compose matches */ int index = 0; for ( int i = 0; i < queryDescriptors.rows; i++ ) { std::vector<int> k_distances; checkKDistances( numres, trainDescriptors.rows, k_distances, i, 256 ); std::vector < DMatch > tempVector; for ( int j = index; j < index + trainDescriptors.rows; j++ ) { // if( numres[j] <= maxDistance ) if( k_distances[j - index] <= maxDistance ) { if( mask.empty() || mask.at < uchar > ( i ) != 0 ) { DMatch dm; dm.queryIdx = i; dm.trainIdx = (int) ( results[j] - 1 ); dm.imgIdx = 0; dm.distance = (float) k_distances[j - index]; tempVector.push_back( dm ); } } } /* decide whether temporary vector should be saved */ if( ( tempVector.size() == 0 && !compactResult ) || tempVector.size() > 0 ) matches.push_back( tempVector ); /* increment pointer */ index += trainDescriptors.rows; } /* delete data */ delete mh; delete[] results; delete[] numres; } /* for every input descriptor, find all the ones falling in a certain matching radius (from one image to a set) */ void BinaryDescriptorMatcher::radiusMatch( const Mat& queryDescriptors, std::vector<std::vector<DMatch> >& matches, float maxDistance, const std::vector<Mat>& masks, bool compactResult ) { /* check data validity */ if( queryDescriptors.rows == 0 ) { std::cout << "Error: descriptors matrices cannot be void" << std::endl; return; } if( masks.size() != 0 && (int) masks.size() != numImages ) { std::cout << "Error: the number of images in dataset is " << numImages << " but radiusMatch function received " << masks.size() << " masks. Program will be terminated" << std::endl; return; } /* populate dataset */ train(); /* set K */ dataset->setK( descrInDS ); /* prepare structures for query */ UINT32 *results = new UINT32[descrInDS * queryDescriptors.rows]; UINT32 * numres = new UINT32[ ( 256 + 1 ) * ( queryDescriptors.rows )]; /* execute query */ dataset->batchquery( results, numres, queryDescriptors, queryDescriptors.rows, queryDescriptors.cols ); /* compose matches */ int index = 0; for ( int counter = 0; counter < queryDescriptors.rows; counter++ ) { std::vector < DMatch > tempVector; for ( int j = index; j < index + descrInDS; j++ ) { std::vector<int> k_distances; checkKDistances( numres, descrInDS, k_distances, counter, 256 ); if( k_distances[j - index] <= maxDistance ) { int currentIndex = results[j] - 1; std::map<int, int>::iterator itup; itup = indexesMap.upper_bound( currentIndex ); itup--; /* data validity check */ if( !masks.empty() && ( masks[itup->second].rows != queryDescriptors.rows || masks[itup->second].cols != 1 ) ) { std::cout << "Error: mask " << itup->second << " in radiusMatch function " << "should have " << queryDescriptors.rows << " and " << "1 column. Program will be terminated" << std::endl; return; } /* add match if necessary */ else if( masks.empty() || masks[itup->second].at < uchar > ( counter ) != 0 ) { DMatch dm; dm.queryIdx = counter; dm.trainIdx = results[j] - 1; dm.imgIdx = itup->second; dm.distance = (float) k_distances[j - index]; tempVector.push_back( dm ); } } } /* decide whether temporary vector should be saved */ if( ( tempVector.size() == 0 && !compactResult ) || tempVector.size() > 0 ) matches.push_back( tempVector ); /* increment pointer */ index += descrInDS; } /* delete data */ delete[] results; delete[] numres; } /* execute a batch query */ void BinaryDescriptorMatcher::Mihasher::batchquery( UINT32 * results, UINT32 *numres, const cv::Mat & queries, UINT32 numq, int dim1queries ) { /* create and initialize a bitarray */ counter = makePtr<bitarray>(); counter->init( N ); UINT32 *res = new UINT32[K * ( D + 1 )]; UINT64 *chunks = new UINT64[m]; UINT32 * presults = results; UINT32 *pnumres = numres; /* make a copy of input queries */ cv::Mat queries_clone = queries.clone(); /* set a pointer to first query (row) */ UINT8 *pq = queries_clone.ptr(); /* loop over number of descriptors */ for ( size_t i = 0; i < numq; i++ ) { /* for every descriptor, query database */ query( presults, pnumres, pq, chunks, res ); /* move pointer to write next K indeces */ presults += K; pnumres += B + 1; /* move forward pointer to current row in descriptors matrix */ pq += dim1queries; } delete[] res; delete[] chunks; } /* execute a single query */ void BinaryDescriptorMatcher::Mihasher::query( UINT32* results, UINT32* numres, UINT8 * Query, UINT64 *chunks, UINT32 *res ) { /* if K == 0 that means we want everything to be processed. So maxres = N in that case. Otherwise K limits the results processed */ UINT32 maxres = K ? K : (UINT32) N; /* number of results so far obtained (up to a distance of s per chunk) */ UINT32 n = 0; /* number of candidates tested with full codes (not counting duplicates) */ UINT32 nc = 0; /* counting everything retrieved (duplicates are counted multiple times) number of lookups (and xors) */ UINT32 nl = 0; UINT32 nd = 0; UINT32 *arr; int size = 0; UINT32 index; int hammd; counter->erase(); memset( numres, 0, ( B + 1 ) * sizeof ( *numres ) ); split( chunks, Query, m, mplus, b ); /* the growing search radius per substring */ int s; /* current b: for the first mplus substrings it is b, for the rest it is (b-1) */ int curb = b; for ( s = 0; s <= d && n < maxres; s++ ) { for ( int k = 0; k < m; k++ ) { if( k < mplus ) curb = b; else curb = b - 1; UINT64 chunksk = chunks[k]; /* number of bit-strings with s number of 1s */ nl += xornum[s + 1] - xornum[s]; /* the bit-string with s number of 1s */ UINT64 bitstr = 0; for ( int i = 0; i < s; i++ ) /* power[i] stores the location of the i'th 1 */ power[i] = i; /* used for stopping criterion (location of (s+1)th 1) */ power[s] = curb + 1; /* bit determines the 1 that should be moving to the left */ int bit = s - 1; /* start from the left-most 1, and move it to the left until it touches another one */ /* the loop for changing bitstr */ bool infiniteWhile = true; while ( infiniteWhile ) { if( bit != -1 ) { bitstr ^= ( power[bit] == bit ) ? (UINT64) 1 << power[bit] : (UINT64) 3 << ( power[bit] - 1 ); power[bit]++; bit--; } else { /* bit == -1 */ /* the binary code bitstr is available for processing */ arr = H[k].query( chunksk ^ bitstr, &size ); // lookup if( size ) { /* the corresponding bucket is not empty */ nd += size; for ( int c = 0; c < size; c++ ) { index = arr[c]; if( !counter->get( index ) ) { /* if it is not a duplicate */ counter->set( index ); hammd = cv::line_descriptor::match( codes.ptr() + (UINT64) index * ( B_over_8 ), Query, B_over_8 ); nc++; if( hammd <= D && numres[hammd] < maxres ) res[hammd * K + numres[hammd]] = index + 1; numres[hammd]++; } } } /* end of processing */ while ( ++bit < s && power[bit] == power[bit + 1] - 1 ) { bitstr ^= (UINT64) 1 << ( power[bit] - 1 ); power[bit] = bit; } if( bit == s ) break; } } n = n + numres[s * m + k]; if( n >= maxres ) break; } } n = 0; for ( s = 0; s <= D && (int) n < K; s++ ) { for ( int c = 0; c < (int) numres[s] && (int) n < K; c++ ) results[n++] = res[s * K + c]; } } /* constructor 2 */ BinaryDescriptorMatcher::Mihasher::Mihasher( int B_val, int _m ) { B = B_val; B_over_8 = B / 8; m = _m; b = (int) ceil( (double) B / m ); /* set radius to search for nearest neighbors to size of descriptor */ D = (int) ceil( B ); d = (int) ceil( (double) D / m ); /* mplus is the number of chunks with b bits (m-mplus) is the number of chunks with (b-1) bits */ mplus = B - m * ( b - 1 ); xornum.resize(d + 2); xornum[0] = 0; for ( int i = 0; i <= d; i++ ) xornum[i + 1] = xornum[i] + (UINT32) choose( b, i ); H.resize(m); /* H[i].init might fail */ for ( int i = 0; i < mplus; i++ ) H[i].init( b ); for ( int i = mplus; i < m; i++ ) H[i].init( b - 1 ); } /* K setter */ void BinaryDescriptorMatcher::Mihasher::setK( int K_val ) { K = K_val; } /* desctructor */ BinaryDescriptorMatcher::Mihasher::~Mihasher() { } /* populate tables */ void BinaryDescriptorMatcher::Mihasher::populate( cv::Mat & _codes, UINT32 N_val, int dim1codes ) { N = N_val; codes = _codes; UINT64 * chunks = new UINT64[m]; UINT8 * pcodes = codes.ptr(); for ( UINT64 i = 0; i < N; i++, pcodes += dim1codes ) { split( chunks, pcodes, m, mplus, b ); for ( int k = 0; k < m; k++ ) H[k].insert( chunks[k], (UINT32) i ); if( i % (int) ceil( N / 1000.0 ) == 0 ) fflush (stdout); } delete[] chunks; } /* constructor */ BinaryDescriptorMatcher::SparseHashtable::SparseHashtable() { size = 0; b = 0; } /* initializer */ int BinaryDescriptorMatcher::SparseHashtable::init( int _b ) { b = _b; if( b < 5 || b > MAX_B || b > (int) ( sizeof(UINT64) * 8 ) ) return 1; size = UINT64_1 << ( b - 5 ); // size = 2 ^ b table = std::vector<BucketGroup>((size_t)size, BucketGroup(false)); return 0; } /* destructor */ BinaryDescriptorMatcher::SparseHashtable::~SparseHashtable() { } /* insert data */ void BinaryDescriptorMatcher::SparseHashtable::insert( UINT64 index, UINT32 data ) { table[(size_t)(index >> 5)].insert( (int) ( index & 31 ), data ); } /* query data */ UINT32* BinaryDescriptorMatcher::SparseHashtable::query( UINT64 index, int *Size ) { return table[(size_t)(index >> 5)].query( (int) ( index & 31 ), Size ); } /* constructor */ BinaryDescriptorMatcher::BucketGroup::BucketGroup(bool needAllocateGroup) { empty = 0; if (needAllocateGroup) group = std::vector < uint32_t > ( 2, 0 ); else group = std::vector < uint32_t > ( 0, 0 ); } /* destructor */ BinaryDescriptorMatcher::BucketGroup::~BucketGroup() { } void BinaryDescriptorMatcher::BucketGroup::insert_value( std::vector<uint32_t>& vec, int index, UINT32 data ) { if( vec.size() > 1 ) { if( vec[0] == vec[1] ) { vec[1] = (UINT32) ceil( vec[0] * 1.1 ); for ( int i = 0; i < (int) ( 2 + vec[1] - vec.size() ); i++ ) vec.push_back( 0 ); } vec.insert( vec.begin() + 2 + index, data ); vec[2 + index] = data; vec[0]++; } else { vec = std::vector < uint32_t > ( 3, 0 ); vec[0] = 1; vec[1] = 1; vec[2] = data; } } void BinaryDescriptorMatcher::BucketGroup::push_value( std::vector<uint32_t>& vec, UINT32 Data ) { if( vec.size() > 0 ) { if( vec[0] == vec[1] ) { vec[1] = (UINT32) std::max( ceil( vec[1] * ARRAY_RESIZE_FACTOR ), vec[1] + ARRAY_RESIZE_ADD_FACTOR ); for ( int i = 0; i < (int) ( 2 + vec[1] - vec.size() ); i++ ) vec.push_back( 0 ); } vec[2 + vec[0]] = Data; vec[0]++; } else { vec = std::vector < uint32_t > ( 2 + (uint32_t) ARRAY_RESIZE_ADD_FACTOR, 0 ); vec[0] = 1; vec[1] = 1; vec[2] = Data; } } /* insert data into the bucket */ void BinaryDescriptorMatcher::BucketGroup::insert( int subindex, UINT32 data ) { if( group.size() == 0 ) { push_value( group, 0 ); } UINT32 lowerbits = ( (UINT32) 1 << subindex ) - 1; int end = popcnt( empty & lowerbits ); if( ! ( empty & ( (UINT32) 1 << subindex ) ) ) { insert_value( group, end, group[end + 2] ); empty |= (UINT32) 1 << subindex; } int totones = popcnt( empty ); insert_value( group, totones + 1 + group[2 + end + 1], data ); for ( int i = end + 1; i < totones + 1; i++ ) group[2 + i]++; } /* perform a query to the bucket */ UINT32* BinaryDescriptorMatcher::BucketGroup::query( int subindex, int *size ) { if( empty & ( (UINT32) 1 << subindex ) ) { UINT32 lowerbits = ( (UINT32) 1 << subindex ) - 1; int end = popcnt( empty & lowerbits ); int totones = popcnt( empty ); *size = group[2 + end + 1] - group[2 + end]; return & ( * ( group.begin() + 2 + totones + 1 + (int) group[2 + end] ) ); } else { *size = 0; return NULL; } } } }