12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292 |
- /***********************************************************************
- * Software License Agreement (BSD License)
- *
- * Copyright 2008-2009 Marius Muja (mariusm@cs.ubc.ca). All rights reserved.
- * Copyright 2008-2009 David G. Lowe (lowe@cs.ubc.ca). All rights reserved.
- *
- * THE BSD LICENSE
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- *
- * 1. Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- * 2. Redistributions 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.
- *
- * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 AUTHOR 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.
- *************************************************************************/
- #ifndef OPENCV_FLANN_DIST_H_
- #define OPENCV_FLANN_DIST_H_
- //! @cond IGNORED
- #include <cmath>
- #include <cstdlib>
- #include <string.h>
- #ifdef _MSC_VER
- typedef unsigned __int32 uint32_t;
- typedef unsigned __int64 uint64_t;
- #else
- #include <stdint.h>
- #endif
- #include "defines.h"
- #if defined _WIN32 && (defined(_M_ARM) || defined(_M_ARM64))
- # include <Intrin.h>
- #endif
- #if defined(__ARM_NEON__) && !defined(__CUDACC__)
- # include "arm_neon.h"
- #endif
- namespace cvflann
- {
- template<typename T>
- inline T abs(T x) { return (x<0) ? -x : x; }
- template<>
- inline int abs<int>(int x) { return ::abs(x); }
- template<>
- inline float abs<float>(float x) { return fabsf(x); }
- template<>
- inline double abs<double>(double x) { return fabs(x); }
- template<typename TargetType>
- inline TargetType round(float x) { return static_cast<TargetType>(x); }
- template<>
- inline unsigned int round<unsigned int>(float x) { return static_cast<unsigned int>(x + 0.5f); }
- template<>
- inline unsigned short round<unsigned short>(float x) { return static_cast<unsigned short>(x + 0.5f); }
- template<>
- inline unsigned char round<unsigned char>(float x) { return static_cast<unsigned char>(x + 0.5f); }
- template<>
- inline long long round<long long>(float x) { return static_cast<long long>(x + 0.5f); }
- template<>
- inline long round<long>(float x) { return static_cast<long>(x + 0.5f); }
- template<>
- inline int round<int>(float x) { return static_cast<int>(x + 0.5f) - (x<0); }
- template<>
- inline short round<short>(float x) { return static_cast<short>(x + 0.5f) - (x<0); }
- template<>
- inline char round<char>(float x) { return static_cast<char>(x + 0.5f) - (x<0); }
- template<typename TargetType>
- inline TargetType round(double x) { return static_cast<TargetType>(x); }
- template<>
- inline unsigned int round<unsigned int>(double x) { return static_cast<unsigned int>(x + 0.5); }
- template<>
- inline unsigned short round<unsigned short>(double x) { return static_cast<unsigned short>(x + 0.5); }
- template<>
- inline unsigned char round<unsigned char>(double x) { return static_cast<unsigned char>(x + 0.5); }
- template<>
- inline long long round<long long>(double x) { return static_cast<long long>(x + 0.5); }
- template<>
- inline long round<long>(double x) { return static_cast<long>(x + 0.5); }
- template<>
- inline int round<int>(double x) { return static_cast<int>(x + 0.5) - (x<0); }
- template<>
- inline short round<short>(double x) { return static_cast<short>(x + 0.5) - (x<0); }
- template<>
- inline char round<char>(double x) { return static_cast<char>(x + 0.5) - (x<0); }
- template<typename T>
- struct Accumulator { typedef T Type; };
- template<>
- struct Accumulator<unsigned char> { typedef float Type; };
- template<>
- struct Accumulator<unsigned short> { typedef float Type; };
- template<>
- struct Accumulator<unsigned int> { typedef float Type; };
- template<>
- struct Accumulator<char> { typedef float Type; };
- template<>
- struct Accumulator<short> { typedef float Type; };
- template<>
- struct Accumulator<int> { typedef float Type; };
- #undef True
- #undef False
- class True
- {
- public:
- static const bool val = true;
- };
- class False
- {
- public:
- static const bool val = false;
- };
- /*
- * This is a "zero iterator". It basically behaves like a zero filled
- * array to all algorithms that use arrays as iterators (STL style).
- * It's useful when there's a need to compute the distance between feature
- * and origin it and allows for better compiler optimisation than using a
- * zero-filled array.
- */
- template <typename T>
- struct ZeroIterator
- {
- T operator*()
- {
- return 0;
- }
- T operator[](int)
- {
- return 0;
- }
- const ZeroIterator<T>& operator ++()
- {
- return *this;
- }
- ZeroIterator<T> operator ++(int)
- {
- return *this;
- }
- ZeroIterator<T>& operator+=(int)
- {
- return *this;
- }
- };
- /**
- * Squared Euclidean distance functor.
- *
- * This is the simpler, unrolled version. This is preferable for
- * very low dimensionality data (eg 3D points)
- */
- template<class T>
- struct L2_Simple
- {
- typedef True is_kdtree_distance;
- typedef True is_vector_space_distance;
- typedef T ElementType;
- typedef typename Accumulator<T>::Type ResultType;
- typedef ResultType CentersType;
- template <typename Iterator1, typename Iterator2>
- ResultType operator()(Iterator1 a, Iterator2 b, size_t size, ResultType /*worst_dist*/ = -1) const
- {
- ResultType result = ResultType();
- ResultType diff;
- for(size_t i = 0; i < size; ++i ) {
- diff = (ResultType)(*a++ - *b++);
- result += diff*diff;
- }
- return result;
- }
- template <typename U, typename V>
- inline ResultType accum_dist(const U& a, const V& b, int) const
- {
- return (a-b)*(a-b);
- }
- };
- /**
- * Squared Euclidean distance functor, optimized version
- */
- template<class T>
- struct L2
- {
- typedef True is_kdtree_distance;
- typedef True is_vector_space_distance;
- typedef T ElementType;
- typedef typename Accumulator<T>::Type ResultType;
- typedef ResultType CentersType;
- /**
- * Compute the squared Euclidean distance between two vectors.
- *
- * This is highly optimised, with loop unrolling, as it is one
- * of the most expensive inner loops.
- *
- * The computation of squared root at the end is omitted for
- * efficiency.
- */
- template <typename Iterator1, typename Iterator2>
- ResultType operator()(Iterator1 a, Iterator2 b, size_t size, ResultType worst_dist = -1) const
- {
- ResultType result = ResultType();
- ResultType diff0, diff1, diff2, diff3;
- Iterator1 last = a + size;
- Iterator1 lastgroup = last - 3;
- /* Process 4 items with each loop for efficiency. */
- while (a < lastgroup) {
- diff0 = (ResultType)(a[0] - b[0]);
- diff1 = (ResultType)(a[1] - b[1]);
- diff2 = (ResultType)(a[2] - b[2]);
- diff3 = (ResultType)(a[3] - b[3]);
- result += diff0 * diff0 + diff1 * diff1 + diff2 * diff2 + diff3 * diff3;
- a += 4;
- b += 4;
- if ((worst_dist>0)&&(result>worst_dist)) {
- return result;
- }
- }
- /* Process last 0-3 pixels. Not needed for standard vector lengths. */
- while (a < last) {
- diff0 = (ResultType)(*a++ - *b++);
- result += diff0 * diff0;
- }
- return result;
- }
- /**
- * Partial euclidean distance, using just one dimension. This is used by the
- * kd-tree when computing partial distances while traversing the tree.
- *
- * Squared root is omitted for efficiency.
- */
- template <typename U, typename V>
- inline ResultType accum_dist(const U& a, const V& b, int) const
- {
- return (a-b)*(a-b);
- }
- };
- /*
- * Manhattan distance functor, optimized version
- */
- template<class T>
- struct L1
- {
- typedef True is_kdtree_distance;
- typedef True is_vector_space_distance;
- typedef T ElementType;
- typedef typename Accumulator<T>::Type ResultType;
- typedef ResultType CentersType;
- /**
- * Compute the Manhattan (L_1) distance between two vectors.
- *
- * This is highly optimised, with loop unrolling, as it is one
- * of the most expensive inner loops.
- */
- template <typename Iterator1, typename Iterator2>
- ResultType operator()(Iterator1 a, Iterator2 b, size_t size, ResultType worst_dist = -1) const
- {
- ResultType result = ResultType();
- ResultType diff0, diff1, diff2, diff3;
- Iterator1 last = a + size;
- Iterator1 lastgroup = last - 3;
- /* Process 4 items with each loop for efficiency. */
- while (a < lastgroup) {
- diff0 = (ResultType)abs(a[0] - b[0]);
- diff1 = (ResultType)abs(a[1] - b[1]);
- diff2 = (ResultType)abs(a[2] - b[2]);
- diff3 = (ResultType)abs(a[3] - b[3]);
- result += diff0 + diff1 + diff2 + diff3;
- a += 4;
- b += 4;
- if ((worst_dist>0)&&(result>worst_dist)) {
- return result;
- }
- }
- /* Process last 0-3 pixels. Not needed for standard vector lengths. */
- while (a < last) {
- diff0 = (ResultType)abs(*a++ - *b++);
- result += diff0;
- }
- return result;
- }
- /**
- * Partial distance, used by the kd-tree.
- */
- template <typename U, typename V>
- inline ResultType accum_dist(const U& a, const V& b, int) const
- {
- return abs(a-b);
- }
- };
- template<class T>
- struct MinkowskiDistance
- {
- typedef True is_kdtree_distance;
- typedef True is_vector_space_distance;
- typedef T ElementType;
- typedef typename Accumulator<T>::Type ResultType;
- typedef ResultType CentersType;
- int order;
- MinkowskiDistance(int order_) : order(order_) {}
- /**
- * Compute the Minkowski (L_p) distance between two vectors.
- *
- * This is highly optimised, with loop unrolling, as it is one
- * of the most expensive inner loops.
- *
- * The computation of squared root at the end is omitted for
- * efficiency.
- */
- template <typename Iterator1, typename Iterator2>
- ResultType operator()(Iterator1 a, Iterator2 b, size_t size, ResultType worst_dist = -1) const
- {
- ResultType result = ResultType();
- ResultType diff0, diff1, diff2, diff3;
- Iterator1 last = a + size;
- Iterator1 lastgroup = last - 3;
- /* Process 4 items with each loop for efficiency. */
- while (a < lastgroup) {
- diff0 = (ResultType)abs(a[0] - b[0]);
- diff1 = (ResultType)abs(a[1] - b[1]);
- diff2 = (ResultType)abs(a[2] - b[2]);
- diff3 = (ResultType)abs(a[3] - b[3]);
- result += pow(diff0,order) + pow(diff1,order) + pow(diff2,order) + pow(diff3,order);
- a += 4;
- b += 4;
- if ((worst_dist>0)&&(result>worst_dist)) {
- return result;
- }
- }
- /* Process last 0-3 pixels. Not needed for standard vector lengths. */
- while (a < last) {
- diff0 = (ResultType)abs(*a++ - *b++);
- result += pow(diff0,order);
- }
- return result;
- }
- /**
- * Partial distance, used by the kd-tree.
- */
- template <typename U, typename V>
- inline ResultType accum_dist(const U& a, const V& b, int) const
- {
- return pow(static_cast<ResultType>(abs(a-b)),order);
- }
- };
- template<class T>
- struct MaxDistance
- {
- typedef False is_kdtree_distance;
- typedef True is_vector_space_distance;
- typedef T ElementType;
- typedef typename Accumulator<T>::Type ResultType;
- typedef ResultType CentersType;
- /**
- * Compute the max distance (L_infinity) between two vectors.
- *
- * This distance is not a valid kdtree distance, it's not dimensionwise additive.
- */
- template <typename Iterator1, typename Iterator2>
- ResultType operator()(Iterator1 a, Iterator2 b, size_t size, ResultType worst_dist = -1) const
- {
- ResultType result = ResultType();
- ResultType diff0, diff1, diff2, diff3;
- Iterator1 last = a + size;
- Iterator1 lastgroup = last - 3;
- /* Process 4 items with each loop for efficiency. */
- while (a < lastgroup) {
- diff0 = abs(a[0] - b[0]);
- diff1 = abs(a[1] - b[1]);
- diff2 = abs(a[2] - b[2]);
- diff3 = abs(a[3] - b[3]);
- if (diff0>result) {result = diff0; }
- if (diff1>result) {result = diff1; }
- if (diff2>result) {result = diff2; }
- if (diff3>result) {result = diff3; }
- a += 4;
- b += 4;
- if ((worst_dist>0)&&(result>worst_dist)) {
- return result;
- }
- }
- /* Process last 0-3 pixels. Not needed for standard vector lengths. */
- while (a < last) {
- diff0 = abs(*a++ - *b++);
- result = (diff0>result) ? diff0 : result;
- }
- return result;
- }
- /* This distance functor is not dimension-wise additive, which
- * makes it an invalid kd-tree distance, not implementing the accum_dist method */
- };
- ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
- /**
- * Hamming distance functor - counts the bit differences between two strings - useful for the Brief descriptor
- * bit count of A exclusive XOR'ed with B
- */
- struct HammingLUT
- {
- typedef False is_kdtree_distance;
- typedef False is_vector_space_distance;
- typedef unsigned char ElementType;
- typedef int ResultType;
- typedef ElementType CentersType;
- /** this will count the bits in a ^ b
- */
- template<typename Iterator2>
- ResultType operator()(const unsigned char* a, const Iterator2 b, size_t size) const
- {
- static const uchar popCountTable[] =
- {
- 0, 1, 1, 2, 1, 2, 2, 3, 1, 2, 2, 3, 2, 3, 3, 4, 1, 2, 2, 3, 2, 3, 3, 4, 2, 3, 3, 4, 3, 4, 4, 5,
- 1, 2, 2, 3, 2, 3, 3, 4, 2, 3, 3, 4, 3, 4, 4, 5, 2, 3, 3, 4, 3, 4, 4, 5, 3, 4, 4, 5, 4, 5, 5, 6,
- 1, 2, 2, 3, 2, 3, 3, 4, 2, 3, 3, 4, 3, 4, 4, 5, 2, 3, 3, 4, 3, 4, 4, 5, 3, 4, 4, 5, 4, 5, 5, 6,
- 2, 3, 3, 4, 3, 4, 4, 5, 3, 4, 4, 5, 4, 5, 5, 6, 3, 4, 4, 5, 4, 5, 5, 6, 4, 5, 5, 6, 5, 6, 6, 7,
- 1, 2, 2, 3, 2, 3, 3, 4, 2, 3, 3, 4, 3, 4, 4, 5, 2, 3, 3, 4, 3, 4, 4, 5, 3, 4, 4, 5, 4, 5, 5, 6,
- 2, 3, 3, 4, 3, 4, 4, 5, 3, 4, 4, 5, 4, 5, 5, 6, 3, 4, 4, 5, 4, 5, 5, 6, 4, 5, 5, 6, 5, 6, 6, 7,
- 2, 3, 3, 4, 3, 4, 4, 5, 3, 4, 4, 5, 4, 5, 5, 6, 3, 4, 4, 5, 4, 5, 5, 6, 4, 5, 5, 6, 5, 6, 6, 7,
- 3, 4, 4, 5, 4, 5, 5, 6, 4, 5, 5, 6, 5, 6, 6, 7, 4, 5, 5, 6, 5, 6, 6, 7, 5, 6, 6, 7, 6, 7, 7, 8
- };
- ResultType result = 0;
- const unsigned char* b2 = reinterpret_cast<const unsigned char*> (b);
- for (size_t i = 0; i < size; i++) {
- result += popCountTable[a[i] ^ b2[i]];
- }
- return result;
- }
- ResultType operator()(const unsigned char* a, const ZeroIterator<unsigned char> b, size_t size) const
- {
- (void)b;
- static const uchar popCountTable[] =
- {
- 0, 1, 1, 2, 1, 2, 2, 3, 1, 2, 2, 3, 2, 3, 3, 4, 1, 2, 2, 3, 2, 3, 3, 4, 2, 3, 3, 4, 3, 4, 4, 5,
- 1, 2, 2, 3, 2, 3, 3, 4, 2, 3, 3, 4, 3, 4, 4, 5, 2, 3, 3, 4, 3, 4, 4, 5, 3, 4, 4, 5, 4, 5, 5, 6,
- 1, 2, 2, 3, 2, 3, 3, 4, 2, 3, 3, 4, 3, 4, 4, 5, 2, 3, 3, 4, 3, 4, 4, 5, 3, 4, 4, 5, 4, 5, 5, 6,
- 2, 3, 3, 4, 3, 4, 4, 5, 3, 4, 4, 5, 4, 5, 5, 6, 3, 4, 4, 5, 4, 5, 5, 6, 4, 5, 5, 6, 5, 6, 6, 7,
- 1, 2, 2, 3, 2, 3, 3, 4, 2, 3, 3, 4, 3, 4, 4, 5, 2, 3, 3, 4, 3, 4, 4, 5, 3, 4, 4, 5, 4, 5, 5, 6,
- 2, 3, 3, 4, 3, 4, 4, 5, 3, 4, 4, 5, 4, 5, 5, 6, 3, 4, 4, 5, 4, 5, 5, 6, 4, 5, 5, 6, 5, 6, 6, 7,
- 2, 3, 3, 4, 3, 4, 4, 5, 3, 4, 4, 5, 4, 5, 5, 6, 3, 4, 4, 5, 4, 5, 5, 6, 4, 5, 5, 6, 5, 6, 6, 7,
- 3, 4, 4, 5, 4, 5, 5, 6, 4, 5, 5, 6, 5, 6, 6, 7, 4, 5, 5, 6, 5, 6, 6, 7, 5, 6, 6, 7, 6, 7, 7, 8
- };
- ResultType result = 0;
- for (size_t i = 0; i < size; i++) {
- result += popCountTable[a[i]];
- }
- return result;
- }
- };
- /**
- * Hamming distance functor (pop count between two binary vectors, i.e. xor them and count the number of bits set)
- * That code was taken from brief.cpp in OpenCV
- */
- template<class T>
- struct Hamming
- {
- typedef False is_kdtree_distance;
- typedef False is_vector_space_distance;
- typedef T ElementType;
- typedef int ResultType;
- typedef ElementType CentersType;
- template<typename Iterator1, typename Iterator2>
- ResultType operator()(const Iterator1 a, const Iterator2 b, size_t size, ResultType /*worst_dist*/ = -1) const
- {
- ResultType result = 0;
- #if defined(__ARM_NEON__) && !defined(__CUDACC__)
- {
- const unsigned char* a2 = reinterpret_cast<const unsigned char*> (a);
- const unsigned char* b2 = reinterpret_cast<const unsigned char*> (b);
- uint32x4_t bits = vmovq_n_u32(0);
- for (size_t i = 0; i < size; i += 16) {
- uint8x16_t A_vec = vld1q_u8 (a2 + i);
- uint8x16_t B_vec = vld1q_u8 (b2 + i);
- uint8x16_t AxorB = veorq_u8 (A_vec, B_vec);
- uint8x16_t bitsSet = vcntq_u8 (AxorB);
- uint16x8_t bitSet8 = vpaddlq_u8 (bitsSet);
- uint32x4_t bitSet4 = vpaddlq_u16 (bitSet8);
- bits = vaddq_u32(bits, bitSet4);
- }
- uint64x2_t bitSet2 = vpaddlq_u32 (bits);
- result = vgetq_lane_s32 (vreinterpretq_s32_u64(bitSet2),0);
- result += vgetq_lane_s32 (vreinterpretq_s32_u64(bitSet2),2);
- }
- #elif defined(__GNUC__)
- {
- //for portability just use unsigned long -- and use the __builtin_popcountll (see docs for __builtin_popcountll)
- typedef unsigned long long pop_t;
- const size_t modulo = size % sizeof(pop_t);
- const pop_t* a2 = reinterpret_cast<const pop_t*> (a);
- const pop_t* b2 = reinterpret_cast<const pop_t*> (b);
- const pop_t* a2_end = a2 + (size / sizeof(pop_t));
- for (; a2 != a2_end; ++a2, ++b2) result += __builtin_popcountll((*a2) ^ (*b2));
- if (modulo) {
- //in the case where size is not dividable by sizeof(size_t)
- //need to mask off the bits at the end
- pop_t a_final = 0, b_final = 0;
- memcpy(&a_final, a2, modulo);
- memcpy(&b_final, b2, modulo);
- result += __builtin_popcountll(a_final ^ b_final);
- }
- }
- #else // NO NEON and NOT GNUC
- HammingLUT lut;
- result = lut(reinterpret_cast<const unsigned char*> (a),
- reinterpret_cast<const unsigned char*> (b), size);
- #endif
- return result;
- }
- template<typename Iterator1>
- ResultType operator()(const Iterator1 a, ZeroIterator<unsigned char> b, size_t size, ResultType /*worst_dist*/ = -1) const
- {
- (void)b;
- ResultType result = 0;
- #if defined(__ARM_NEON__) && !defined(__CUDACC__)
- {
- const unsigned char* a2 = reinterpret_cast<const unsigned char*> (a);
- uint32x4_t bits = vmovq_n_u32(0);
- for (size_t i = 0; i < size; i += 16) {
- uint8x16_t A_vec = vld1q_u8 (a2 + i);
- uint8x16_t bitsSet = vcntq_u8 (A_vec);
- uint16x8_t bitSet8 = vpaddlq_u8 (bitsSet);
- uint32x4_t bitSet4 = vpaddlq_u16 (bitSet8);
- bits = vaddq_u32(bits, bitSet4);
- }
- uint64x2_t bitSet2 = vpaddlq_u32 (bits);
- result = vgetq_lane_s32 (vreinterpretq_s32_u64(bitSet2),0);
- result += vgetq_lane_s32 (vreinterpretq_s32_u64(bitSet2),2);
- }
- #elif defined(__GNUC__)
- {
- //for portability just use unsigned long -- and use the __builtin_popcountll (see docs for __builtin_popcountll)
- typedef unsigned long long pop_t;
- const size_t modulo = size % sizeof(pop_t);
- const pop_t* a2 = reinterpret_cast<const pop_t*> (a);
- const pop_t* a2_end = a2 + (size / sizeof(pop_t));
- for (; a2 != a2_end; ++a2) result += __builtin_popcountll(*a2);
- if (modulo) {
- //in the case where size is not dividable by sizeof(size_t)
- //need to mask off the bits at the end
- pop_t a_final = 0;
- memcpy(&a_final, a2, modulo);
- result += __builtin_popcountll(a_final);
- }
- }
- #else // NO NEON and NOT GNUC
- HammingLUT lut;
- result = lut(reinterpret_cast<const unsigned char*> (a), b, size);
- #endif
- return result;
- }
- };
- template<typename T>
- struct Hamming2
- {
- typedef False is_kdtree_distance;
- typedef False is_vector_space_distance;
- typedef T ElementType;
- typedef int ResultType;
- typedef ElementType CentersType;
- /** This is popcount_3() from:
- * http://en.wikipedia.org/wiki/Hamming_weight */
- unsigned int popcnt32(uint32_t n) const
- {
- n -= ((n >> 1) & 0x55555555);
- n = (n & 0x33333333) + ((n >> 2) & 0x33333333);
- return (((n + (n >> 4))& 0xF0F0F0F)* 0x1010101) >> 24;
- }
- #ifdef FLANN_PLATFORM_64_BIT
- unsigned int popcnt64(uint64_t n) const
- {
- n -= ((n >> 1) & 0x5555555555555555);
- n = (n & 0x3333333333333333) + ((n >> 2) & 0x3333333333333333);
- return (((n + (n >> 4))& 0x0f0f0f0f0f0f0f0f)* 0x0101010101010101) >> 56;
- }
- #endif
- template <typename Iterator1, typename Iterator2>
- ResultType operator()(const Iterator1 a, const Iterator2 b, size_t size, ResultType /*worst_dist*/ = -1) const
- {
- CV_DbgAssert(!(size % long_word_size_) && "vectors size must be multiple of long words size (i.e. 8)");
- #ifdef FLANN_PLATFORM_64_BIT
- const uint64_t* pa = reinterpret_cast<const uint64_t*>(a);
- const uint64_t* pb = reinterpret_cast<const uint64_t*>(b);
- ResultType result = 0;
- size /= long_word_size_;
- for(size_t i = 0; i < size; ++i ) {
- result += popcnt64(*pa ^ *pb);
- ++pa;
- ++pb;
- }
- #else
- const uint32_t* pa = reinterpret_cast<const uint32_t*>(a);
- const uint32_t* pb = reinterpret_cast<const uint32_t*>(b);
- ResultType result = 0;
- size /= long_word_size_;
- for(size_t i = 0; i < size; ++i ) {
- result += popcnt32(*pa ^ *pb);
- ++pa;
- ++pb;
- }
- #endif
- return result;
- }
- template <typename Iterator1>
- ResultType operator()(const Iterator1 a, ZeroIterator<unsigned char> b, size_t size, ResultType /*worst_dist*/ = -1) const
- {
- CV_DbgAssert(!(size % long_word_size_) && "vectors size must be multiple of long words size (i.e. 8)");
- (void)b;
- #ifdef FLANN_PLATFORM_64_BIT
- const uint64_t* pa = reinterpret_cast<const uint64_t*>(a);
- ResultType result = 0;
- size /= long_word_size_;
- for(size_t i = 0; i < size; ++i ) {
- result += popcnt64(*pa);
- ++pa;
- }
- #else
- const uint32_t* pa = reinterpret_cast<const uint32_t*>(a);
- ResultType result = 0;
- size /= long_word_size_;
- for(size_t i = 0; i < size; ++i ) {
- result += popcnt32(*pa);
- ++pa;
- }
- #endif
- return result;
- }
- private:
- #ifdef FLANN_PLATFORM_64_BIT
- static const size_t long_word_size_ = sizeof(uint64_t)/sizeof(unsigned char);
- #else
- static const size_t long_word_size_ = sizeof(uint32_t)/sizeof(unsigned char);
- #endif
- };
- ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
- struct DNAmmingLUT
- {
- typedef False is_kdtree_distance;
- typedef False is_vector_space_distance;
- typedef unsigned char ElementType;
- typedef int ResultType;
- typedef ElementType CentersType;
- /** this will count the bits in a ^ b
- */
- template<typename Iterator2>
- ResultType operator()(const unsigned char* a, const Iterator2 b, size_t size) const
- {
- static const uchar popCountTable[] =
- {
- 0, 1, 1, 1, 1, 2, 2, 2, 1, 2, 2, 2, 1, 2, 2, 2, 1, 2, 2, 2, 2, 3, 3, 3, 2, 3, 3, 3, 2, 3, 3, 3,
- 1, 2, 2, 2, 2, 3, 3, 3, 2, 3, 3, 3, 2, 3, 3, 3, 1, 2, 2, 2, 2, 3, 3, 3, 2, 3, 3, 3, 2, 3, 3, 3,
- 1, 2, 2, 2, 2, 3, 3, 3, 2, 3, 3, 3, 2, 3, 3, 3, 2, 3, 3, 3, 3, 4, 4, 4, 3, 4, 4, 4, 3, 4, 4, 4,
- 2, 3, 3, 3, 3, 4, 4, 4, 3, 4, 4, 4, 3, 4, 4, 4, 2, 3, 3, 3, 3, 4, 4, 4, 3, 4, 4, 4, 3, 4, 4, 4,
- 1, 2, 2, 2, 2, 3, 3, 3, 2, 3, 3, 3, 2, 3, 3, 3, 2, 3, 3, 3, 3, 4, 4, 4, 3, 4, 4, 4, 3, 4, 4, 4,
- 2, 3, 3, 3, 3, 4, 4, 4, 3, 4, 4, 4, 3, 4, 4, 4, 2, 3, 3, 3, 3, 4, 4, 4, 3, 4, 4, 4, 3, 4, 4, 4,
- 1, 2, 2, 2, 2, 3, 3, 3, 2, 3, 3, 3, 2, 3, 3, 3, 2, 3, 3, 3, 3, 4, 4, 4, 3, 4, 4, 4, 3, 4, 4, 4,
- 2, 3, 3, 3, 3, 4, 4, 4, 3, 4, 4, 4, 3, 4, 4, 4, 2, 3, 3, 3, 3, 4, 4, 4, 3, 4, 4, 4, 3, 4, 4, 4
- };
- ResultType result = 0;
- const unsigned char* b2 = reinterpret_cast<const unsigned char*> (b);
- for (size_t i = 0; i < size; i++) {
- result += popCountTable[a[i] ^ b2[i]];
- }
- return result;
- }
- ResultType operator()(const unsigned char* a, const ZeroIterator<unsigned char> b, size_t size) const
- {
- (void)b;
- static const uchar popCountTable[] =
- {
- 0, 1, 1, 1, 1, 2, 2, 2, 1, 2, 2, 2, 1, 2, 2, 2, 1, 2, 2, 2, 2, 3, 3, 3, 2, 3, 3, 3, 2, 3, 3, 3,
- 1, 2, 2, 2, 2, 3, 3, 3, 2, 3, 3, 3, 2, 3, 3, 3, 1, 2, 2, 2, 2, 3, 3, 3, 2, 3, 3, 3, 2, 3, 3, 3,
- 1, 2, 2, 2, 2, 3, 3, 3, 2, 3, 3, 3, 2, 3, 3, 3, 2, 3, 3, 3, 3, 4, 4, 4, 3, 4, 4, 4, 3, 4, 4, 4,
- 2, 3, 3, 3, 3, 4, 4, 4, 3, 4, 4, 4, 3, 4, 4, 4, 2, 3, 3, 3, 3, 4, 4, 4, 3, 4, 4, 4, 3, 4, 4, 4,
- 1, 2, 2, 2, 2, 3, 3, 3, 2, 3, 3, 3, 2, 3, 3, 3, 2, 3, 3, 3, 3, 4, 4, 4, 3, 4, 4, 4, 3, 4, 4, 4,
- 2, 3, 3, 3, 3, 4, 4, 4, 3, 4, 4, 4, 3, 4, 4, 4, 2, 3, 3, 3, 3, 4, 4, 4, 3, 4, 4, 4, 3, 4, 4, 4,
- 1, 2, 2, 2, 2, 3, 3, 3, 2, 3, 3, 3, 2, 3, 3, 3, 2, 3, 3, 3, 3, 4, 4, 4, 3, 4, 4, 4, 3, 4, 4, 4,
- 2, 3, 3, 3, 3, 4, 4, 4, 3, 4, 4, 4, 3, 4, 4, 4, 2, 3, 3, 3, 3, 4, 4, 4, 3, 4, 4, 4, 3, 4, 4, 4
- };
- ResultType result = 0;
- for (size_t i = 0; i < size; i++) {
- result += popCountTable[a[i]];
- }
- return result;
- }
- };
- template<typename T>
- struct DNAmming2
- {
- typedef False is_kdtree_distance;
- typedef False is_vector_space_distance;
- typedef T ElementType;
- typedef int ResultType;
- typedef ElementType CentersType;
- /** This is popcount_3() from:
- * http://en.wikipedia.org/wiki/Hamming_weight */
- unsigned int popcnt32(uint32_t n) const
- {
- n = ((n >> 1) | n) & 0x55555555;
- n = (n & 0x33333333) + ((n >> 2) & 0x33333333);
- return (((n + (n >> 4))& 0x0F0F0F0F)* 0x01010101) >> 24;
- }
- #ifdef FLANN_PLATFORM_64_BIT
- unsigned int popcnt64(uint64_t n) const
- {
- n = ((n >> 1) | n) & 0x5555555555555555;
- n = (n & 0x3333333333333333) + ((n >> 2) & 0x3333333333333333);
- return (((n + (n >> 4))& 0x0f0f0f0f0f0f0f0f)* 0x0101010101010101) >> 56;
- }
- #endif
- template <typename Iterator1, typename Iterator2>
- ResultType operator()(const Iterator1 a, const Iterator2 b, size_t size, ResultType /*worst_dist*/ = -1) const
- {
- CV_DbgAssert(!(size % long_word_size_) && "vectors size must be multiple of long words size (i.e. 8)");
- #ifdef FLANN_PLATFORM_64_BIT
- const uint64_t* pa = reinterpret_cast<const uint64_t*>(a);
- const uint64_t* pb = reinterpret_cast<const uint64_t*>(b);
- ResultType result = 0;
- size /= long_word_size_;
- for(size_t i = 0; i < size; ++i ) {
- result += popcnt64(*pa ^ *pb);
- ++pa;
- ++pb;
- }
- #else
- const uint32_t* pa = reinterpret_cast<const uint32_t*>(a);
- const uint32_t* pb = reinterpret_cast<const uint32_t*>(b);
- ResultType result = 0;
- size /= long_word_size_;
- for(size_t i = 0; i < size; ++i ) {
- result += popcnt32(*pa ^ *pb);
- ++pa;
- ++pb;
- }
- #endif
- return result;
- }
- template <typename Iterator1>
- ResultType operator()(const Iterator1 a, ZeroIterator<unsigned char> b, size_t size, ResultType /*worst_dist*/ = -1) const
- {
- CV_DbgAssert(!(size % long_word_size_) && "vectors size must be multiple of long words size (i.e. 8)");
- (void)b;
- #ifdef FLANN_PLATFORM_64_BIT
- const uint64_t* pa = reinterpret_cast<const uint64_t*>(a);
- ResultType result = 0;
- size /= long_word_size_;
- for(size_t i = 0; i < size; ++i ) {
- result += popcnt64(*pa);
- ++pa;
- }
- #else
- const uint32_t* pa = reinterpret_cast<const uint32_t*>(a);
- ResultType result = 0;
- size /= long_word_size_;
- for(size_t i = 0; i < size; ++i ) {
- result += popcnt32(*pa);
- ++pa;
- }
- #endif
- return result;
- }
- private:
- #ifdef FLANN_PLATFORM_64_BIT
- static const size_t long_word_size_= sizeof(uint64_t)/sizeof(unsigned char);
- #else
- static const size_t long_word_size_= sizeof(uint32_t)/sizeof(unsigned char);
- #endif
- };
- template<class T>
- struct HistIntersectionDistance
- {
- typedef True is_kdtree_distance;
- typedef True is_vector_space_distance;
- typedef T ElementType;
- typedef typename Accumulator<T>::Type ResultType;
- typedef ResultType CentersType;
- /**
- * Compute the histogram intersection distance
- */
- template <typename Iterator1, typename Iterator2>
- ResultType operator()(Iterator1 a, Iterator2 b, size_t size, ResultType worst_dist = -1) const
- {
- ResultType result = ResultType();
- ResultType min0, min1, min2, min3;
- Iterator1 last = a + size;
- Iterator1 lastgroup = last - 3;
- /* Process 4 items with each loop for efficiency. */
- while (a < lastgroup) {
- min0 = (ResultType)(a[0] < b[0] ? a[0] : b[0]);
- min1 = (ResultType)(a[1] < b[1] ? a[1] : b[1]);
- min2 = (ResultType)(a[2] < b[2] ? a[2] : b[2]);
- min3 = (ResultType)(a[3] < b[3] ? a[3] : b[3]);
- result += min0 + min1 + min2 + min3;
- a += 4;
- b += 4;
- if ((worst_dist>0)&&(result>worst_dist)) {
- return result;
- }
- }
- /* Process last 0-3 pixels. Not needed for standard vector lengths. */
- while (a < last) {
- min0 = (ResultType)(*a < *b ? *a : *b);
- result += min0;
- ++a;
- ++b;
- }
- return result;
- }
- /**
- * Partial distance, used by the kd-tree.
- */
- template <typename U, typename V>
- inline ResultType accum_dist(const U& a, const V& b, int) const
- {
- return a<b ? a : b;
- }
- };
- template<class T>
- struct HellingerDistance
- {
- typedef True is_kdtree_distance;
- typedef True is_vector_space_distance;
- typedef T ElementType;
- typedef typename Accumulator<T>::Type ResultType;
- typedef ResultType CentersType;
- /**
- * Compute the Hellinger distance
- */
- template <typename Iterator1, typename Iterator2>
- ResultType operator()(Iterator1 a, Iterator2 b, size_t size, ResultType /*worst_dist*/ = -1) const
- {
- ResultType result = ResultType();
- ResultType diff0, diff1, diff2, diff3;
- Iterator1 last = a + size;
- Iterator1 lastgroup = last - 3;
- /* Process 4 items with each loop for efficiency. */
- while (a < lastgroup) {
- diff0 = sqrt(static_cast<ResultType>(a[0])) - sqrt(static_cast<ResultType>(b[0]));
- diff1 = sqrt(static_cast<ResultType>(a[1])) - sqrt(static_cast<ResultType>(b[1]));
- diff2 = sqrt(static_cast<ResultType>(a[2])) - sqrt(static_cast<ResultType>(b[2]));
- diff3 = sqrt(static_cast<ResultType>(a[3])) - sqrt(static_cast<ResultType>(b[3]));
- result += diff0 * diff0 + diff1 * diff1 + diff2 * diff2 + diff3 * diff3;
- a += 4;
- b += 4;
- }
- while (a < last) {
- diff0 = sqrt(static_cast<ResultType>(*a++)) - sqrt(static_cast<ResultType>(*b++));
- result += diff0 * diff0;
- }
- return result;
- }
- /**
- * Partial distance, used by the kd-tree.
- */
- template <typename U, typename V>
- inline ResultType accum_dist(const U& a, const V& b, int) const
- {
- ResultType diff = sqrt(static_cast<ResultType>(a)) - sqrt(static_cast<ResultType>(b));
- return diff * diff;
- }
- };
- template<class T>
- struct ChiSquareDistance
- {
- typedef True is_kdtree_distance;
- typedef True is_vector_space_distance;
- typedef T ElementType;
- typedef typename Accumulator<T>::Type ResultType;
- typedef ResultType CentersType;
- /**
- * Compute the chi-square distance
- */
- template <typename Iterator1, typename Iterator2>
- ResultType operator()(Iterator1 a, Iterator2 b, size_t size, ResultType worst_dist = -1) const
- {
- ResultType result = ResultType();
- ResultType sum, diff;
- Iterator1 last = a + size;
- while (a < last) {
- sum = (ResultType)(*a + *b);
- if (sum>0) {
- diff = (ResultType)(*a - *b);
- result += diff*diff/sum;
- }
- ++a;
- ++b;
- if ((worst_dist>0)&&(result>worst_dist)) {
- return result;
- }
- }
- return result;
- }
- /**
- * Partial distance, used by the kd-tree.
- */
- template <typename U, typename V>
- inline ResultType accum_dist(const U& a, const V& b, int) const
- {
- ResultType result = ResultType();
- ResultType sum, diff;
- sum = (ResultType)(a+b);
- if (sum>0) {
- diff = (ResultType)(a-b);
- result = diff*diff/sum;
- }
- return result;
- }
- };
- template<class T>
- struct KL_Divergence
- {
- typedef True is_kdtree_distance;
- typedef True is_vector_space_distance;
- typedef T ElementType;
- typedef typename Accumulator<T>::Type ResultType;
- typedef ResultType CentersType;
- /**
- * Compute the Kullback-Leibler divergence
- */
- template <typename Iterator1, typename Iterator2>
- ResultType operator()(Iterator1 a, Iterator2 b, size_t size, ResultType worst_dist = -1) const
- {
- ResultType result = ResultType();
- Iterator1 last = a + size;
- while (a < last) {
- if ( *a != 0 && *b != 0 ) {
- ResultType ratio = (ResultType)(*a / *b);
- if (ratio>0) {
- result += *a * log(ratio);
- }
- }
- ++a;
- ++b;
- if ((worst_dist>0)&&(result>worst_dist)) {
- return result;
- }
- }
- return result;
- }
- /**
- * Partial distance, used by the kd-tree.
- */
- template <typename U, typename V>
- inline ResultType accum_dist(const U& a, const V& b, int) const
- {
- ResultType result = ResultType();
- if( a != 0 && b != 0 ) {
- ResultType ratio = (ResultType)(a / b);
- if (ratio>0) {
- result = a * log(ratio);
- }
- }
- return result;
- }
- };
- /*
- * Depending on processed distances, some of them are already squared (e.g. L2)
- * and some are not (e.g.Hamming). In KMeans++ for instance we want to be sure
- * we are working on ^2 distances, thus following templates to ensure that.
- */
- template <typename Distance, typename ElementType>
- struct squareDistance
- {
- typedef typename Distance::ResultType ResultType;
- ResultType operator()( ResultType dist ) { return dist*dist; }
- };
- template <typename ElementType>
- struct squareDistance<L2_Simple<ElementType>, ElementType>
- {
- typedef typename L2_Simple<ElementType>::ResultType ResultType;
- ResultType operator()( ResultType dist ) { return dist; }
- };
- template <typename ElementType>
- struct squareDistance<L2<ElementType>, ElementType>
- {
- typedef typename L2<ElementType>::ResultType ResultType;
- ResultType operator()( ResultType dist ) { return dist; }
- };
- template <typename ElementType>
- struct squareDistance<MinkowskiDistance<ElementType>, ElementType>
- {
- typedef typename MinkowskiDistance<ElementType>::ResultType ResultType;
- ResultType operator()( ResultType dist ) { return dist; }
- };
- template <typename ElementType>
- struct squareDistance<HellingerDistance<ElementType>, ElementType>
- {
- typedef typename HellingerDistance<ElementType>::ResultType ResultType;
- ResultType operator()( ResultType dist ) { return dist; }
- };
- template <typename ElementType>
- struct squareDistance<ChiSquareDistance<ElementType>, ElementType>
- {
- typedef typename ChiSquareDistance<ElementType>::ResultType ResultType;
- ResultType operator()( ResultType dist ) { return dist; }
- };
- template <typename Distance>
- typename Distance::ResultType ensureSquareDistance( typename Distance::ResultType dist )
- {
- typedef typename Distance::ElementType ElementType;
- squareDistance<Distance, ElementType> dummy;
- return dummy( dist );
- }
- /*
- * ...a template to tell the user if the distance he is working with is actually squared
- */
- template <typename Distance, typename ElementType>
- struct isSquareDist
- {
- bool operator()() { return false; }
- };
- template <typename ElementType>
- struct isSquareDist<L2_Simple<ElementType>, ElementType>
- {
- bool operator()() { return true; }
- };
- template <typename ElementType>
- struct isSquareDist<L2<ElementType>, ElementType>
- {
- bool operator()() { return true; }
- };
- template <typename ElementType>
- struct isSquareDist<MinkowskiDistance<ElementType>, ElementType>
- {
- bool operator()() { return true; }
- };
- template <typename ElementType>
- struct isSquareDist<HellingerDistance<ElementType>, ElementType>
- {
- bool operator()() { return true; }
- };
- template <typename ElementType>
- struct isSquareDist<ChiSquareDistance<ElementType>, ElementType>
- {
- bool operator()() { return true; }
- };
- template <typename Distance>
- bool isSquareDistance()
- {
- typedef typename Distance::ElementType ElementType;
- isSquareDist<Distance, ElementType> dummy;
- return dummy();
- }
- /*
- * ...and a template to ensure the user that he will process the normal distance,
- * and not squared distance, without losing processing time calling sqrt(ensureSquareDistance)
- * that will result in doing actually sqrt(dist*dist) for L1 distance for instance.
- */
- template <typename Distance, typename ElementType>
- struct simpleDistance
- {
- typedef typename Distance::ResultType ResultType;
- ResultType operator()( ResultType dist ) { return dist; }
- };
- template <typename ElementType>
- struct simpleDistance<L2_Simple<ElementType>, ElementType>
- {
- typedef typename L2_Simple<ElementType>::ResultType ResultType;
- ResultType operator()( ResultType dist ) { return sqrt(dist); }
- };
- template <typename ElementType>
- struct simpleDistance<L2<ElementType>, ElementType>
- {
- typedef typename L2<ElementType>::ResultType ResultType;
- ResultType operator()( ResultType dist ) { return sqrt(dist); }
- };
- template <typename ElementType>
- struct simpleDistance<MinkowskiDistance<ElementType>, ElementType>
- {
- typedef typename MinkowskiDistance<ElementType>::ResultType ResultType;
- ResultType operator()( ResultType dist ) { return sqrt(dist); }
- };
- template <typename ElementType>
- struct simpleDistance<HellingerDistance<ElementType>, ElementType>
- {
- typedef typename HellingerDistance<ElementType>::ResultType ResultType;
- ResultType operator()( ResultType dist ) { return sqrt(dist); }
- };
- template <typename ElementType>
- struct simpleDistance<ChiSquareDistance<ElementType>, ElementType>
- {
- typedef typename ChiSquareDistance<ElementType>::ResultType ResultType;
- ResultType operator()( ResultType dist ) { return sqrt(dist); }
- };
- template <typename Distance>
- typename Distance::ResultType ensureSimpleDistance( typename Distance::ResultType dist )
- {
- typedef typename Distance::ElementType ElementType;
- simpleDistance<Distance, ElementType> dummy;
- return dummy( dist );
- }
- }
- //! @endcond
- #endif //OPENCV_FLANN_DIST_H_
|