From 444e362ed906597776e01ec67e72a3b455852f79 Mon Sep 17 00:00:00 2001 From: generatedunixname89002005279527 Date: Wed, 16 Oct 2024 01:42:37 -0700 Subject: [PATCH] fbcode/mapillary/opensfm/opensfm/src/third_party/vlfeat/vl Reviewed By: bal-a Differential Revision: D63971206 fbshipit-source-id: bc3487af5506ee36768712541eb3f546234a22b1 --- opensfm/src/third_party/vlfeat/vl/aib.c | 643 ---- opensfm/src/third_party/vlfeat/vl/aib.h | 134 - opensfm/src/third_party/vlfeat/vl/array.c | 206 - opensfm/src/third_party/vlfeat/vl/array.h | 105 - opensfm/src/third_party/vlfeat/vl/covdet.c | 3400 ----------------- opensfm/src/third_party/vlfeat/vl/covdet.h | 263 -- opensfm/src/third_party/vlfeat/vl/dsift.c | 775 ---- opensfm/src/third_party/vlfeat/vl/dsift.h | 354 -- opensfm/src/third_party/vlfeat/vl/fisher.c | 586 --- opensfm/src/third_party/vlfeat/vl/fisher.h | 57 - opensfm/src/third_party/vlfeat/vl/float.h | 116 - opensfm/src/third_party/vlfeat/vl/generic.c | 1679 -------- opensfm/src/third_party/vlfeat/vl/generic.h | 213 -- .../src/third_party/vlfeat/vl/getopt_long.c | 326 -- .../src/third_party/vlfeat/vl/getopt_long.h | 43 - opensfm/src/third_party/vlfeat/vl/gmm.c | 1709 --------- opensfm/src/third_party/vlfeat/vl/gmm.h | 149 - opensfm/src/third_party/vlfeat/vl/heap-def.h | 464 --- opensfm/src/third_party/vlfeat/vl/hikmeans.c | 371 -- opensfm/src/third_party/vlfeat/vl/hikmeans.h | 80 - opensfm/src/third_party/vlfeat/vl/hog.c | 1072 ------ opensfm/src/third_party/vlfeat/vl/hog.h | 89 - opensfm/src/third_party/vlfeat/vl/homkermap.c | 580 --- opensfm/src/third_party/vlfeat/vl/homkermap.h | 86 - opensfm/src/third_party/vlfeat/vl/host.c | 586 --- opensfm/src/third_party/vlfeat/vl/host.h | 662 ---- opensfm/src/third_party/vlfeat/vl/ikmeans.c | 297 -- opensfm/src/third_party/vlfeat/vl/ikmeans.h | 87 - opensfm/src/third_party/vlfeat/vl/imopv.c | 1074 ------ opensfm/src/third_party/vlfeat/vl/imopv.h | 164 - .../src/third_party/vlfeat/vl/imopv_sse2.c | 289 -- .../src/third_party/vlfeat/vl/imopv_sse2.h | 54 - opensfm/src/third_party/vlfeat/vl/kdtree.c | 1082 ------ opensfm/src/third_party/vlfeat/vl/kdtree.h | 185 - opensfm/src/third_party/vlfeat/vl/kmeans.c | 2101 ---------- opensfm/src/third_party/vlfeat/vl/kmeans.h | 435 --- opensfm/src/third_party/vlfeat/vl/lbp.c | 347 -- opensfm/src/third_party/vlfeat/vl/lbp.h | 44 - opensfm/src/third_party/vlfeat/vl/liop.c | 641 ---- opensfm/src/third_party/vlfeat/vl/liop.h | 78 - opensfm/src/third_party/vlfeat/vl/mathop.c | 1032 ----- opensfm/src/third_party/vlfeat/vl/mathop.h | 719 ---- .../src/third_party/vlfeat/vl/mathop_avx.c | 275 -- .../src/third_party/vlfeat/vl/mathop_avx.h | 61 - .../src/third_party/vlfeat/vl/mathop_sse2.c | 564 --- .../src/third_party/vlfeat/vl/mathop_sse2.h | 85 - opensfm/src/third_party/vlfeat/vl/mser.c | 1001 ----- opensfm/src/third_party/vlfeat/vl/mser.h | 424 -- opensfm/src/third_party/vlfeat/vl/pgm.c | 542 --- opensfm/src/third_party/vlfeat/vl/pgm.h | 73 - opensfm/src/third_party/vlfeat/vl/qsort-def.h | 200 - .../src/third_party/vlfeat/vl/quickshift.c | 465 --- .../src/third_party/vlfeat/vl/quickshift.h | 211 - opensfm/src/third_party/vlfeat/vl/random.c | 266 -- opensfm/src/third_party/vlfeat/vl/random.h | 162 - opensfm/src/third_party/vlfeat/vl/rodrigues.c | 329 -- opensfm/src/third_party/vlfeat/vl/rodrigues.h | 33 - .../src/third_party/vlfeat/vl/scalespace.c | 821 ---- .../src/third_party/vlfeat/vl/scalespace.h | 99 - .../src/third_party/vlfeat/vl/shuffle-def.h | 101 - opensfm/src/third_party/vlfeat/vl/sift.c | 2197 ----------- opensfm/src/third_party/vlfeat/vl/sift.h | 418 -- opensfm/src/third_party/vlfeat/vl/slic.c | 411 -- opensfm/src/third_party/vlfeat/vl/slic.h | 30 - opensfm/src/third_party/vlfeat/vl/stringop.c | 462 --- opensfm/src/third_party/vlfeat/vl/stringop.h | 58 - opensfm/src/third_party/vlfeat/vl/svm.c | 2172 ----------- opensfm/src/third_party/vlfeat/vl/svm.h | 195 - .../src/third_party/vlfeat/vl/svmdataset.c | 407 -- .../src/third_party/vlfeat/vl/svmdataset.h | 82 - opensfm/src/third_party/vlfeat/vl/vlad.c | 323 -- opensfm/src/third_party/vlfeat/vl/vlad.h | 53 - 72 files changed, 35897 deletions(-) delete mode 100644 opensfm/src/third_party/vlfeat/vl/aib.c delete mode 100644 opensfm/src/third_party/vlfeat/vl/aib.h delete mode 100644 opensfm/src/third_party/vlfeat/vl/array.c delete mode 100644 opensfm/src/third_party/vlfeat/vl/array.h delete mode 100644 opensfm/src/third_party/vlfeat/vl/covdet.c delete mode 100644 opensfm/src/third_party/vlfeat/vl/covdet.h delete mode 100644 opensfm/src/third_party/vlfeat/vl/dsift.c delete mode 100644 opensfm/src/third_party/vlfeat/vl/dsift.h delete mode 100644 opensfm/src/third_party/vlfeat/vl/fisher.c delete mode 100644 opensfm/src/third_party/vlfeat/vl/fisher.h delete mode 100644 opensfm/src/third_party/vlfeat/vl/float.h delete mode 100644 opensfm/src/third_party/vlfeat/vl/generic.c delete mode 100644 opensfm/src/third_party/vlfeat/vl/generic.h delete mode 100644 opensfm/src/third_party/vlfeat/vl/getopt_long.c delete mode 100644 opensfm/src/third_party/vlfeat/vl/getopt_long.h delete mode 100644 opensfm/src/third_party/vlfeat/vl/gmm.c delete mode 100644 opensfm/src/third_party/vlfeat/vl/gmm.h delete mode 100644 opensfm/src/third_party/vlfeat/vl/heap-def.h delete mode 100644 opensfm/src/third_party/vlfeat/vl/hikmeans.c delete mode 100644 opensfm/src/third_party/vlfeat/vl/hikmeans.h delete mode 100644 opensfm/src/third_party/vlfeat/vl/hog.c delete mode 100644 opensfm/src/third_party/vlfeat/vl/hog.h delete mode 100644 opensfm/src/third_party/vlfeat/vl/homkermap.c delete mode 100644 opensfm/src/third_party/vlfeat/vl/homkermap.h delete mode 100644 opensfm/src/third_party/vlfeat/vl/host.c delete mode 100644 opensfm/src/third_party/vlfeat/vl/host.h delete mode 100644 opensfm/src/third_party/vlfeat/vl/ikmeans.c delete mode 100644 opensfm/src/third_party/vlfeat/vl/ikmeans.h delete mode 100644 opensfm/src/third_party/vlfeat/vl/imopv.c delete mode 100644 opensfm/src/third_party/vlfeat/vl/imopv.h delete mode 100644 opensfm/src/third_party/vlfeat/vl/imopv_sse2.c delete mode 100644 opensfm/src/third_party/vlfeat/vl/imopv_sse2.h delete mode 100644 opensfm/src/third_party/vlfeat/vl/kdtree.c delete mode 100644 opensfm/src/third_party/vlfeat/vl/kdtree.h delete mode 100644 opensfm/src/third_party/vlfeat/vl/kmeans.c delete mode 100644 opensfm/src/third_party/vlfeat/vl/kmeans.h delete mode 100644 opensfm/src/third_party/vlfeat/vl/lbp.c delete mode 100644 opensfm/src/third_party/vlfeat/vl/lbp.h delete mode 100644 opensfm/src/third_party/vlfeat/vl/liop.c delete mode 100644 opensfm/src/third_party/vlfeat/vl/liop.h delete mode 100644 opensfm/src/third_party/vlfeat/vl/mathop.c delete mode 100644 opensfm/src/third_party/vlfeat/vl/mathop.h delete mode 100644 opensfm/src/third_party/vlfeat/vl/mathop_avx.c delete mode 100644 opensfm/src/third_party/vlfeat/vl/mathop_avx.h delete mode 100644 opensfm/src/third_party/vlfeat/vl/mathop_sse2.c delete mode 100644 opensfm/src/third_party/vlfeat/vl/mathop_sse2.h delete mode 100644 opensfm/src/third_party/vlfeat/vl/mser.c delete mode 100644 opensfm/src/third_party/vlfeat/vl/mser.h delete mode 100644 opensfm/src/third_party/vlfeat/vl/pgm.c delete mode 100644 opensfm/src/third_party/vlfeat/vl/pgm.h delete mode 100644 opensfm/src/third_party/vlfeat/vl/qsort-def.h delete mode 100644 opensfm/src/third_party/vlfeat/vl/quickshift.c delete mode 100644 opensfm/src/third_party/vlfeat/vl/quickshift.h delete mode 100644 opensfm/src/third_party/vlfeat/vl/random.c delete mode 100644 opensfm/src/third_party/vlfeat/vl/random.h delete mode 100644 opensfm/src/third_party/vlfeat/vl/rodrigues.c delete mode 100644 opensfm/src/third_party/vlfeat/vl/rodrigues.h delete mode 100644 opensfm/src/third_party/vlfeat/vl/scalespace.c delete mode 100644 opensfm/src/third_party/vlfeat/vl/scalespace.h delete mode 100644 opensfm/src/third_party/vlfeat/vl/shuffle-def.h delete mode 100644 opensfm/src/third_party/vlfeat/vl/sift.c delete mode 100644 opensfm/src/third_party/vlfeat/vl/sift.h delete mode 100644 opensfm/src/third_party/vlfeat/vl/slic.c delete mode 100644 opensfm/src/third_party/vlfeat/vl/slic.h delete mode 100644 opensfm/src/third_party/vlfeat/vl/stringop.c delete mode 100644 opensfm/src/third_party/vlfeat/vl/stringop.h delete mode 100644 opensfm/src/third_party/vlfeat/vl/svm.c delete mode 100644 opensfm/src/third_party/vlfeat/vl/svm.h delete mode 100644 opensfm/src/third_party/vlfeat/vl/svmdataset.c delete mode 100644 opensfm/src/third_party/vlfeat/vl/svmdataset.h delete mode 100644 opensfm/src/third_party/vlfeat/vl/vlad.c delete mode 100644 opensfm/src/third_party/vlfeat/vl/vlad.h diff --git a/opensfm/src/third_party/vlfeat/vl/aib.c b/opensfm/src/third_party/vlfeat/vl/aib.c deleted file mode 100644 index 1c07b7084..000000000 --- a/opensfm/src/third_party/vlfeat/vl/aib.c +++ /dev/null @@ -1,643 +0,0 @@ -/** @file aib.c - ** @brief AIB - Definition - ** @author Brian Fulkerson - ** @author Andrea Vedaldi - **/ - -/* -Copyright (C) 2007-12 Andrea Vedaldi and Brian Fulkerson. -All rights reserved. - -This file is part of the VLFeat library and is made available under -the terms of the BSD license (see the COPYING file). -*/ - -/** - - -@page aib Agglomerative Information Bottleneck (AIB) -@author Brian Fulkerson -@author Andrea Vedaldi - - -@ref aib.h implemens the Agglomerative Information Bottleneck (AIB) -algorithm as first described in @cite{slonim99agglomerative}. - -AIB takes a discrete valued feature @f$x@f$ and a label @f$c@f$ and -gradually compresses @f$x@f$ by iteratively merging values which -minimize the loss in mutual information @f$I(x,c)@f$. - -While the algorithm is equivalent to the one described in -@cite{slonim99agglomerative}, it has some speedups that enable -handling much larger datasets. Let N be the number of feature -values and C the number of labels. The algorithm of -@cite{slonim99agglomerative} is @f$O(N^2)@f$ in space and @f$O(C -N^3)@f$ in time. This algorithm is @f$O(N)@f$ space and @f$O(C N^2)@f$ -time in common cases (@f$O(C N^3)@f$ in the worst case). - - -@section aib-overview Overview - - -Given a discrete feature @f$x \in \mathcal{X} = \{x_1,\dots,x_N\}@f$ -and a category label @f$c = 1,\dots,C@f$ with joint probability -@f$p(x,c)@f$, AIB computes a compressed feature @f$[x]_{ij}@f$ by -merging two values @f$x_i@f$ and @f$x_j@f$. Among all the pairs -@f$ij@f$, AIB chooses the one that yields the smallest loss in the -mutual information - -@f[ - D_{ij} = I(x,c) - I([x]_{ij},c) = - \sum_c p(x_i) \log \frac{p(x_i,c)}{p(x_i)p(c)} + - \sum_c p(x_i) \log \frac{p(x_i,c)}{p(x_i)p(c)} - - \sum_c (p(x_i)+p(x_j)) \log \frac {p(x_i,c)+p(x_i,c)}{(p(x_i)+p(x_j))p(c)} -@f] - -AIB iterates this procedure until the desired level of -compression is achieved. - -@section aib-algorithm Algorithm details - -Computing @f$D_{ij}@f$ requires @f$O(C)@f$ operations. For example, in -standard AIB we need to calculate - -@f[ - D_{ij} = I(x,c) - I([x]_{ij},c) = - \sum_c p(x_i) \log \frac{p(x_i,c)}{p(x_i)p(c)} + - \sum_c p(x_i) \log \frac{p(x_i,c)}{p(x_i)p(c)} - - \sum_c (p(x_i)+p(x_j)) \log \frac {p(x_i,c)+p(x_i,c)}{(p(x_i)+p(x_j))p(c)} -@f] - -Thus in a basic implementation of AIB, finding the optimal pair -@f$ij@f$ of feature values requires @f$O(CN^2)@f$ operations in -total. In order to join all the @f$N@f$ values, we repeat this -procedure @f$O(N)@f$ times, yielding @f$O(N^3 C)@f$ time and -@f$O(1)@f$ space complexity (this does not account for the space need -to store the input). - -The complexity can be improved by reusing computations. For instance, -we can store the matrix @f$D = [ D_{ij} ]@f$ (which requires -@f$O(N^2)@f$ space). Then, after joining @f$ij@f$, all of the matrix -D except the rows and columns (the matrix is symmetric) of -indexes i and j is unchanged. These two rows and -columns are deleted and a new row and column, whose computation -requires @f$O(NC)@f$ operations, are added for the merged value -@f$x_{ij}@f$. Finding the minimal element of the matrix still -requires @f$O(N^2)@f$ operations, so the complexity of this algorithm -is @f$O(N^2C + N^3)@f$ time and @f$O(N^2)@f$ space. - -We can obtain a much better expected complexity as follows. First, -instead of storing the whole matrix D, we store the smallest -element (index and value) of each row as @f$(q_i, D_i)@f$ (notice that -this is also the best element of each column since D is -symmetric). This requires @f$O(N)@f$ space and finding the minimal -element of the matrix requires @f$O(N)@f$ operations. After joining -@f$ij@f$, we have to efficiently update this representation. This is -done as follows: - -- The entries @f$(q_i,D_i)@f$ and @f$(q_j,D_j)@f$ are deleted. -- A new entry @f$(q_{ij},D_{ij})@f$ for the joint value @f$x_{ij}@f$ - is added. This requires @f$O(CN)@f$ operations. -- We test which other entries @f$(q_{k},D_{k})@f$ need to - be updated. Recall that @f$(q_{k},D_{k})@f$ means that, before the - merge, the value - closest to @f$x_k@f$ was @f$x_{q_k}@f$ at a distance @f$D_k@f$. Then - - If @f$q_k \not = i@f$, @f$q_k \not = j@f$ and @f$D_{k,ij} \geq D_k@f$, then - @f$q_k@f$ is still the closest element and we do not do anything. - - If @f$q_k \not = i@f$, @f$q_k \not = j@f$ and @f$D_{k,ij} < - D_k@f$, then the closest element is @f$ij@f$ and we update the - entry in constant time. - - If @f$q_k = i@f$ or @f$q_k = j@f$, then we need to re-compute - the closest element in @f$O(CN)@f$ operations. - -This algorithm requires only @f$O(N)@f$ space and @f$O(\gamma(N) C -N^2)@f$ time, where @f$\gamma(N)@f$ is the expected number of times we -fall in the last case. In common cases one has @f$\gamma(N) \approx -\mathrm{const.}@f$, so the time saving is significant. - -**/ - -#include "aib.h" -#include -#include -#include -#include - -/* The maximum value which beta may take */ -#define BETA_MAX DBL_MAX - -/** ------------------------------------------------------------------ - ** @internal - ** @brief Normalizes an array of probabilities to sum to 1 - ** - ** @param P The array of probabilities - ** @param nelem The number of elements in the array - ** - ** @return Modifies P to contain values which sum to 1 - **/ - -void vl_aib_normalize_P (double * P, vl_uint nelem) -{ - vl_uint i; - double sum = 0; - for(i=0; ibeta to find the minimum value and fills @a minbeta and - ** @a besti and @a bestj with this information. - **/ - -void vl_aib_min_beta -(VlAIB * aib, vl_uint * besti, vl_uint * bestj, double * minbeta) -{ - vl_uint i; - *minbeta = aib->beta[0]; - *besti = 0; - *bestj = aib->bidx[0]; - - for(i=0; inentries; i++) - { - if(aib->beta[i] < *minbeta) - { - *minbeta = aib->beta[i]; - *besti = i; - *bestj = aib->bidx[i]; - } - } -} - -/** ------------------------------------------------------------------ - ** @internal - ** @brief Merges two nodes i,j in the internal datastructure - ** - ** @param aib A pointer to the internal data structure - ** @param i The index of one member of the pair to merge - ** @param j The index of the other member of the pair to merge - ** @param new The index of the new node which corresponds to the union of - ** (@a i, @a j). - ** - ** Nodes are merged by replacing the entry @a i with the union of @c - ** ij, moving the node stored in last position (called @c lastnode) - ** back to jth position and the entry at the end. - ** - ** After the nodes have been merged, it updates which nodes should be - ** considered on the next iteration based on which beta values could - ** potentially change. The merged node will always be part of this - ** list. - **/ - -void -vl_aib_merge_nodes (VlAIB * aib, vl_uint i, vl_uint j, vl_uint new) -{ - vl_uint last_entry = aib->nentries - 1 ; - vl_uint c, n ; - - /* clear the list of nodes to update */ - aib->nwhich = 0; - - /* make sure that i is smaller than j */ - if(i > j) { vl_uint tmp = j; j = i; i = tmp; } - - /* ----------------------------------------------------------------- - * Merge entries i and j, storing the result in i - * -------------------------------------------------------------- */ - - aib-> Px [i] += aib->Px[j] ; - aib-> beta [i] = BETA_MAX ; - aib-> nodes[i] = new ; - - for (c = 0; c < aib->nlabels; c++) - aib-> Pcx [i*aib->nlabels + c] += aib-> Pcx [j*aib->nlabels + c] ; - - /* ----------------------------------------------------------------- - * Move last entry to j - * -------------------------------------------------------------- */ - - aib-> Px [j] = aib-> Px [last_entry]; - aib-> beta [j] = aib-> beta [last_entry]; - aib-> bidx [j] = aib-> bidx [last_entry]; - aib-> nodes [j] = aib-> nodes [last_entry]; - - for (c = 0 ; c < aib->nlabels ; c++) - aib-> Pcx[j*aib->nlabels + c] = aib-> Pcx [last_entry*aib->nlabels + c] ; - - /* delete last entry */ - aib-> nentries -- ; - - /* ----------------------------------------------------------------- - * Scan for entries to update - * -------------------------------------------------------------- */ - - /* - * After mergin entries i and j, we need to update all other entries - * that had one of these two as closest match. We also need to - * update the renewend entry i. This is added by the loop below - * since bidx [i] = j exactly because i was merged. - * - * Additionaly, since we moved the last entry back to the entry j, - * we need to adjust the valeus of bidx to reflect this. - */ - - for (n = 0 ; n < aib->nentries; n++) { - if(aib->bidx[n] == i || aib->bidx[n] == j) { - aib->bidx [n] = 0; - aib->beta [n] = BETA_MAX; - aib->which [aib->nwhich++] = n ; - } - else if(aib->bidx[n] == last_entry) { - aib->bidx[n] = j ; - } - } -} - -/** ------------------------------------------------------------------ - ** @internal - ** @brief Updates @c aib->beta and @c aib->bidx according to @c aib->which - ** - ** @param aib AIB data structure. - ** - ** The function calculates @c beta[i] and @c bidx[i] for the nodes @c - ** i listed in @c aib->which. @c beta[i] is the minimal variation of mutual - ** information (or other score) caused by merging entry @c i with another entry - ** and @c bidx[i] is the index of this best matching entry. - ** - ** Notice that for each entry @c i that we need to update, a full - ** scan of all the other entries must be performed. - **/ - -void -vl_aib_update_beta (VlAIB * aib) -{ - -#define PLOGP(x) ((x)*log((x))) - - vl_uint i; - double * Px = aib->Px; - double * Pcx = aib->Pcx; - double * tmp = vl_malloc(sizeof(double)*aib->nentries); - vl_uint a, b, c ; - - /* - * T1 = I(x,c) - I([x]_ij) = A + B - C - * - * A = \sum_c p(xa,c) \log ( p(xa,c) / p(xa) ) - * B = \sum_c p(xb,c) \log ( p(xb,c) / p(xb) ) - * C = \sum_c (p(xa,c)+p(xb,c)) \log ((p(xa,c)+p(xb,c)) / (p(xa)+p(xb))) - * - * C = C1 + C2 - * C1 = \sum_c (p(xa,c)+p(xb,c)) \log (p(xa,c)+p(xb,c)) - * C2 = - (p(xa)+p(xb) \log (p(xa)+p(xb)) - */ - - /* precalculate A and B */ - for (a = 0; a < aib->nentries; a++) { - tmp[a] = 0; - for (c = 0; c < aib->nlabels; c++) { - double Pac = Pcx [a*aib->nlabels + c] ; - if(Pac != 0) tmp[a] += Pac * log (Pac / Px[a]) ; - } - } - - /* for each entry listed in which */ - for (i = 0 ; i < aib->nwhich; i++) { - a = aib->which[i]; - - /* for each other entry */ - for(b = 0 ; b < aib->nentries ; b++) { - double T1 = 0 ; - - if (a == b || Px [a] == 0 || Px [b] == 0) continue ; - - - T1 = PLOGP ((Px[a] + Px[b])) ; /* - C2 */ - T1 += tmp[a] + tmp[b] ; /* + A + B */ - - for (c = 0 ; c < aib->nlabels; ++ c) { - double Pac = Pcx [a*aib->nlabels + c] ; - double Pbc = Pcx [b*aib->nlabels + c] ; - if (Pac == 0 && Pbc == 0) continue; - T1 += - PLOGP ((Pac + Pbc)) ; /* - C1 */ - } - - /* - * Now we have beta(a,b). We check wether this is the best beta - * for entries a and b. - */ - { - double beta = T1 ; - - if (beta < aib->beta[a]) - { - aib->beta[a] = beta; - aib->bidx[a] = b; - } - if (beta < aib->beta[b]) - { - aib->beta[b] = beta; - aib->bidx[b] = a; - } - } - } - } - vl_free(tmp); -} - -/** ------------------------------------------------------------------ - ** @internal @brief Calculates the current information and entropy - ** - ** @param aib A pointer to the internal data structure - ** @param I The current mutual information (out). - ** @param H The current entropy (out). - ** - ** Calculates the current mutual information and entropy of Pcx and sets - ** @a I and @a H to these new values. - **/ -void vl_aib_calculate_information(VlAIB * aib, double * I, double * H) -{ - vl_uint r, c; - *H = 0; - *I = 0; - - /* - * H(x) = - sum_x p(x) \ log p(x) - * I(x,c) = sum_xc p(x,c) \ log (p(x,c) / p(x)p(c)) - */ - - /* for each entry */ - for(r = 0 ; r< aib->nentries ; r++) { - - if (aib->Px[r] == 0) continue ; - *H += -log(aib->Px[r]) * aib->Px[r] ; - - for(c=0; cnlabels; c++) { - if (aib->Pcx[r*aib->nlabels+c] == 0) continue; - *I += aib->Pcx[r*aib->nlabels+c] * - log (aib->Pcx[r*aib->nlabels+c] / (aib->Px[r]*aib->Pc[c])) ; - } - } -} - -/** ------------------------------------------------------------------ - ** @brief Allocates and initializes the internal data structure - ** - ** @param Pcx A pointer to a 2D array of probabilities - ** @param nvalues The number of rows in the array - ** @param nlabels The number of columns in the array - ** - ** Creates a new @a VlAIB struct containing pointers to all the data that - ** will be used during the AIB process. - ** - ** Allocates memory for the following: - ** - Px (nvalues*sizeof(double)) - ** - Pc (nlabels*sizeof(double)) - ** - nodelist (nvalues*sizeof(vl_uint)) - ** - which (nvalues*sizeof(vl_uint)) - ** - beta (nvalues*sizeof(double)) - ** - bidx (nvalues*sizeof(vl_uint)) - ** - parents ((2*nvalues-1)*sizeof(vl_uint)) - ** - costs (nvalues*sizeof(double)) - ** - ** Since it simply copies to pointer to Pcx, the total additional memory - ** requirement is: - ** - ** (3*nvalues+nlabels)*sizeof(double) + 4*nvalues*sizeof(vl_uint) - ** - ** @returns An allocated and initialized @a VlAIB pointer - **/ -VlAIB * vl_aib_new(double * Pcx, vl_uint nvalues, vl_uint nlabels) -{ - VlAIB * aib = vl_malloc(sizeof(VlAIB)); - vl_uint i ; - - aib->verbosity = 0 ; - aib->Pcx = Pcx ; - aib->nvalues = nvalues ; - aib->nlabels = nlabels ; - - vl_aib_normalize_P (aib->Pcx, aib->nvalues * aib->nlabels) ; - - aib->Px = vl_aib_new_Px (aib->Pcx, aib->nvalues, aib->nlabels) ; - aib->Pc = vl_aib_new_Pc (aib->Pcx, aib->nvalues, aib->nlabels) ; - - aib->nentries = aib->nvalues ; - aib->nodes = vl_aib_new_nodelist(aib->nentries) ; - aib->beta = vl_malloc(sizeof(double) * aib->nentries) ; - aib->bidx = vl_malloc(sizeof(vl_uint) * aib->nentries) ; - - for(i = 0 ; i < aib->nentries ; i++) - aib->beta [i] = BETA_MAX ; - - /* Initially we must consider all nodes */ - aib->nwhich = aib->nvalues; - aib->which = vl_aib_new_nodelist (aib->nwhich) ; - - aib->parents = vl_malloc(sizeof(vl_uint)*(aib->nvalues*2-1)); - /* Initially, all parents point to a nonexistent node */ - for (i = 0 ; i < 2 * aib->nvalues - 1 ; i++) - aib->parents [i] = 2 * aib->nvalues ; - - /* Allocate cost output vector */ - aib->costs = vl_malloc (sizeof(double) * (aib->nvalues - 1 + 1)) ; - - - return aib ; -} - -/** ------------------------------------------------------------------ - ** @brief Deletes AIB data structure - ** @param aib data structure to delete. - **/ - -void -vl_aib_delete (VlAIB * aib) -{ - if (aib) { - if (aib-> nodes) vl_free (aib-> nodes); - if (aib-> beta) vl_free (aib-> beta); - if (aib-> bidx) vl_free (aib-> bidx); - if (aib-> which) vl_free (aib-> which); - if (aib-> Px) vl_free (aib-> Px); - if (aib-> Pc) vl_free (aib-> Pc); - if (aib-> parents) vl_free (aib-> parents); - if (aib-> costs) vl_free (aib-> costs); - - vl_free (aib) ; - } -} - -/** ------------------------------------------------------------------ - ** @brief Runs AIB on Pcx - ** - ** @param aib AIB object to process - ** - ** The function runs Agglomerative Information Bottleneck (AIB) on - ** the joint probability table @a aib->Pcx which has labels along the - ** columns and feature values along the rows. AIB iteratively merges - ** the two values of the feature @c x that causes the smallest - ** decrease in mutual information between the random variables @c x - ** and @c c. - ** - ** Merge operations are arranged in a binary tree. The nodes of the - ** tree correspond to the original feature values and any other value - ** obtained as a result of a merge operation. The nodes are indexed - ** in breadth-first order, starting from the leaves. The first index - ** is zero. In this way, the leaves correspond directly to the - ** original feature values. In total there are @c 2*nvalues-1 nodes. - ** - ** The results may be accessed through vl_aib_get_parents which - ** returns an array with one element per tree node. Each - ** element is the index the parent node. The root parent is equal to - ** zero. The array has @c 2*nvalues-1 elements. - ** - ** Feature values with null probability are ignored by the algorithm - ** and their nodes have parents indexing a non-existent tree node (a - ** value bigger than @c 2*nvalues-1). - ** - ** Then the function will also compute the information level after each - ** merge. vl_get_costs will return a vector with the information level - ** after each merge. @a - ** cost has @c nvalues entries: The first is the value of the cost - ** functional before any merge, and the others are the cost after the - ** @c nvalues-1 merges. - ** - **/ - -VL_EXPORT -void vl_aib_process(VlAIB *aib) -{ - vl_uint i, besti, bestj, newnode, nodei, nodej; - double I, H; - double minbeta; - - /* Calculate initial value of cost function */ - vl_aib_calculate_information (aib, &I, &H) ; - aib->costs[0] = I; - - /* Initially which = all */ - - /* For each merge */ - for(i = 0 ; i < aib->nvalues - 1 ; i++) { - - /* update entries in aib-> which */ - vl_aib_update_beta(aib); - - /* find best pair of nodes to merge */ - vl_aib_min_beta (aib, &besti, &bestj, &minbeta); - - if(minbeta == BETA_MAX) - /* only null-probability entries remain */ - break; - - /* Add the parent pointers for the new node */ - newnode = aib->nvalues + i ; - nodei = aib->nodes[besti]; - nodej = aib->nodes[bestj]; - - aib->parents [nodei] = newnode ; - aib->parents [nodej] = newnode ; - aib->parents [newnode] = 0 ; - - /* Merge the nodes which produced the minimum beta */ - vl_aib_merge_nodes (aib, besti, bestj, newnode) ; - vl_aib_calculate_information (aib, &I, &H) ; - - aib->costs[i+1] = I; - - if (aib->verbosity > 0) { - VL_PRINTF ("aib: (%5d,%5d)=%5d dE: %10.3g I: %6.4g H: %6.4g updt: %5d\n", - nodei, - nodej, - newnode, - minbeta, - I, - H, - aib->nwhich) ; - } - } - - /* fill ignored entries with NaNs */ - for(; i < aib->nvalues - 1 ; i++) - aib->costs[i+1] = VL_NAN_D ; -} diff --git a/opensfm/src/third_party/vlfeat/vl/aib.h b/opensfm/src/third_party/vlfeat/vl/aib.h deleted file mode 100644 index ab7d4be21..000000000 --- a/opensfm/src/third_party/vlfeat/vl/aib.h +++ /dev/null @@ -1,134 +0,0 @@ -/** @file aib.h - ** @brief AIB (@ref aib) - ** @author Brian Fulkerson - ** @author Andrea Vedaldi - **/ - -/* -Copyright (C) 2007-12 Andrea Vedaldi and Brian Fulkerson. -All rights reserved. - -This file is part of the VLFeat library and is made available under -the terms of the BSD license (see the COPYING file). -*/ - -#ifndef VL_AIB_H -#define VL_AIB_H - -#include "generic.h" -#include "mathop.h" - -/** ------------------------------------------------------------------ - ** @internal - ** @brief AIB algorithm data - ** - ** The implementation is quite straightforward, but the way feature - ** values are handled in order to support efficient joins, - ** deletions and re-arrangement needs to be explained. This is - ** achieved by adding a layer of indirection: - ** - Call each feature value (either original or obtained by a join - ** operation) a node. Nodes are identified by numbers. - ** - Call each element of the various arrays (such as VlAIB::Px) - ** an entry. - ** - Entries are dynamically associated to nodes as specified by - ** VlAIB::nodes. For example, @c Px[i] refers to the node @c - ** nodes[i]. - **/ - -typedef struct _VlAIB -{ - vl_uint *nodes ; /**< Entires to nodes */ - vl_uint nentries ; /**< Total number of entries (= # active nodes) */ - double *beta ; /**< Minimum distance to an entry */ - vl_uint *bidx ; /**< Closest entry */ - - - vl_uint *which ; /**< List of entries to update */ - vl_uint nwhich ; /**< Number of entries to update */ - - double *Pcx; /**< Joint probability table */ - double *Px; /**< Marginal. */ - double *Pc; /**< Marginal. */ - vl_uint nvalues; /**< Number of feature values */ - vl_uint nlabels; /**< Number of labels */ - - vl_uint *parents; /**< Array of parents */ - double *costs; /**< Cost of each merge */ - - vl_uint verbosity ; /** Verbosity level */ -} VlAIB; - -/** @name Create and destroy - ** @{ - **/ -VL_EXPORT -VlAIB * vl_aib_new(double * Pcx, vl_uint nvalues, vl_uint nlabels); - -VL_EXPORT -void vl_aib_delete (VlAIB * aib); -/** @} */ - -/** @name Process data - ** @{ - **/ -VL_EXPORT -void vl_aib_process(VlAIB * aib); -/** @} */ - -/** @name Retrieve results - ** @{ - **/ -VL_INLINE vl_uint * vl_aib_get_parents(VlAIB const * aib); -VL_INLINE double * vl_aib_get_costs(VlAIB const * aib); -/** @} */ - - -/* ------------------------------------------------------------------- - * Inline functions implementation - * ---------------------------------------------------------------- */ - -/** ------------------------------------------------------------------ - ** @brief Get resulting list of parents - ** @param aib AIB filter. - ** @return An array of parents - **/ -VL_INLINE -vl_uint * vl_aib_get_parents(VlAIB const * aib) -{ - return aib->parents; -} - -/** ------------------------------------------------------------------ - ** @brief Get a list of merge costs - ** @param aib AIB filter. - ** @return An array of costs - **/ -VL_INLINE -double * vl_aib_get_costs(VlAIB const * aib) -{ - return aib->costs; -} - -/* ----------------------------------------------------------------- */ -/** @brief Set the verbosity - ** @param self AIB object. - ** @param verbosity a non-negative integer. - **/ -VL_INLINE void -vl_aib_set_verbosity (VlAIB * self, int verbosity) -{ - self->verbosity = verbosity ; -} - -/** @brief Get the verbosity - ** @param self AIB object. - ** @return the verbosity level. - **/ -VL_INLINE int -vl_aib_get_verbosity (VlAIB const * self) -{ - return self->verbosity ; -} - -/* VL_AIB_H */ -#endif diff --git a/opensfm/src/third_party/vlfeat/vl/array.c b/opensfm/src/third_party/vlfeat/vl/array.c deleted file mode 100644 index a81b438ec..000000000 --- a/opensfm/src/third_party/vlfeat/vl/array.c +++ /dev/null @@ -1,206 +0,0 @@ -/** @file array.h - ** @brief Array - ** @author Andrea Vedaldi - **/ - -/* -Copyright (C) 2007-12 Andrea Vedaldi and Brian Fulkerson. -All rights reserved. - -This file is part of the VLFeat library and is made available under -the terms of the BSD license (see the COPYING file). -*/ - -#include "array.h" -#include - -/** @brief Get number of elements in array - ** @param self array. - ** @return number of elements. - **/ - -VL_EXPORT vl_size -vl_array_get_num_elements (VlArray const * self) -{ - vl_size numElements = 1 ; - vl_uindex k ; - if (self->numDimensions == 0) { - return 0 ; - } - for (k = 0 ; k < self->numDimensions ; ++k) { - numElements *= self->dimensions[k] ; - } - return numElements ; -} - -/* ---------------------------------------------------------------- */ -/* init & dealloc */ -/* ---------------------------------------------------------------- */ - -/** @brief New numeric array - ** @param self array to initialize. - ** @param type data type. - ** @param numDimensions number of dimensions. - ** @param dimensions dimensions. - ** - ** The function initializes the specified array and allocates - ** the necessary memory for storage. - **/ - -VL_EXPORT VlArray * -vl_array_init (VlArray* self, vl_type type, - vl_size numDimensions, vl_size const * dimensions) -{ - assert (numDimensions <= VL_ARRAY_MAX_NUM_DIMENSIONS) ; - self->type = type ; - self->numDimensions = numDimensions ; - memcpy(self->dimensions, dimensions, sizeof(vl_size) * numDimensions) ; - self->data = vl_malloc(vl_get_type_size(type) * vl_array_get_num_elements (self)) ; - self->isEnvelope = VL_FALSE ; - self->isSparse = VL_FALSE ; - return self ; -} - -/** @brief New numeric array envelope - ** @param self array to initialize. - ** @param data data to envelople. - ** @param type data type. - ** @param numDimensions number of dimensions. - ** @param dimensions dimensions. - ** - ** The function initializes the specified array wrapping the - ** specified buffer. - **/ - -VL_EXPORT VlArray * -vl_array_init_envelope (VlArray * self, void * data, vl_type type, - vl_size numDimensions, vl_size const * dimensions) -{ - assert (numDimensions <= VL_ARRAY_MAX_NUM_DIMENSIONS) ; - self->type = type ; - self->numDimensions = numDimensions ; - memcpy(self->dimensions, dimensions, sizeof(vl_size) * numDimensions) ; - self->data = data ; - self->isEnvelope = VL_TRUE ; - self->isSparse = VL_FALSE ; - return self ; -} - -/** @brief New numeric array with matrix shape - ** @param self array to initialize. - ** @param type type. - ** @param numRows number of rows. - ** @param numColumns number of columns. - **/ - -VL_EXPORT VlArray * -vl_array_init_matrix (VlArray * self, vl_type type, vl_size numRows, vl_size numColumns) -{ - vl_size dimensions [2] = {numRows, numColumns} ; - return vl_array_init (self, type, 2, dimensions) ; -} - -/** @brief New numeric array envelpe with matrix shape - ** @param self array to initialize. - ** @param data data to envelope. - ** @param type type. - ** @param numRows number of rows. - ** @param numColumns number of columns. - **/ - -VL_EXPORT VlArray * -vl_array_init_matrix_envelope (VlArray * self, void * data, - vl_type type, vl_size numRows, vl_size numColumns) -{ - vl_size dimensions [2] = {numRows, numColumns} ; - return vl_array_init_envelope (self, data, type, 2, dimensions) ; -} - -/** @brief Delete array - ** @param self array. - **/ - -VL_EXPORT void -vl_array_dealloc (VlArray * self) -{ - if (! self->isEnvelope) { - if (self->data) { - vl_free(self->data) ; - self->data = NULL ; - } - } -} - -/* ---------------------------------------------------------------- */ -/* new & delete */ -/* ---------------------------------------------------------------- */ - - -/** @brief New numeric array - ** @param type data type. - ** @param numDimensions number of dimensions. - ** @param dimensions dimensions. - ** - ** The function creates a new VLArray instance and allocates - ** the necessary memory for storage. - **/ - -VL_EXPORT VlArray * -vl_array_new (vl_type type, vl_size numDimensions, vl_size const * dimensions) -{ - VlArray * self = vl_malloc(sizeof(VlArray)) ; - return vl_array_init(self, type, numDimensions, dimensions) ; -} - -/** @brief New numeric array with matrix shape - ** @param type type. - ** @param numRows number of rows. - ** @param numColumns number of columns. - **/ - -VL_EXPORT VlArray * -vl_array_new_matrix (vl_type type, vl_size numRows, vl_size numColumns) -{ - vl_size dimensions [2] = {numRows, numColumns} ; - return vl_array_new (type, 2, dimensions) ; -} - -/** @brief New numeric array envelope - ** @param data data to envelople. - ** @param type data type. - ** @param numDimensions number of dimensions. - ** @param dimensions dimensions. - **/ - -VL_EXPORT VlArray * -vl_array_new_envelope (void * data, vl_type type, - vl_size numDimensions, vl_size const * dimensions) -{ - VlArray * self = vl_malloc(sizeof(VlArray)) ; - return vl_array_init_envelope(self, data, type, numDimensions, dimensions) ; -} - -/** @brief New numeric array envelpe with matrix shape - ** @param data data to envelope. - ** @param type type. - ** @param numRows number of rows. - ** @param numColumns number of columns. - **/ - -VL_EXPORT VlArray * -vl_array_new_matrix_envelope (void * data, vl_type type, vl_size numRows, vl_size numColumns) -{ - vl_size dimensions [2] = {numRows, numColumns} ; - return vl_array_new_envelope (data, type, 2, dimensions) ; -} - -/** @brief Delete array - ** @param self array. - **/ - -VL_EXPORT void -vl_array_delete (VlArray * self) -{ - vl_array_dealloc(self) ; - vl_free(self) ; -} diff --git a/opensfm/src/third_party/vlfeat/vl/array.h b/opensfm/src/third_party/vlfeat/vl/array.h deleted file mode 100644 index d29dc483b..000000000 --- a/opensfm/src/third_party/vlfeat/vl/array.h +++ /dev/null @@ -1,105 +0,0 @@ -/** @file array.h - ** @brief Array - Definition - ** @author Andrea Vedaldi - **/ - -/* -Copyright (C) 2007-12 Andrea Vedaldi and Brian Fulkerson. -All rights reserved. - -This file is part of the VLFeat library and is made available under -the terms of the BSD license (see the COPYING file). -*/ - -#ifndef VL_ARRAY_H -#define VL_ARRAY_H - -#include "generic.h" - -/** @brief Maximum number of array dimensions */ -#define VL_ARRAY_MAX_NUM_DIMENSIONS 16 - -/** @brief Numeric array */ -typedef struct _VlArray -{ - vl_type type ; - vl_bool isEnvelope ; - vl_bool isSparse ; - vl_size numDimensions ; - vl_size dimensions [VL_ARRAY_MAX_NUM_DIMENSIONS] ; - void * data ; - void * rowPointers ; - void * columnPointers ; -} VlArray ; - - -/** @name Get data and parameters - ** @{ */ - -/** @brief Get number of dimensions - ** @param self array. - ** @return number of dimensions. - **/ - -VL_INLINE vl_size -vl_array_get_num_dimensions (VlArray const * self) -{ - return self->numDimensions ; -} - -/** @brief Get dimensions - ** @param self array. - ** @return dimensions. - **/ - -VL_INLINE vl_size const * -vl_array_get_dimensions (VlArray const * self) -{ - return self->dimensions ; -} - -/** @brief Get data - ** @param self array. - ** @return data. - **/ - -VL_INLINE void * -vl_array_get_data (VlArray const * self) -{ - return self->data; -} - -/** @brief Get type - ** @param self array. - ** @return type. - **/ - -VL_INLINE vl_type -vl_array_get_data_type (VlArray const * self) -{ - return self->type ; -} - -VL_EXPORT vl_size vl_array_get_num_elements (VlArray const * self) ; - -/** @{ */ - -/** @name Constructing and destroying - ** @{ */ - -VL_EXPORT VlArray * vl_array_init (VlArray * self, vl_type type, vl_size numDimension, vl_size const * dimensions) ; -VL_EXPORT VlArray * vl_array_init_envelope (VlArray *self, void * data, vl_type type, vl_size numDimension, vl_size const * dimensions) ; -VL_EXPORT VlArray * vl_array_init_matrix (VlArray * self, vl_type type, vl_size numRows, vl_size numColumns) ; -VL_EXPORT VlArray * vl_array_init_matrix_envelope (VlArray * self, void * data, vl_type type, vl_size numRows, vl_size numColumns) ; - -VL_EXPORT VlArray * vl_array_new (vl_type type, vl_size numDimension, vl_size const * dimensions) ; -VL_EXPORT VlArray * vl_array_new_envelope (void * data, vl_type type, vl_size numDimension, vl_size const * dimensions) ; -VL_EXPORT VlArray * vl_array_new_matrix (vl_type type, vl_size numRows, vl_size numColumns) ; -VL_EXPORT VlArray * vl_array_new_matrix_envelope (void * data, vl_type type, vl_size numRows, vl_size numColumns) ; - -VL_EXPORT void vl_array_dealloc (VlArray * self) ; -VL_EXPORT void vl_array_delete (VlArray * self) ; -/** @} */ - -/* VL_ARRAY_H */ -#endif diff --git a/opensfm/src/third_party/vlfeat/vl/covdet.c b/opensfm/src/third_party/vlfeat/vl/covdet.c deleted file mode 100644 index 0b0592f0d..000000000 --- a/opensfm/src/third_party/vlfeat/vl/covdet.c +++ /dev/null @@ -1,3400 +0,0 @@ -/** @file covdet.c - ** @brief Covariant feature detectors - Definition - ** @author Karel Lenc - ** @author Andrea Vedaldi - ** @author Michal Perdoch - **/ - -/* -Copyright (C) 2013-14 Andrea Vedaldi. -Copyright (C) 2012 Karel Lenc, Andrea Vedaldi and Michal Perdoch. -All rights reserved. - -This file is part of the VLFeat library and is made available under -the terms of the BSD license (see the COPYING file). -*/ - -/** - -@page covdet Covariant feature detectors -@author Karel Lenc -@author Andrea Vedaldi -@author Michal Perdoch -@tableofcontents - - -@ref covdet.h implements a number of covariant feature detectors, based -on three cornerness measures (determinant of the Hessian, trace of the Hessian -(aka Difference of Gaussians, and Harris). It supprots affine adaptation, -orientation estimation, as well as Laplacian scale detection. - -- @subpage covdet-fundamentals -- @subpage covdet-principles -- @subpage covdet-differential -- @subpage covdet-corner-types - - -@section covdet-starting Getting started - - -The ::VlCovDet object implements a number of covariant feature -detectors: Difference of Gaussian, Harris, determinant of Hessian. -Variant of the basic detectors support scale selection by maximizing -the Laplacian measure as well as affine normalization. - -@code -// create a detector object -VlCovDet * covdet = vl_covdet_new(method) ; - -// set various parameters (optional) -vl_covdet_set_first_octave(covdet, -1) ; // start by doubling the image resolution -vl_covdet_set_octave_resolution(covdet, octaveResolution) ; -vl_covdet_set_peak_threshold(covdet, peakThreshold) ; -vl_covdet_set_edge_threshold(covdet, edgeThreshold) ; - -// process the image and run the detector -vl_covdet_put_image(covdet, image, numRows, numCols) ; -vl_covdet_detect(covdet) ; - -// drop features on the margin (optional) -vl_covdet_drop_features_outside (covdet, boundaryMargin) ; - -// compute the affine shape of the features (optional) -vl_covdet_extract_affine_shape(covdet) ; - -// compute the orientation of the features (optional) -vl_covdet_extract_orientations(covdet) ; - -// get feature frames back -vl_size numFeatures = vl_covdet_get_num_features(covdet) ; -VlCovDetFeature const * feature = vl_covdet_get_features(covdet) ; - -// get normalized feature appearance patches (optional) -vl_size w = 2*patchResolution + 1 ; -for (i = 0 ; i < numFeatures ; ++i) { - float * patch = malloc(w*w*sizeof(*desc)) ; - vl_covdet_extract_patch_for_frame(covdet, - patch, - patchResolution, - patchRelativeExtent, - patchRelativeSmoothing, - feature[i].frame) ; - // do something with patch -} -@endcode - -This example code: - -- Calls ::vl_covdet_new constructs a new detector object. @ref - covdet.h supports a variety of different detectors (see - ::VlCovDetMethod). -- Optionally calls various functions to set the detector parameters if - needed (e.g. ::vl_covdet_set_peak_threshold). -- Calls ::vl_covdet_put_image to start processing a new image. It - causes the detector to compute the scale space representation of the - image, but does not compute the features yet. -- Calls ::vl_covdet_detect runs the detector. At this point features are - ready to be extracted. However, one or all of the following steps - may be executed in order to process the features further. -- Optionally calls ::vl_covdet_drop_features_outside to drop features - outside the image boundary. -- Optionally calls ::vl_covdet_extract_affine_shape to compute the - affine shape of features using affine adaptation. -- Optionally calls ::vl_covdet_extract_orientations to compute the - dominant orientation of features looking for the dominant gradient - orientation in patches. -- Optionally calls ::vl_covdet_extract_patch_for_frame to extract a - normalized feature patch, for example to compute an invariant - feature descriptor. - - -@page covdet-fundamentals Covariant detectors fundamentals -@tableofcontents - - -This page describes the fundamental concepts required to understand a -covariant feature detector, the geometry of covariant features, and -the process of feature normalization. - - -@section covdet-covariance Covariant detection - - -The purpose of a *covariant detector* is to extract from an image a -set of local features in a manner which is consistent with spatial -transformations of the image itself. For instance, a covariant -detector that extracts interest points $\bx_1,\dots,\bx_n$ from image -$\ell$ extracts the translated points $\bx_1+T,\dots,\bx_n+T$ from the -translated image $\ell'(\bx) = \ell(\bx-T)$. - -More in general, consider a image $\ell$ and a transformed version -$\ell' = \ell \circ w^{-1}$ of it, as in the following figure: - -@image html covdet.png "Covariant detection of local features." - -The transformation or warp $w : \real^2 \mapsto \real^2$ is a -deformation of the image domain which may capture a change of camera -viewpoint or similar imaging factor. Examples of warps typically -considered are translations, scaling, rotations, and general affine -transformations; however, in $w$ could be another type of continuous -and invertible transformation. - -Given an image $\ell$, a **detector** selects features $R_1,\dots,R_n$ -(one such features is shown in the example as a green circle). The -detector is said to be **covariant** with the warps $w$ if it extracts -the transformed features $w[R_1],\dots, w[R_n]$ from the transformed -image $w[\ell]$. Intuitively, this means that the “same -features” are extracted in both cases up to the transformation -$w$. This property is described more formally in @ref -covdet-principles. - -Covariance is a key property of local feature detectors as it allows -extracting corresponding features from two or more images, making it -possible to match them in a meaningful way. - -The @ref covdet.h module in VLFeat implements an array of feature -detection algorithm that have are covariant to different classes of -transformations. - - -@section covdet-frame Feature geometry and feature frames - - -As we have seen, local features are subject to image transformations, -and they apply a fundamental role in matching and normalizing -images. To operates effectively with local features is therefore -necessary to understand their geometry. - -The geometry of a local feature is captured by a feature frame -$R$. In VLFeat, depending on the specific detector, the frame can be -either a point, a disc, an ellipse, an oriented disc, or an oriented -ellipse. - -A frame captures both the extent of the local features, useful to know -which portions of two images are put in correspondence, as well their -shape. The latter can be used to associate to diagnose the -transformation that affects a feature and remove it through the -process of **normalization**. - -More precisely, in covariant detection feature frames are constructed -to be compatible with a certain class of transformations. For example, -circles are compatible with similarity transformations as they are -closed under them. Likewise, ellipses are compatible with affine -transformations. - -Beyond this closure property, the key idea here is that all feature -occurrences can be seen as transformed versions of a base or -canonical feature. For example, all discs $R$ can be obtained -by applying a similarity transformation to the unit disc $\bar R$ -centered at the origin. $\bar R$ is an example of canonical frame -as any other disc can be written as $R = w[\bar R]$ for a suitable -similarity $w$. - -@image html frame-canonical.png "The idea of canonical frame and normalization" - -The equation $R = w[\bar R_0]$ matching the canonical and detected -feature frames establishes a constraint on the warp $w$, very similar -to the way two reference frames in geometry establish a transformation -between spaces. The transformation $w$ can be thought as a the -**pose** of the detected feature, a generalization of its location. - -In the case of discs and similarity transformations, the equation $R = -w[\bar R_0]$ fixes $w$ up to a residual rotation. This can be -addressed by considering oriented discs instead. An **oriented disc** -is a disc with a radius highlighted to represent the feature -orientation. - -While discs are appropriate for similarity transformations, they are -not closed under general affine transformations. In this case, one -should consider the more general class of (oriented) ellipses. The -following image illustrates the five types of feature frames used in -VLFeat: - -@image html frame-types.png "Types of local feature frames: points, discs, oriented discs, ellipses, oriented ellipses." - -Note that these frames are described respectively by 2, 3, 4, 5 and 6 -parameters. The most general type are the oriented ellipses, which can -be used to represent all the other frame types as well. - - -@section covdet-frame-transformation Transforming feature frames - - -Consider a warp $w$ mapping image $\ell$ into image $\ell'$ as in the -figure below. A feature $R$ in the first image co-variantly transform -into a feature $R'=w[R]$ in the second image: - -@image html covdet-normalization.png "Normalization removes the effect of an image deformation." - -The poses $u,u'$ of $R=u[R_0]$ and $R' = u'[R_0]$ are then related by -the simple expression: - -\[ - u' = w \circ u. -\] - - -@section covdet-frame-normalization Normalizing feature frames - - -In the example above, the poses $u$ and $u'$ relate the two -occurrences $R$ and $R'$ of the feature to its canonical version -$R_0$. If the pose $u$ of the feature in image $\ell$ is known, the -canonical feature appearance can be computed by un-warping it: - -\[ - \ell_0 = u^{-1}[\ell] = \ell \circ u. -\] - -This process is known as **normalization** and is the key in the -computation of invariant feature descriptors as well as in the -construction of most co-variant detectors. - - -@page covdet-principles Principles of covariant detection -@tableofcontents - - -The goals of a co-variant detector were discussed in @ref -covdet-fundamentals. This page introduces a few general principles -that are at the basis of most covariant detection algorithms. Consider -an input image $\ell$ and a two dimensional continuous and invertible -warp $w$. The *warped image* $w[\ell]$ is defined to be - -\[ - w[\ell] = \ell \circ w^{-1}, -\] - -or, equivalently, - -\[ - w[\ell](x,y) = \ell(w^{-1}(x,y)), \qquad \forall (x,y)\in\real^2. -\] - -Note that, while $w$ pushes pixels forward, from the original to the -transformed image domain, defining the transformed image $\ell'$ -requires inverting the warp and composing $\ell$ with $w^{-1}$. - -The goal a covariant detector is to extract the same local features -irregardless of image transformations. The detector is said to be -covariant or equivariant with a class of warps -$w\in\mathcal{W}$ if, when the feature $R$ is detected in image -$\ell$, then the transformed feature $w[R]$ is detected in the -transformed image $w[\ell]$. - -The net effect is that a covariant feature detector appears to -“track” image transformations; however, it is important to -note that a detector *is not a tracker* because it processes images -individually rather than jointly as part of a sequence. - -An intuitive way to construct a covariant feature detector is to -extract features in correspondence of images structures that are -easily identifiable even after a transformation. Example of specific -structures include dots, corners, and blobs. These will be generically -indicated as **corners** in the followup. - -A covariant detector faces two challenges. First, corners have, in -practice, an infinite variety of individual appearances and the -detector must be able to capture them to be of general applicability. -Second, the way corners are identified and detected must remain stable -under transformations of the image. These two problems are addressed -in @ref covdet-cornerness-localmax and @ref -covdet-cornerness-normalization respectively. - - -@section covdet-cornerness Detection using a cornerness measure - - -One way to decide whether an image region $R$ contains a corner is to -compare the local appearance to a model or template of the corner; the -result of this comparisons produces a *cornerness score* at that -location. This page describe general theoretical properties of the -cornerness and the detection process. Concrete examples of cornerness -are given in @ref covdet-corner-types. - -A **cornerness measure** associate a score to all possible feature -locations in an image $\ell$. As described in @ref covdet-frame, the -location or, more in general, pose $u$ of a feature $R$ is the warp -$w$ that maps the canonical feature frame $R_0$ to $R$: - -\[ - R = u[R_0]. -\] - -The goal of a cornerness measure is to associate a score $F(u;\ell)$ -to all possible feature poses $u$ and use this score to extract a -finite number of co-variant features from any image. - - -@subsection covdet-cornerness-localmax Local maxima of a cornerness measure - - -Given the cornerness of each candidate feature, the detector must -extract a finite number of them. However, the cornerness of features -with nearly identical pose must be similar (otherwise the cornerness -measure would be unstable). As such, simply thresholding $F(w;\ell)$ -would detect an infinite number of nearly identical features rather -than a finite number. - -The solution is to detect features in correspondence of the local -maxima of the score measure: - -\[ - \{w_1,\dots,w_n\} = \operatorname{localmax}_{w\in\mathcal{W}} F(w;\ell). -\] - -This also means that features are never detected in isolation, but by -comparing neighborhoods of them. - - -@subsection covdet-cornerness-normalization Covariant detection by normalization - - -The next difficulty is to guarantee that detection is co-variant with -image transformations. Hence, if $u$ is the pose of a feature -extracted from image $\ell$, then the transformed pose $u' = w[u]$ -must be detected in the transformed image $\ell' = w[\ell]$. - -Since features are extracted in correspondence of the local maxima of -the cornerness score, a sufficient condition is that corresponding -features attain the same score in the two images: - -\[ -\forall u\in\mathcal{W}: \quad F(u;\ell) = F(w[u];w[\ell]), -\qquad\text{or}\qquad -F(u;\ell) = F(w \circ u ;\ell \circ w^{-1}). -\] - -One simple way to satisfy this equation is to compute a cornerness -score *after normalizing the image* by the inverse of the candidate -feature pose warp $u$, as follows: - -\[ - F(u;\ell) = F(1;u^{-1}[\ell]) = F(1;\ell \circ u) = \mathcal{F}(\ell \circ u), -\] - -where $1 = u^{-1} \circ u$ is the identity transformation and -$\mathcal{F}$ is an arbitrary functional. Intuitively, co-variant -detection is obtained by looking if the appearance of the feature -resembles a corner only *after normalization*. Formally: - -@f{align*} -F(w[u];w[\ell]) -&= -F(w \circ u ;\ell \circ w^{-1}) -\\ -&= -F(1; \ell \circ w^{-1} \circ w \circ u) -\\ -&= -\mathcal{F}(\ell\circ u) -\\ -&= -F(u;\ell). -@f} - -Concrete examples of the functional $\mathcal{F}$ are given in @ref -covdet-corner-types. - - -@subsection covdet-locality Locality of the detected features - - -In the definition above, the cornenress functional $\mathcal{F}$ is an -arbitrary functional of the entire normalized image $u^{-1}[\ell]$. -In practice, one is always interested in detecting **local features** -(at the very least because the image extent is finite). - -This is easily obtained by considering a cornerness $\mathcal{F}$ -which only looks in a small region of the normalized image, usually -corresponding to the extent of the canonical feature $R_0$ (e.g. a -unit disc centered at the origin). - -In this case the extent of the local feature in the original image is -simply given by $R = u[R_0]$. - - -@section covdet-partial Partial and iterated normalization - - -Practical detectors implement variants of the ideas above. Very often, -for instance, detection is an iterative process, in which successive -parameters of the pose of a feature are determined. For instance, it -is typical to first detect the location and scale of a feature using a -rotation-invariant cornerness score $\mathcal{F}$. Once these two -parameters are known, the rotation can be determined using a different -score, sensitive to the orientation of the local image structures. - -Certain detectors (such as Harris-Laplace and Hessian-Laplace) use -even more sophisticated schemes, in which different scores are used to -jointly (rather than in succession) different parameters of the pose -of a feature, such as its translation and scale. While a formal -treatment of these cases is possible as well, we point to the original -papers. - - -@page covdet-differential Differential and integral image operations -@tableofcontents - - -Dealing with covariant interest point detector requires working a good -deal with derivatives, convolutions, and transformations of images. -The notation and fundamental properties of interest here are discussed -next. - - -@section covdet-derivatives Derivative operations: gradients - - -For the derivatives, we borrow the notation of -@cite{kinghorn96integrals}. Let $f: \mathbb{R}^m \rightarrow -\mathbb{R}^n, \bx \mapsto f(\bx)$ be a vector function. The derivative -of the function with respect to $\bx$ is given by its *Jacobian -matrix* denoted by the symbol: - -\[ -\frac{\partial f}{\partial \bx^\top} -= -\begin{bmatrix} - \frac{\partial f_1}{x_1} & \frac{\partial f_1}{x_2} & \dots \\ - \frac{\partial f_2}{x_1} & \frac{\partial f_2}{x_2} & \dots \\ - \vdots & \vdots & \ddots \\ -\end{bmatrix}. -\] - -When the function $ f $ is scalar ($n=1$), the Jacobian is the same as -the gradient of the function (or, in fact, its transpose). More -precisely, the gradient $\nabla f $ of $ f $ denotes the column -vector of partial derivatives: - -\[ -\nabla f - = \frac{\partial f}{\partial \bx} - = - \begin{bmatrix} - \frac{\partial f}{\partial x_1} \\ - \frac{\partial f}{\partial x_2} \\ - \vdots -\end{bmatrix}. -\] - -The second derivative $H_f $ of a scalar function $ f $, or -Hessian, is denoted as - -\[ -H_f -= \frac{\partial f}{\partial \bx \partial \bx^\top} -= \frac{\partial \nabla f}{\partial \bx^\top} -= -\begin{bmatrix} - \frac{\partial f}{\partial x_1 \partial x_1} & \frac{\partial f}{\partial x_1 \partial x_2} & \dots \\ - \frac{\partial f}{\partial x_2 \partial x_1} & \frac{\partial f}{\partial x_2 \partial x_2} & \dots \\ - \vdots & \vdots & \ddots \\ -\end{bmatrix}. -\] - -The determinant of the Hessian is also known as Laplacian and denoted as - -\[ - \Delta f = \operatorname{det} H_f = -\frac{\partial f}{\partial x_1^2} + -\frac{\partial f}{\partial x_2^2} + -\dots -\] - - -@subsection covdet-derivative-transformations Derivative and image warps - - -In the following, we will often been interested in domain warpings $u: -\mathbb{R}^m \rightarrow \mathbb{R}^n, \bx \mapsto u(\bx)$ of a -function $f(\bar\bx) $ and its effect on the derivatives of the -function. The key transformation is the chain rule: - -\[ -\frac{\partial f \circ u}{\partial \bx^\top} -= -\left(\frac{\partial f}{\partial \bar\bx^\top} \circ u\right) -\frac{\partial u}{\partial \bx^\top} -\] - -In particular, for an affine transformation $u = (A,T) : \bx \mapsto -A\bx + T$, one obtains the transformation rules: - -\[ -\begin{align*} -\frac{\partial f \circ (A,T)}{\partial \bx^\top} -&= -\left(\frac{\partial f}{\partial \bar\bx^\top} \circ (A,T)\right)A, -\\ -\nabla (f \circ (A,T)) -&= A^\top (\nabla f) \circ (A,T), -\\ -H_{f \circ(A,T)} -&= A^\top (H_f \circ (A,T)) A, -\\ -\Delta (f \circ(A,T)) -&= \det(A)^2\, (\Delta f) \circ (A,T). -\end{align*} -\] - - -@section covdet-smoothing Integral operations: smoothing - - -In practice, given an image $\ell$ expressed in digital format, good -derivative approximations can be computed only if the bandwidth of the -image is limited and, in particular, compatible with the sampling -density. Since it is unreasonable to expect real images to be -band-limited, the bandwidth is artificially constrained by suitably -smoothing the image prior to computing its derivatives. This is also -interpreted as a form of regularization or as a way of focusing on the -image content at a particular scale. - -Formally, we will focus on Gaussian smoothing kernels. For the 2D case -$\bx\in\real^2$, the Gaussian kernel of covariance $\Sigma$ is given -by - -\[ -g_{\Sigma}(\bx) = \frac{1}{2\pi \sqrt{\det\Sigma}} - \exp\left( - - \frac{1}{2} \bx^\top \Sigma^{-1} \bx - \right). -\] - -The symbol $g_{\sigma^2}$ will be used to denote a Gaussian kernel -with isotropic standard deviation $\sigma$, i.e. $\Sigma = \sigma^2 -I$. Given an image $\ell$, the symbol $\ell_\Sigma$ will be used to -denote the image smoothed by the Gaussian kernel of parameter -$\Sigma$: - -\[ -\ell_\Sigma(\bx) = (g_\Sigma * \ell)(\bx) -= -\int_{\real^m} -g_\Sigma(\bx - \by) \ell(\by)\,d\by. -\] - - -@subsection covdet-smoothing-transformations Smoothing and image warps - - -One advantage of Gaussian kernels is that they are (up to -renormalization) closed under a linear warp: - -\[ - |A|\, g_\Sigma \circ A = g_{A^{-1} \Sigma A^{-\top}} -\] - -This also means that smoothing a warped image is the same as warping -the result of smoothing the original image by a suitably adjusted -Gaussian kernel: - -\[ -g_{\Sigma} * (\ell \circ (A,T)) -= -(g_{A\Sigma A^\top} * \ell) \circ (A,T). -\] - - -@page covdet-corner-types Cornerness measures -@tableofcontents - - -The goal of a cornerness measure (@ref covdet-cornerness) is to -associate to an image patch a score proportional to how strongly the -patch contain a certain strucuture, for example a corner or a -blob. This page reviews the most important cornerness measures as -implemented in VLFeat: - -- @ref covdet-harris -- @ref covdet-laplacian -- @ref covdet-hessian - -This page makes use of notation introduced in @ref -covdet-differential. - - -@section covdet-harris Harris corners - - -This section introduces the fist of the cornerness measure -$\mathcal{F}[\ell]$. Recall (@ref covdet-cornerness) that the goal of -this functional is to respond strongly to images $\ell$ of corner-like -structure. - -Rather than explicitly encoding the appearance of corners, the idea of -the Harris measure is to label as corner *any* image patch whose -appearance is sufficiently distinctive to allow accurate -localization. In particular, consider an image patch $\ell(\bx), -\bx\in\Omega$, where $\Omega$ is a smooth circular window of radius -approximately $\sigma_i$; at necessary condition for the patch to -allow accurate localization is that even a small translation -$\ell(\bx+\delta)$ causes the appearance to vary significantly (if not -the origin and location $\delta$ would not be distinguishable from the -image alone). This variation is measured by the sum of squared -differences - -\[ -E(\delta) = \int g_{\sigma_i^2}(\bx) -(\ell_{\sigma_d^2}(\bx+\delta) - - \ell_{\sigma_d^2}(\bx))^2 \,d\bx -\] - -Note that images are compared at scale $\sigma_d$, known as - *differentiation scale* for reasons that will be clear in a moment, -and that the squared differences are summed over a window softly -defined by $\sigma_i$, also known as *integration scale*. This -function can be approximated as $E(\delta)\approx \delta^\top -M[\ell;\sigma_i^2,\sigma_d^2] \delta$ where - -\[ - M[\ell;\sigma_i^2,\sigma_d^2] -= \int g_{\sigma_i^2}(\bx) - (\nabla \ell_{\sigma_d^2}(\bx)) - (\nabla \ell_{\sigma_d^2}(\bx))^\top \, d\bx. -\] - -is the so called **structure tensor**. - -A corner is identified when the sum of squared differences $E(\delta)$ -is large for displacements $\delta$ in all directions. This condition -is obtained when both the eignenvalues $\lambda_1,\lambda_2$ of the -structure tensor $M$ are large. The **Harris cornerness measure** -captures this fact: - -\[ - \operatorname{Harris}[\ell;\sigma_i^2,\sigma_d^2] = - \det M - \kappa \operatorname{trace}^2 M = - \lambda_1\lambda_2 - \kappa (\lambda_1+\lambda_2)^2 -\] - - -@subsection covdet-harris-warped Harris in the warped domain - - -The cornerness measure of a feature a location $u$ (recall that -locations $u$ are in general defined as image warps) should be -computed after normalizing the image (by applying to it the warp -$u^{-1}$). This section shows that, for affine warps, the Harris -cornerness measure can be computed directly in the Gaussian affine -scale space of the image. In particular, for similarities, it can be -computed in the standard Gaussian scale space. - -To this end, let $u=(A,T)$ be an affine warp identifying a feature -location in image $\ell(\bx)$. Let $\bar\ell(\bar\bx) = -\ell(A\bar\bx+T)$ be the normalized image and rewrite the structure -tensor of the normalized image as follows: - -\[ - M[\bar\ell; \bar\Sigma_i, \bar\Sigma_d] -= - M[\bar\ell; \bar\Sigma_i, \bar\Sigma_d](\mathbf{0}) -= -\left[ -g_{\bar\Sigma_i} * -(\nabla\bar\ell_{\bar\Sigma_d}) -(\nabla\bar\ell_{\bar\Sigma_d})^\top -\right](\mathbf{0}) -\] - -This notation emphasizes that the structure tensor is obtained by -taking derivatives and convolutions of the image. Using the fact that -$\nabla g_{\bar\Sigma_d} * \bar\ell = A^\top (\nabla g_{A\bar\Sigma -A^\top} * \ell) \circ (A,T)$ and that $g_{\bar\Sigma} * \bar \ell = -(g_{A\bar\Sigma A^\top} * \ell) \circ (A,T)$, we get the equivalent -expression: - -\[ - M[\bar\ell; \bar\Sigma_i, \bar\Sigma_d](\mathbf{0}) - = -A^\top -\left[ -g_{A\bar\Sigma_i A^\top} * -(\nabla\ell_{A\bar\Sigma_dA^\top})(\nabla\ell_{A\bar\Sigma_d A^\top})^\top -\right](A\mathbf{0}+T) -A. -\] - -In other words, the structure tensor of the normalized image can be -computed as: - -\[ -M[\bar\ell; \bar\Sigma_i, \bar\Sigma_d](\mathbf{0}) -= -A^\top M[\ell; \Sigma_i, \Sigma_d](T) A, -\quad -\Sigma_{i} = A\bar\Sigma_{i}A^\top, -\quad -\Sigma_{d} = A\bar\Sigma_{d}A^\top. -\] - -This equation allows to compute the structure tensor for feature at -all locations directly in the original image. In particular, features -at all translations $T$ can be evaluated efficiently by computing -convolutions and derivatives of the image -$\ell_{A\bar\Sigma_dA^\top}$. - -A case of particular instance is when $\bar\Sigma_i= \bar\sigma_i^2 I$ -and $\bar\Sigma_d = \bar\sigma_d^2$ are both isotropic covariance -matrices and the affine transformation is a similarity $A=sR$. Using -the fact that $\det\left( s^2 R^\top M R \right)= s^4 \det M$ and -$\operatorname{tr}\left(s^2 R^\top M R\right) = s^2 \operatorname{tr} -M$, one obtains the relation - -\[ - \operatorname{Harris}[\bar \ell;\bar\sigma_i^2,\bar\sigma_d^2] = - s^4 \operatorname{Harris}[\ell;s^2\bar\sigma_i^2,s^2\bar\sigma_d^2](T). -\] - -This equation indicates that, for similarity transformations, not only -the structure tensor, but directly the Harris cornerness measure can -be computed on the original image and then be transferred back to the -normalized domain. Note, however, that this requires rescaling the -measure by the factor $s^4$. - -Another important consequence of this relation is that the Harris -measure is invariant to pure image rotations. It cannot, therefore, be -used to associate an orientation to the detected features. - - -@section covdet-hessian Hessian blobs - - -The *(determinant of the) Hessian* cornerness measure is given -determinant of the Hessian of the image: - -\[ - \operatorname{DetHess}[\ell;\sigma_d^2] - = - \det H_{g_{\sigma_d^2} * \ell}(\mathbf{0}) -\] - -This number is large and positive if the image is locally curved -(peaked), roughly corresponding to blob-like structures in the image. -In particular, a large score requires the product of the eigenvalues -of the Hessian to be large, which requires both of them to have the -same sign and are large in absolute value. - - -@subsection covdet-hessian-warped Hessian in the warped domain - - -Similarly to the Harris measure, it is possible to work with the -Hessian measure on the original unnormalized image. As before, let -$\bar\ell(\bar\bx) = \ell(A\bar\bx+T)$ be the normalized image and -rewrite the Hessian of the normalized image as follows: - -\[ -H_{g_{\bar\Sigma_d} * \bar\ell}(\mathbf{0}) = A^\top \left(H_{g_{\Sigma_d} * \ell}(T)\right) A. -\] - -Then - -\[ - \operatorname{DetHess}[\bar\ell;\bar\Sigma_d] - = - (\det A)^2 \operatorname{DetHess}[\ell;A\bar\Sigma_d A^\top](T). -\] - -In particular, for isotropic covariance matrices and similarity -transformations $A=sR$: - -\[ - \operatorname{DetHess}[\bar\ell;\bar\sigma_d^2] - = - s^4 \operatorname{DetHess}[\ell;s^2\bar\sigma_d^2](T) -\] - - -@section covdet-laplacian Laplacian and Difference of Gaussians blobs - - -The **Laplacian of Gaussian (LoG)** or **trace of the Hessian** -cornerness measure is given by the trace of the Hessian of the image: - -\[ - \operatorname{Lap}[\ell;\sigma_d^2] - = - \operatorname{tr} H_{g_{\sigma_d}^2 * \ell} -\] - - -@subsection covdet-laplacian-warped Laplacian in the warped domain - - -Similarly to the Hessian measure, the Laplacian cornenress can often -be efficiently computed for features at all locations in the original -unnormalized image domain. In particular, if the derivative covariance -matrix $\Sigma_d$ is isotropic and one considers as warpings -similarity transformations $A=sR$, where $R$ is a rotatin and $s$ a -rescaling, one has - -\[ - \operatorname{Lap}[\bar\ell;\bar\sigma_d^2] - = - s^2 \operatorname{Lap}[\ell;s^2\bar\sigma_d^2](T) -\] - -Note that, comparing to the Harris and determinant of Hessian -measures, the scaling for the Laplacian is $s^2$ rather than $s^4$. - - -@subsection covdet-laplacian-matched Laplacian as a matched filter - - -The Laplacian is given by the trace of the Hessian -operator. Differently from the determinant of the Hessian, this is a -linear operation. This means that computing the Laplacian cornerness -measure can be seen as applying a linear filtering operator to the -image. This filter can then be interpreted as a *template* of a corner -being matched to the image. Hence, the Laplacian cornerness measure -can be interpreted as matching this corner template at all possible -image locations. - -To see this formally, compute the Laplacian score in the input image domain: - -\[ - \operatorname{Lap}[\bar\ell;\bar\sigma_d^2] - = - s^2 \operatorname{Lap}[\ell;s^2\bar\sigma_d^2](T) - = - s^2 (\Delta g_{s^2\bar\sigma_d^2} * \ell)(T) -\] - -The Laplacian fitler is obtained by moving the Laplacian operator from -the image to the Gaussian smoothing kernel: - -\[ - s^2 (\Delta g_{s^2\bar\sigma_d^2} * \ell) -= - (s^2 \Delta g_{s^2\bar\sigma_d^2}) * \ell -\] - -Note that the filter is rescaled by the $s^2$; sometimes, this factor -is incorporated in the Laplacian operator, yielding the so-called -normalized Laplacian. - -The Laplacian of Gaussian is also called *top-hat function* and has -the expression: - -\[ -\Delta g_{\sigma^2}(x,y) -= -\frac{x^2+y^2 - 2 \sigma^2}{\sigma^4} g_{\sigma^2}(x,y). -\] - -This filter, which acts as corner template, resembles a blob (a dark -disk surrounded by a bright ring). - - -@subsection covdet-laplacian-dog Difference of Gaussians - - -The **Difference of Gaussian** (DoG) cornerness measure can be -interpreted as an approximation of the Laplacian that is easy to -obtain once a scalespace of the input image has been computed. - -As noted above, the Laplacian cornerness of the normalized feature can -be computed directly from the input image by convolving the image by -the normalized Laplacian of Gaussian filter $s^2 \Delta -g_{s^2\bar\sigma_d^2}$. - -Like the other derivative operators, this filter is simpe to -discriteize. However, it is often approximated by computing the the -*Difference of Gaussians* (DoG) approximation instead. This -approximation is obtained from the easily-proved identity: - -\[ - \frac{\partial}{\partial \sigma} g_{\sigma^2} = - \sigma \Delta g_{\sigma^2}. -\] - -This indicates that computing the normalized Laplacian of a Gaussian -filter is, in the limit, the same as taking the difference between -Gaussian filters of slightly increasing standard deviation $\sigma$ -and $\kappa\sigma$, where $\kappa \approx 1$: - -\[ -\sigma^2 \Delta g_{\sigma^2} -\approx -\sigma \frac{g_{(\kappa\sigma)^2} - g_{\sigma^2}}{\kappa\sigma - \sigma} -= -\frac{1}{\kappa - 1} -(g_{(\kappa\sigma)^2} - g_{\sigma^2}). -\] - -One nice propery of this expression is that the factor $\sigma$ -cancels out in the right-hand side. Usually, scales $\sigma$ and -$\kappa\sigma$ are pre-computed in the image scale-space and -successive scales are sampled with uniform geometric spacing, meaning -that the factor $\kappa$ is the same for all scales. Then, up to a -overall scaling factor, the LoG cornerness measure can be obtained by -taking the difference of successive scale space images -$\ell_{(\kappa\sigma)^2}$ and $\ell_{\sigma^2}$. - - -@page covdet-affine-adaptation Affine adaptation - - - -@page covdet-dominant-orientation Dominant orientation - -**/ - -#include "covdet.h" -#include - -/** @brief Reallocate buffer - ** @param buffer - ** @param bufferSize - ** @param targetSize - ** @return error code - **/ - -static int -_vl_resize_buffer (void ** buffer, vl_size * bufferSize, vl_size targetSize) { - void * newBuffer ; - if (*buffer == NULL) { - *buffer = vl_malloc(targetSize) ; - if (*buffer) { - *bufferSize = targetSize ; - return VL_ERR_OK ; - } else { - *bufferSize = 0 ; - return VL_ERR_ALLOC ; - } - } - newBuffer = vl_realloc(*buffer, targetSize) ; - if (newBuffer) { - *buffer = newBuffer ; - *bufferSize = targetSize ; - return VL_ERR_OK ; - } else { - return VL_ERR_ALLOC ; - } -} - -/** @brief Enlarge buffer - ** @param buffer - ** @param bufferSize - ** @param targetSize - ** @return error code - **/ - -static int -_vl_enlarge_buffer (void ** buffer, vl_size * bufferSize, vl_size targetSize) { - if (*bufferSize >= targetSize) return VL_ERR_OK ; - return _vl_resize_buffer(buffer,bufferSize,targetSize) ; -} - -/* ---------------------------------------------------------------- */ -/* Finding local extrema */ -/* ---------------------------------------------------------------- */ - -/* Todo: make this generally available in the library */ - -typedef struct _VlCovDetExtremum2 -{ - vl_index xi ; - vl_index yi ; - float x ; - float y ; - float peakScore ; - float edgeScore ; -} VlCovDetExtremum2 ; - -typedef struct _VlCovDetExtremum3 -{ - vl_index xi ; - vl_index yi ; - vl_index zi ; - float x ; - float y ; - float z ; - float peakScore ; - float edgeScore ; -} VlCovDetExtremum3 ; - -VL_EXPORT vl_size -vl_find_local_extrema_3 (vl_index ** extrema, vl_size * bufferSize, - float const * map, - vl_size width, vl_size height, vl_size depth, - double threshold) ; - -VL_EXPORT vl_size -vl_find_local_extrema_2 (vl_index ** extrema, vl_size * bufferSize, - float const * map, - vl_size width, vl_size height, - double threshold) ; - -VL_EXPORT vl_bool -vl_refine_local_extreum_3 (VlCovDetExtremum3 * refined, - float const * map, - vl_size width, vl_size height, vl_size depth, - vl_index x, vl_index y, vl_index z) ; - -VL_EXPORT vl_bool -vl_refine_local_extreum_2 (VlCovDetExtremum2 * refined, - float const * map, - vl_size width, vl_size height, - vl_index x, vl_index y) ; - -/** @internal - ** @brief Find the extrema of a 3D function - ** @param extrema buffer containing the extrema found (in/out). - ** @param bufferSize size of the @a extrema buffer in bytes (in/out). - ** @param map a 3D array representing the map. - ** @param width of the map. - ** @param height of the map. - ** @param depth of the map. - ** @param threshold minumum extremum value. - ** @return number of extrema found. - ** @see @ref ::vl_refine_local_extreum_2. - **/ - -vl_size -vl_find_local_extrema_3 (vl_index ** extrema, vl_size * bufferSize, - float const * map, - vl_size width, vl_size height, vl_size depth, - double threshold) -{ - vl_index x, y, z ; - vl_size const xo = 1 ; - vl_size const yo = width ; - vl_size const zo = width * height ; - float const *pt = map + xo + yo + zo ; - - vl_size numExtrema = 0 ; - vl_size requiredSize = 0 ; - -#define CHECK_NEIGHBORS_3(v,CMP,SGN) (\ -v CMP ## = SGN threshold && \ -v CMP *(pt + xo) && \ -v CMP *(pt - xo) && \ -v CMP *(pt + zo) && \ -v CMP *(pt - zo) && \ -v CMP *(pt + yo) && \ -v CMP *(pt - yo) && \ -\ -v CMP *(pt + yo + xo) && \ -v CMP *(pt + yo - xo) && \ -v CMP *(pt - yo + xo) && \ -v CMP *(pt - yo - xo) && \ -\ -v CMP *(pt + xo + zo) && \ -v CMP *(pt - xo + zo) && \ -v CMP *(pt + yo + zo) && \ -v CMP *(pt - yo + zo) && \ -v CMP *(pt + yo + xo + zo) && \ -v CMP *(pt + yo - xo + zo) && \ -v CMP *(pt - yo + xo + zo) && \ -v CMP *(pt - yo - xo + zo) && \ -\ -v CMP *(pt + xo - zo) && \ -v CMP *(pt - xo - zo) && \ -v CMP *(pt + yo - zo) && \ -v CMP *(pt - yo - zo) && \ -v CMP *(pt + yo + xo - zo) && \ -v CMP *(pt + yo - xo - zo) && \ -v CMP *(pt - yo + xo - zo) && \ -v CMP *(pt - yo - xo - zo) ) - - for (z = 1 ; z < (signed)depth - 1 ; ++z) { - for (y = 1 ; y < (signed)height - 1 ; ++y) { - for (x = 1 ; x < (signed)width - 1 ; ++x) { - float value = *pt ; - if (CHECK_NEIGHBORS_3(value,>,+) || CHECK_NEIGHBORS_3(value,<,-)) { - numExtrema ++ ; - requiredSize += sizeof(vl_index) * 3 ; - if (*bufferSize < requiredSize) { - int err = _vl_resize_buffer((void**)extrema, bufferSize, - requiredSize + 2000 * 3 * sizeof(vl_index)) ; - if (err != VL_ERR_OK) abort() ; - } - (*extrema) [3 * (numExtrema - 1) + 0] = x ; - (*extrema) [3 * (numExtrema - 1) + 1] = y ; - (*extrema) [3 * (numExtrema - 1) + 2] = z ; - } - pt += xo ; - } - pt += 2*xo ; - } - pt += 2*yo ; - } - return numExtrema ; -} - -/** @internal - ** @brief Find extrema in a 2D function - ** @param extrema buffer containing the found extrema (in/out). - ** @param bufferSize size of the @a extrema buffer in bytes (in/out). - ** @param map a 3D array representing the map. - ** @param width of the map. - ** @param height of the map. - ** @param threshold minumum extremum value. - ** @return number of extrema found. - ** - ** An extremum contains 2 ::vl_index values; they are arranged - ** sequentially. - ** - ** The function can reuse an already allocated buffer if - ** @a extrema and @a bufferSize are initialized on input. - ** It may have to @a realloc the memory if the buffer is too small. - **/ - -vl_size -vl_find_local_extrema_2 (vl_index ** extrema, vl_size * bufferSize, - float const* map, - vl_size width, vl_size height, - double threshold) -{ - vl_index x, y ; - vl_size const xo = 1 ; - vl_size const yo = width ; - float const *pt = map + xo + yo ; - - vl_size numExtrema = 0 ; - vl_size requiredSize = 0 ; -#define CHECK_NEIGHBORS_2(v,CMP,SGN) (\ -v CMP ## = SGN threshold && \ -v CMP *(pt + xo) && \ -v CMP *(pt - xo) && \ -v CMP *(pt + yo) && \ -v CMP *(pt - yo) && \ -\ -v CMP *(pt + yo + xo) && \ -v CMP *(pt + yo - xo) && \ -v CMP *(pt - yo + xo) && \ -v CMP *(pt - yo - xo) ) - - for (y = 1 ; y < (signed)height - 1 ; ++y) { - for (x = 1 ; x < (signed)width - 1 ; ++x) { - float value = *pt ; - if (CHECK_NEIGHBORS_2(value,>,+) || CHECK_NEIGHBORS_2(value,<,-)) { - numExtrema ++ ; - requiredSize += sizeof(vl_index) * 2 ; - if (*bufferSize < requiredSize) { - int err = _vl_resize_buffer((void**)extrema, bufferSize, - requiredSize + 2000 * 2 * sizeof(vl_index)) ; - if (err != VL_ERR_OK) abort() ; - } - (*extrema) [2 * (numExtrema - 1) + 0] = x ; - (*extrema) [2 * (numExtrema - 1) + 1] = y ; - } - pt += xo ; - } - pt += 2*xo ; - } - return numExtrema ; -} - -/** @internal - ** @brief Refine the location of a local extremum of a 3D map - ** @param refined refined extremum (out). - ** @param map a 3D array representing the map. - ** @param width of the map. - ** @param height of the map. - ** @param depth of the map. - ** @param x initial x position. - ** @param y initial y position. - ** @param z initial z position. - ** @return a flat indicating whether the extrema refinement was stable. - **/ - -VL_EXPORT vl_bool -vl_refine_local_extreum_3 (VlCovDetExtremum3 * refined, - float const * map, - vl_size width, vl_size height, vl_size depth, - vl_index x, vl_index y, vl_index z) -{ - vl_size const xo = 1 ; - vl_size const yo = width ; - vl_size const zo = width * height ; - - double Dx=0,Dy=0,Dz=0,Dxx=0,Dyy=0,Dzz=0,Dxy=0,Dxz=0,Dyz=0 ; - double A [3*3], b [3] ; - -#define at(dx,dy,dz) (*(pt + (dx)*xo + (dy)*yo + (dz)*zo)) -#define Aat(i,j) (A[(i)+(j)*3]) - - float const * pt ; - vl_index dx = 0 ; - vl_index dy = 0 ; - /*vl_index dz = 0 ;*/ - vl_index iter ; - int err ; - - assert (map) ; - assert (1 <= x && x <= (signed)width - 2) ; - assert (1 <= y && y <= (signed)height - 2) ; - assert (1 <= z && z <= (signed)depth - 2) ; - - for (iter = 0 ; iter < 5 ; ++iter) { - x += dx ; - y += dy ; - pt = map + x*xo + y*yo + z*zo ; - - /* compute the gradient */ - Dx = 0.5 * (at(+1,0,0) - at(-1,0,0)) ; - Dy = 0.5 * (at(0,+1,0) - at(0,-1,0)); - Dz = 0.5 * (at(0,0,+1) - at(0,0,-1)) ; - - /* compute the Hessian */ - Dxx = (at(+1,0,0) + at(-1,0,0) - 2.0 * at(0,0,0)) ; - Dyy = (at(0,+1,0) + at(0,-1,0) - 2.0 * at(0,0,0)) ; - Dzz = (at(0,0,+1) + at(0,0,-1) - 2.0 * at(0,0,0)) ; - - Dxy = 0.25 * (at(+1,+1,0) + at(-1,-1,0) - at(-1,+1,0) - at(+1,-1,0)) ; - Dxz = 0.25 * (at(+1,0,+1) + at(-1,0,-1) - at(-1,0,+1) - at(+1,0,-1)) ; - Dyz = 0.25 * (at(0,+1,+1) + at(0,-1,-1) - at(0,-1,+1) - at(0,+1,-1)) ; - - /* solve linear system */ - Aat(0,0) = Dxx ; - Aat(1,1) = Dyy ; - Aat(2,2) = Dzz ; - Aat(0,1) = Aat(1,0) = Dxy ; - Aat(0,2) = Aat(2,0) = Dxz ; - Aat(1,2) = Aat(2,1) = Dyz ; - - b[0] = - Dx ; - b[1] = - Dy ; - b[2] = - Dz ; - - err = vl_solve_linear_system_3(b, A, b) ; - - if (err != VL_ERR_OK) { - b[0] = 0 ; - b[1] = 0 ; - b[2] = 0 ; - break ; - } - - /* Keep going if there is sufficient translation */ - - dx = (b[0] > 0.6 && x < (signed)width - 2 ? 1 : 0) - + (b[0] < -0.6 && x > 1 ? -1 : 0) ; - - dy = (b[1] > 0.6 && y < (signed)height - 2 ? 1 : 0) - + (b[1] < -0.6 && y > 1 ? -1 : 0) ; - - if (dx == 0 && dy == 0) break ; - } - - /* check threshold and other conditions */ - { - double peakScore = at(0,0,0) - + 0.5 * (Dx * b[0] + Dy * b[1] + Dz * b[2]) ; - double alpha = (Dxx+Dyy)*(Dxx+Dyy) / (Dxx*Dyy - Dxy*Dxy) ; - double edgeScore ; - - if (alpha < 0) { - /* not an extremum */ - edgeScore = VL_INFINITY_D ; - } else { - edgeScore = (0.5*alpha - 1) + sqrt(VL_MAX(0.25*alpha - 1,0)*alpha) ; - } - - refined->xi = x ; - refined->yi = y ; - refined->zi = z ; - refined->x = x + b[0] ; - refined->y = y + b[1] ; - refined->z = z + b[2] ; - refined->peakScore = peakScore ; - refined->edgeScore = edgeScore ; - - return - err == VL_ERR_OK && - vl_abs_d(b[0]) < 1.5 && - vl_abs_d(b[1]) < 1.5 && - vl_abs_d(b[2]) < 1.5 && - 0 <= refined->x && refined->x <= (signed)width - 1 && - 0 <= refined->y && refined->y <= (signed)height - 1 && - 0 <= refined->z && refined->z <= (signed)depth - 1 ; - } -#undef Aat -#undef at -} - -/** @internal - ** @brief Refine the location of a local extremum of a 2D map - ** @param refined refined extremum (out). - ** @param map a 2D array representing the map. - ** @param width of the map. - ** @param height of the map. - ** @param x initial x position. - ** @param y initial y position. - ** @return a flat indicating whether the extrema refinement was stable. - **/ - -VL_EXPORT vl_bool -vl_refine_local_extreum_2 (VlCovDetExtremum2 * refined, - float const * map, - vl_size width, vl_size height, - vl_index x, vl_index y) -{ - vl_size const xo = 1 ; - vl_size const yo = width ; - - double Dx=0,Dy=0,Dxx=0,Dyy=0,Dxy=0; - double A [2*2], b [2] ; - -#define at(dx,dy) (*(pt + (dx)*xo + (dy)*yo )) -#define Aat(i,j) (A[(i)+(j)*2]) - - float const * pt ; - vl_index dx = 0 ; - vl_index dy = 0 ; - vl_index iter ; - int err ; - - assert (map) ; - assert (1 <= x && x <= (signed)width - 2) ; - assert (1 <= y && y <= (signed)height - 2) ; - - for (iter = 0 ; iter < 5 ; ++iter) { - x += dx ; - y += dy ; - pt = map + x*xo + y*yo ; - - /* compute the gradient */ - Dx = 0.5 * (at(+1,0) - at(-1,0)) ; - Dy = 0.5 * (at(0,+1) - at(0,-1)); - - /* compute the Hessian */ - Dxx = (at(+1,0) + at(-1,0) - 2.0 * at(0,0)) ; - Dyy = (at(0,+1) + at(0,-1) - 2.0 * at(0,0)) ; - Dxy = 0.25 * (at(+1,+1) + at(-1,-1) - at(-1,+1) - at(+1,-1)) ; - - /* solve linear system */ - Aat(0,0) = Dxx ; - Aat(1,1) = Dyy ; - Aat(0,1) = Aat(1,0) = Dxy ; - - b[0] = - Dx ; - b[1] = - Dy ; - - err = vl_solve_linear_system_2(b, A, b) ; - - if (err != VL_ERR_OK) { - b[0] = 0 ; - b[1] = 0 ; - break ; - } - - /* Keep going if there is sufficient translation */ - - dx = (b[0] > 0.6 && x < (signed)width - 2 ? 1 : 0) - + (b[0] < -0.6 && x > 1 ? -1 : 0) ; - - dy = (b[1] > 0.6 && y < (signed)height - 2 ? 1 : 0) - + (b[1] < -0.6 && y > 1 ? -1 : 0) ; - - if (dx == 0 && dy == 0) break ; - } - - /* check threshold and other conditions */ - { - double peakScore = at(0,0) + 0.5 * (Dx * b[0] + Dy * b[1]) ; - double alpha = (Dxx+Dyy)*(Dxx+Dyy) / (Dxx*Dyy - Dxy*Dxy) ; - double edgeScore ; - - if (alpha < 0) { - /* not an extremum */ - edgeScore = VL_INFINITY_D ; - } else { - edgeScore = (0.5*alpha - 1) + sqrt(VL_MAX(0.25*alpha - 1,0)*alpha) ; - } - - refined->xi = x ; - refined->yi = y ; - refined->x = x + b[0] ; - refined->y = y + b[1] ; - refined->peakScore = peakScore ; - refined->edgeScore = edgeScore ; - - return - err == VL_ERR_OK && - vl_abs_d(b[0]) < 1.5 && - vl_abs_d(b[1]) < 1.5 && - 0 <= refined->x && refined->x <= (signed)width - 1 && - 0 <= refined->y && refined->y <= (signed)height - 1 ; - } -#undef Aat -#undef at -} - -/* ---------------------------------------------------------------- */ -/* Covarant detector */ -/* ---------------------------------------------------------------- */ - -#define VL_COVDET_MAX_NUM_ORIENTATIONS 4 -#define VL_COVDET_MAX_NUM_LAPLACIAN_SCALES 4 -#define VL_COVDET_AA_PATCH_RESOLUTION 20 -#define VL_COVDET_AA_MAX_NUM_ITERATIONS 15 -#define VL_COVDET_OR_NUM_ORIENTATION_HISTOGAM_BINS 36 -#define VL_COVDET_AA_RELATIVE_INTEGRATION_SIGMA 3 -#define VL_COVDET_AA_RELATIVE_DERIVATIVE_SIGMA 1 -#define VL_COVDET_AA_MAX_ANISOTROPY 5 -#define VL_COVDET_AA_CONVERGENCE_THRESHOLD 1.001 -#define VL_COVDET_AA_ACCURATE_SMOOTHING VL_FALSE -#define VL_COVDET_AA_PATCH_EXTENT (3*VL_COVDET_AA_RELATIVE_INTEGRATION_SIGMA) -#define VL_COVDET_OR_ADDITIONAL_PEAKS_RELATIVE_SIZE 0.8 -#define VL_COVDET_LAP_NUM_LEVELS 10 -#define VL_COVDET_LAP_PATCH_RESOLUTION 16 -#define VL_COVDET_LAP_DEF_PEAK_THRESHOLD 0.01 -#define VL_COVDET_DOG_DEF_PEAK_THRESHOLD VL_COVDET_LAP_DEF_PEAK_THRESHOLD -#define VL_COVDET_DOG_DEF_EDGE_THRESHOLD 10.0 -#define VL_COVDET_HARRIS_DEF_PEAK_THRESHOLD 0.000002 -#define VL_COVDET_HARRIS_DEF_EDGE_THRESHOLD 10.0 -#define VL_COVDET_HESSIAN_DEF_PEAK_THRESHOLD 0.003 -#define VL_COVDET_HESSIAN_DEF_EDGE_THRESHOLD 10.0 - -/** @brief Covariant feature detector */ -struct _VlCovDet -{ - VlScaleSpace *gss ; /**< Gaussian scale space. */ - VlScaleSpace *css ; /**< Cornerness scale space. */ - VlCovDetMethod method ; /**< feature extraction method. */ - double peakThreshold ; /**< peak threshold. */ - double edgeThreshold ; /**< edge threshold. */ - double lapPeakThreshold; /**< peak threshold for Laplacian scale selection. */ - vl_size octaveResolution ; /**< resolution of each octave. */ - vl_index firstOctave ; /**< index of the first octave. */ - - double nonExtremaSuppression ; - vl_size numNonExtremaSuppressed ; - - VlCovDetFeature *features ; - vl_size numFeatures ; - vl_size numFeatureBufferSize ; - - float * patch ; - vl_size patchBufferSize ; - - vl_bool transposed ; - VlCovDetFeatureOrientation orientations [VL_COVDET_MAX_NUM_ORIENTATIONS] ; - VlCovDetFeatureLaplacianScale scales [VL_COVDET_MAX_NUM_LAPLACIAN_SCALES] ; - - vl_bool aaAccurateSmoothing ; - float aaPatch [(2*VL_COVDET_AA_PATCH_RESOLUTION+1)*(2*VL_COVDET_AA_PATCH_RESOLUTION+1)] ; - float aaPatchX [(2*VL_COVDET_AA_PATCH_RESOLUTION+1)*(2*VL_COVDET_AA_PATCH_RESOLUTION+1)] ; - float aaPatchY [(2*VL_COVDET_AA_PATCH_RESOLUTION+1)*(2*VL_COVDET_AA_PATCH_RESOLUTION+1)] ; - float aaMask [(2*VL_COVDET_AA_PATCH_RESOLUTION+1)*(2*VL_COVDET_AA_PATCH_RESOLUTION+1)] ; - - float lapPatch [(2*VL_COVDET_LAP_PATCH_RESOLUTION+1)*(2*VL_COVDET_LAP_PATCH_RESOLUTION+1)] ; - float laplacians [(2*VL_COVDET_LAP_PATCH_RESOLUTION+1)*(2*VL_COVDET_LAP_PATCH_RESOLUTION+1)*VL_COVDET_LAP_NUM_LEVELS] ; - vl_size numFeaturesWithNumScales [VL_COVDET_MAX_NUM_LAPLACIAN_SCALES + 1] ; -} ; - -VlEnumerator vlCovdetMethods [VL_COVDET_METHOD_NUM] = { - {"DoG" , (vl_index)VL_COVDET_METHOD_DOG }, - {"Hessian", (vl_index)VL_COVDET_METHOD_HESSIAN }, - {"HessianLaplace", (vl_index)VL_COVDET_METHOD_HESSIAN_LAPLACE }, - {"HarrisLaplace", (vl_index)VL_COVDET_METHOD_HARRIS_LAPLACE }, - {"MultiscaleHessian", (vl_index)VL_COVDET_METHOD_MULTISCALE_HESSIAN}, - {"MultiscaleHarris", (vl_index)VL_COVDET_METHOD_MULTISCALE_HARRIS }, - {0, 0 } -} ; - -/** @brief Create a new object instance - ** @param method method for covariant feature detection. - ** @return new covariant detector. - **/ - -VlCovDet * -vl_covdet_new (VlCovDetMethod method) -{ - VlCovDet * self = vl_calloc(sizeof(VlCovDet),1) ; - self->method = method ; - self->octaveResolution = 3 ; - self->firstOctave = -1 ; - switch (self->method) { - case VL_COVDET_METHOD_DOG : - self->peakThreshold = VL_COVDET_DOG_DEF_PEAK_THRESHOLD ; - self->edgeThreshold = VL_COVDET_DOG_DEF_EDGE_THRESHOLD ; - self->lapPeakThreshold = 0 ; /* not used */ - break ; - case VL_COVDET_METHOD_HARRIS_LAPLACE: - case VL_COVDET_METHOD_MULTISCALE_HARRIS: - self->peakThreshold = VL_COVDET_HARRIS_DEF_PEAK_THRESHOLD ; - self->edgeThreshold = VL_COVDET_HARRIS_DEF_EDGE_THRESHOLD ; - self->lapPeakThreshold = VL_COVDET_LAP_DEF_PEAK_THRESHOLD ; - break ; - case VL_COVDET_METHOD_HESSIAN : - case VL_COVDET_METHOD_HESSIAN_LAPLACE: - case VL_COVDET_METHOD_MULTISCALE_HESSIAN: - self->peakThreshold = VL_COVDET_HESSIAN_DEF_PEAK_THRESHOLD ; - self->edgeThreshold = VL_COVDET_HESSIAN_DEF_EDGE_THRESHOLD ; - self->lapPeakThreshold = VL_COVDET_LAP_DEF_PEAK_THRESHOLD ; - break; - default: - assert(0) ; - } - - self->nonExtremaSuppression = 0.5 ; - self->features = NULL ; - self->numFeatures = 0 ; - self->numFeatureBufferSize = 0 ; - self->patch = NULL ; - self->patchBufferSize = 0 ; - self->transposed = VL_FALSE ; - self->aaAccurateSmoothing = VL_COVDET_AA_ACCURATE_SMOOTHING ; - - { - vl_index const w = VL_COVDET_AA_PATCH_RESOLUTION ; - vl_index i,j ; - double step = (2.0 * VL_COVDET_AA_PATCH_EXTENT) / (2*w+1) ; - double sigma = VL_COVDET_AA_RELATIVE_INTEGRATION_SIGMA ; - for (j = -w ; j <= w ; ++j) { - for (i = -w ; i <= w ; ++i) { - double dx = i*step/sigma ; - double dy = j*step/sigma ; - self->aaMask[(i+w) + (2*w+1)*(j+w)] = exp(-0.5*(dx*dx+dy*dy)) ; - } - } - } - - { - /* - Covers one octave of Laplacian filters, from sigma=1 to sigma=2. - The spatial sampling step is 0.5. - */ - vl_index s ; - for (s = 0 ; s < VL_COVDET_LAP_NUM_LEVELS ; ++s) { - double sigmaLap = pow(2.0, -0.5 + - (double)s / (VL_COVDET_LAP_NUM_LEVELS - 1)) ; - double const sigmaImage = 1.0 / sqrt(2.0) ; - double const step = 0.5 * sigmaImage ; - double const sigmaDelta = sqrt(sigmaLap*sigmaLap - sigmaImage*sigmaImage) ; - vl_size const w = VL_COVDET_LAP_PATCH_RESOLUTION ; - vl_size const num = 2 * w + 1 ; - float * pt = self->laplacians + s * (num * num) ; - - memset(pt, 0, num * num * sizeof(float)) ; - -#define at(x,y) pt[(x+w)+(y+w)*(2*w+1)] - at(0,0) = - 4.0 ; - at(-1,0) = 1.0 ; - at(+1,0) = 1.0 ; - at(0,1) = 1.0 ; - at(0,-1) = 1.0 ; -#undef at - - vl_imsmooth_f(pt, num, - pt, num, num, num, - sigmaDelta / step, sigmaDelta / step) ; - -#if 0 - { - char name [200] ; - snprintf(name, 200, "/tmp/%f-lap.pgm", sigmaDelta) ; - vl_pgm_write_f(name, pt, num, num) ; - } -#endif - - } - } - return self ; -} - -/** @brief Reset object - ** @param self object. - ** - ** This function removes any buffered features and frees other - ** internal buffers. - **/ - -void -vl_covdet_reset (VlCovDet * self) -{ - if (self->features) { - vl_free(self->features) ; - self->features = NULL ; - } - if (self->css) { - vl_scalespace_delete(self->css) ; - self->css = NULL ; - } - if (self->gss) { - vl_scalespace_delete(self->gss) ; - self->gss = NULL ; - } -} - -/** @brief Delete object instance - ** @param self object. - **/ - -void -vl_covdet_delete (VlCovDet * self) -{ - vl_covdet_reset(self) ; - if (self->patch) vl_free (self->patch) ; - vl_free(self) ; -} - -/** @brief Append a feature to the internal buffer. - ** @param self object. - ** @param feature a pointer to the feature to append. - ** @return status. - ** - ** The feature is copied. The function may fail with @c status - ** equal to ::VL_ERR_ALLOC if there is insufficient memory. - **/ - -int -vl_covdet_append_feature (VlCovDet * self, VlCovDetFeature const * feature) -{ - vl_size requiredSize ; - assert(self) ; - assert(feature) ; - self->numFeatures ++ ; - requiredSize = self->numFeatures * sizeof(VlCovDetFeature) ; - if (requiredSize > self->numFeatureBufferSize) { - int err = _vl_resize_buffer((void**)&self->features, &self->numFeatureBufferSize, - (self->numFeatures + 1000) * sizeof(VlCovDetFeature)) ; - if (err) { - self->numFeatures -- ; - return err ; - } - } - self->features[self->numFeatures - 1] = *feature ; - return VL_ERR_OK ; -} - -/* ---------------------------------------------------------------- */ -/* Process a new image */ -/* ---------------------------------------------------------------- */ - -/** @brief Detect features in an image - ** @param self object. - ** @param image image to process. - ** @param width image width. - ** @param height image height. - ** @return status. - ** - ** @a width and @a height must be at least one pixel. The function - ** fails by returing ::VL_ERR_ALLOC if the memory is insufficient. - **/ - -int -vl_covdet_put_image (VlCovDet * self, - float const * image, - vl_size width, vl_size height) -{ - vl_size const minOctaveSize = 16 ; - vl_index lastOctave ; - vl_index octaveFirstSubdivision ; - vl_index octaveLastSubdivision ; - VlScaleSpaceGeometry geom = vl_scalespace_get_default_geometry(width,height) ; - - assert (self) ; - assert (image) ; - assert (width >= 1) ; - assert (height >= 1) ; - - /* (minOctaveSize - 1) 2^lastOctave <= min(width,height) - 1 */ - lastOctave = vl_floor_d(vl_log2_d(VL_MIN((double)width-1,(double)height-1) / (minOctaveSize - 1))) ; - - if (self->method == VL_COVDET_METHOD_DOG) { - octaveFirstSubdivision = -1 ; - octaveLastSubdivision = self->octaveResolution + 1 ; - } else if (self->method == VL_COVDET_METHOD_HESSIAN) { - octaveFirstSubdivision = -1 ; - octaveLastSubdivision = self->octaveResolution ; - } else { - octaveFirstSubdivision = 0 ; - octaveLastSubdivision = self->octaveResolution - 1 ; - } - - geom.width = width ; - geom.height = height ; - geom.firstOctave = self->firstOctave ; - geom.lastOctave = lastOctave ; - geom.octaveResolution = self->octaveResolution ; - geom.octaveFirstSubdivision = octaveFirstSubdivision ; - geom.octaveLastSubdivision = octaveLastSubdivision ; - - if (self->gss == NULL || - ! vl_scalespacegeometry_is_equal (geom, - vl_scalespace_get_geometry(self->gss))) - { - if (self->gss) vl_scalespace_delete(self->gss) ; - self->gss = vl_scalespace_new_with_geometry(geom) ; - if (self->gss == NULL) return VL_ERR_ALLOC ; - } - vl_scalespace_put_image(self->gss, image) ; - return VL_ERR_OK ; -} - -/* ---------------------------------------------------------------- */ -/* Cornerness measures */ -/* ---------------------------------------------------------------- */ - -/** @brief Scaled derminant of the Hessian filter - ** @param hessian output image. - ** @param image input image. - ** @param width image width. - ** @param height image height. - ** @param step image sampling step (pixel size). - ** @param sigma Gaussian smoothing of the input image. - **/ - -static void -_vl_det_hessian_response (float * hessian, - float const * image, - vl_size width, vl_size height, - double step, double sigma) -{ - float factor = (float) pow(sigma/step, 4.0) ; - vl_index const xo = 1 ; /* x-stride */ - vl_index const yo = width; /* y-stride */ - vl_size r, c; - - float p11, p12, p13, p21, p22, p23, p31, p32, p33; - - /* setup input pointer to be centered at 0,1 */ - float const *in = image + yo ; - - /* setup output pointer to be centered at 1,1 */ - float *out = hessian + xo + yo; - - /* move 3x3 window and convolve */ - for (r = 1; r < height - 1; ++r) - { - /* fill in shift registers at the beginning of the row */ - p11 = in[-yo]; p12 = in[xo - yo]; - p21 = in[ 0]; p22 = in[xo ]; - p31 = in[+yo]; p32 = in[xo + yo]; - /* setup input pointer to (2,1) of the 3x3 square */ - in += 2; - for (c = 1; c < width - 1; ++c) - { - float Lxx, Lyy, Lxy; - /* fetch remaining values (last column) */ - p13 = in[-yo]; p23 = *in; p33 = in[+yo]; - - /* Compute 3x3 Hessian values from pixel differences. */ - Lxx = (-p21 + 2*p22 - p23); - Lyy = (-p12 + 2*p22 - p32); - Lxy = ((p11 - p31 - p13 + p33)/4.0f); - - /* normalize and write out */ - *out = (Lxx * Lyy - Lxy * Lxy) * factor ; - - /* move window */ - p11=p12; p12=p13; - p21=p22; p22=p23; - p31=p32; p32=p33; - - /* move input/output pointers */ - in++; out++; - } - out += 2; - } - - /* Copy the computed values to borders */ - in = hessian + yo + xo ; - out = hessian + xo ; - - /* Top row without corners */ - memcpy(out, in, (width - 2)*sizeof(float)); - out--; - in -= yo; - - /* Left border columns without last row */ - for (r = 0; r < height - 1; r++){ - *out = *in; - *(out + yo - 1) = *(in + yo - 3); - in += yo; - out += yo; - } - - /* Bottom corners */ - in -= yo; - *out = *in; - *(out + yo - 1) = *(in + yo - 3); - - /* Bottom row without corners */ - out++; - memcpy(out, in, (width - 2)*sizeof(float)); -} - -/** @brief Scale-normalised Harris response - ** @param harris output image. - ** @param image input image. - ** @param width image width. - ** @param height image height. - ** @param step image sampling step (pixel size). - ** @param sigma Gaussian smoothing of the input image. - ** @param sigmaI integration scale. - ** @param alpha factor in the definition of the Harris score. - **/ - -static void -_vl_harris_response (float * harris, - float const * image, - vl_size width, vl_size height, - double step, double sigma, - double sigmaI, double alpha) -{ - float factor = (float) pow(sigma/step, 4.0) ; - vl_index k ; - - float * LxLx ; - float * LyLy ; - float * LxLy ; - - LxLx = vl_malloc(sizeof(float) * width * height) ; - LyLy = vl_malloc(sizeof(float) * width * height) ; - LxLy = vl_malloc(sizeof(float) * width * height) ; - - vl_imgradient_f (LxLx, LyLy, 1, width, image, width, height, width) ; - - for (k = 0 ; k < (signed)(width * height) ; ++k) { - float dx = LxLx[k] ; - float dy = LyLy[k] ; - LxLx[k] = dx*dx ; - LyLy[k] = dy*dy ; - LxLy[k] = dx*dy ; - } - - vl_imsmooth_f(LxLx, width, LxLx, width, height, width, - sigmaI / step, sigmaI / step) ; - - vl_imsmooth_f(LyLy, width, LyLy, width, height, width, - sigmaI / step, sigmaI / step) ; - - vl_imsmooth_f(LxLy, width, LxLy, width, height, width, - sigmaI / step, sigmaI / step) ; - - for (k = 0 ; k < (signed)(width * height) ; ++k) { - float a = LxLx[k] ; - float b = LyLy[k] ; - float c = LxLy[k] ; - - float determinant = a * b - c * c ; - float trace = a + b ; - - harris[k] = factor * (determinant - alpha * (trace * trace)) ; - } - - vl_free(LxLy) ; - vl_free(LyLy) ; - vl_free(LxLx) ; -} - -/** @brief Difference of Gaussian - ** @param dog output image. - ** @param level1 input image at the smaller Gaussian scale. - ** @param level2 input image at the larger Gaussian scale. - ** @param width image width. - ** @param height image height. - **/ - -static void -_vl_dog_response (float * dog, - float const * level1, - float const * level2, - vl_size width, vl_size height) -{ - vl_index k ; - for (k = 0 ; k < (signed)(width*height) ; ++k) { - dog[k] = level2[k] - level1[k] ; - } -} - -/* ---------------------------------------------------------------- */ -/* Detect features */ -/* ---------------------------------------------------------------- */ - -/** @brief Detect scale-space features - ** @param self object. - ** - ** This function runs the configured feature detector on the image - ** that was passed by using ::vl_covdet_put_image. - **/ - -void -vl_covdet_detect (VlCovDet * self, vl_size max_num_features) -{ - VlScaleSpaceGeometry geom = vl_scalespace_get_geometry(self->gss) ; - VlScaleSpaceGeometry cgeom ; - float * levelxx = NULL ; - float * levelyy = NULL ; - float * levelxy = NULL ; - vl_index o, s ; - - assert (self) ; - assert (self->gss) ; - - /* clear previous detections if any */ - self->numFeatures = 0 ; - - /* prepare buffers ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ */ - cgeom = geom ; - if (self->method == VL_COVDET_METHOD_DOG) { - cgeom.octaveLastSubdivision -= 1 ; - } - if (!self->css || - !vl_scalespacegeometry_is_equal(cgeom, - vl_scalespace_get_geometry(self->css))) - { - if (self->css) vl_scalespace_delete(self->css) ; - self->css = vl_scalespace_new_with_geometry(cgeom) ; - } - if (self->method == VL_COVDET_METHOD_HARRIS_LAPLACE || - self->method == VL_COVDET_METHOD_MULTISCALE_HARRIS) { - VlScaleSpaceOctaveGeometry oct = vl_scalespace_get_octave_geometry(self->gss, geom.firstOctave) ; - levelxx = vl_malloc(oct.width * oct.height * sizeof(float)) ; - levelyy = vl_malloc(oct.width * oct.height * sizeof(float)) ; - levelxy = vl_malloc(oct.width * oct.height * sizeof(float)) ; - } - - /* compute cornerness ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ */ - for (o = cgeom.firstOctave ; o <= cgeom.lastOctave ; ++o) { - VlScaleSpaceOctaveGeometry oct = vl_scalespace_get_octave_geometry(self->css, o) ; - - for (s = cgeom.octaveFirstSubdivision ; s <= cgeom.octaveLastSubdivision ; ++s) { - float * level = vl_scalespace_get_level(self->gss, o, s) ; - float * clevel = vl_scalespace_get_level(self->css, o, s) ; - double sigma = vl_scalespace_get_level_sigma(self->css, o, s) ; - switch (self->method) { - case VL_COVDET_METHOD_DOG: - _vl_dog_response(clevel, - vl_scalespace_get_level(self->gss, o, s + 1), - level, - oct.width, oct.height) ; - break ; - - case VL_COVDET_METHOD_HARRIS_LAPLACE: - case VL_COVDET_METHOD_MULTISCALE_HARRIS: - _vl_harris_response(clevel, - level, oct.width, oct.height, oct.step, - sigma, 1.4 * sigma, 0.05) ; - break ; - - case VL_COVDET_METHOD_HESSIAN: - case VL_COVDET_METHOD_HESSIAN_LAPLACE: - case VL_COVDET_METHOD_MULTISCALE_HESSIAN: - _vl_det_hessian_response(clevel, level, oct.width, oct.height, oct.step, sigma) ; - break ; - - default: - assert(0) ; - } - } - } - - /* find and refine local maxima ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ */ - { - vl_index * extrema = NULL ; - vl_size extremaBufferSize = 0 ; - vl_size numExtrema ; - vl_size index ; - for (o = cgeom.lastOctave; o >= cgeom.firstOctave; --o) { - VlScaleSpaceOctaveGeometry octgeom = vl_scalespace_get_octave_geometry(self->css, o) ; - double step = octgeom.step ; - vl_size width = octgeom.width ; - vl_size height = octgeom.height ; - vl_size depth = cgeom.octaveLastSubdivision - cgeom.octaveFirstSubdivision + 1 ; - - switch (self->method) { - case VL_COVDET_METHOD_DOG: - case VL_COVDET_METHOD_HESSIAN: - { - /* scale-space extrema */ - float const * octave = - vl_scalespace_get_level(self->css, o, cgeom.octaveFirstSubdivision) ; - numExtrema = vl_find_local_extrema_3(&extrema, &extremaBufferSize, - octave, width, height, depth, - 0.8 * self->peakThreshold); - for (index = 0 ; index < numExtrema ; ++index) { - VlCovDetExtremum3 refined ; - VlCovDetFeature feature ; - vl_bool ok ; - memset(&feature, 0, sizeof(feature)) ; - ok = vl_refine_local_extreum_3(&refined, - octave, width, height, depth, - extrema[3*index+0], - extrema[3*index+1], - extrema[3*index+2]) ; - ok &= fabs(refined.peakScore) > self->peakThreshold ; - ok &= refined.edgeScore < self->edgeThreshold ; - if (ok) { - double sigma = cgeom.baseScale * - pow(2.0, o + (refined.z + cgeom.octaveFirstSubdivision) - / cgeom.octaveResolution) ; - feature.frame.x = refined.x * step ; - feature.frame.y = refined.y * step ; - feature.frame.a11 = sigma ; - feature.frame.a12 = 0.0 ; - feature.frame.a21 = 0.0 ; - feature.frame.a22 = sigma ; - feature.o = o ; - feature.s = round(refined.z) ; - feature.peakScore = refined.peakScore ; - feature.edgeScore = refined.edgeScore ; - vl_covdet_append_feature(self, &feature) ; - } - } - break ; - } - - default: - { - for (s = cgeom.octaveFirstSubdivision ; s < cgeom.octaveLastSubdivision ; ++s) { - /* space extrema */ - float const * level = vl_scalespace_get_level(self->css,o,s) ; - numExtrema = vl_find_local_extrema_2(&extrema, &extremaBufferSize, - level, - width, height, - 0.8 * self->peakThreshold); - for (index = 0 ; index < numExtrema ; ++index) { - VlCovDetExtremum2 refined ; - VlCovDetFeature feature ; - vl_bool ok ; - memset(&feature, 0, sizeof(feature)) ; - ok = vl_refine_local_extreum_2(&refined, - level, width, height, - extrema[2*index+0], - extrema[2*index+1]); - ok &= fabs(refined.peakScore) > self->peakThreshold ; - ok &= refined.edgeScore < self->edgeThreshold ; - if (ok) { - double sigma = cgeom.baseScale * - pow(2.0, o + (double)s / cgeom.octaveResolution) ; - feature.frame.x = refined.x * step ; - feature.frame.y = refined.y * step ; - feature.frame.a11 = sigma ; - feature.frame.a12 = 0.0 ; - feature.frame.a21 = 0.0 ; - feature.frame.a22 = sigma ; - feature.o = o ; - feature.s = s ; - feature.peakScore = refined.peakScore ; - feature.edgeScore = refined.edgeScore ; - vl_covdet_append_feature(self, &feature) ; - } - } - } - break ; - } - } - if (self->numFeatures >= max_num_features) { - break; - } - } /* next octave */ - - if (extrema) { vl_free(extrema) ; extrema = 0 ; } - } - - /* Laplacian scale selection for certain methods */ - switch (self->method) { - case VL_COVDET_METHOD_HARRIS_LAPLACE : - case VL_COVDET_METHOD_HESSIAN_LAPLACE : - vl_covdet_extract_laplacian_scales (self) ; - break ; - default: - break ; - } - - if (self->nonExtremaSuppression) { - vl_index i, j ; - double tol = self->nonExtremaSuppression ; - self->numNonExtremaSuppressed = 0 ; - for (i = 0 ; i < (signed)self->numFeatures ; ++i) { - double x = self->features[i].frame.x ; - double y = self->features[i].frame.y ; - double sigma = self->features[i].frame.a11 ; - double score = self->features[i].peakScore ; - if (score == 0) continue ; - - for (j = 0 ; j < (signed)self->numFeatures ; ++j) { - double dx_ = self->features[j].frame.x - x ; - double dy_ = self->features[j].frame.y - y ; - double sigma_ = self->features[j].frame.a11 ; - double score_ = self->features[j].peakScore ; - if (score_ == 0) continue ; - if (sigma < (1+tol) * sigma_ && - sigma_ < (1+tol) * sigma && - vl_abs_d(dx_) < tol * sigma && - vl_abs_d(dy_) < tol * sigma && - vl_abs_d(score) > vl_abs_d(score_)) { - self->features[j].peakScore = 0 ; - self->numNonExtremaSuppressed ++ ; - } - } - } - j = 0 ; - for (i = 0 ; i < (signed)self->numFeatures ; ++i) { - VlCovDetFeature feature = self->features[i] ; - if (self->features[i].peakScore != 0) { - self->features[j++] = feature ; - } - } - self->numFeatures = j ; - } - - if (levelxx) vl_free(levelxx) ; - if (levelyy) vl_free(levelyy) ; - if (levelxy) vl_free(levelxy) ; -} - -/* ---------------------------------------------------------------- */ -/* Extract patches */ -/* ---------------------------------------------------------------- */ - -/** @internal - ** @brief Helper for extracting patches - ** @param self object. - ** @param[out] sigma1 actual patch smoothing along the first axis. - ** @param[out] sigma2 actual patch smoothing along the second axis. - ** @param patch buffer. - ** @param resolution patch resolution. - ** @param extent patch extent. - ** @param sigma desired smoothing in the patch frame. - ** @param A_ linear transfomration from patch to image. - ** @param T_ translation from patch to image. - ** @param d1 first singular value @a A. - ** @param d2 second singular value of @a A. - **/ - -vl_bool -vl_covdet_extract_patch_helper (VlCovDet * self, - double * sigma1, - double * sigma2, - float * patch, - vl_size resolution, - double extent, - double sigma, - double A_ [4], - double T_ [2], - double d1, double d2) -{ - vl_index o, s ; - double factor ; - double sigma_ ; - float const * level ; - vl_size width, height ; - double step ; - - double A [4] = {A_[0], A_[1], A_[2], A_[3]} ; - double T [2] = {T_[0], T_[1]} ; - - VlScaleSpaceGeometry geom = vl_scalespace_get_geometry(self->gss) ; - VlScaleSpaceOctaveGeometry oct ; - - /* Starting from a pre-smoothed image at scale sigma_ - because of the mapping A the resulting smoothing in - the warped patch is S, where - - sigma_^2 I = A S A', - - S = sigma_^2 inv(A) inv(A)' = sigma_^2 V D^-2 V', - - A = U D V'. - - Thus we rotate A by V to obtain an axis-aligned smoothing: - - A = U*D, - - S = sigma_^2 D^-2. - - Then we search the scale-space for the best sigma_ such - that the target smoothing is approximated from below: - - max sigma_(o,s) : simga_(o,s) factor <= sigma, - factor = max{abs(D11), abs(D22)}. - */ - - - /* - Determine the best level (o,s) such that sigma_(o,s) factor <= sigma. - This can be obtained by scanning octaves from smallest to largest - and stopping when no level in the octave satisfies the relation. - - Given the range of octave availables, do the best you can. - */ - - factor = 1.0 / VL_MIN(d1, d2) ; - - for (o = geom.firstOctave + 1 ; o <= geom.lastOctave ; ++o) { - s = vl_floor_d(vl_log2_d(sigma / (factor * geom.baseScale)) - o) ; - s = VL_MAX(s, geom.octaveFirstSubdivision) ; - s = VL_MIN(s, geom.octaveLastSubdivision) ; - sigma_ = geom.baseScale * pow(2.0, o + (double)s / geom.octaveResolution) ; - /*VL_PRINTF(".. %d D=%g %g; sigma_=%g factor*sigma_=%g\n", o, d1, d2, sigma_, factor* sigma_) ;*/ - if (factor * sigma_ > sigma) { - o -- ; - break ; - } - } - o = VL_MIN(o, geom.lastOctave) ; - s = vl_floor_d(vl_log2_d(sigma / (factor * geom.baseScale)) - o) ; - s = VL_MAX(s, geom.octaveFirstSubdivision) ; - s = VL_MIN(s, geom.octaveLastSubdivision) ; - sigma_ = geom.baseScale * pow(2.0, o + (double)s / geom.octaveResolution) ; - if (sigma1) *sigma1 = sigma_ / d1 ; - if (sigma2) *sigma2 = sigma_ / d2 ; - - /*VL_PRINTF("%d %d %g %g %g %g\n", o, s, factor, sigma_, factor * sigma_, sigma) ;*/ - - /* - Now the scale space level to be used for this warping has been - determined. - - If the patch is partially or completely out of the image boundary, - create a padded copy of the required region first. - */ - - level = vl_scalespace_get_level(self->gss, o, s) ; - oct = vl_scalespace_get_octave_geometry(self->gss, o) ; - width = oct.width ; - height = oct.height ; - step = oct.step ; - - A[0] /= step ; - A[1] /= step ; - A[2] /= step ; - A[3] /= step ; - T[0] /= step ; - T[1] /= step ; - - { - /* - Warp the patch domain [x0hat,y0hat,x1hat,y1hat] to the image domain/ - Obtain a box [x0,y0,x1,y1] enclosing that wrapped box, and then - an integer vertexes version [x0i, y0i, x1i, y1i], making room - for one pixel at the boundary to simplify bilinear interpolation - later on. - */ - vl_index x0i, y0i, x1i, y1i ; - double x0 = +VL_INFINITY_D ; - double x1 = -VL_INFINITY_D ; - double y0 = +VL_INFINITY_D ; - double y1 = -VL_INFINITY_D ; - double boxx [4] = {extent, extent, -extent, -extent} ; - double boxy [4] = {-extent, extent, extent, -extent} ; - int i ; - for (i = 0 ; i < 4 ; ++i) { - double x = A[0] * boxx[i] + A[2] * boxy[i] + T[0] ; - double y = A[1] * boxx[i] + A[3] * boxy[i] + T[1] ; - x0 = VL_MIN(x0, x) ; - x1 = VL_MAX(x1, x) ; - y0 = VL_MIN(y0, y) ; - y1 = VL_MAX(y1, y) ; - } - - /* Leave one pixel border for bilinear interpolation. */ - x0i = floor(x0) - 1 ; - y0i = floor(y0) - 1 ; - x1i = ceil(x1) + 1 ; - y1i = ceil(y1) + 1 ; - - /* - If the box [x0i,y0i,x1i,y1i] is not fully contained in the - image domain, then create a copy of this region by padding - the image. The image is extended by continuity. - */ - - if (x0i < 0 || x1i > (signed)width-1 || - y0i < 0 || y1i > (signed)height-1) { - vl_index xi, yi ; - - /* compute the amount of l,r,t,b padding needed to complete the patch */ - vl_index padx0 = VL_MAX(0, - x0i) ; - vl_index pady0 = VL_MAX(0, - y0i) ; - vl_index padx1 = VL_MAX(0, x1i - ((signed)width - 1)) ; - vl_index pady1 = VL_MAX(0, y1i - ((signed)height - 1)) ; - - /* make enough room for the patch */ - vl_index patchWidth = x1i - x0i + 1 ; - vl_index patchHeight = y1i - y0i + 1 ; - vl_size patchBufferSize = patchWidth * patchHeight * sizeof(float) ; - if (patchBufferSize > self->patchBufferSize) { - int err = _vl_resize_buffer((void**)&self->patch, &self->patchBufferSize, patchBufferSize) ; - if (err) return vl_set_last_error(VL_ERR_ALLOC, NULL) ; - } - - if (pady0 < patchHeight - pady1) { - /* start by filling the central horizontal band */ - for (yi = y0i + pady0 ; yi < y0i + patchHeight - pady1 ; ++ yi) { - float *dst = self->patch + (yi - y0i) * patchWidth ; - float const *src = level + yi * width + VL_MIN(VL_MAX(0, x0i),(signed)width-1) ; - for (xi = x0i ; xi < x0i + padx0 ; ++xi) *dst++ = *src ; - for ( ; xi < x0i + patchWidth - padx1 - 2 ; ++xi) *dst++ = *src++ ; - for ( ; xi < x0i + patchWidth ; ++xi) *dst++ = *src ; - } - /* now extend the central band up and down */ - for (yi = 0 ; yi < pady0 ; ++yi) { - memcpy(self->patch + yi * patchWidth, - self->patch + pady0 * patchWidth, - patchWidth * sizeof(float)) ; - } - for (yi = patchHeight - pady1 ; yi < patchHeight ; ++yi) { - memcpy(self->patch + yi * patchWidth, - self->patch + (patchHeight - pady1 - 1) * patchWidth, - patchWidth * sizeof(float)) ; - } - } else { - /* should be handled better! */ - memset(self->patch, 0, self->patchBufferSize) ; - } -#if 0 - { - char name [200] ; - snprintf(name, 200, "/tmp/%20.0f-ext.pgm", 1e10*vl_get_cpu_time()) ; - vl_pgm_write_f(name, patch, patchWidth, patchWidth) ; - } -#endif - - level = self->patch ; - width = patchWidth ; - height = patchHeight ; - T[0] -= x0i ; - T[1] -= y0i ; - } - } - - /* - Resample by using bilinear interpolation. - */ - { - float * pt = patch ; - double yhat = -extent ; - vl_index xxi ; - vl_index yyi ; - double stephat = extent / resolution ; - - for (yyi = 0 ; yyi < 2 * (signed)resolution + 1 ; ++yyi) { - double xhat = -extent ; - double rx = A[2] * yhat + T[0] ; - double ry = A[3] * yhat + T[1] ; - for (xxi = 0 ; xxi < 2 * (signed)resolution + 1 ; ++xxi) { - double x = A[0] * xhat + rx ; - double y = A[1] * xhat + ry ; - vl_index xi = vl_floor_d(x) ; - vl_index yi = vl_floor_d(y) ; - double i00 = level[yi * width + xi] ; - double i10 = level[yi * width + xi + 1] ; - double i01 = level[(yi + 1) * width + xi] ; - double i11 = level[(yi + 1) * width + xi + 1] ; - double wx = x - xi ; - double wy = y - yi ; - - assert(xi >= 0 && xi <= (signed)width - 1) ; - assert(yi >= 0 && yi <= (signed)height - 1) ; - - *pt++ = - (1.0 - wy) * ((1.0 - wx) * i00 + wx * i10) + - wy * ((1.0 - wx) * i01 + wx * i11) ; - - xhat += stephat ; - } - yhat += stephat ; - } - } -#if 0 - { - char name [200] ; - snprintf(name, 200, "/tmp/%20.0f.pgm", 1e10*vl_get_cpu_time()) ; - vl_pgm_write_f(name, patch, 2*resolution+1, 2*resolution+1) ; - } -#endif - return VL_ERR_OK ; -} - -/** @brief Helper for extracting patches - ** @param self object. - ** @param patch buffer. - ** @param resolution patch resolution. - ** @param extent patch extent. - ** @param sigma desired smoothing in the patch frame. - ** @param frame feature frame. - ** - ** The function considers a patch of extent [-extent,extent] - ** on each side, with a side counting 2*resolution+1 pixels. - ** In attempts to extract from the scale space a patch - ** based on the affine warping specified by @a frame in such a way - ** that the resulting smoothing of the image is @a sigma (in the - ** patch frame). - ** - ** The transformation is specified by the matrices @c A and @c T - ** embedded in the feature @a frame. Note that this transformation maps - ** pixels from the patch frame to the image frame. - **/ - -vl_bool -vl_covdet_extract_patch_for_frame (VlCovDet * self, - float * patch, - vl_size resolution, - double extent, - double sigma, - VlFrameOrientedEllipse frame) -{ - double A[2*2] = {frame.a11, frame.a21, frame.a12, frame.a22} ; - double T[2] = {frame.x, frame.y} ; - double D[4], U[4], V[4] ; - - vl_svd2(D, U, V, A) ; - - return vl_covdet_extract_patch_helper - (self, NULL, NULL, patch, resolution, extent, sigma, A, T, D[0], D[3]) ; -} - -/* ---------------------------------------------------------------- */ -/* Affine shape */ -/* ---------------------------------------------------------------- */ - -/** @brief Extract the affine shape for a feature frame - ** @param self object. - ** @param adapted the shape-adapted frame. - ** @param frame the input frame. - ** @return ::VL_ERR_OK if affine adaptation is successful. - ** - ** This function may fail if adaptation is unsuccessful or if - ** memory is insufficient. - **/ - -int -vl_covdet_extract_affine_shape_for_frame (VlCovDet * self, - VlFrameOrientedEllipse * adapted, - VlFrameOrientedEllipse frame) -{ - vl_index iter = 0 ; - - double A [2*2] = {frame.a11, frame.a21, frame.a12, frame.a22} ; - double T [2] = {frame.x, frame.y} ; - double U [2*2] ; - double V [2*2] ; - double D [2*2] ; - double M [2*2] ; - double P [2*2] ; - double P_ [2*2] ; - double Q [2*2] ; - double sigma1, sigma2 ; - double sigmaD = VL_COVDET_AA_RELATIVE_DERIVATIVE_SIGMA ; - double factor ; - double anisotropy ; - double referenceScale ; - vl_size const resolution = VL_COVDET_AA_PATCH_RESOLUTION ; - vl_size const side = 2*VL_COVDET_AA_PATCH_RESOLUTION + 1 ; - double const extent = VL_COVDET_AA_PATCH_EXTENT ; - - - *adapted = frame ; - - while (1) { - double lxx = 0, lxy = 0, lyy = 0 ; - vl_index k ; - int err ; - - /* A = U D V' */ - vl_svd2(D, U, V, A) ; - anisotropy = VL_MAX(D[0]/D[3], D[3]/D[0]) ; - - /* VL_PRINTF("anisot: %g\n", anisotropy); */ - - if (anisotropy > VL_COVDET_AA_MAX_ANISOTROPY) { - /* diverged, give up with current solution */ - break ; - } - - /* make sure that the smallest singluar value stays fixed - after the first iteration */ - if (iter == 0) { - referenceScale = VL_MIN(D[0], D[3]) ; - factor = 1.0 ; - } else { - factor = referenceScale / VL_MIN(D[0],D[3]) ; - } - - D[0] *= factor ; - D[3] *= factor ; - - A[0] = U[0] * D[0] ; - A[1] = U[1] * D[0] ; - A[2] = U[2] * D[3] ; - A[3] = U[3] * D[3] ; - - adapted->a11 = A[0] ; - adapted->a21 = A[1] ; - adapted->a12 = A[2] ; - adapted->a22 = A[3] ; - - if (++iter >= VL_COVDET_AA_MAX_NUM_ITERATIONS) break ; - - err = vl_covdet_extract_patch_helper(self, - &sigma1, &sigma2, - self->aaPatch, - resolution, - extent, - sigmaD, - A, T, D[0], D[3]) ; - if (err) return err ; - - if (self->aaAccurateSmoothing ) { - double deltaSigma1 = sqrt(VL_MAX(sigmaD*sigmaD - sigma1*sigma1,0)) ; - double deltaSigma2 = sqrt(VL_MAX(sigmaD*sigmaD - sigma2*sigma2,0)) ; - double stephat = extent / resolution ; - vl_imsmooth_f(self->aaPatch, side, - self->aaPatch, side, side, side, - deltaSigma1 / stephat, deltaSigma2 / stephat) ; - } - - /* compute second moment matrix */ - vl_imgradient_f (self->aaPatchX, self->aaPatchY, 1, side, - self->aaPatch, side, side, side) ; - - for (k = 0 ; k < (signed)(side*side) ; ++k) { - double lx = self->aaPatchX[k] ; - double ly = self->aaPatchY[k] ; - lxx += lx * lx * self->aaMask[k] ; - lyy += ly * ly * self->aaMask[k] ; - lxy += lx * ly * self->aaMask[k] ; - } - M[0] = lxx ; - M[1] = lxy ; - M[2] = lxy ; - M[3] = lyy ; - - if (lxx == 0 || lyy == 0) { - *adapted = frame ; - break ; - } - - /* decompose M = P * Q * P' */ - vl_svd2 (Q, P, P_, M) ; - - /* - Setting A <- A * dA results in M to change approximatively as - - M --> dA' M dA = dA' P Q P dA - - To make this proportional to the identity, we set - - dA ~= P Q^1/2 - - we also make it so the smallest singular value of A is unchanged. - */ - - if (Q[3]/Q[0] < VL_COVDET_AA_CONVERGENCE_THRESHOLD && - Q[0]/Q[3] < VL_COVDET_AA_CONVERGENCE_THRESHOLD) { - break ; - } - - { - double Ap [4] ; - double q0 = sqrt(Q[0]) ; - double q1 = sqrt(Q[3]) ; - Ap[0] = (A[0] * P[0] + A[2] * P[1]) / q0 ; - Ap[1] = (A[1] * P[0] + A[3] * P[1]) / q0 ; - Ap[2] = (A[0] * P[2] + A[2] * P[3]) / q1 ; - Ap[3] = (A[1] * P[2] + A[3] * P[3]) / q1 ; - memcpy(A,Ap,4*sizeof(double)) ; - } - - } /* next iteration */ - - /* - Make upright. - - Shape adaptation does not estimate rotation. This is fixed by default - so that a selected axis is not rotated at all (usually this is the - vertical axis for upright features). To do so, the frame is rotated - as follows. - */ - { - double A [2*2] = {adapted->a11, adapted->a21, adapted->a12, adapted->a22} ; - double ref [2] ; - double ref_ [2] ; - double angle ; - double angle_ ; - double dangle ; - double r1, r2 ; - - if (self->transposed) { - /* up is the x axis */ - ref[0] = 1 ; - ref[1] = 0 ; - } else { - /* up is the y axis */ - ref[0] = 0 ; - ref[1] = 1 ; - } - - vl_solve_linear_system_2 (ref_, A, ref) ; - angle = atan2(ref[1], ref[0]) ; - angle_ = atan2(ref_[1], ref_[0]) ; - dangle = angle_ - angle ; - r1 = cos(dangle) ; - r2 = sin(dangle) ; - adapted->a11 = + A[0] * r1 + A[2] * r2 ; - adapted->a21 = + A[1] * r1 + A[3] * r2 ; - adapted->a12 = - A[0] * r2 + A[2] * r1 ; - adapted->a22 = - A[1] * r2 + A[3] * r1 ; - } - - return VL_ERR_OK ; -} - -/** @brief Extract the affine shape for the stored features - ** @param self object. - ** - ** This function may discard features for which no affine - ** shape can reliably be detected. - **/ - -void -vl_covdet_extract_affine_shape (VlCovDet * self) -{ - vl_index i, j = 0 ; - vl_size numFeatures = vl_covdet_get_num_features(self) ; - VlCovDetFeature * feature = vl_covdet_get_features(self); - for (i = 0 ; i < (signed)numFeatures ; ++i) { - int status ; - VlFrameOrientedEllipse adapted ; - status = vl_covdet_extract_affine_shape_for_frame(self, &adapted, feature[i].frame) ; - if (status == VL_ERR_OK) { - feature[j] = feature[i] ; - feature[j].frame = adapted ; - ++ j ; - } - } - self->numFeatures = j ; -} - -/* ---------------------------------------------------------------- */ -/* Orientation */ -/* ---------------------------------------------------------------- */ - -static int -_vl_covdet_compare_orientations_descending (void const * a_, - void const * b_) -{ - VlCovDetFeatureOrientation const * a = a_ ; - VlCovDetFeatureOrientation const * b = b_ ; - if (a->score > b->score) return -1 ; - if (a->score < b->score) return +1 ; - return 0 ; -} - -/** @brief Extract the orientation(s) for a feature - ** @param self object. - ** @param numOrientations the number of detected orientations. - ** @param frame pose of the feature. - ** @return an array of detected orientations with their scores. - ** - ** The returned array is a matrix of size @f$ 2 \times n @f$ - ** where n is the number of detected orientations. - ** - ** The function returns @c NULL if memory is insufficient. - **/ - -VlCovDetFeatureOrientation * -vl_covdet_extract_orientations_for_frame (VlCovDet * self, - vl_size * numOrientations, - VlFrameOrientedEllipse frame) -{ - int err ; - vl_index k, i ; - vl_index iter ; - - double extent = VL_COVDET_AA_PATCH_EXTENT ; - vl_size resolution = VL_COVDET_AA_PATCH_RESOLUTION ; - vl_size side = 2 * resolution + 1 ; - - vl_size const numBins = VL_COVDET_OR_NUM_ORIENTATION_HISTOGAM_BINS ; - double hist [VL_COVDET_OR_NUM_ORIENTATION_HISTOGAM_BINS] ; - double const binExtent = 2 * VL_PI / VL_COVDET_OR_NUM_ORIENTATION_HISTOGAM_BINS ; - double const peakRelativeSize = VL_COVDET_OR_ADDITIONAL_PEAKS_RELATIVE_SIZE ; - double maxPeakValue ; - - double A [2*2] = {frame.a11, frame.a21, frame.a12, frame.a22} ; - double T [2] = {frame.x, frame.y} ; - double U [2*2] ; - double V [2*2] ; - double D [2*2] ; - double sigma1, sigma2 ; - double sigmaD = 1.0 ; - double theta0 ; - - assert(self); - assert(numOrientations) ; - - /* - The goal is to estimate a rotation R(theta) such that the patch given - by the transformation A R(theta) has the strongest average - gradient pointing right (or down for transposed conventions). - - To compensate for tha anisotropic smoothing due to warping, - A is decomposed as A = U D V' and the patch is warped by - U D only, meaning that the matrix R_(theta) will be estimated instead, - where: - - A R(theta) = U D V' R(theta) = U D R_(theta) - - such that R(theta) = V R(theta). That is an extra rotation of - theta0 = atan2(V(2,1),V(1,1)). - */ - - /* axis aligned anisotropic smoothing for easier compensation */ - vl_svd2(D, U, V, A) ; - - A[0] = U[0] * D[0] ; - A[1] = U[1] * D[0] ; - A[2] = U[2] * D[3] ; - A[3] = U[3] * D[3] ; - - theta0 = atan2(V[1],V[0]) ; - - err = vl_covdet_extract_patch_helper(self, - &sigma1, &sigma2, - self->aaPatch, - resolution, - extent, - sigmaD, - A, T, D[0], D[3]) ; - - if (err) { - *numOrientations = 0 ; - return NULL ; - } - - if (1) { - double deltaSigma1 = sqrt(VL_MAX(sigmaD*sigmaD - sigma1*sigma1,0)) ; - double deltaSigma2 = sqrt(VL_MAX(sigmaD*sigmaD - sigma2*sigma2,0)) ; - double stephat = extent / resolution ; - vl_imsmooth_f(self->aaPatch, side, - self->aaPatch, side, side, side, - deltaSigma1 / stephat, deltaSigma2 / stephat) ; - } - - /* histogram of oriented gradients */ - vl_imgradient_polar_f (self->aaPatchX, self->aaPatchY, 1, side, - self->aaPatch, side, side, side) ; - - memset (hist, 0, sizeof(double) * numBins) ; - - for (k = 0 ; k < (signed)(side*side) ; ++k) { - double modulus = self->aaPatchX[k] ; - double angle = self->aaPatchY[k] ; - double weight = self->aaMask[k] ; - - double x = angle / binExtent ; - vl_index bin = vl_floor_d(x) ; - double w2 = x - bin ; - double w1 = 1.0 - w2 ; - - hist[(bin + numBins) % numBins] += w1 * (modulus * weight) ; - hist[(bin + numBins + 1) % numBins] += w2 * (modulus * weight) ; - } - - /* smooth histogram */ - for (iter = 0; iter < 6; iter ++) { - double prev = hist [numBins - 1] ; - double first = hist [0] ; - vl_index i ; - for (i = 0; i < (signed)numBins - 1; ++i) { - double curr = (prev + hist[i] + hist[(i + 1) % numBins]) / 3.0 ; - prev = hist[i] ; - hist[i] = curr ; - } - hist[i] = (prev + hist[i] + first) / 3.0 ; - } - - /* find the histogram maximum */ - maxPeakValue = 0 ; - for (i = 0 ; i < (signed)numBins ; ++i) { - maxPeakValue = VL_MAX (maxPeakValue, hist[i]) ; - } - - /* find peaks within 80% from max */ - *numOrientations = 0 ; - for(i = 0 ; i < (signed)numBins ; ++i) { - double h0 = hist [i] ; - double hm = hist [(i - 1 + numBins) % numBins] ; - double hp = hist [(i + 1 + numBins) % numBins] ; - - /* is this a peak? */ - if (h0 > peakRelativeSize * maxPeakValue && h0 > hm && h0 > hp) { - /* quadratic interpolation */ - double di = - 0.5 * (hp - hm) / (hp + hm - 2 * h0) ; - double th = binExtent * (i + di) + theta0 ; - if (self->transposed) { - /* the axis to the right is y, measure orientations from this */ - th = th - VL_PI/2 ; - } - self->orientations[*numOrientations].angle = th ; - self->orientations[*numOrientations].score = h0 ; - *numOrientations += 1 ; - //VL_PRINTF("%d %g\n", *numOrientations, th) ; - - if (*numOrientations >= VL_COVDET_MAX_NUM_ORIENTATIONS) break ; - } - } - - /* sort the orientations by decreasing scores */ - qsort(self->orientations, - *numOrientations, - sizeof(VlCovDetFeatureOrientation), - _vl_covdet_compare_orientations_descending) ; - - return self->orientations ; -} - -/** @brief Extract the orientation(s) for the stored features. - ** @param self object. - ** - ** Note that, since more than one orientation can be detected - ** for each feature, this function may create copies of them, - ** one for each orientation. - **/ - -void -vl_covdet_extract_orientations (VlCovDet * self) -{ - vl_index i, j ; - vl_size numFeatures = vl_covdet_get_num_features(self) ; - for (i = 0 ; i < (signed)numFeatures ; ++i) { - vl_size numOrientations ; - VlCovDetFeature feature = self->features[i] ; - VlCovDetFeatureOrientation* orientations = - vl_covdet_extract_orientations_for_frame(self, &numOrientations, feature.frame) ; - - for (j = 0 ; j < (signed)numOrientations ; ++j) { - double A [2*2] = { - feature.frame.a11, - feature.frame.a21, - feature.frame.a12, - feature.frame.a22} ; - double r1 = cos(orientations[j].angle) ; - double r2 = sin(orientations[j].angle) ; - VlCovDetFeature * oriented ; - - if (j == 0) { - oriented = & self->features[i] ; - } else { - vl_covdet_append_feature(self, &feature) ; - oriented = & self->features[self->numFeatures -1] ; - } - - oriented->orientationScore = orientations[j].score ; - oriented->frame.a11 = + A[0] * r1 + A[2] * r2 ; - oriented->frame.a21 = + A[1] * r1 + A[3] * r2 ; - oriented->frame.a12 = - A[0] * r2 + A[2] * r1 ; - oriented->frame.a22 = - A[1] * r2 + A[3] * r1 ; - } - } -} - -/* ---------------------------------------------------------------- */ -/* Laplacian scales */ -/* ---------------------------------------------------------------- */ - -/** @brief Extract the Laplacian scale(s) for a feature frame. - ** @param self object. - ** @param numScales the number of detected scales. - ** @param frame pose of the feature. - ** @return an array of detected scales. - ** - ** The function returns @c NULL if memory is insufficient. - **/ - -VlCovDetFeatureLaplacianScale * -vl_covdet_extract_laplacian_scales_for_frame (VlCovDet * self, - vl_size * numScales, - VlFrameOrientedEllipse frame) -{ - /* - We try to explore one octave, with the nominal detection scale 1.0 - (in the patch reference frame) in the middle. Thus the goal is to sample - the response of the tr-Laplacian operator at logarithmically - spaced scales in 1/sqrt(2), sqrt(2). - - To this end, the patch is warped with a smoothing of at most - sigmaImage = 1 / sqrt(2) (beginning of the scale), sampled at - roughly twice the Nyquist frequency (so step = 1 / (2*sqrt(2))). - This maes it possible to approximate the Laplacian operator at - that scale by simple finite differences. - - */ - int err ; - double const sigmaImage = 1.0 / sqrt(2.0) ; - double const step = 0.5 * sigmaImage ; - double actualSigmaImage ; - vl_size const resolution = VL_COVDET_LAP_PATCH_RESOLUTION ; - vl_size const num = 2 * resolution + 1 ; - double extent = step * resolution ; - double scores [VL_COVDET_LAP_NUM_LEVELS] ; - double factor = 1.0 ; - float const * pt ; - vl_index k ; - - double A[2*2] = {frame.a11, frame.a21, frame.a12, frame.a22} ; - double T[2] = {frame.x, frame.y} ; - double D[4], U[4], V[4] ; - double sigma1, sigma2 ; - - assert(self) ; - assert(numScales) ; - - *numScales = 0 ; - - vl_svd2(D, U, V, A) ; - - err = vl_covdet_extract_patch_helper - (self, &sigma1, &sigma2, self->lapPatch, resolution, extent, sigmaImage, A, T, D[0], D[3]) ; - if (err) return NULL ; - - /* the actual smoothing after warping is never the target one */ - if (sigma1 == sigma2) { - actualSigmaImage = sigma1 ; - } else { - /* here we could compensate */ - actualSigmaImage = sqrt(sigma1*sigma2) ; - } - - /* now multiply by the bank of Laplacians */ - pt = self->laplacians ; - for (k = 0 ; k < VL_COVDET_LAP_NUM_LEVELS ; ++k) { - vl_index q ; - double score = 0 ; - double sigmaLap = pow(2.0, -0.5 + (double)k / (VL_COVDET_LAP_NUM_LEVELS - 1)) ; - /* note that the sqrt argument cannot be negative since by construction - sigmaLap >= sigmaImage */ - sigmaLap = sqrt(sigmaLap*sigmaLap - - sigmaImage*sigmaImage - + actualSigmaImage*actualSigmaImage) ; - - for (q = 0 ; q < (signed)(num * num) ; ++q) { - score += (*pt++) * self->lapPatch[q] ; - } - scores[k] = score * sigmaLap * sigmaLap ; - } - - /* find and interpolate maxima */ - for (k = 1 ; k < VL_COVDET_LAP_NUM_LEVELS - 1 ; ++k) { - double a = scores[k-1] ; - double b = scores[k] ; - double c = scores[k+1] ; - double t = self->lapPeakThreshold ; - - if ((((b > a) && (b > c)) || ((b < a) && (b < c))) && (vl_abs_d(b) >= t)) { - double dk = - 0.5 * (c - a) / (c + a - 2 * b) ; - double s = k + dk ; - double sigmaLap = pow(2.0, -0.5 + s / (VL_COVDET_LAP_NUM_LEVELS - 1)) ; - double scale ; - sigmaLap = sqrt(sigmaLap*sigmaLap - - sigmaImage*sigmaImage - + actualSigmaImage*actualSigmaImage) ; - scale = sigmaLap / 1.0 ; - /* - VL_PRINTF("** k:%d, s:%f, sigmaLapFilter:%f, sigmaLap%f, scale:%f (%f %f %f)\n", - k,s,sigmaLapFilter,sigmaLap,scale,a,b,c) ; - */ - if (*numScales < VL_COVDET_MAX_NUM_LAPLACIAN_SCALES) { - self->scales[*numScales].scale = scale * factor ; - self->scales[*numScales].score = b + 0.5 * (c - a) * dk ; - *numScales += 1 ; - } - } - } - return self->scales ; -} - -/** @brief Extract the Laplacian scales for the stored features - ** @param self object. - ** - ** Note that, since more than one orientation can be detected - ** for each feature, this function may create copies of them, - ** one for each orientation. - **/ -void -vl_covdet_extract_laplacian_scales (VlCovDet * self) -{ - vl_index i, j ; - vl_bool dropFeaturesWithoutScale = VL_TRUE ; - vl_size numFeatures = vl_covdet_get_num_features(self) ; - memset(self->numFeaturesWithNumScales, 0, - sizeof(self->numFeaturesWithNumScales)) ; - - for (i = 0 ; i < (signed)numFeatures ; ++i) { - vl_size numScales ; - VlCovDetFeature feature = self->features[i] ; - VlCovDetFeatureLaplacianScale const * scales = - vl_covdet_extract_laplacian_scales_for_frame(self, &numScales, feature.frame) ; - - self->numFeaturesWithNumScales[numScales] ++ ; - - if (numScales == 0 && dropFeaturesWithoutScale) { - self->features[i].peakScore = 0 ; - } - - for (j = 0 ; j < (signed)numScales ; ++j) { - VlCovDetFeature * scaled ; - - if (j == 0) { - scaled = & self->features[i] ; - } else { - vl_covdet_append_feature(self, &feature) ; - scaled = & self->features[self->numFeatures -1] ; - } - - scaled->laplacianScaleScore = scales[j].score ; - scaled->frame.a11 *= scales[j].scale ; - scaled->frame.a21 *= scales[j].scale ; - scaled->frame.a12 *= scales[j].scale ; - scaled->frame.a22 *= scales[j].scale ; - } - } - if (dropFeaturesWithoutScale) { - j = 0 ; - for (i = 0 ; i < (signed)self->numFeatures ; ++i) { - VlCovDetFeature feature = self->features[i] ; - if (feature.peakScore) { - self->features[j++] = feature ; - } - } - self->numFeatures = j ; - } - -} - -/* ---------------------------------------------------------------- */ -/* Checking that features are inside an image */ -/* ---------------------------------------------------------------- */ - -vl_bool -_vl_covdet_check_frame_inside (VlCovDet * self, VlFrameOrientedEllipse frame, double margin) -{ - double extent = margin ; - double A [2*2] = {frame.a11, frame.a21, frame.a12, frame.a22} ; - double T[2] = {frame.x, frame.y} ; - double x0 = +VL_INFINITY_D ; - double x1 = -VL_INFINITY_D ; - double y0 = +VL_INFINITY_D ; - double y1 = -VL_INFINITY_D ; - double boxx [4] = {extent, extent, -extent, -extent} ; - double boxy [4] = {-extent, extent, extent, -extent} ; - VlScaleSpaceGeometry geom = vl_scalespace_get_geometry(self->gss) ; - int i ; - for (i = 0 ; i < 4 ; ++i) { - double x = A[0] * boxx[i] + A[2] * boxy[i] + T[0] ; - double y = A[1] * boxx[i] + A[3] * boxy[i] + T[1] ; - x0 = VL_MIN(x0, x) ; - x1 = VL_MAX(x1, x) ; - y0 = VL_MIN(y0, y) ; - y1 = VL_MAX(y1, y) ; - } - - return - 0 <= x0 && x1 <= geom.width-1 && - 0 <= y0 && y1 <= geom.height-1 ; -} - -/** @brief Drop features (partially) outside the image - ** @param self object. - ** @param margin geometric marging. - ** - ** The feature extent is defined by @c maring. A bounding box - ** in the normalised feature frame containin a circle of radius - ** @a maring is created and mapped to the image by - ** the feature frame transformation. Then the feature - ** is dropped if the bounding box is not contained in the image. - ** - ** For example, setting @c margin to zero drops a feature only - ** if its center is not contained. - ** - ** Typically a valua of @c margin equal to 1 or 2 is used. - **/ - -void -vl_covdet_drop_features_outside (VlCovDet * self, double margin) -{ - vl_index i, j = 0 ; - vl_size numFeatures = vl_covdet_get_num_features(self) ; - for (i = 0 ; i < (signed)numFeatures ; ++i) { - vl_bool inside = - _vl_covdet_check_frame_inside (self, self->features[i].frame, margin) ; - if (inside) { - self->features[j] = self->features[i] ; - ++j ; - } - } - self->numFeatures = j ; -} - -/* ---------------------------------------------------------------- */ -/* Setters and getters */ -/* ---------------------------------------------------------------- */ - -/* ---------------------------------------------------------------- */ -/** @brief Get wether images are passed in transposed - ** @param self object. - ** @return whether images are transposed. - **/ -vl_bool -vl_covdet_get_transposed (VlCovDet const * self) -{ - return self->transposed ; -} - -/** @brief Set the index of the first octave - ** @param self object. - ** @param t whether images are transposed. - **/ -void -vl_covdet_set_transposed (VlCovDet * self, vl_bool t) -{ - self->transposed = t ; -} - -/* ---------------------------------------------------------------- */ -/** @brief Get the edge threshold - ** @param self object. - ** @return the edge threshold. - **/ -double -vl_covdet_get_edge_threshold (VlCovDet const * self) -{ - return self->edgeThreshold ; -} - -/** @brief Set the edge threshold - ** @param self object. - ** @param edgeThreshold the edge threshold. - ** - ** The edge threshold must be non-negative. - **/ -void -vl_covdet_set_edge_threshold (VlCovDet * self, double edgeThreshold) -{ - assert(edgeThreshold >= 0) ; - self->edgeThreshold = edgeThreshold ; -} - -/* ---------------------------------------------------------------- */ -/** @brief Get the peak threshold - ** @param self object. - ** @return the peak threshold. - **/ -double -vl_covdet_get_peak_threshold (VlCovDet const * self) -{ - return self->peakThreshold ; -} - -/** @brief Set the peak threshold - ** @param self object. - ** @param peakThreshold the peak threshold. - ** - ** The peak threshold must be non-negative. - **/ -void -vl_covdet_set_peak_threshold (VlCovDet * self, double peakThreshold) -{ - assert(peakThreshold >= 0) ; - self->peakThreshold = peakThreshold ; -} - -/* ---------------------------------------------------------------- */ -/** @brief Get the Laplacian peak threshold - ** @param self object. - ** @return the Laplacian peak threshold. - ** - ** This parameter affects only the detecors using the Laplacian - ** scale selectino method such as Harris-Laplace. - **/ -double -vl_covdet_get_laplacian_peak_threshold (VlCovDet const * self) -{ - return self->lapPeakThreshold ; -} - -/** @brief Set the Laplacian peak threshold - ** @param self object. - ** @param peakThreshold the Laplacian peak threshold. - ** - ** The peak threshold must be non-negative. - **/ -void -vl_covdet_set_laplacian_peak_threshold (VlCovDet * self, double peakThreshold) -{ - assert(peakThreshold >= 0) ; - self->lapPeakThreshold = peakThreshold ; -} - -/* ---------------------------------------------------------------- */ -/** @brief Get the index of the first octave - ** @param self object. - ** @return index of the first octave. - **/ -vl_index -vl_covdet_get_first_octave (VlCovDet const * self) -{ - return self->firstOctave ; -} - -/** @brief Set the index of the first octave - ** @param self object. - ** @param o index of the first octave. - ** - ** Calling this function resets the detector. - **/ -void -vl_covdet_set_first_octave (VlCovDet * self, vl_index o) -{ - self->firstOctave = o ; - vl_covdet_reset(self) ; -} - -/* ---------------------------------------------------------------- */ -/** @brief Get the octave resolution. - ** @param self object. - ** @return octave resolution. - **/ - -vl_size -vl_covdet_get_octave_resolution (VlCovDet const * self) -{ - return self->octaveResolution ; -} - -/** @brief Set the octave resolutuon. - ** @param self object. - ** @param r octave resoltuion. - ** - ** Calling this function resets the detector. - **/ - -void -vl_covdet_set_octave_resolution (VlCovDet * self, vl_size r) -{ - self->octaveResolution = r ; - vl_covdet_reset(self) ; -} - -/* ---------------------------------------------------------------- */ -/** @brief Get whether affine adaptation uses accurate smoothing. - ** @param self object. - ** @return @c true if accurate smoothing is used. - **/ - -vl_bool -vl_covdet_get_aa_accurate_smoothing (VlCovDet const * self) -{ - return self->aaAccurateSmoothing ; -} - -/** @brief Set whether affine adaptation uses accurate smoothing. - ** @param self object. - ** @param x whether accurate smoothing should be usd. - **/ - -void -vl_covdet_set_aa_accurate_smoothing (VlCovDet * self, vl_bool x) -{ - self->aaAccurateSmoothing = x ; -} - -/* ---------------------------------------------------------------- */ -/** @brief Get the non-extrema suppression threshold - ** @param self object. - ** @return threshold. - **/ - -double -vl_covdet_get_non_extrema_suppression_threshold (VlCovDet const * self) -{ - return self->nonExtremaSuppression ; -} - -/** @brief Set the non-extrema suppression threshod - ** @param self object. - ** @param x threshold. - **/ - -void -vl_covdet_set_non_extrema_suppression_threshold (VlCovDet * self, double x) -{ - self->nonExtremaSuppression = x ; -} - -/** @brief Get the number of non-extrema suppressed - ** @param self object. - ** @return number. - **/ - -vl_size -vl_covdet_get_num_non_extrema_suppressed (VlCovDet const * self) -{ - return self->numNonExtremaSuppressed ; -} - - -/* ---------------------------------------------------------------- */ -/** @brief Get number of stored frames - ** @return number of frames stored in the detector. - **/ -vl_size -vl_covdet_get_num_features (VlCovDet const * self) -{ - return self->numFeatures ; -} - -/** @brief Get the stored frames - ** @return frames stored in the detector. - **/ -VlCovDetFeature * -vl_covdet_get_features (VlCovDet * self) -{ - return self->features ; -} - -/** @brief Get the Gaussian scale space - ** @return Gaussian scale space. - ** - ** A Gaussian scale space exists only after calling ::vl_covdet_put_image. - ** Otherwise the function returns @c NULL. - **/ - -VlScaleSpace * -vl_covdet_get_gss (VlCovDet const * self) -{ - return self->gss ; -} - -/** @brief Get the cornerness measure scale space - ** @return cornerness measure scale space. - ** - ** A cornerness measure scale space exists only after calling - ** ::vl_covdet_detect. Otherwise the function returns @c NULL. - **/ - -VlScaleSpace * -vl_covdet_get_css (VlCovDet const * self) -{ - return self->css ; -} - -/** @brief Get the number of features found with a certain number of scales - ** @param self object. - ** @param numScales length of the histogram (out). - ** @return histogram. - ** - ** Calling this function makes sense only after running a detector - ** that uses the Laplacian as a secondary measure for scale - ** detection - **/ - -vl_size const * -vl_covdet_get_laplacian_scales_statistics (VlCovDet const * self, - vl_size * numScales) -{ - *numScales = VL_COVDET_MAX_NUM_LAPLACIAN_SCALES ; - return self->numFeaturesWithNumScales ; -} diff --git a/opensfm/src/third_party/vlfeat/vl/covdet.h b/opensfm/src/third_party/vlfeat/vl/covdet.h deleted file mode 100644 index c0fdabb72..000000000 --- a/opensfm/src/third_party/vlfeat/vl/covdet.h +++ /dev/null @@ -1,263 +0,0 @@ -/** @file covdet.h - ** @brief Covariant feature detectors (@ref covdet) - ** @author Karel Lenc - ** @author Andrea Vedaldi - ** @author Michal Perdoch - **/ - -/* -Copyright (C) 2013-14 Andrea Vedaldi. -Copyright (C) 2012 Karel Lenc, Andrea Vedaldi and Michal Perdoch. -All rights reserved. - -This file is part of the VLFeat library and is made available under -the terms of the BSD license (see the COPYING file). -*/ - -#ifndef VL_COVDET_H -#define VL_COVDET_H - -#include "generic.h" -#include "stringop.h" -#include "scalespace.h" - -#include - -/* ---------------------------------------------------------------- */ -/* Feature Frames */ -/* ---------------------------------------------------------------- */ - -/** @name Feature frames - ** @{ */ - -/** @brief Types of feature frames */ -typedef enum _VlFrameType { - VL_FRAMETYPE_DISC = 1, /**< A disc. */ - VL_FRAMETYPE_ORIENTED_DISC, /**< An oriented disc. */ - VL_FRAMETYPE_ELLIPSE, /**< An ellipse. */ - VL_FRAMETYPE_ORIENTED_ELLIPSE, /**< An oriented ellipse. */ - VL_FRAMETYPE_NUM -} VlFrameType ; - -/** @brief Names of the frame types */ -VL_EXPORT const char* vlFrameNames [VL_FRAMETYPE_NUM] ; - -/** @brief Mapping between string values and VlFrameType values */ -VL_EXPORT VlEnumerator vlFrameTypes [VL_FRAMETYPE_NUM] ; - -/** @brief Disc feature frame */ -typedef struct _VlFrameDisc -{ - float x ; /**< center x-coordinate */ - float y ; /**< center y-coordinate */ - float sigma ; /**< radius or scale */ -} VlFrameDisc ; - -/** @brief Oriented disc feature frame - ** An upright frame has @c angle equal to zero. - **/ -typedef struct _VlFrameOrientedDisc { - float x ; /**< center x-coordinate */ - float y ; /**< center y-coordinate */ - float sigma ; /**< radius or scale */ - float angle ; /**< rotation angle (rad) */ -} VlFrameOrientedDisc ; - -/** @brief Ellipse feature frame */ -typedef struct _VlFrameEllipse { - float x ; /**< center x-coordinate */ - float y ; /**< center y-coordinate */ - float e11 ; /**< */ - float e12 ; - float e22 ; -} VlFrameEllipse ; - -/** @brief Oriented ellipse feature frame - ** The affine transformation transforms the ellipse shape into - ** a circular region. */ -typedef struct _VlFrameOrientedEllipse { - float x ; /**< center x-coordinate */ - float y ; /**< center y-coordinate */ - float a11 ; /**< */ - float a12 ; - float a21 ; - float a22 ; -} VlFrameOrientedEllipse; - -/** @brief Get the size of a frame structure - ** @param frameType identifier of the type of frame. - ** @return size of the corresponding frame structure in bytes. - **/ -VL_INLINE vl_size -vl_get_frame_size (VlFrameType frameType) { - switch (frameType) { - case VL_FRAMETYPE_DISC: return sizeof(VlFrameDisc); - case VL_FRAMETYPE_ORIENTED_DISC: return sizeof(VlFrameOrientedDisc); - case VL_FRAMETYPE_ELLIPSE: return sizeof(VlFrameEllipse); - case VL_FRAMETYPE_ORIENTED_ELLIPSE: return sizeof(VlFrameOrientedEllipse); - default: - assert(0); - break; - } - return 0; -} - -/** @brief Get the size of a frame structure - ** @param affineAdaptation whether the detector use affine adaptation. - ** @param orientation whether the detector estimates the feature orientation. - ** @return the type of extracted frame. - ** - ** Depedning on whether the detector estimate the affine shape - ** and orientation of a feature, different frame types - ** are extracted. */ - -VL_INLINE VlFrameType -vl_get_frame_type (vl_bool affineAdaptation, vl_bool orientation) -{ - if (affineAdaptation) { - if (orientation) { - return VL_FRAMETYPE_ORIENTED_ELLIPSE; - } else { - return VL_FRAMETYPE_ELLIPSE; - } - } else { - if (orientation) { - return VL_FRAMETYPE_ORIENTED_DISC; - } else { - return VL_FRAMETYPE_DISC; - } - } -} - -/* ---------------------------------------------------------------- */ -/* Covariant Feature Detector */ -/* ---------------------------------------------------------------- */ - -/** @brief A detected feature shape and location */ -typedef struct _VlCovDetFeature -{ - VlFrameOrientedEllipse frame ; /**< feature frame. */ - int o ; /**< Detected octave. */ - int s ; /**< Octave subdivision. */ - float peakScore ; /**< peak score. */ - float edgeScore ; /**< edge score. */ - float orientationScore ; /**< orientation score. */ - float laplacianScaleScore ; /**< Laplacian scale score. */ -} VlCovDetFeature ; - -/** @brief A detected feature orientation */ -typedef struct _VlCovDetFeatureOrientation -{ - double angle ; - double score ; -} VlCovDetFeatureOrientation ; - -/** @brief A detected feature Laplacian scale */ -typedef struct _VlCovDetFeatureLaplacianScale -{ - double scale ; - double score ; -} VlCovDetFeatureLaplacianScale ; - -/** @brief Covariant feature detection method */ -typedef enum _VlCovDetMethod -{ - VL_COVDET_METHOD_DOG = 1, - VL_COVDET_METHOD_HESSIAN, - VL_COVDET_METHOD_HESSIAN_LAPLACE, - VL_COVDET_METHOD_HARRIS_LAPLACE, - VL_COVDET_METHOD_MULTISCALE_HESSIAN, - VL_COVDET_METHOD_MULTISCALE_HARRIS, - VL_COVDET_METHOD_NUM -} VlCovDetMethod; - -/** @brief Mapping between strings and ::VlCovDetMethod values */ -VL_EXPORT VlEnumerator vlCovdetMethods [VL_COVDET_METHOD_NUM] ; - -#ifdef __DOXYGEN__ -/** @brief Covariant feature detector - ** @see @ref covdet */ -struct _VlCovDet { } -#endif - -/** @brief Covariant feature detector - ** @see @ref covdet */ -typedef struct _VlCovDet VlCovDet ; - -/** @name Create and destroy - ** @{ */ -VL_EXPORT VlCovDet * vl_covdet_new (VlCovDetMethod method) ; -VL_EXPORT void vl_covdet_delete (VlCovDet * self) ; -VL_EXPORT void vl_covdet_reset (VlCovDet * self) ; -/** @} */ - -/** @name Process data - ** @{ */ -VL_EXPORT int vl_covdet_put_image (VlCovDet * self, - float const * image, - vl_size width, vl_size height) ; - -VL_EXPORT void vl_covdet_detect (VlCovDet * self, vl_size max_num_features) ; -VL_EXPORT int vl_covdet_append_feature (VlCovDet * self, VlCovDetFeature const * feature) ; -VL_EXPORT void vl_covdet_extract_orientations (VlCovDet * self) ; -VL_EXPORT void vl_covdet_extract_laplacian_scales (VlCovDet * self) ; -VL_EXPORT void vl_covdet_extract_affine_shape (VlCovDet * self) ; - -VL_EXPORT VlCovDetFeatureOrientation * -vl_covdet_extract_orientations_for_frame (VlCovDet * self, - vl_size *numOrientations, - VlFrameOrientedEllipse frame) ; - -VL_EXPORT VlCovDetFeatureLaplacianScale * -vl_covdet_extract_laplacian_scales_for_frame (VlCovDet * self, - vl_size * numScales, - VlFrameOrientedEllipse frame) ; -VL_EXPORT int -vl_covdet_extract_affine_shape_for_frame (VlCovDet * self, - VlFrameOrientedEllipse * adapted, - VlFrameOrientedEllipse frame) ; - -VL_EXPORT vl_bool -vl_covdet_extract_patch_for_frame (VlCovDet * self, float * patch, - vl_size resolution, - double extent, - double sigma, - VlFrameOrientedEllipse frame) ; - -VL_EXPORT void -vl_covdet_drop_features_outside (VlCovDet * self, double margin) ; -/** @} */ - -/** @name Retrieve data and parameters - ** @{ */ -VL_EXPORT vl_size vl_covdet_get_num_features (VlCovDet const * self) ; -VL_EXPORT VlCovDetFeature * vl_covdet_get_features (VlCovDet * self) ; -VL_EXPORT vl_index vl_covdet_get_first_octave (VlCovDet const * self) ; -VL_EXPORT vl_size vl_covdet_get_octave_resolution (VlCovDet const * self) ; -VL_EXPORT double vl_covdet_get_peak_threshold (VlCovDet const * self) ; -VL_EXPORT double vl_covdet_get_edge_threshold (VlCovDet const * self) ; -VL_EXPORT double vl_covdeg_get_laplacian_peak_threshold (VlCovDet const * self) ; -VL_EXPORT vl_bool vl_covdet_get_transposed (VlCovDet const * self) ; -VL_EXPORT VlScaleSpace * vl_covdet_get_gss (VlCovDet const * self) ; -VL_EXPORT VlScaleSpace * vl_covdet_get_css (VlCovDet const * self) ; -VL_EXPORT vl_bool vl_covdet_get_aa_accurate_smoothing (VlCovDet const * self) ; -VL_EXPORT vl_size const * vl_covdet_get_laplacian_scales_statistics (VlCovDet const * self, vl_size * numScales) ; -VL_EXPORT double vl_covdet_get_non_extrema_suppression_threshold (VlCovDet const * self) ; -VL_EXPORT vl_size vl_covdet_get_num_non_extrema_suppressed (VlCovDet const * self) ; - -/** @} */ - -/** @name Set parameters - ** @{ */ -VL_EXPORT void vl_covdet_set_first_octave (VlCovDet * self, vl_index o) ; -VL_EXPORT void vl_covdet_set_octave_resolution (VlCovDet * self, vl_size r) ; -VL_EXPORT void vl_covdet_set_peak_threshold (VlCovDet * self, double peakThreshold) ; -VL_EXPORT void vl_covdet_set_edge_threshold (VlCovDet * self, double edgeThreshold) ; -VL_EXPORT void vl_covdet_set_laplacian_peak_threshold (VlCovDet * self, double peakThreshold) ; -VL_EXPORT void vl_covdet_set_transposed (VlCovDet * self, vl_bool t) ; -VL_EXPORT void vl_covdet_set_aa_accurate_smoothing (VlCovDet * self, vl_bool x) ; -VL_EXPORT void vl_covdet_set_non_extrema_suppression_threshold (VlCovDet * self, double x) ; -/** @} */ - -/* VL_COVDET_H */ -#endif diff --git a/opensfm/src/third_party/vlfeat/vl/dsift.c b/opensfm/src/third_party/vlfeat/vl/dsift.c deleted file mode 100644 index b76c6184d..000000000 --- a/opensfm/src/third_party/vlfeat/vl/dsift.c +++ /dev/null @@ -1,775 +0,0 @@ -/** @file dsift.c - ** @brief Dense SIFT - Definition - ** @author Andrea Vedaldi - ** @author Brian Fulkerson - **/ - -/* -Copyright (C) 2007-12 Andrea Vedaldi and Brian Fulkerson. -All rights reserved. - -This file is part of the VLFeat library and is made available under -the terms of the BSD license (see the COPYING file). -*/ - -#include "dsift.h" -#include "pgm.h" -#include "mathop.h" -#include "imopv.h" -#include -#include - -/** - -@page dsift Dense Scale Invariant Feature Transform (DSIFT) -@author Andrea Vedaldi -@author Brian Fulkerson -@tableofcontents - - -@ref dsift.h implements a dense version of @ref sift.h "SIFT". This is -an object that can quickly compute descriptors for densely sampled -keypoints with identical size and orientation. It can be reused for -multiple images of the same size. - - -@section dsift-intro Overview - - -@sa @ref sift "The SIFT module", @ref dsift-tech "Technical details" - -This module implements a fast algorithm for the calculation of a large -number of SIFT descriptors of densely sampled features of the same -scale and orientation. See the @ref sift "SIFT module" for an -overview of SIFT. - -The feature frames (keypoints) are indirectly specified by the -sampling steps (::vl_dsift_set_steps) and the sampling bounds -(::vl_dsift_set_bounds). The descriptor geometry (number and size of -the spatial bins and number of orientation bins) can be customized -(::vl_dsift_set_geometry, ::VlDsiftDescriptorGeometry). - -@image html dsift-geom.png "Dense SIFT descriptor geometry" - -By default, SIFT uses a Gaussian windowing function that discounts -contributions of gradients further away from the descriptor -centers. This function can be changed to a flat window by invoking -::vl_dsift_set_flat_window. In this case, gradients are accumulated -using only bilinear interpolation, but instad of being reweighted by a -Gassuain window, they are all weighted equally. However, after -gradients have been accumulated into a spatial bin, the whole bin is -reweighted by the average of the Gaussian window over the spatial -support of that bin. This “approximation” substantially -improves speed with little or no loss of performance in applications. - -Keypoints are sampled in such a way that the centers of the spatial -bins are at integer coordinates within the image boundaries. For -instance, the top-left bin of the top-left descriptor is centered on -the pixel (0,0). The bin immediately to the right at -(binSizeX,0), where binSizeX is a paramtere -in the ::VlDsiftDescriptorGeometry structure. ::vl_dsift_set_bounds -can be used to further restrict sampling to the keypoints in an image. - - - @section dsift-usage Usage - - -DSIFT is implemented by a ::VlDsiftFilter object that can be used -to process a sequence of images of a given geometry. -To use the DSIFT filter: - -- Initialize a new DSIFT filter object by ::vl_dsift_new (or the simplified -::vl_dsift_new_basic). Customize the descriptor parameters by -::vl_dsift_set_steps, ::vl_dsift_set_geometry, etc. -- Process an image by ::vl_dsift_process. -- Retrieve the number of keypoints (::vl_dsift_get_keypoint_num), the - keypoints (::vl_dsift_get_keypoints), and their descriptors - (::vl_dsift_get_descriptors). -- Optionally repeat for more images. -- Delete the DSIFT filter by ::vl_dsift_delete. - - -@section dsift-tech Technical details - - -This section extends the @ref sift-tech-descriptor "SIFT descriptor section" -and specialzies it to the case of dense keypoints. - - -@subsection dsift-tech-descriptor-dense Dense descriptors - - -When computing descriptors for many keypoints differing only by their -position (and with null rotation), further simplifications are -possible. In this case, in fact, - -@f{eqnarray*} - \mathbf{x} &=& m \sigma \hat{\mathbf{x}} + T,\\ - h(t,i,j) - &=& - m \sigma \int - g_{\sigma_\mathrm{win}}(\mathbf{x} - T)\, - w_\mathrm{ang}(\angle J(\mathbf{x}) - \theta_t)\, - w\left(\frac{x - T_x}{m\sigma} - \hat{x}_i\right)\, - w\left(\frac{y - T_y}{m\sigma} - \hat{y}_j\right)\, - |J(\mathbf{x})|\, - d\mathbf{x}. -@f} - -Since many different values of @e T are sampled, this is conveniently -expressed as a separable convolution. First, we translate by @f$ -\mathbf{x}_{ij} = m\sigma(\hat x_i,\ \hat y_i)^\top @f$ and we use the -symmetry of the various binning and windowing functions to write - -@f{eqnarray*} - h(t,i,j) - &=& - m \sigma \int - g_{\sigma_\mathrm{win}}(T' - \mathbf{x} - \mathbf{x}_{ij})\, - w_\mathrm{ang}(\angle J(\mathbf{x}) - \theta_t)\, - w\left(\frac{T'_x - x}{m\sigma}\right)\, - w\left(\frac{T'_y - y}{m\sigma}\right)\, - |J(\mathbf{x})|\, - d\mathbf{x}, -\\ -T' &=& T + m\sigma -\left[\begin{array}{cc} x_i \\ y_j \end{array}\right]. -@f} - -Then we define kernels - -@f{eqnarray*} - k_i(x) &=& - \frac{1}{\sqrt{2\pi} \sigma_{\mathrm{win}}} - \exp\left( - -\frac{1}{2} - \frac{(x-x_i)^2}{\sigma_{\mathrm{win}}^2} - \right) - w\left(\frac{x}{m\sigma}\right), - \\ - k_j(y) &=& - \frac{1}{\sqrt{2\pi} \sigma_{\mathrm{win}}} - \exp\left( - -\frac{1}{2} - \frac{(y-y_j)^2}{\sigma_{\mathrm{win}}^2} - \right) - w\left(\frac{y}{m\sigma}\right), -@f} - -and obtain - -@f{eqnarray*} - h(t,i,j) &=& (k_ik_j * \bar J_t)\left( T + m\sigma -\left[\begin{array}{cc} x_i \\ y_j \end{array}\right] \right), -\\ -\bar J_t(\mathbf{x}) &=& w_\mathrm{ang}(\angle J(\mathbf{x}) - \theta_t)\,|J(\mathbf{x})|. -@f} - -Furthermore, if we use a flat rather than Gaussian windowing function, -the kernels do not depend on the bin, and we have - -@f{eqnarray*} - k(z) &=& - \frac{1}{\sigma_{\mathrm{win}}} - w\left(\frac{z}{m\sigma}\right), -\\ - h(t,i,j) &=& (k(x)k(y) * \bar J_t)\left( T + m\sigma -\left[\begin{array}{cc} x_i \\ y_j \end{array}\right] \right), -@f} - -(here @f$ \sigma_\mathrm{win} @f$ is the side of the flat window). - -@note In this case the binning functions @f$ k(z) @f$ are triangular -and the convolution can be computed in time independent on the filter -(i.e. descriptor bin) support size by integral signals. - - -@subsection dsift-tech-sampling Sampling - - -To avoid resampling and dealing with special boundary conditions, we -impose some mild restrictions on the geometry of the descriptors that -can be computed. In particular, we impose that the bin centers @f$ T + -m\sigma (x_i,\ y_j) @f$ are always at integer coordinates within the -image boundaries. This eliminates the need for costly interpolation. -This condition amounts to (expressed in terms of the @e x coordinate, -and equally applicable to @e y) - -@f[ - \{0,\dots, W-1\} \ni T_x + m\sigma x_i = - T_x + m\sigma i - \frac{N_x-1}{2} - = \bar T_x + m\sigma i, - \qquad i = 0,\dots,N_x-1. -@f] - -Notice that for this condition to be satisfied, the @em descriptor -center @f$ T_x @f$ needs to be either fractional or integer depending -on @f$ N_x @f$ being even or odd. To eliminate this complication, -it is simpler to use as a reference not the descriptor center @e T, -but the coordinates of the upper-left bin @f$ \bar T @f$. Thus we -sample the latter on a regular (integer) grid - -@f[ - \left[\begin{array}{cc} - 0 \\ - 0 - \end{array}\right] - \leq - \bar T = - \left[\begin{array}{cc} - \bar T_x^{\min} + p \Delta_x \\ - \bar T_y^{\min} + q \Delta_y \\ - \end{array}\right] - \leq - \left[\begin{array}{cc} - W - 1 - m\sigma N_x \\ - H - 1 - m\sigma N_y - \end{array}\right], - \quad - \bar T = - \left[\begin{array}{cc} - T_x - \frac{N_x - 1}{2} \\ - T_y - \frac{N_y - 1}{2} \\ - \end{array}\right] -@f] - -and we impose that the bin size @f$ m \sigma @f$ is integer as well. - -**/ - -/** ------------------------------------------------------------------ - ** @internal @brief Initialize new convolution kernel - ** @param binSize - ** @param numBins - ** @param binIndex negative to use flat window. - ** @param windowSize - ** @return a pointer to new filter. - **/ - -float * -_vl_dsift_new_kernel (int binSize, int numBins, int binIndex, double windowSize) -{ - int filtLen = 2 * binSize - 1 ; - float * ker = vl_malloc (sizeof(float) * filtLen) ; - float * kerIter = ker ; - float delta = binSize * (binIndex - 0.5F * (numBins - 1)) ; - /* - float sigma = 0.5F * ((numBins - 1) * binSize + 1) ; - float sigma = 0.5F * ((numBins) * binSize) ; - */ - float sigma = (float) binSize * (float) windowSize ; - int x ; - - for (x = - binSize + 1 ; x <= + binSize - 1 ; ++ x) { - float z = (x - delta) / sigma ; - *kerIter++ = (1.0F - fabsf(x) / binSize) * - ((binIndex >= 0) ? expf(- 0.5F * z*z) : 1.0F) ; - } - return ker ; -} - -static float -_vl_dsift_get_bin_window_mean -(int binSize, int numBins, int binIndex, double windowSize) -{ - float delta = binSize * (binIndex - 0.5F * (numBins - 1)) ; - /*float sigma = 0.5F * ((numBins - 1) * binSize + 1) ;*/ - float sigma = (float) binSize * (float) windowSize ; - int x ; - - float acc = 0.0 ; - for (x = - binSize + 1 ; x <= + binSize - 1 ; ++ x) { - float z = (x - delta) / sigma ; - acc += ((binIndex >= 0) ? expf(- 0.5F * z*z) : 1.0F) ; - } - return acc /= (2 * binSize - 1) ; -} - -/** ------------------------------------------------------------------ - ** @internal @brief Normalize histogram - ** @param begin first element of the histogram. - ** @param end last plus one element of the histogram. - ** - ** The function divides the specified histogram by its l2 norm. - **/ - -VL_INLINE float -_vl_dsift_normalize_histogram (float * begin, float * end) -{ - float * iter ; - float norm = 0.0F ; - - for (iter = begin ; iter < end ; ++ iter) { - norm += (*iter) * (*iter) ; - } - norm = vl_fast_sqrt_f (norm) + VL_EPSILON_F ; - - for (iter = begin; iter < end ; ++ iter) { - *iter /= norm ; - } - return norm ; -} - -/** ------------------------------------------------------------------ - ** @internal @brief Free internal buffers - ** @param self DSIFT filter. - **/ - -static void -_vl_dsift_free_buffers (VlDsiftFilter* self) -{ - if (self->frames) { - vl_free(self->frames) ; - self->frames = NULL ; - } - if (self->descrs) { - vl_free(self->descrs) ; - self->descrs = NULL ; - } - if (self->grads) { - int t ; - for (t = 0 ; t < self->numGradAlloc ; ++t) - if (self->grads[t]) vl_free(self->grads[t]) ; - vl_free(self->grads) ; - self->grads = NULL ; - } - self->numFrameAlloc = 0 ; - self->numBinAlloc = 0 ; - self->numGradAlloc = 0 ; -} - -/** ------------------------------------------------------------------ - ** @internal @brief Updates internal buffers to current geometry - **/ - -VL_EXPORT void -_vl_dsift_update_buffers (VlDsiftFilter * self) -{ - int x1 = self->boundMinX ; - int x2 = self->boundMaxX ; - int y1 = self->boundMinY ; - int y2 = self->boundMaxY ; - - int rangeX = x2 - x1 - (self->geom.numBinX - 1) * self->geom.binSizeX ; - int rangeY = y2 - y1 - (self->geom.numBinY - 1) * self->geom.binSizeY ; - - int numFramesX = (rangeX >= 0) ? rangeX / self->stepX + 1 : 0 ; - int numFramesY = (rangeY >= 0) ? rangeY / self->stepY + 1 : 0 ; - - self->numFrames = numFramesX * numFramesY ; - self->descrSize = self->geom.numBinT * - self->geom.numBinX * - self->geom.numBinY ; -} - -/** ------------------------------------------------------------------ - ** @internal @brief Allocate internal buffers - ** @param self DSIFT filter. - ** - ** The function (re)allocates the internal buffers in accordance with - ** the current image and descriptor geometry. - **/ - -static void -_vl_dsift_alloc_buffers (VlDsiftFilter* self) -{ - _vl_dsift_update_buffers (self) ; - { - int numFrameAlloc = vl_dsift_get_keypoint_num (self) ; - int numBinAlloc = vl_dsift_get_descriptor_size (self) ; - int numGradAlloc = self->geom.numBinT ; - - /* see if we need to update the buffers */ - if (numBinAlloc != self->numBinAlloc || - numGradAlloc != self->numGradAlloc || - numFrameAlloc != self->numFrameAlloc) { - - int t ; - - _vl_dsift_free_buffers(self) ; - - self->frames = vl_malloc(sizeof(VlDsiftKeypoint) * numFrameAlloc) ; - self->descrs = vl_malloc(sizeof(float) * numBinAlloc * numFrameAlloc) ; - self->grads = vl_malloc(sizeof(float*) * numGradAlloc) ; - for (t = 0 ; t < numGradAlloc ; ++t) { - self->grads[t] = - vl_malloc(sizeof(float) * self->imWidth * self->imHeight) ; - } - self->numBinAlloc = numBinAlloc ; - self->numGradAlloc = numGradAlloc ; - self->numFrameAlloc = numFrameAlloc ; - } - } -} - -/** ------------------------------------------------------------------ - ** @brief Create a new DSIFT filter - ** - ** @param imWidth width of the image. - ** @param imHeight height of the image - ** - ** @return new filter. - **/ - -VL_EXPORT VlDsiftFilter * -vl_dsift_new (int imWidth, int imHeight) -{ - VlDsiftFilter * self = vl_malloc (sizeof(VlDsiftFilter)) ; - self->imWidth = imWidth ; - self->imHeight = imHeight ; - - self->stepX = 5 ; - self->stepY = 5 ; - - self->boundMinX = 0 ; - self->boundMinY = 0 ; - self->boundMaxX = imWidth - 1 ; - self->boundMaxY = imHeight - 1 ; - - self->geom.numBinX = 4 ; - self->geom.numBinY = 4 ; - self->geom.numBinT = 8 ; - self->geom.binSizeX = 5 ; - self->geom.binSizeY = 5 ; - - self->useFlatWindow = VL_FALSE ; - self->windowSize = 2.0 ; - - self->convTmp1 = vl_malloc(sizeof(float) * self->imWidth * self->imHeight) ; - self->convTmp2 = vl_malloc(sizeof(float) * self->imWidth * self->imHeight) ; - - self->numBinAlloc = 0 ; - self->numFrameAlloc = 0 ; - self->numGradAlloc = 0 ; - - self->descrSize = 0 ; - self->numFrames = 0 ; - self->grads = NULL ; - self->frames = NULL ; - self->descrs = NULL ; - - _vl_dsift_update_buffers(self) ; - return self ; -} - -/** ------------------------------------------------------------------ - ** @brief Create a new DSIFT filter (basic interface) - ** @param imWidth width of the image. - ** @param imHeight height of the image. - ** @param step sampling step. - ** @param binSize bin size. - ** @return new filter. - ** - ** The descriptor geometry matches the standard SIFT descriptor. - **/ - -VL_EXPORT VlDsiftFilter * -vl_dsift_new_basic (int imWidth, int imHeight, int step, int binSize) -{ - VlDsiftFilter* self = vl_dsift_new(imWidth, imHeight) ; - VlDsiftDescriptorGeometry geom = *vl_dsift_get_geometry(self) ; - geom.binSizeX = binSize ; - geom.binSizeY = binSize ; - vl_dsift_set_geometry(self, &geom) ; - vl_dsift_set_steps(self, step, step) ; - return self ; -} - -/** ------------------------------------------------------------------ - ** @brief Delete DSIFT filter - ** @param self DSIFT filter. - **/ - -VL_EXPORT void -vl_dsift_delete (VlDsiftFilter * self) -{ - _vl_dsift_free_buffers (self) ; - if (self->convTmp2) vl_free (self->convTmp2) ; - if (self->convTmp1) vl_free (self->convTmp1) ; - vl_free (self) ; -} - - -/** ------------------------------------------------------------------ - ** @internal @brief Process with Gaussian window - ** @param self DSIFT filter. - **/ - -VL_INLINE void -_vl_dsift_with_gaussian_window (VlDsiftFilter * self) -{ - int binx, biny, bint ; - int framex, framey ; - float *xker, *yker ; - - int Wx = self->geom.binSizeX - 1 ; - int Wy = self->geom.binSizeY - 1 ; - - for (biny = 0 ; biny < self->geom.numBinY ; ++biny) { - - yker = _vl_dsift_new_kernel (self->geom.binSizeY, - self->geom.numBinY, - biny, - self->windowSize) ; - - for (binx = 0 ; binx < self->geom.numBinX ; ++binx) { - - xker = _vl_dsift_new_kernel(self->geom.binSizeX, - self->geom.numBinX, - binx, - self->windowSize) ; - - for (bint = 0 ; bint < self->geom.numBinT ; ++bint) { - - vl_imconvcol_vf (self->convTmp1, self->imHeight, - self->grads[bint], self->imWidth, self->imHeight, - self->imWidth, - yker, -Wy, +Wy, 1, - VL_PAD_BY_CONTINUITY|VL_TRANSPOSE) ; - - vl_imconvcol_vf (self->convTmp2, self->imWidth, - self->convTmp1, self->imHeight, self->imWidth, - self->imHeight, - xker, -Wx, +Wx, 1, - VL_PAD_BY_CONTINUITY|VL_TRANSPOSE) ; - - { - float *dst = self->descrs - + bint - + binx * self->geom.numBinT - + biny * (self->geom.numBinX * self->geom.numBinT) ; - - float *src = self->convTmp2 ; - - int frameSizeX = self->geom.binSizeX * (self->geom.numBinX - 1) + 1 ; - int frameSizeY = self->geom.binSizeY * (self->geom.numBinY - 1) + 1 ; - int descrSize = vl_dsift_get_descriptor_size (self) ; - - for (framey = self->boundMinY ; - framey <= self->boundMaxY - frameSizeY + 1 ; - framey += self->stepY) { - for (framex = self->boundMinX ; - framex <= self->boundMaxX - frameSizeX + 1 ; - framex += self->stepX) { - *dst = src [(framex + binx * self->geom.binSizeX) * 1 + - (framey + biny * self->geom.binSizeY) * self->imWidth] ; - dst += descrSize ; - } /* framex */ - } /* framey */ - } - - } /* for bint */ - vl_free (xker) ; - } /* for binx */ - vl_free (yker) ; - } /* for biny */ -} - -/** ------------------------------------------------------------------ - ** @internal @brief Process with flat window. - ** @param self DSIFT filter object. - **/ - -VL_INLINE void -_vl_dsift_with_flat_window (VlDsiftFilter* self) -{ - int binx, biny, bint ; - int framex, framey ; - - /* for each orientation bin */ - for (bint = 0 ; bint < self->geom.numBinT ; ++bint) { - - vl_imconvcoltri_f (self->convTmp1, self->imHeight, - self->grads [bint], self->imWidth, self->imHeight, - self->imWidth, - self->geom.binSizeY, /* filt size */ - 1, /* subsampling step */ - VL_PAD_BY_CONTINUITY|VL_TRANSPOSE) ; - - vl_imconvcoltri_f (self->convTmp2, self->imWidth, - self->convTmp1, self->imHeight, self->imWidth, - self->imHeight, - self->geom.binSizeX, - 1, - VL_PAD_BY_CONTINUITY|VL_TRANSPOSE) ; - - for (biny = 0 ; biny < self->geom.numBinY ; ++biny) { - - /* - This fast version of DSIFT does not use a proper Gaussian - weighting scheme for the gradiens that are accumulated on the - spatial bins. Instead each spatial bins is accumulated based on - the triangular kernel only, equivalent to bilinear interpolation - plus a flat, rather than Gaussian, window. Eventually, however, - the magnitude of the spatial bins in the SIFT descriptor is - reweighted by the average of the Gaussian window on each bin. - */ - - float wy = _vl_dsift_get_bin_window_mean - (self->geom.binSizeY, self->geom.numBinY, biny, - self->windowSize) ; - - /* The convolution functions vl_imconvcoltri_* convolve by a - * triangular kernel with unit integral. Instead for SIFT the - * triangular kernel should have unit height. This is - * compensated for by multiplying by the bin size: - */ - - wy *= self->geom.binSizeY ; - - for (binx = 0 ; binx < self->geom.numBinX ; ++binx) { - float w ; - float wx = _vl_dsift_get_bin_window_mean (self->geom.binSizeX, - self->geom.numBinX, - binx, - self->windowSize) ; - - float *dst = self->descrs - + bint - + binx * self->geom.numBinT - + biny * (self->geom.numBinX * self->geom.numBinT) ; - - float *src = self->convTmp2 ; - - int frameSizeX = self->geom.binSizeX * (self->geom.numBinX - 1) + 1 ; - int frameSizeY = self->geom.binSizeY * (self->geom.numBinY - 1) + 1 ; - int descrSize = vl_dsift_get_descriptor_size (self) ; - - wx *= self->geom.binSizeX ; - w = wx * wy ; - - for (framey = self->boundMinY ; - framey <= self->boundMaxY - frameSizeY + 1 ; - framey += self->stepY) { - for (framex = self->boundMinX ; - framex <= self->boundMaxX - frameSizeX + 1 ; - framex += self->stepX) { - *dst = w * src [(framex + binx * self->geom.binSizeX) * 1 + - (framey + biny * self->geom.binSizeY) * self->imWidth] ; - dst += descrSize ; - } /* framex */ - } /* framey */ - } /* binx */ - } /* biny */ - } /* bint */ -} - -/** ------------------------------------------------------------------ - ** @brief Compute keypoints and descriptors - ** - ** @param self DSIFT filter. - ** @param im image data. - **/ - -void vl_dsift_process (VlDsiftFilter* self, float const* im) -{ - int t, x, y ; - - /* update buffers */ - _vl_dsift_alloc_buffers (self) ; - - /* clear integral images */ - for (t = 0 ; t < self->geom.numBinT ; ++t) - memset (self->grads[t], 0, - sizeof(float) * self->imWidth * self->imHeight) ; - -#undef at -#define at(x,y) (im[(y)*self->imWidth+(x)]) - - /* Compute gradients, their norm, and their angle */ - - for (y = 0 ; y < self->imHeight ; ++ y) { - for (x = 0 ; x < self->imWidth ; ++ x) { - float gx, gy ; - float angle, mod, nt, rbint ; - int bint ; - - /* y derivative */ - if (y == 0) { - gy = at(x,y+1) - at(x,y) ; - } else if (y == self->imHeight - 1) { - gy = at(x,y) - at(x,y-1) ; - } else { - gy = 0.5F * (at(x,y+1) - at(x,y-1)) ; - } - - /* x derivative */ - if (x == 0) { - gx = at(x+1,y) - at(x,y) ; - } else if (x == self->imWidth - 1) { - gx = at(x,y) - at(x-1,y) ; - } else { - gx = 0.5F * (at(x+1,y) - at(x-1,y)) ; - } - - /* angle and modulus */ - angle = vl_fast_atan2_f (gy,gx) ; - mod = vl_fast_sqrt_f (gx*gx + gy*gy) ; - - /* quantize angle */ - nt = vl_mod_2pi_f (angle) * (self->geom.numBinT / (2*VL_PI)) ; - bint = (int) vl_floor_f (nt) ; - rbint = nt - bint ; - - /* write it back */ - self->grads [(bint ) % self->geom.numBinT][x + y * self->imWidth] = (1 - rbint) * mod ; - self->grads [(bint + 1) % self->geom.numBinT][x + y * self->imWidth] = ( rbint) * mod ; - } - } - - if (self->useFlatWindow) { - _vl_dsift_with_flat_window(self) ; - } else { - _vl_dsift_with_gaussian_window(self) ; - } - - { - VlDsiftKeypoint* frameIter = self->frames ; - float * descrIter = self->descrs ; - int framex, framey, bint ; - - int frameSizeX = self->geom.binSizeX * (self->geom.numBinX - 1) + 1 ; - int frameSizeY = self->geom.binSizeY * (self->geom.numBinY - 1) + 1 ; - int descrSize = vl_dsift_get_descriptor_size (self) ; - - float deltaCenterX = 0.5F * self->geom.binSizeX * (self->geom.numBinX - 1) ; - float deltaCenterY = 0.5F * self->geom.binSizeY * (self->geom.numBinY - 1) ; - - float normConstant = frameSizeX * frameSizeY ; - - for (framey = self->boundMinY ; - framey <= self->boundMaxY - frameSizeY + 1 ; - framey += self->stepY) { - - for (framex = self->boundMinX ; - framex <= self->boundMaxX - frameSizeX + 1 ; - framex += self->stepX) { - - frameIter->x = framex + deltaCenterX ; - frameIter->y = framey + deltaCenterY ; - - /* mass */ - { - float mass = 0 ; - for (bint = 0 ; bint < descrSize ; ++ bint) - mass += descrIter[bint] ; - mass /= normConstant ; - frameIter->norm = mass ; - } - - /* L2 normalize */ - _vl_dsift_normalize_histogram (descrIter, descrIter + descrSize) ; - - /* clamp */ - for(bint = 0 ; bint < descrSize ; ++ bint) - if (descrIter[bint] > 0.2F) descrIter[bint] = 0.2F ; - - /* L2 normalize */ - _vl_dsift_normalize_histogram (descrIter, descrIter + descrSize) ; - - frameIter ++ ; - descrIter += descrSize ; - } /* for framex */ - } /* for framey */ - } -} diff --git a/opensfm/src/third_party/vlfeat/vl/dsift.h b/opensfm/src/third_party/vlfeat/vl/dsift.h deleted file mode 100644 index 8bb301b7e..000000000 --- a/opensfm/src/third_party/vlfeat/vl/dsift.h +++ /dev/null @@ -1,354 +0,0 @@ -/** @file dsift.h - ** @brief Dense SIFT (@ref dsift) - ** @author Andrea Vedaldi - ** @author Brian Fulkerson - **/ - -/* -Copyright (C) 2007-12 Andrea Vedaldi and Brian Fulkerson. -All rights reserved. - -This file is part of the VLFeat library and is made available under -the terms of the BSD license (see the COPYING file). -*/ - -#ifndef VL_DSIFT_H -#define VL_DSIFT_H - -#include "generic.h" - -/** @brief Dense SIFT keypoint */ -typedef struct VlDsiftKeypoint_ -{ - double x ; /**< x coordinate */ - double y ; /**< y coordinate */ - double s ; /**< scale */ - double norm ; /**< SIFT descriptor norm */ -} VlDsiftKeypoint ; - -/** @brief Dense SIFT descriptor geometry */ -typedef struct VlDsiftDescriptorGeometry_ -{ - int numBinT ; /**< number of orientation bins */ - int numBinX ; /**< number of bins along X */ - int numBinY ; /**< number of bins along Y */ - int binSizeX ; /**< size of bins along X */ - int binSizeY ; /**< size of bins along Y */ -} VlDsiftDescriptorGeometry ; - -/** @brief Dense SIFT filter */ -typedef struct VlDsiftFilter_ -{ - int imWidth ; /**< @internal @brief image width */ - int imHeight ; /**< @internal @brief image height */ - - int stepX ; /**< frame sampling step X */ - int stepY ; /**< frame sampling step Y */ - - int boundMinX ; /**< frame bounding box min X */ - int boundMinY ; /**< frame bounding box min Y */ - int boundMaxX ; /**< frame bounding box max X */ - int boundMaxY ; /**< frame bounding box max Y */ - - /** descriptor parameters */ - VlDsiftDescriptorGeometry geom ; - - int useFlatWindow ; /**< flag: whether to approximate the Gaussian window with a flat one */ - double windowSize ; /**< size of the Gaussian window */ - - int numFrames ; /**< number of sampled frames */ - int descrSize ; /**< size of a descriptor */ - VlDsiftKeypoint *frames ; /**< frame buffer */ - float *descrs ; /**< descriptor buffer */ - - int numBinAlloc ; /**< buffer allocated: descriptor size */ - int numFrameAlloc ; /**< buffer allocated: number of frames */ - int numGradAlloc ; /**< buffer allocated: number of orientations */ - - float **grads ; /**< gradient buffer */ - float *convTmp1 ; /**< temporary buffer */ - float *convTmp2 ; /**< temporary buffer */ -} VlDsiftFilter ; - -VL_EXPORT VlDsiftFilter *vl_dsift_new (int width, int height) ; -VL_EXPORT VlDsiftFilter *vl_dsift_new_basic (int width, int height, int step, int binSize) ; -VL_EXPORT void vl_dsift_delete (VlDsiftFilter *self) ; -VL_EXPORT void vl_dsift_process (VlDsiftFilter *self, float const* im) ; -VL_INLINE void vl_dsift_transpose_descriptor (float* dst, - float const* src, - int numBinT, - int numBinX, - int numBinY) ; - -/** @name Setting parameters - ** @{ - **/ -VL_INLINE void vl_dsift_set_steps (VlDsiftFilter *self, - int stepX, - int stepY) ; -VL_INLINE void vl_dsift_set_bounds (VlDsiftFilter *self, - int minX, - int minY, - int maxX, - int maxY) ; -VL_INLINE void vl_dsift_set_geometry (VlDsiftFilter *self, - VlDsiftDescriptorGeometry const* geom) ; -VL_INLINE void vl_dsift_set_flat_window (VlDsiftFilter *self, vl_bool useFlatWindow) ; -VL_INLINE void vl_dsift_set_window_size (VlDsiftFilter *self, double windowSize) ; -/** @} */ - -/** @name Retrieving data and parameters - ** @{ - **/ -VL_INLINE float const *vl_dsift_get_descriptors (VlDsiftFilter const *self) ; -VL_INLINE int vl_dsift_get_descriptor_size (VlDsiftFilter const *self) ; -VL_INLINE int vl_dsift_get_keypoint_num (VlDsiftFilter const *self) ; -VL_INLINE VlDsiftKeypoint const *vl_dsift_get_keypoints (VlDsiftFilter const *self) ; -VL_INLINE void vl_dsift_get_bounds (VlDsiftFilter const *self, - int* minX, - int* minY, - int* maxX, - int* maxY) ; -VL_INLINE void vl_dsift_get_steps (VlDsiftFilter const* self, - int* stepX, - int* stepY) ; -VL_INLINE VlDsiftDescriptorGeometry const* vl_dsift_get_geometry (VlDsiftFilter const *self) ; -VL_INLINE vl_bool vl_dsift_get_flat_window (VlDsiftFilter const *self) ; -VL_INLINE double vl_dsift_get_window_size (VlDsiftFilter const *self) ; -/** @} */ - -VL_EXPORT -void _vl_dsift_update_buffers (VlDsiftFilter *self) ; - -/** ------------------------------------------------------------------ - ** @brief Get descriptor size. - ** @param self DSIFT filter object. - ** @return size of a descriptor. - **/ - -int -vl_dsift_get_descriptor_size (VlDsiftFilter const *self) -{ - return self->descrSize ; -} - -/** ------------------------------------------------------------------ - ** @brief Get descriptors. - ** @param self DSIFT filter object. - ** @return descriptors. - **/ - -float const * -vl_dsift_get_descriptors (VlDsiftFilter const *self) -{ - return self->descrs ; -} - -/** ------------------------------------------------------------------ - ** @brief Get keypoints - ** @param self DSIFT filter object. - **/ - -VlDsiftKeypoint const * -vl_dsift_get_keypoints (VlDsiftFilter const *self) -{ - return self->frames ; -} - -/** ------------------------------------------------------------------ - ** @brief Get number of keypoints - ** @param self DSIFT filter object. - **/ - -int -vl_dsift_get_keypoint_num (VlDsiftFilter const *self) -{ - return self->numFrames ; -} - -/** ------------------------------------------------------------------ - ** @brief Get SIFT descriptor geometry - ** @param self DSIFT filter object. - ** @return DSIFT descriptor geometry. - **/ - -VlDsiftDescriptorGeometry const* vl_dsift_get_geometry (VlDsiftFilter const *self) -{ - return &self->geom ; -} - -/** ------------------------------------------------------------------ - ** @brief Get bounds - ** @param self DSIFT filter object. - ** @param minX bounding box minimum X coordinate. - ** @param minY bounding box minimum Y coordinate. - ** @param maxX bounding box maximum X coordinate. - ** @param maxY bounding box maximum Y coordinate. - **/ - -void -vl_dsift_get_bounds (VlDsiftFilter const* self, - int *minX, int *minY, int *maxX, int *maxY) -{ - *minX = self->boundMinX ; - *minY = self->boundMinY ; - *maxX = self->boundMaxX ; - *maxY = self->boundMaxY ; -} - -/** ------------------------------------------------------------------ - ** @brief Get flat window flag - ** @param self DSIFT filter object. - ** @return @c TRUE if the DSIFT filter uses a flat window. - **/ - -int -vl_dsift_get_flat_window (VlDsiftFilter const* self) -{ - return self->useFlatWindow ; -} - -/** ------------------------------------------------------------------ - ** @brief Get steps - ** @param self DSIFT filter object. - ** @param stepX sampling step along X. - ** @param stepY sampling step along Y. - **/ - -void -vl_dsift_get_steps (VlDsiftFilter const* self, - int* stepX, - int* stepY) -{ - *stepX = self->stepX ; - *stepY = self->stepY ; -} - -/** ------------------------------------------------------------------ - ** @brief Set steps - ** @param self DSIFT filter object. - ** @param stepX sampling step along X. - ** @param stepY sampling step along Y. - **/ - -void -vl_dsift_set_steps (VlDsiftFilter* self, - int stepX, - int stepY) -{ - self->stepX = stepX ; - self->stepY = stepY ; - _vl_dsift_update_buffers(self) ; -} - -/** ------------------------------------------------------------------ - ** @brief Set bounds - ** @param self DSIFT filter object. - ** @param minX bounding box minimum X coordinate. - ** @param minY bounding box minimum Y coordinate. - ** @param maxX bounding box maximum X coordinate. - ** @param maxY bounding box maximum Y coordinate. - **/ - -void -vl_dsift_set_bounds (VlDsiftFilter* self, - int minX, int minY, int maxX, int maxY) -{ - self->boundMinX = minX ; - self->boundMinY = minY ; - self->boundMaxX = maxX ; - self->boundMaxY = maxY ; - _vl_dsift_update_buffers(self) ; -} - -/** ------------------------------------------------------------------ - ** @brief Set SIFT descriptor geometry - ** @param self DSIFT filter object. - ** @param geom descriptor geometry parameters. - **/ - -void -vl_dsift_set_geometry (VlDsiftFilter *self, - VlDsiftDescriptorGeometry const *geom) -{ - self->geom = *geom ; - _vl_dsift_update_buffers(self) ; -} - -/** ------------------------------------------------------------------ - ** @brief Set flat window flag - ** @param self DSIFT filter object. - ** @param useFlatWindow @c true if the DSIFT filter should use a flat window. - **/ - -void -vl_dsift_set_flat_window (VlDsiftFilter* self, - vl_bool useFlatWindow) -{ - self->useFlatWindow = useFlatWindow ; -} - -/** ------------------------------------------------------------------ - ** @brief Transpose descriptor - ** - ** @param dst destination buffer. - ** @param src source buffer. - ** @param numBinT - ** @param numBinX - ** @param numBinY - ** - ** The function writes to @a dst the transpose of the SIFT descriptor - ** @a src. Let I be an image. The transpose operator - ** satisfies the equation transpose(dsift(I,x,y)) = - ** dsift(transpose(I),y,x) - **/ - -VL_INLINE void -vl_dsift_transpose_descriptor (float* dst, - float const* src, - int numBinT, - int numBinX, - int numBinY) -{ - int t, x, y ; - - for (y = 0 ; y < numBinY ; ++y) { - for (x = 0 ; x < numBinX ; ++x) { - int offset = numBinT * (x + y * numBinX) ; - int offsetT = numBinT * (y + x * numBinY) ; - - for (t = 0 ; t < numBinT ; ++t) { - int tT = numBinT / 4 - t ; - dst [offsetT + (tT + numBinT) % numBinT] = src [offset + t] ; - } - } - } -} - -/** ------------------------------------------------------------------ - ** @brief Set SIFT descriptor Gaussian window size - ** @param self DSIFT filter object. - ** @param windowSize window size. - **/ - -void -vl_dsift_set_window_size(VlDsiftFilter * self, double windowSize) -{ - assert(windowSize >= 0.0) ; - self->windowSize = windowSize ; -} - -/** ------------------------------------------------------------------ - ** @brief Get SIFT descriptor Gaussian window size - ** @param self DSIFT filter object. - ** @return window size. - **/ - -VL_INLINE double -vl_dsift_get_window_size(VlDsiftFilter const * self) -{ - return self->windowSize ; -} - -/* VL_DSIFT_H */ -#endif diff --git a/opensfm/src/third_party/vlfeat/vl/fisher.c b/opensfm/src/third_party/vlfeat/vl/fisher.c deleted file mode 100644 index 480e29fc6..000000000 --- a/opensfm/src/third_party/vlfeat/vl/fisher.c +++ /dev/null @@ -1,586 +0,0 @@ -/** @file fisher.c - ** @brief Fisher - Declaration - ** @author David Novotny - **/ - -/* -Copyright (C) 2013 David Novotny and Andrea Vedaldi. -All rights reserved. - -This file is part of the VLFeat library and is made available under -the terms of the BSD license (see the COPYING file). -*/ - -/** - -@page fisher Fisher Vector encoding (FV) -@author David Novotny -@author Andrea Vedaldi - - -@ref fisher.h implements the Fisher Vectors (FV) image representation -@cite{perronnin06fisher} @cite{perronnin10improving}. A FV is a -statistics capturing the distribution of a set of vectors, usually a -set of local image descriptors. - -@ref fisher-starting demonstrates how to use the C API to compute the -FV representation of an image. For further details refer to: - -- @subpage fisher-fundamentals - Fisher Vector definition. -- @subpage fisher-derivation - Deriving the Fisher Vectors as a Fisher Kernel. -- @subpage fisher-kernel - The Fisher Kernel in general. - - -@section fisher-starting Getting started - - -The Fisher Vector encoding of a set of features is obtained by using -the function ::vl_fisher_encode. Note that the function requires a -@ref gmm "Gaussian Mixture Model" (GMM) of the encoded feature -distribution. In the following code, the result of the coding process -is stored in the @c enc array and the improved fisher vector -normalization is used. - -@code -float * means ; -float * covariances ; -float * priors ; -float * posteriors ; -float * enc; - -// create a GMM object and cluster input data to get means, covariances -// and priors of the estimated mixture -gmm = vl_gmm_new (VL_TYPE_FLOAT) ; -vl_gmm_cluster (gmm, data, dimension, numData, numClusters); - -// allocate space for the encoding -enc = vl_malloc(sizeof(float) * 2 * dimension * numClusters); - -// run fisher encoding -vl_fisher_encode - (enc, VL_F_TYPE, - vl_gmm_get_means(gmm), dimension, numClusters, - vl_gmm_get_covariances(gmm), - vl_gmm_get_priors(gmm), - dataToEncode, numDataToEncode, - VL_FISHER_FLAG_IMPROVED - ) ; -@endcode - -The performance of the standard Fisher Vector can be significantly -improved @cite{perronnin10improving} by using appropriate @ref -fisher-normalization normalizations. These are controlled by the @c -flag parameter of ::vl_fisher_encode. - - -@page fisher-fundamentals Fisher vector fundamentals -@tableofcontents - - -This page describes the *Fisher Vector* (FV) of -@cite{perronnin06fisher} @cite{perronnin10improving}. See @ref fisher -for an overview of the C API and @ref fisher-kernel for its relation -to the more general notion of Fisher kernel. - -The FV is an image representation obtained by pooling local image -features. It is frequently used as a global image descriptor in visual -classification. - -While the FV can be @ref fisher-kernel "derived" as a special, -approximate, and improved case of the general Fisher Kernel framework, -it is easy to describe directly. Let $I = (\bx_1,\dots,\bx_N)$ be a -set of $D$ dimensional feature vectors (e.g. SIFT descriptors) -extracted from an image. Let -$\Theta=(\mu_k,\Sigma_k,\pi_k:k=1,\dots,K)$ be the parameters of a -@ref gmm "Gaussian Mixture Model" fitting the distribution of -descriptors. The GMM associates each vector $\bx_i$ to a mode $k$ in -the mixture with a strength given by the posterior probability: - -\[ - q_{ik} = - \frac - {\exp\left[-\frac{1}{2}(\bx_i - \mu_k)^T \Sigma_k^{-1} (\bx_i - \mu_k)\right]} - {\sum_{t=1}^K \exp\left[-\frac{1}{2}(\bx_i - \mu_t)^T \Sigma_k^{-1} (\bx_i - \mu_t)\right]}. -\] - -For each mode $k$, consider the mean and covariance deviation vectors - -@f{align*} -u_{jk} &= -{1 \over {N \sqrt{\pi_k}}} -\sum_{i=1}^{N} -q_{ik} \frac{x_{ji} - \mu_{jk}}{\sigma_{jk}}, -\\ -v_{jk} &= -{1 \over {N \sqrt{2 \pi_k}}} -\sum_{i=1}^{N} -q_{ik} \left[ \left(\frac{x_{ji} - \mu_{jk}}{\sigma_{jk}}\right)^2 - 1 \right]. -@f} - -where $j=1,2,\dots,D$ spans the vector dimensions. The FV of image $I$ -is the stacking of the vectors $\bu_k$ and then of the vectors -$\bv_k$ for each of the $K$ modes in the Gaussian mixtures: - -\[ - \Phi(I) = \begin{bmatrix} \vdots \\ \bu_k \\ \vdots \\ \bv_k \\ \vdots \end{bmatrix}. -\] - - -@section fisher-normalization Normalization and improved Fisher vectors - - -The *improved* Fisher Vector @cite{perronnin10improving} (IFV) improves the -classification performance of the representation by using to ideas: - -1. *Non-linear additive kernel.* The Hellinger's kernel (or - Bhattacharya coefficient) can be used instead of the linear one at - no cost by signed squared rooting. This is obtained by applying the - function $|z| \sign z$ to each dimension of the vector $\Phi(I)$. - Other @ref homkermap "additive kernels" can also be used at an - increased space or time cost. -2. *Normalization.* Before using the representation in a linear model - (e.g. a @ref svm "support vector machine"), the vector $\Phi(I)$ is - further normalized by the $l^2$ norm (note that the standard Fisher - vector is normalized by the number of encoded feature vectors). - -After square-rooting and normalization, the IFV is often used in a -linear classifier such as an @ref svm "SVM". - - -@section fisher-fast Faster computations - - -In practice, several data to cluster assignments $q_{ik}$ are likely -to be very small or even negligible. The *fast* version of the FV sets -to zero all but the largest assignment for each input feature $\bx_i$. - - -@page fisher-derivation Fisher vector derivation - - -The FV of @cite{perronnin06fisher} is a special case of the @ref -fisher-kernel "Fisher kernel" construction. It is designed to encode -local image features in a format that is suitable for learning and -comparison with simple metrics such as the Euclidean. In this -construction, an image is modeled as a collection of $D$-dimensional -feature vectors $I=(\bx_1,\dots,\bx_n)$ generated by a GMM with $K$ -components $\Theta=(\mu_k,\Sigma_k,\pi_k:k=1,\dots,K)$. The covariance -matrices are assumed to be diagonal, i.e. $\Sigma_k = \diag -\bsigma_k^2$, $\bsigma_k \in \real^D_+$. - -The generative model of *one* feature vector $\bx$ is given by the GMM -density function: - -\[ - p(\bx|\Theta) = -\sum_{k=1}^K \pi_k p(\bx|\Theta_k), -\quad -p(\bx|\Theta_k) -= -\frac{1}{(2\pi)^\frac{D}{2} (\det \Sigma_k)^{\frac{1}{2}}} -\exp -\left[ --\frac{1}{2} -(\bx - \mu_k)^\top \Sigma_k^{-1} (\bx - \mu_k) -\right] -\] - -where $\Theta_k = (\mu_k,\Sigma_k)$. The Fisher Vector requires -computing the derivative of the log-likelihood function with respect -to the various model parameters. Consider in particular the parameters -$\Theta_k$ of a mode. Due to the exponent in the Gaussian density -function, the derivative can be written as - -\[ -\nabla_{\Theta_k} p(\bx|\Theta_k) = -p(\bx|\Theta_k) -g(\bx|\Theta_k) -\] - -for a simple vector function $g$. The derivative of the log-likelihood -function is then - -\[ -\nabla_{\Theta_k} \log p(\bx|\Theta) -= -\frac{\pi_k p(\bx|\Theta_k)}{\sum_{t=1}^K \pi_k p(\bx|\Theta_k)} -g(\bx|\Theta_k) -= -q_k(\bx) g(\bx|\Theta_k) -\] - -where $q_k(\bx)$ is the soft-assignment of the point $\bx$ to the mode -$k$. We make the approximation that $q_k(\bx)\approx 1$ if $\bx$ is -sampled from mode $k$ and $\approx 0$ otherwise -@cite{perronnin06fisher}. Hence one gets: - -\[ -E_{\bx \sim p(\bx|\Theta)} -[ -\nabla_{\Theta_k} \log p(\bx|\Theta) -\nabla_{\Theta_t} \log p(\bx|\Theta)^\top -] -\approx -\begin{cases} -\pi_k E_{\bx \sim p(\bx|\Theta_k)} [ g(\bx|\Theta_k) g(\bx|\Theta_k)^\top], & t = k, \\ -0, & t\not=k. -\end{cases} -\] - -Thus under this approximation there is no correlation between the -parameters of the various Gaussian modes. - -The function $g$ can be further broken down as the stacking of the -derivative w.r.t. the mean and the diagonal covariance. - -\[ -g(\bx|\Theta_k) -= -\begin{bmatrix} -g(\bx|\mu_k) \\ -g(\bx|\bsigma_k) -\end{bmatrix}, -\quad -[g(\bx|\mu_k)]_j -= -\frac{x_j - \mu_{jk}}{\sigma_{jk}^2}, -\quad -[g(\bx|\bsigma_k^2)]_j -= -\frac{1}{2\sigma_{jk}^2} -\left( -\left(\frac{x_j - \mu_{jk}}{\sigma_{jk}}\right)^2 -- -1 -\right) -\] - -Thus the covariance of the model (Fisher information) is diagonal and -the diagonal entries are given by - -\[ - H_{\mu_{jk}} = \pi_k E[g(\bx|\mu_{jk})g(\bx|\mu_{jk})] - = \frac{\pi_k}{\sigma_{jk}^2}, - \quad - H_{\sigma_{jk}^2} = \frac{\pi_k}{2 \sigma_{jk}^4}. -\] - -where in the calculation it was used the fact that the fourth moment -of the standard Gaussian distribution is 3. Multiplying the inverse -square root of the matrix $H$ by the derivative of the log-likelihood -function results in the Fisher vector encoding of one image feature -$\bx$: - -\[ - \Phi_{\mu_{jk}}(\bx) = H_{\mu_{jk}}^{-\frac{1}{2}} q_k(\bx) g(\bx|\mu_{jk}) -= q_k(\bx) \frac{x_j - \mu_{jk}}{\sqrt{\pi_k}\sigma_{jk}}, -\qquad - \Phi_{\sigma^2_{jk}}(\bx) = -\frac{q_k(\bx)}{\sqrt{2 \pi_k}} -\left( -\left(\frac{x_j - \mu_{jk}}{\sigma_{jk}}\right)^2 -- -1 -\right) -\] - -Assuming that features are sampled i.i.d. from the GMM results in the -formulas given in @ref fisher-fundamentals (note the normalization -factor). Note that: - -* The Fisher components relative to the prior probabilities $\pi_k$ - have been ignored. This is because they have little effect on the - representation @cite{perronnin10improving}. - -* Technically, the derivation of the Fisher Vector for multiple image - features requires the number of features to be the same in both - images. Ultimately, however, the representation can be computed by - using any number of features. - - -@page fisher-kernel Fisher kernel - - -This page discusses the Fisher Kernels (FK) of -@cite{jaakkola98exploiting} and shows how the FV of -@cite{perronnin06fisher} can be derived from it as a special case. The -FK induces a similarity measures between data points $\bx$ and $\bx'$ -from a parametric generative model $p(\bx|\Theta)$ of the data. The -parameter $\Theta$ of the model is selected to fit the a-priori -distribution of the data, and is usually the Maximum Likelihood (MLE) -estimate obtained from a set of training examples. Once the generative -model is learned, each particular datum $\bx$ is represented by -looking at how it affects the MLE parameter estimate. This effect is -measured by computing the gradient of the log-likelihood term -corresponding to $\bx$: - -\[ - \hat\Phi(\bx) = \nabla_\Theta \log p(\bx|\Theta) -\] - -The vectors $\hat\Phi(\bx)$ should be appropriately scaled before they -can be meaningfully compared. This is obtained by *whitening* the data -by multiplying the vectors by the inverse of the square root of their -*covariance matrix*. The covariance matrix can be obtained from the -generative model $p(\bx|\Theta)$ itself. Since $\Theta$ is the ML -parameter and $\hat\Phi(\bx)$ is the gradient of the log-likelihood -function, its expected value $E[\hat\Phi(\bx)]$ is zero. Thus, since -the vectors are already centered, their covariance matrix is simply: - -\[ -H = E_{\bx \sim p(\bx|\Theta)} [\hat\Phi(\bx) \hat\Phi(\bx)^\top] -\] - -Note that $H$ is also the *Fisher information matrix* of the -model. The final FV encoding $\Phi(\bx)$ is given by the whitened -gradient of the log-likelihood function, i.e.: - -\[ - \Phi(\bx) = H^{-\frac{1}{2}} \nabla_\Theta \log p(\bx|\Theta). -\] - -Taking the inner product of two such vectors yields the *Fisher -kernel*: - -\[ - K(\bx,\bx') -= \langle \Phi(\bx),\Phi(\bx') \rangle -= \nabla_\Theta \log p(\bx|\Theta)^\top H^{-1} \nabla_\Theta \log p(\bx'|\Theta). -\] - -**/ - -#include "fisher.h" -#include "gmm.h" -#include "mathop.h" - -#include -#include -#include - -#ifdef VL_FISHER_INSTANTIATING - -static vl_size -VL_XCAT(_vl_fisher_encode_, SFX) -(TYPE * enc, - TYPE const * means, vl_size dimension, vl_size numClusters, - TYPE const * covariances, - TYPE const * priors, - TYPE const * data, vl_size numData, - int flags) -{ - vl_size dim; - vl_index i_cl, i_d; - vl_size numTerms = 0 ; - TYPE * posteriors ; - TYPE * sqrtInvSigma; - - assert(numClusters >= 1) ; - assert(dimension >= 1) ; - - posteriors = vl_malloc(sizeof(TYPE) * numClusters * numData); - sqrtInvSigma = vl_malloc(sizeof(TYPE) * dimension * numClusters); - - memset(enc, 0, sizeof(TYPE) * 2 * dimension * numClusters) ; - - for (i_cl = 0 ; i_cl < (signed)numClusters ; ++i_cl) { - for(dim = 0; dim < dimension; dim++) { - sqrtInvSigma[i_cl*dimension + dim] = sqrt(1.0 / covariances[i_cl*dimension + dim]); - } - } - - VL_XCAT(vl_get_gmm_data_posteriors_, SFX)(posteriors, numClusters, numData, - priors, - means, dimension, - covariances, - data) ; - - /* sparsify posterior assignments with the FAST option */ - if (flags & VL_FISHER_FLAG_FAST) { - for(i_d = 0; i_d < (signed)numData; i_d++) { - /* find largest posterior assignment for datum i_d */ - vl_index best = 0 ; - TYPE bestValue = posteriors[i_d * numClusters] ; - for (i_cl = 1 ; i_cl < (signed)numClusters; ++ i_cl) { - TYPE p = posteriors[i_cl + i_d * numClusters] ; - if (p > bestValue) { - bestValue = p ; - best = i_cl ; - } - } - /* make all posterior assignments zero but the best one */ - for (i_cl = 0 ; i_cl < (signed)numClusters; ++ i_cl) { - posteriors[i_cl + i_d * numClusters] = - (TYPE)(i_cl == best) ; - } - } - } - -#if defined(_OPENMP) -#pragma omp parallel for default(shared) private(i_cl, i_d, dim) num_threads(vl_get_max_threads()) reduction(+:numTerms) -#endif - for(i_cl = 0; i_cl < (signed)numClusters; ++ i_cl) { - TYPE uprefix; - TYPE vprefix; - - TYPE * uk = enc + i_cl*dimension ; - TYPE * vk = enc + i_cl*dimension + numClusters * dimension ; - - /* - If the GMM component is degenerate and has a null prior, then it - must have null posterior as well. Hence it is safe to skip it. In - practice, we skip over it even if the prior is very small; if by - any chance a feature is assigned to such a mode, then its weight - would be very high due to the division by priors[i_cl] below. - */ - if (priors[i_cl] < 1e-6) { continue ; } - - for(i_d = 0; i_d < (signed)numData; i_d++) { - TYPE p = posteriors[i_cl + i_d * numClusters] ; - if (p < 1e-6) continue ; - numTerms += 1; - for(dim = 0; dim < dimension; dim++) { - TYPE diff = data[i_d*dimension + dim] - means[i_cl*dimension + dim] ; - diff *= sqrtInvSigma[i_cl*dimension + dim] ; - *(uk + dim) += p * diff ; - *(vk + dim) += p * (diff * diff - 1); - } - } - - if (numData > 0) { - uprefix = 1/(numData*sqrt(priors[i_cl])); - vprefix = 1/(numData*sqrt(2*priors[i_cl])); - for(dim = 0; dim < dimension; dim++) { - *(uk + dim) = *(uk + dim) * uprefix; - *(vk + dim) = *(vk + dim) * vprefix; - } - } - } - - vl_free(posteriors); - vl_free(sqrtInvSigma) ; - - if (flags & VL_FISHER_FLAG_SQUARE_ROOT) { - for(dim = 0; dim < 2 * dimension * numClusters ; dim++) { - TYPE z = enc [dim] ; - if (z >= 0) { - enc[dim] = VL_XCAT(vl_sqrt_, SFX)(z) ; - } else { - enc[dim] = - VL_XCAT(vl_sqrt_, SFX)(- z) ; - } - } - } - - if (flags & VL_FISHER_FLAG_NORMALIZED) { - TYPE n = 0 ; - for(dim = 0 ; dim < 2 * dimension * numClusters ; dim++) { - TYPE z = enc [dim] ; - n += z * z ; - } - n = VL_XCAT(vl_sqrt_, SFX)(n) ; - n = VL_MAX(n, 1e-12) ; - for(dim = 0 ; dim < 2 * dimension * numClusters ; dim++) { - enc[dim] /= n ; - } - } - - return numTerms ; -} - -#else -/* not VL_FISHER_INSTANTIATING */ - -#ifndef __DOXYGEN__ -#define FLT VL_TYPE_FLOAT -#define TYPE float -#define SFX f -#define VL_FISHER_INSTANTIATING -#include "fisher.c" - -#define FLT VL_TYPE_DOUBLE -#define TYPE double -#define SFX d -#define VL_FISHER_INSTANTIATING -#include "fisher.c" -#endif - -/* not VL_FISHER_INSTANTIATING */ -#endif - -/* ================================================================ */ -#ifndef VL_FISHER_INSTANTIATING - -/** @brief Fisher vector encoding of a set of vectors. - ** @param dataType the type of the input data (::VL_TYPE_DOUBLE or ::VL_TYPE_FLOAT). - ** @param enc Fisher vector (output). - ** @param means Gaussian mixture means. - ** @param dimension dimension of the data. - ** @param numClusters number of Gaussians mixture components. - ** @param covariances Gaussian mixture diagonal covariances. - ** @param priors Gaussian mixture prior probabilities. - ** @param data vectors to encode. - ** @param numData number of vectors to encode. - ** @param flags options. - ** @return number of averaging operations. - ** - ** @a means and @a covariances have @a dimension rows and @a - ** numCluster columns. @a priors is a vector of size @a - ** numCluster. @a data has @a dimension rows and @a numData - ** columns. @a enc is a vecotr of size equal to twice the product of - ** @a dimension and @a numClusters. All these vectors and matrices - ** have the same class, as specified by @a dataType, and must be - ** stored in column-major format. - ** - ** @a flag can be used to control several options: - ** ::VL_FISHER_FLAG_SQUARE_ROOT, ::VL_FISHER_FLAG_NORMALIZED, - ** ::VL_FISHER_FLAG_IMPROVED, and ::VL_FISHER_FLAG_FAST. - ** - ** The function returns the number of averaging operations actually - ** performed. The upper bound is the number of input features by the - ** number of GMM modes; however, assignments are usually failry - ** sparse, so this number is often much smaller. In particular, with - ** the ::VL_FISHER_FLAG_FAST, is equal to the number of input - ** features. This information can be used for diagnostic purposes. - ** - ** @sa @ref fisher - **/ - -VL_EXPORT vl_size -vl_fisher_encode -(void * enc, vl_type dataType, - void const * means, vl_size dimension, vl_size numClusters, - void const * covariances, - void const * priors, - void const * data, vl_size numData, - int flags -) -{ - switch(dataType) { - case VL_TYPE_FLOAT: - return _vl_fisher_encode_f - ((float *) enc, - (float const *) means, dimension, numClusters, - (float const *) covariances, - (float const *) priors, - (float const *) data, numData, - flags); - case VL_TYPE_DOUBLE: - return _vl_fisher_encode_d - ((double *) enc, - (double const *) means, dimension, numClusters, - (double const *) covariances, - (double const *) priors, - (double const *) data, numData, - flags); - break; - default: - abort(); - } -} -/* not VL_FISHER_INSTANTIATING */ -#endif - -#undef SFX -#undef TYPE -#undef FLT -#undef VL_FISHER_INSTANTIATING diff --git a/opensfm/src/third_party/vlfeat/vl/fisher.h b/opensfm/src/third_party/vlfeat/vl/fisher.h deleted file mode 100644 index 907e66a48..000000000 --- a/opensfm/src/third_party/vlfeat/vl/fisher.h +++ /dev/null @@ -1,57 +0,0 @@ -/** @file fisher.h - ** @brief Fisher encoding (@ref fisher) - ** @author David Novotny - ** @author Andrea Vedaldi - ** @see @ref fisher - **/ - -/* -Copyright (C) 2013 David Novotny and Andrea Vedaldi. -All rights reserved. - -This file is part of the VLFeat library and is made available under -the terms of the BSD license (see the COPYING file). -*/ - -#ifndef VL_FISHER_H -#define VL_FISHER_H - -#include "generic.h" - -/** @name Fisher vector options - ** @{ */ -#define VL_FISHER_FLAG_SQUARE_ROOT (0x1 << 0) -#define VL_FISHER_FLAG_NORMALIZED (0x1 << 1) -#define VL_FISHER_FLAG_IMPROVED (VL_FISHER_FLAG_NORMALIZED|VL_FISHER_FLAG_SQUARE_ROOT) -#define VL_FISHER_FLAG_FAST (0x1 << 2) - -/** @def VL_FISHER_FLAG_SQUARE_ROOT - ** @brief Use signed squared-root (@ref fisher-normalization). - **/ - -/** @def VL_FISHER_FLAG_NORMALIZED - ** @brief Gobally normalize the Fisher vector in L2 norm (@ref fisher-normalization). - **/ - -/** @def VL_FISHER_FLAG_IMPROVED - ** @brief Improved Fisher vector. - ** This is the same as @c VL_FISHER_FLAG_SQUARE_ROOT|VL_FISHER_FLAG_NORMALIZED. - **/ - -/** @def VL_FISHER_FLAG_FAST - ** @brief Fast but more approximate calculations (@ref fisher-fast). - ** Keep only the larges data to cluster assignment (posterior). - **/ - -/** @} */ - -VL_EXPORT vl_size vl_fisher_encode -(void * enc, vl_type dataType, - void const * means, vl_size dimension, vl_size numClusters, - void const * covariances, - void const * priors, - void const * data, vl_size numData, - int flags) ; - -/* VL_FISHER_H */ -#endif diff --git a/opensfm/src/third_party/vlfeat/vl/float.h b/opensfm/src/third_party/vlfeat/vl/float.h deleted file mode 100644 index 267ca98f8..000000000 --- a/opensfm/src/third_party/vlfeat/vl/float.h +++ /dev/null @@ -1,116 +0,0 @@ -/** @file float.h - ** @brief Float - Template - ** @author Andrea Vedaldi - ** @author David Novotny - **/ - -/* -Copyright (C) 2014 Andrea Vedaldi. -Copyright (C) 2013 David Novotny. -Copyright (C) 2007-12 Andrea Vedaldi and Brian Fulkerson. -All rights reserved. - -This file is part of the VLFeat library and is made available under -the terms of the BSD license (see the COPYING file). -*/ - -#include "generic.h" - -#undef T -#undef SFX -#undef VSIZE -#undef VSFX -#undef VTYPE -#undef VSIZEavx -#undef VSFXavx -#undef VTYPEavx - -#if (FLT == VL_TYPE_FLOAT) -# define T float -# define SFX f -#elif (FLT == VL_TYPE_DOUBLE) -# define T double -# define SFX d -#elif (FLT == VL_TYPE_UINT32) -# define T vl_uint32 -# define SFX ui32 -#elif (FLT == VL_TYPE_INT32) -# define T vl_int32 -# define SFX i32 -#endif - -/* ---------------------------------------------------------------- */ -/* AVX */ -/* ---------------------------------------------------------------- */ - -#ifdef __AVX__ - -#if (FLT == VL_TYPE_FLOAT) -# define VSIZEavx 8 -# define VSFXavx s -# define VTYPEavx __m256 -#elif (FLT == VL_TYPE_DOUBLE) -# define VSIZEavx 4 -# define VSFXavx d -# define VTYPEavx __m256d -#endif - -#define VALIGNEDavx(x) (! (((vl_uintptr)(x)) & 0x1F)) - -#define VMULavx VL_XCAT(_mm256_mul_p, VSFX) -#define VDIVavx VL_XCAT(_mm256_div_p, VSFX) -#define VADDavx VL_XCAT(_mm256_add_p, VSFX) -#define VHADDavx VL_XCAT(_mm_hadd_p, VSFX) -#define VHADD2avx VL_XCAT(_mm256_hadd_p, VSFX) -#define VSUBavx VL_XCAT(_mm256_sub_p, VSFX) -#define VSTZavx VL_XCAT(_mm256_setzero_p, VSFX) -#define VLD1avx VL_XCAT(_mm256_broadcast_s, VSFX) -#define VLDUavx VL_XCAT(_mm256_loadu_p, VSFX) -#define VST1avx VL_XCAT(_mm256_store_s, VSFX) -#define VST2avx VL_XCAT(_mm256_store_p, VSFX) -#define VST2Uavx VL_XCAT(_mm256_storeu_p, VSFX) -#define VPERMavx VL_XCAT(_mm256_permute2f128_p, VSFX) -//#define VCSTavx VL_XCAT( _mm256_castps256_ps128, VSFX) -#define VCSTavx VL_XCAT5(_mm256_castp,VSFX,256_p,VSFX,128) - -/* __AVX__ */ -#endif - -/* ---------------------------------------------------------------- */ -/* SSE2 */ -/* ---------------------------------------------------------------- */ - -#ifdef __SSE2__ - -#if (FLT == VL_TYPE_FLOAT) -# define VSIZE 4 -# define VSFX s -# define VTYPE __m128 -#elif (FLT == VL_TYPE_DOUBLE) -# define VSIZE 2 -# define VSFX d -# define VTYPE __m128d -#endif - -#define VALIGNED(x) (! (((vl_uintptr)(x)) & 0xF)) - -#define VMAX VL_XCAT(_mm_max_p, VSFX) -#define VMUL VL_XCAT(_mm_mul_p, VSFX) -#define VDIV VL_XCAT(_mm_div_p, VSFX) -#define VADD VL_XCAT(_mm_add_p, VSFX) -#define VSUB VL_XCAT(_mm_sub_p, VSFX) -#define VSTZ VL_XCAT(_mm_setzero_p, VSFX) -#define VLD1 VL_XCAT(_mm_load1_p, VSFX) -#define VLDU VL_XCAT(_mm_loadu_p, VSFX) -#define VST1 VL_XCAT(_mm_store_s, VSFX) -#define VSET1 VL_XCAT(_mm_set_s, VSFX) -#define VSHU VL_XCAT(_mm_shuffle_p, VSFX) -#define VNEQ VL_XCAT(_mm_cmpneq_p, VSFX) -#define VAND VL_XCAT(_mm_and_p, VSFX) -#define VANDN VL_XCAT(_mm_andnot_p, VSFX) -#define VST2 VL_XCAT(_mm_store_p, VSFX) -#define VST2U VL_XCAT(_mm_storeu_p, VSFX) - -/* __SSE2__ */ -#endif - diff --git a/opensfm/src/third_party/vlfeat/vl/generic.c b/opensfm/src/third_party/vlfeat/vl/generic.c deleted file mode 100644 index d4982e43b..000000000 --- a/opensfm/src/third_party/vlfeat/vl/generic.c +++ /dev/null @@ -1,1679 +0,0 @@ -/** @file generic.c - ** @brief Generic - Definition - ** @author Andrea Vedaldi - **/ - -/* -Copyright (C) 2007-12 Andrea Vedaldi and Brian Fulkerson. -Copyright (C) 2013 Andrea Vedaldi. -All rights reserved. - -This file is part of the VLFeat library and is made available under -the terms of the BSD license (see the COPYING file). -*/ - -/** - -@mainpage Vision Lab Features Library (VLFeat) -@version __VLFEAT_VERSION__ -@author The VLFeat Team -@par Copyright © 2012-14 The VLFeat Authors -@par Copyright © 2007-11 Andrea Vedaldi and Brian Fulkerson - - -The VLFeat C library implements common computer -vision algorithms, with a special focus on visual features, as used -in state-of-the-art object recognition and image -matching applications. - -VLFeat strives to be clutter-free, simple, portable, and well documented. - - -@section main-contents Contents - - -- **Visual feature detectors and descriptors** - - @subpage sift - - @subpage dsift - - @subpage mser - - @subpage covdet - - @subpage scalespace - - @subpage hog - - @subpage fisher - - @subpage vlad - - @subpage liop - - @subpage lbp - -- **Clustering and indexing** - - @subpage kmeans - - @subpage ikmeans.h "Integer K-means (IKM)" - - @subpage hikmeans.h "Hierarchical Integer K-means (HIKM)" - - @subpage gmm - - @subpage aib - - @subpage kdtree - -- **Segmentation** - - @subpage slic - - @subpage quickshift - -- **Statistical methods** - - @subpage aib - - @subpage homkermap - - @subpage svm - -- **Utilities** - - @subpage random - - @subpage mathop - - @subpage stringop.h "String operations" - - @subpage imopv.h "Image operations" - - @subpage pgm.h "PGM image format" - - @subpage heap-def.h "Generic heap object (priority queue)" - - @subpage rodrigues.h "Rodrigues formula" - - @subpage mexutils.h "MATLAB MEX helper functions" - - @subpage getopt_long.h "Drop-in @c getopt_long replacement" - -- **General information** - - @subpage conventions - - @subpage generic - - @subpage portability - - @ref resources - - @subpage objects - - @ref threads - - @subpage matlab - - @subpage metaprogram - -- @subpage dev -- @subpage glossary -**/ - -/** - -@page resources Memory and resource handling -@author Andrea Vedaldi - - -Some VLFeat functions return pointers to memory blocks or -objects. Only ::vl_malloc, ::vl_calloc, ::vl_realloc and functions -whose name contains either the keywords @c new or @c copy transfer the -ownership of the memory block or object to the caller. The caller must -dispose explicitly of all the resources it owns (by calling ::vl_free -for a memory block, or the appropriate deletion function for an -object). - -The memory allocation functions can be customized by -::vl_set_alloc_func (which sets the implementations of ::vl_malloc, -::vl_realloc, ::vl_calloc and ::vl_free). Remapping the memory -allocation functions can be done only if there are no currently -allocated VLFeat memory blocks or objects -- thus typically at the -very beginning of a program. The memory allocation functions are a -global property, shared by all threads. - -VLFeat uses three rules that simplify handling exceptions when used in -combination which certain environment such as MATLAB. - -- The library allocates local memory only through the re-programmable - ::vl_malloc, ::vl_calloc, and ::vl_realloc functions. - -- The only resource referenced by VLFeat objects is memory (for - instance, it is illegal for an object to reference an open file). - Other resources such as files or threads may be allocated within a - VLFeat function call, but they are all released before the function - ends, or their ownership is directly transferred to the caller. - -- The global library state is an exception. It cannot reference any - local object created by the caller and uses the standard C memory - allocation functions. - -In this way, the VLFeat local state can be reset at any time simply by -disposing of all the memory allocated by the library so far. The -latter can be done easily by mapping the memory allocation functions -to implementations that track the memory blocks allocated, and then -disposing of all such blocks. Since the global state does not -reference any local object nor uses the remapped memory functions, it -is unaffected by such an operation; conversely, since no VLFeat object -references anything but memory, this guarantees that all allocated -resources are properly disposed (avoiding leaking resource). This is -used extensively in the design of MATLAB MEX files (see @ref -matlab). -**/ - -/** - -@page conventions Conventions -@author Andrea Vedaldi -@tableofcontents - - -This page summarizes some of the conventions used by the library. - -@section conventions-storage Matrix and image storage conventions - -If not otherwise specified, matrices in VLFeat are stored in memory in -column major order. Given a matrix $[A_{ij}] \in \real^{m -\times n}$, this amounts of enumerating the elements one column per -time: $A_{11}, A_{21}, \dots, A_{m1}, A_{12}, \dots, A_{mn}$. This -convention is compatible with Fortran, MATLAB, and popular numerical -libraries. - -Matrices are often used in the library to pack a number data vectors -$\bx_1,\dots,\bx_n \in \real^m$ of equal dimension together. These are -normally stored as the columns of the matrix: - -\[ -X = \begin{bmatrix} \bx_1, \dots, \bx_n \end{bmatrix}, -\qquad -X \in \real_{m\times n} -\] - -In this manner, consecutive elements of each data vector $\bx_i$ is -stored in consecutive memory locations, improving memory access -locality in most algorithms. - -Images $I(x,y)$ are stored instead in row-major order, -i.e. one row after the other. Note that an image can be naturally -identified as a matrix $I_{yx}$, where the vertical coordinate $y$ -indexes the rows and the horizontal coordinate $x$ the columns. The -image convention amounts to storing this matrix in row-major rather -than column-major order, which is in conflict with the rule given -above. The reason for this choice is that most image processing and -graphical libraries assume this convention; it is, however, -not the same as MATLAB's. - -**/ - -/** - -@page objects Objects -@author Andrea Vedaldi -@tableofcontents - - -Many VLFeat algorithms are available in the form of *objects*. The C -language, used by VLFeat, does not support objects explicitly. Here an -object is intended a C structure along with a number of functions (the -object member functions or methods) operating on it. Ideally, the -object data structure is kept opaque to the user, for example by -defining it in the @c .c implementation files which are not accessible -to the library user. - -Object names are capitalized and start with the Vl prefix -(for example @c VlExampleObject). Object methods are lowercase and -start with the vl__ suffix -(e.g. @c vl_example_object_new). - - -@section objects-lifecycle Object lifecycle - - -Conceptually, an object undergoes four phases during its lifecycle: -allocation, initialization, finalization, and deallocation: - -- **Allocation.** The memory to hold the object structure is allocated. - This is usually done by calling a memory allocation function such as - ::vl_calloc to reserve an object of the required size @c - sizeof(VlExampleObject). Alternatively, the object can simply by - allocated on the stack by declaring a local variable of type - VlExampleObject. -- **Initialization.** The object is initialized by assigning a value to - its data members and potentially allocating a number of resources, - including other objects or memory buffers. Initialization is - done by methods containing the @c init keyword, e.g. @c - vl_example_object_init. Several such methods may be provided. -- **Finalization.** Initialization is undone by finalization, whose main - purpose is to release any resource allocated and still owned by the - object. Finalization is done by the @c vl_example_object_finalize - method. -- **Deallocation.** The memory holding the object structure is - disposed of, for example by calling ::vl_free or automatically when - the corresponding local variable is popped from the stack. - -In practice, most VlFeat object are supposed to be created on the -heap. To this end, allocation/initialization and -finalization/deallocation are combined into two operations: - -- **Creating a new object.** This allocates a new object on the heap - and initializes it, combining allocation and initialization in a - single operation. It is done by methods containing the @c new keyword, - e.g. @c vl_example_object_new. -- **Deleting an object.** This disposes of an object created by a @c - new method, combining finalization and deallocation, for example - @c vl_example_object_delete. - - -@section objects-getters-setters Getters and setters - - -Most objects contain a number of methods to get (getters) and set -(setters) properties. These should contain the @c get and @c set -keywords in their name, for example - -@code -double x = vl_example_object_get_property () ; -vl_example_object_set_property(x) ; -@endcode -**/ - -/** - -@page matlab MATLAB integration -@author Andrea Vedaldi - - -The VLFeat C library is designed to integrate seamlessly with MATLAB. -Binary compatibility is simplified by the use of the C language -(rather than C++). In addition, the library design follows certain -restrictions that make it compatible with the MATLAB MEX interface. - -The main issue in calling a library function from a MATLAB MEX -function is that MATLAB can abort the execution of the MEX function -at any point, either due to an error, or directly upon a user request -(Ctrl-C) (empirically, however, a MEX function seems to be -incorruptible only during the invocation of certain functions of the -MEX API such as @c mexErrMsgTxt). - -When a MEX function is interrupted, resources (memory blocks or -objects) whose ownership was transferred from VLFeat to the MEX -function may be leaked. Notice that interrupting a MEX function would -similarly leak any memory block allocated within the MEX function. To -solve this issue, MATLAB provides his own memory manager (@c -mxMalloc, @c mxRealloc, ...). When a MEX file is interrupted or ends, -all memory blocks allocated by using one of such functions are -released, preventing leakage. - -In order to integrate VLFeat with this model in the most seamless -way, VLFeat memory allocation functions (::vl_malloc, ::vl_realloc, -::vl_calloc) are mapped to the corresponding MEX memory allocation -functions. Such functions automatically dispose of all the memory -allocated by a MEX function when the function ends (even because of -an exception). Because of the restrictions of the library design -illustrated in @ref resources, this operation is safe and -correctly dispose of VLFeat local state. As a consequence, it is -possible to call @c mexErrMsgTxt at any point in the MEX function -without worrying about leaking resources. - -This however comes at the price of some limitations. Beyond the -restrictions illustrated in @ref resources, here we note that no -VLFeat local resource (memory blocks or objects) can persist across -MEX file invocations. This implies that any result produced by a -VLFeat MEX function must be converted back to a MATLAB object such as -a vector or a structure. In particular, there is no direct way of -creating an object within a MEX file, returning it to MATLAB, and -passing it again to another MEX file. -**/ - -/** - -@page metaprogram Preprocessor metaprogramming -@author Andrea Vedaldi - - -Part of VLFeat code uses a simple form of preprocessor metaprogramming. -This technique is used, similarly to C++ templates, to instantiate -multiple version of a given algorithm for different data types -(e.g. @c float and @c double). - -In most cases preprocessor metaprogramming is invisible to the library -user, as it is used only internally. -**/ - -/** - -@page glossary Glossary - - - - Column-major. A M x N matrix A is - stacked with column-major order as the sequence \f$(A_{11}, A_{21}, - \dots, A_{12}, \dots)\f$. More in general, when stacking a multi - dimensional array this indicates that the first index is the one - varying most quickly, with the other followed in the natural order. - - Opaque structure. A structure is opaque if the user is not supposed - to access its member directly, but through appropriate interface functions. - Opaque structures are commonly used to define objects. - - Row-major. A M x N matrix A is - stacked with row-major order as the sequence \f$(A_{11}, A_{12}, - \dots, A_{21}, \dots)\f$. More in general, when stacking a multi - dimensional array this indicates that the last index is the one - varying most quickly, with the other followed in reverse order. - - Feature frame. A feature frame is the geometrical - description of a visual features. For instance, the frame of - a @ref sift.h "SIFT feature" is oriented disk and the frame of - @ref mser.h "MSER feature" is either a compact and connected set or - a disk. - - Feature descriptor. A feature descriptor is a quantity - (usually a vector) which describes compactly the appearance of an - image region (usually corresponding to a feature frame). -**/ - -/** - - -@page dev Developing the library -@tableofcontents - - -This page contains information useful to the developer of VLFeat. - - -@section dev-copy Copyright - - -A short copyright notice is added at the beginning of each file. For -example: - -
-Copyright (C) 2013 Milan Sulc
-Copyright (C) 2012 Daniele Perrone.
-Copyright (C) 2011-13 Andrea Vedaldi.
-All rights reserved.
-
-This file is part of the VLFeat library and is made available under
-the terms of the BSD license (see the COPYING file).
-
- -The copyright of each file is assigned to the authors of the file. -Every author making a substantial contribution to a file should -note its copyright by adding a line to the copyright list with the year -of the modification. Year ranges are acceptable. Lines are never -deleted, only appended, or potentially modified to list -more years. - - -@section dev-style Coding style - - -
    - -
  • Look at existing code before you start. The general rule -is: try to match the style of the existing code as much as -possible.
  • - -
  • No white spaces at the end of lines. White spaces introduce -invisible changes in the code that are however picked up by control -version systems such as Git.
  • - -
  • Descriptive variable names. Most variable names start with -a lower case letter and are capitalized, e.g., @c numElements. Only -the following abbreviations are considered acceptable: @c num. The @c -dimension of a vector is the number of elements it contains (for other -objects that could be a @c size, a @c length, or a @c -numElements). For multi-dimensional arrays, @c dimensions could -indicate the array with each of the @c numDimensions dimensions.
  • - -
  • Short variable names. For indexes in short for loops it is -fine to use short index names such as @c i, @c j, and @c k. For example: -
    -for (i = 0 ; i < numEntries ; ++i) values[i] ++ ;
    -
    -is considered acceptable.
  • - -
  • Function arguments. VLFeat functions that operate on an -object (member functions) should be passed the object address as first -argument; this argument should be called @c self. For example: -
    -   void vl_object_do_something(VlObject *self) ;
    -
    -Multi-dimensional arrays should be specified first by their address, -and then by their dimensions. For example -
    -  void vl_use_array (float * array, vl_size numColumns, vl_size numRows) ; // good
    -  void vl_use_array (vl_size numColumns, vl_size numRows, float * array) ; // bad
    -
    -Arguments that are used as outputs should be specified first (closer to -the left-hand side of an expression). For example -
    - void vl_sum_numbers (float * output, float input1, float input2) ; // good
    - void vl_sum_numbers (float input1, float input2, float * output) ; // bad
    -
    -These rules can be combined. For example -
    - void vl_object_sum_to_array (VlObject * self, float * outArray,
    -        vl_size numColumns, vl_size numRows, float * inArray) ; // good
    -
    -Note that in this case no dimension for @c inArray is specified as it -is assumed that @c numColumns and @c numRows are the dimensions of -both arrays. -
  • -
- - -@subsection dev-style-matlab MATLAB coding style - - -
    -
  • Help messages. Each @c .m file should include a standard -help comment block (accessible from MATLAB @c help() command). -The first line of the block has a space, the name of the function, -4 spaces, and a brief command description. The body of the help -message is indented with 4 spaces. For example -@code -% VL_FUNCTION An example function -% VL_FUNCTION() does nothing. -@endcode -The content HELP message itself should follow MATLAB default style. -For example, rather than giving a list of formal input and output -arguments as often done, one simply shows how to use the function, explaining -along the way the different ways the function can be called and -the format of the parameters. -
  • -
- - -@section dev-doc Documenting the code - - -The VLFeat C library code contains its own in documentation Doxygen format. The -documentation consists in generic pages, such as the @ref index -"index" and the page you are reading, and documentations for each -library module, usually corresponding to a certain header file. - -- **Inline comments.** Inline Doxygen comments are discouraged except - in the documentation of data members of structures. They start with - a capital letter and end with a period. For example: - @code - struct VlExampleStructure { - int aMember ; /\*\*< A useful data member. - } - @endcode - -- **Brief comments.** Brief Doxygen comments starts by a capital - and end with a period. The documentation of all functions start - with a brief comment. - - -@subsection devl-doc-modules Documenting the library modules - - -A library module groups a number of data types and functions that -implement a certain functionality of VLFeat. The documentation of a -library module is generally organized as follows: - -1. A page introducing the module and including a getting started - section (3.g. @ref svm-starting) containing a short tutorial to - quickly familiarize the user with the module (e.g. @ref svm). -2. One or more pages of detailed technical background discussing the - algorithms implemented. These sections are used not just as part of - the C API, but also as documentation for other APIs such as MATLAB - (e.g. @ref svm-fundamentals). -3. One or more pages with the structure and function documentation - (e.g. @ref svm.h). - -More in detail, consider a module called Example Module. Then one would -typically have: - -
    -
  • A header or declaration file @c example-module.h. Such a file has an -heading of the type: - -@verbinclude example-module-doc.h - -This comment block contains a file directive, causing the file to be -included in the documentation, a brief directive, specifying a short -description of what the file is, and a list of authors. A -(non-Doxygen) comment block with a short the copyright notice follows. -The brief directive should include a @@ref directive to point -to the main documentation page describing the module, if there is one. -
  • - -
  • An implementation or definition file @c example-module.c. This file -has an heading of the type: - -@verbinclude example-module-doc.c - -This is similar to the declaration file, except for the content of the -brief comment. -
  • -
- - -@subsection devl-doc-functions Documenting functions - - - -@subsection devl-doc-structures Documenting structures - - - -@subsection devl-doc-structures Documenting objects - - -As seen in @ref objects, VLFeat treats certain structures with -an object-like semantics. Usually, a module defines exactly one such -objects. In this case, the object member functions should be grouped -(by using Doxygen grouping functionality) as - -- **Construct and destroy** for the @c vl_object_new, @c - vl_object_delete and similar member functions. -- **Set parameters** for setter functions. -- **Retrieve parameters and data** for getter functions. -- **Process data** for functions processing data. - - -@subsection devl-doc-bib Bibliographic references - - -Since version 0.9.14, the VLFeat C library documentation makes use of -a proper bibliographic reference in BibTeX format (see the file @c -docsrc/vlfeat.bib). Doxygen uses this file when it sees instances of -the @@cite{xyz} command. Here @c xyz is a BibTeX -key. For example, @c vlfeat.bib file contains the entry: - -
-@@inproceedings{martin97the-det-curve,
-	Author = {A. Martin and G. Doddington and T. Kamm and M. Ordowski and M. Przybocki},
-	Booktitle = {Proc. Conf. on Speech Communication and Technology},
-	Title = {The {DET} curve in assessment of detection task performance},
-	Year = {1997}}
-
- -For example, the Doxygen directive -@@cite{martin97the-det-curve} generates the output -@cite{martin97the-det-curve}, which is a link to the corresponding -entry in the bibliography. - -**/ - -/** - -@file generic.h - - -@page generic General support functionalities -@author Andrea Vedaldi - - -VLFeat contains several support functionalities addressing the C -preprocessors, using multiple threads (including parallel computations), -handling errors, allocating memory, etc. These are described in -the following pages: - -- @subpage resources -- @subpage threads -- @subpage misc -**/ - -/** - - -@page misc Preprocssor, library state, etc. -@author Andrea Vedaldi -@tableofcontents - - - -@section misc-preproc C preprocessor helpers - - -VLFeat provides a few C preprocessor macros of general -utility. These include stringification (::VL_STRINGIFY, -::VL_XSTRINGIFY) and concatenation (::VL_CAT, ::VL_XCAT) of symbols. - - -@section misc-state VLFeat state and configuration parameters - - -VLFeat has some global configuration parameters that can -changed. Changing the configuration is thread unsave -(@ref threads). Use ::vl_set_simd_enabled to toggle the use of -a SIMD unit (Intel SSE code), ::vl_set_alloc_func to change -the memory allocation functions, and ::vl_set_printf_func -to change the logging function. - - -@section misc-error Error handling - - -Some VLFeat functions signal errors in a way similar to the -standard C library. In case of error, a VLFeat function -may return an error code directly, -or an invalid result (for instance a negative file descriptor or a null -pointer). Then ::vl_get_last_error and ::vl_get_last_error_message can be used -to retrieve further details about the error (these functions should be -used right after an error has occurred, before any other VLFeat call). - - -@section misc-memory Memory allocation - - -VLFeat uses the ::vl_malloc, ::vl_realloc, ::vl_calloc and ::vl_free -functions to allocate memory. Normally these functions are mapped to -the underlying standard C library implementations. However -::vl_set_alloc_func can be used to map them to other -implementations. For instance, in MATALB MEX files these functions -are mapped to the MATLAB equivalent which has a garbage collection -mechanism to cope with interruptions during execution. - - -@section misc-logging Logging - - -VLFeat uses the macros ::VL_PRINT and ::VL_PRINTF to print progress -or debug informations. These functions are normally mapped to the @c -printf function of the underlying standard C library. However -::vl_set_printf_func can be used to map it to a different -implementation. For instance, in MATLAB MEX files this function is -mapped to @c mexPrintf. Setting the function to @c NULL disables -logging. - - -@section misc-time Measuring time - - -VLFeat provides ::vl_tic and ::vl_toc as an easy way of measuring -elapsed time. - -**/ - -/** - -@page threads Threading -@tableofcontents - - -VLFeat supports for threaded computations can be used to take advantage -of multi-core architectures. Threading support includes: - -- Supporting using VLFeat functions and objects from multiple threads - simultaneously. This is discussed in @ref threads-multiple. -- Using multiple cores to accelerate computations. This is - discussed in @ref threads-parallel. - - -@section threads-multiple Using VLFeat from multiple threads - - -VLFeat can be used from multiple threads simultaneously if proper -rules are followed. - -- A VLFeat object instance is accessed only from one thread at any - given time. Functions operating on objects (member functions) - are conditionally thread safe: the same function may be called - simultaneously from multiple threads provided that it operates on - different, independent objects. However, modifying the same object - from multiple threads (using the same or different member functions) - is possible only from one thread at any given time, and should - therefore be synchronized. Certain VLFeat objects may contain - features specific to simplify multi-threaded operations - (e.g. ::VlKDForest). -- Thread-safe global functions are used. These include - thread-specific operations such as retrieving the last error by - ::vl_get_last_error and obtaining the thread-specific random number - generator instance by ::vl_get_rand. In these cases, the functions - operate on thread-specific data that VLFeat creates and - maintains. Note in particular that each thread has an independent - default random number generator (as returned by - ::vl_get_rand). VLFeat objects that involve using random numbers - will typically use the random number generator of the thread - currently accessing the object (although an object-specific - generator can be often be specified instead). -- Any other global function is considered non-thread safe and is - accessed exclusively by one thread at a time. A small number of - operations are non-reentrant and affect all threads - simultaneously. These are restricted to changing certain global - configuration parameters, such as the memory allocation functions by - ::vl_set_alloc_func. These operations are not thread safe - and are preferably executed before multiple threads start to operate - with the library. - - -@section threads-parallel Parallel computations - - -VLFeat uses OpenMP to implement parallel computations. Generally, this -means that multiple cores are uses appropriately and transparently, -provided that other multi-threaded parts of the application use OpenMP -and that VLFeat and the application link to the same OpenMP library. -If finer control is required, read on. - -VLFeat functions avoids affecting OpenMP global state, including the -desired number of computational threads, in order to minimize side -effects to the linked application (e.g. MATLAB). Instead, VLFeat -duplicates a few OpenMP control parameters when needed (this approach -is similar to the method used by other libraries such as Intel MKL). - -The maximum number of threads available to the application can be -obtained by ::vl_get_thread_limit (for OpenMP version 3.0 and -greater). This limit is controlled by the OpenMP library (the function -is a wrapper around @c omp_get_thread_limit), which in turn may -determined that based on the number of computational cores or the -value of the @c OMP_THREAD_LIMIT variable when the program is -launched. This value is an upper bound on the number of computation -threads that can be used at any time. - -The maximum number of computational thread that VLFeat should use is -set by ::vl_set_num_threads() and retrieved by ::vl_get_max_threads(). -This number is a target value as well as an upper bound to the number -of threads used by VLFeat. This value is stored in the VLFeat private -state and is not necessarily equal to the corresponding OpenMP state -variable retrieved by calling @c omp_get_max_threads(). @c -vl_set_num_threads(1) disables the use of multiple threads and @c -vl_set_num_threads(0) uses the value returned by the OpenMP call @c -omp_get_max_threads(). The latter value is controlled, for example, by -calling @c omp_set_num_threads() in the application. Note that: - -- @c vl_set_num_threads(0) determines the number of treads using @c - omp_get_max_threads() *when it is called*. Subsequent calls to @c - omp_set_num_threads() will therefore *not* affect the number of - threads used by VLFeat. -- @c vl_set_num_threads(vl_get_thread_limit()) causes VLFeat use all - the available threads, regardless on the number of threads set - within the application by calls to @c omp_set_num_threads(). -- OpenMP may still dynamically decide to use a smaller number of - threads in any specific parallel computation. - -@sa http://software.intel.com/sites/products/documentation/doclib/mkl_sa/11/mkl_userguide_win/GUID-C2295BC8-DD22-466B-94C9-5FAA79D4F56D.htm - http://software.intel.com/sites/products/documentation/doclib/mkl_sa/11/mkl_userguide_win/index.htm#GUID-DEEF0363-2B34-4BAB-87FA-A75DBE842040.htm - http://software.intel.com/sites/products/documentation/hpc/mkl/lin/MKL_UG_managing_performance/Using_Additional_Threading_Control.htm - -**/ - -#include "generic.h" - -#include -#include -#include -#include -#include - -#if defined(VL_OS_WIN) -#include -#else -#include -#endif - -#if ! defined(VL_DISABLE_THREADS) && defined(VL_THREADS_POSIX) -#include -#endif - -#if defined(_OPENMP) -#include -#endif - -/* ---------------------------------------------------------------- */ -/* Global and thread states */ -/* ---------------------------------------------------------------- */ - -/* Thread state */ -typedef struct _VlThreadState -{ - /* errors */ - int lastError ; - char lastErrorMessage [VL_ERR_MSG_LEN] ; - - /* random number generator */ - VlRand rand ; - - /* time */ -#if defined(VL_OS_WIN) - LARGE_INTEGER ticFreq ; - LARGE_INTEGER ticMark ; -#else - clock_t ticMark ; -#endif -} VlThreadState ; - -/* Gobal state */ -typedef struct _VlState -{ - /* The thread state uses either a mutex (POSIX) - or a critical section (Win) */ -#if defined(VL_DISABLE_THREADS) - VlThreadState * threadState ; -#else -#if defined(VL_THREADS_POSIX) - pthread_key_t threadKey ; - pthread_mutex_t mutex ; - pthread_t mutexOwner ; - pthread_cond_t mutexCondition ; - size_t mutexCount ; -#elif defined(VL_THREADS_WIN) - DWORD tlsIndex ; - CRITICAL_SECTION mutex ; -#endif -#endif /* VL_DISABLE_THREADS */ - - /* Configurable functions */ - int (*printf_func) (char const * format, ...) ; - void *(*malloc_func) (size_t) ; - void *(*realloc_func) (void*,size_t) ; - void *(*calloc_func) (size_t, size_t) ; - void (*free_func) (void*) ; - -#if defined(VL_ARCH_IX86) || defined(VL_ARCH_X64) || defined(VL_ARCH_IA64) - VlX86CpuInfo cpuInfo ; -#endif - vl_size numCPUs ; - vl_bool simdEnabled ; - vl_size numThreads ; -} VlState ; - -/* Global state instance */ -VlState _vl_state ; - -/* ----------------------------------------------------------------- */ -VL_INLINE VlState * vl_get_state () ; -VL_INLINE VlThreadState * vl_get_thread_specific_state () ; -static void vl_lock_state (void) ; -static void vl_unlock_state (void) ; -static VlThreadState * vl_thread_specific_state_new (void) ; -static void vl_thread_specific_state_delete (VlThreadState * self) ; - -/** @brief Get VLFeat version string - ** @return the library version string. - **/ - -char const * -vl_get_version_string () -{ - return VL_VERSION_STRING ; -} - -/** @brief Get VLFeat configuration string. - ** @return a new configuration string. - ** - ** The function returns a new string containing a human readable - ** description of the library configuration. - **/ - -char * -vl_configuration_to_string_copy () -{ - char * string = 0 ; - int length = 0 ; - char * staticString = vl_static_configuration_to_string_copy() ; - char * cpuString = -#if defined(VL_ARCH_IX86) || defined(VL_ARCH_X64) || defined(VL_ARCH_IA64) - _vl_x86cpu_info_to_string_copy(&vl_get_state()->cpuInfo) ; -#else - "Generic CPU" ; -#endif -#if defined(DEBUG) - int const debug = 1 ; -#else - int const debug = 0 ; -#endif - - while (string == 0) { - if (length > 0) { - string = vl_malloc(sizeof(char) * length) ; - if (string == NULL) break ; - } - length = snprintf(string, length, - "VLFeat version %s\n" - " Static config: %s\n" - " %" VL_FMT_SIZE " CPU(s): %s\n" -#if defined(_OPENMP) - " OpenMP: max threads: %d (library: %" VL_FMT_SIZE ")\n" -#endif - " Debug: %s\n", - vl_get_version_string (), - staticString, - vl_get_num_cpus(), cpuString, -#if defined(_OPENMP) - omp_get_max_threads(), vl_get_max_threads(), -#endif - VL_YESNO(debug)) ; - length += 1 ; - } - - if (staticString) vl_free(staticString) ; - if (cpuString) vl_free(cpuString) ; - return string ; -} - -/** @internal @brief A printf that does not do anything */ -static int -do_nothing_printf (char const* format VL_UNUSED, ...) -{ - return 0 ; -} - -/** @internal - ** @brief Lock VLFeat state - ** - ** The function locks VLFeat global state mutex. - ** - ** The mutex is recursive: locking multiple times from the same thread - ** is a valid operations, but requires an equivalent number - ** of calls to ::vl_unlock_state. - ** - ** @sa ::vl_unlock_state - **/ - -static void -vl_lock_state (void) -{ -#if ! defined(VL_DISABLE_THREADS) -#if defined(VL_THREADS_POSIX) - VlState * state = vl_get_state () ; - pthread_t thisThread = pthread_self () ; - pthread_mutex_lock (&state->mutex) ; - if (state->mutexCount >= 1 && - pthread_equal (state->mutexOwner, thisThread)) { - state->mutexCount ++ ; - } else { - while (state->mutexCount >= 1) { - pthread_cond_wait (&state->mutexCondition, &state->mutex) ; - } - state->mutexOwner = thisThread ; - state->mutexCount = 1 ; - } - pthread_mutex_unlock (&state->mutex) ; -#elif defined(VL_THREADS_WIN) - EnterCriticalSection (&vl_get_state()->mutex) ; -#endif -#endif -} - -/** @internal - ** @brief Unlock VLFeat state - ** - ** The function unlocks VLFeat global state mutex. - ** - ** @sa ::vl_lock_state - **/ - -static void -vl_unlock_state (void) -{ -#if ! defined(VL_DISABLE_THREADS) -#if defined(VL_THREADS_POSIX) - VlState * state = vl_get_state () ; - pthread_mutex_lock (&state->mutex) ; - -- state->mutexCount ; - if (state->mutexCount == 0) { - pthread_cond_signal (&state->mutexCondition) ; - } - pthread_mutex_unlock (&state->mutex) ; -#elif defined(VL_THREADS_WIN) - LeaveCriticalSection (&vl_get_state()->mutex) ; -#endif -#endif -} - -/** @internal - ** @brief Return VLFeat global state - ** - ** The function returns a pointer to VLFeat global state. - ** - ** @return pointer to the global state structure. - **/ - -VL_INLINE VlState * -vl_get_state (void) -{ - return &_vl_state ; -} - -/** @internal@brief Get VLFeat thread state - ** @return pointer to the thread state structure. - ** - ** The function returns a pointer to VLFeat thread state. - **/ - -VL_INLINE VlThreadState * -vl_get_thread_specific_state (void) -{ -#ifdef VL_DISABLE_THREADS - return vl_get_state()->threadState ; -#else - VlState * state ; - VlThreadState * threadState ; - - vl_lock_state() ; - state = vl_get_state() ; - -#if defined(VL_THREADS_POSIX) - threadState = (VlThreadState *) pthread_getspecific(state->threadKey) ; -#elif defined(VL_THREADS_WIN) - threadState = (VlThreadState *) TlsGetValue(state->tlsIndex) ; -#endif - - if (! threadState) { - threadState = vl_thread_specific_state_new () ; - } - -#if defined(VL_THREADS_POSIX) - pthread_setspecific(state->threadKey, threadState) ; -#elif defined(VL_THREADS_WIN) - TlsSetValue(state->tlsIndex, threadState) ; -#endif - - vl_unlock_state() ; - return threadState ; -#endif -} - -/* ---------------------------------------------------------------- */ -/** @brief Get the number of CPU cores of the host - ** @return number of CPU cores. - **/ - -vl_size -vl_get_num_cpus (void) -{ - return vl_get_state()->numCPUs ; -} - -/** @fn ::vl_set_simd_enabled(vl_bool) - ** @brief Toggle usage of SIMD instructions - ** @param x @c true if SIMD instructions are used. - ** - ** Notice that SIMD instructions are used only if the CPU model - ** supports them. Note also that data alignment may restrict the use - ** of such instructions. - ** - ** @see ::vl_cpu_has_sse2(), ::vl_cpu_has_sse3(), etc. - **/ - -void -vl_set_simd_enabled (vl_bool x) -{ - vl_get_state()->simdEnabled = x ; -} - -/** @brief Are SIMD instructons enabled? - ** @return @c true if SIMD instructions are enabled. - **/ - -vl_bool -vl_get_simd_enabled (void) -{ - return vl_get_state()->simdEnabled ; -} - -/** @brief Check for AVX instruction set - ** @return @c true if AVX is present. - **/ - -vl_bool -vl_cpu_has_avx (void) -{ -#if defined(VL_ARCH_IX86) || defined(VL_ARCH_X64) || defined(VL_ARCH_IA64) - return vl_get_state()->cpuInfo.hasAVX ; -#else - return VL_FALSE ; -#endif -} - -/** @brief Check for SSE3 instruction set - ** @return @c true if SSE3 is present. - **/ - -vl_bool -vl_cpu_has_sse3 (void) -{ -#if defined(VL_ARCH_IX86) || defined(VL_ARCH_X64) || defined(VL_ARCH_IA64) - return vl_get_state()->cpuInfo.hasSSE3 ; -#else - return VL_FALSE ; -#endif -} - -/** @brief Check for SSE2 instruction set - ** @return @c true if SSE2 is present. - **/ - -vl_bool -vl_cpu_has_sse2 (void) -{ -#if defined(VL_ARCH_IX86) || defined(VL_ARCH_X64) || defined(VL_ARCH_IA64) - return vl_get_state()->cpuInfo.hasSSE2 ; -#else - return VL_FALSE ; -#endif -} - -/* ---------------------------------------------------------------- */ - -/** @brief Get the number of computational threads available to the application - ** @return number of threads. - ** - ** This function wraps the OpenMP function @c - ** omp_get_thread_limit(). If VLFeat was compiled without OpenMP - ** support, this function returns 1. If VLFeat was compiled with - ** OpenMP prior to version 3.0 (2008/05), it returns 0. - ** - ** @sa @ref threads-parallel - **/ - -vl_size -vl_get_thread_limit (void) -{ -#if defined(_OPENMP) -#if _OPENMP >= 200805 - /* OpenMP version >= 3.0 */ - return omp_get_thread_limit() ; -#else - return 0 ; -#endif -#else - return 1 ; -#endif -} - -/** @brief Get the maximum number of computational threads used by VLFeat. - ** @return number of threads. - ** - ** This function returns the maximum number of thread used by - ** VLFeat. VLFeat will try to use this number of computational - ** threads and never exceed it. - ** - ** This is similar to the OpenMP function @c omp_get_max_threads(); - ** however, it reads a parameter private to VLFeat which is - ** independent of the value used by the OpenMP library. - ** - ** If VLFeat was compiled without OpenMP support, this function - ** returns 1. - ** - ** @sa vl_set_num_threads(), @ref threads-parallel - **/ - -vl_size -vl_get_max_threads (void) -{ -#if defined(_OPENMP) - return vl_get_state()->numThreads ; -#else - return 1 ; -#endif -} - -/** @brief Set the maximum number of threads used by VLFeat. - ** @param numThreads number of threads to use. - ** - ** This function sets the maximum number of computational threads - ** that will be used by VLFeat. VLFeat may in practice use fewer - ** threads (for example because @a numThreads is larger than the - ** number of computational cores in the host, or because the number - ** of threads exceeds the limit available to the application). - ** - ** If @c numThreads is set to 0, then VLFeat sets the number of - ** threads to the OpenMP current maximum, obtained by calling @c - ** omp_get_max_threads(). - ** - ** This function is similar to @c omp_set_num_threads() but changes a - ** parameter internal to VLFeat rather than affecting OpenMP global - ** state. - ** - ** If VLFeat was compiled without, this function does nothing. - ** - ** @sa vl_get_max_threads(), @ref threads-parallel - **/ - -#if defined(_OPENMP) -void -vl_set_num_threads (vl_size numThreads) -{ - if (numThreads == 0) { - numThreads = omp_get_max_threads() ; - } - vl_get_state()->numThreads = numThreads ; -} -#else -void -vl_set_num_threads (vl_size numThreads VL_UNUSED) { } -#endif - -/* ---------------------------------------------------------------- */ -/** @brief Set last VLFeat error - ** @param error error code. - ** @param errorMessage error message format string. - ** @param ... format string arguments. - ** @return error code. - ** - ** The function sets the code and optionally the error message - ** of the last encountered error. @a errorMessage is the message - ** format. It uses the @c printf convention and is followed by - ** the format arguments. The maximum length of the error message is - ** given by ::VL_ERR_MSG_LEN (longer messages are truncated). - ** - ** Passing @c NULL as @a errorMessage - ** sets the error message to the empty string. - **/ - -int -vl_set_last_error (int error, char const * errorMessage, ...) -{ - VlThreadState * state = vl_get_thread_specific_state() ; - va_list args; - va_start(args, errorMessage) ; - if (errorMessage) { -#ifdef VL_COMPILER_LCC - vsprintf(state->lastErrorMessage, errorMessage, args) ; -#else - vsnprintf(state->lastErrorMessage, - sizeof(state->lastErrorMessage)/sizeof(char), - errorMessage, args) ; -#endif - } else { - state->lastErrorMessage[0] = 0 ; - } - state->lastError = error ; - va_end(args) ; - return error ; -} - -/** @brief Get the code of the last error - ** @return error code. - ** @sa ::vl_get_last_error_message. - **/ - -int -vl_get_last_error (void) { - return vl_get_thread_specific_state()->lastError ; -} - -/** @brief Get the last error message - ** @return pointer to the error message. - ** @sa ::vl_get_last_error. - **/ - -char const * -vl_get_last_error_message (void) -{ - return vl_get_thread_specific_state()->lastErrorMessage ; -} - -/* ---------------------------------------------------------------- */ -/** @brief Set memory allocation functions - ** @param malloc_func pointer to @c malloc. - ** @param realloc_func pointer to @c realloc. - ** @param calloc_func pointer to @c calloc. - ** @param free_func pointer to @c free. - **/ - -void -vl_set_alloc_func (void *(*malloc_func) (size_t), - void *(*realloc_func) (void*, size_t), - void *(*calloc_func) (size_t, size_t), - void (*free_func) (void*)) -{ - VlState * state ; - vl_lock_state () ; - state = vl_get_state() ; - state->malloc_func = malloc_func ; - state->realloc_func = realloc_func ; - state->calloc_func = calloc_func ; - state->free_func = free_func ; - vl_unlock_state () ; -} - -/** @brief Allocate a memory block - ** @param n size in bytes of the new block. - ** @return pointer to the allocated block. - ** - ** This function allocates a memory block of the specified size. - ** The synopsis is the same as the POSIX @c malloc function. - **/ - -void * -vl_malloc (size_t n) -{ - return (vl_get_state()->malloc_func)(n) ; - //return (memalign)(32,n) ; -} - - -/** @brief Reallocate a memory block - ** @param ptr pointer to a memory block previously allocated. - ** @param n size in bytes of the new block. - ** @return pointer to the new block. - ** - ** This function reallocates a memory block to change its size. - ** The synopsis is the same as the POSIX @c realloc function. - **/ - -void * -vl_realloc (void* ptr, size_t n) -{ - return (vl_get_state()->realloc_func)(ptr, n) ; -} - -/** @brief Free and clear a memory block - ** @param n number of items to allocate. - ** @param size size in bytes of an item. - ** @return pointer to the new block. - ** - ** This function allocates and clears a memory block. - ** The synopsis is the same as the POSIX @c calloc function. - **/ - -void * -vl_calloc (size_t n, size_t size) -{ - return (vl_get_state()->calloc_func)(n, size) ; -} - -/** @brief Free a memory block - ** @param ptr pointer to the memory block. - ** - ** This function frees a memory block allocated by ::vl_malloc, - ** ::vl_calloc, or ::vl_realloc. The synopsis is the same as the POSIX - ** @c malloc function. - **/ - -void -vl_free (void *ptr) -{ - (vl_get_state()->free_func)(ptr) ; -} - -/* ---------------------------------------------------------------- */ - -/** @brief Set the printf function - ** @param printf_func pointer to a @c printf implementation. - ** Set @c print_func to NULL to disable printf. - **/ - -void -vl_set_printf_func (printf_func_t printf_func) -{ - vl_get_state()->printf_func = printf_func ? printf_func : do_nothing_printf ; -} - -/** @brief Get the printf function - ** @return printf_func pointer to the @c printf implementation. - ** @sa ::vl_set_printf_func. - **/ - -printf_func_t -vl_get_printf_func (void) { - return vl_get_state()->printf_func ; -} - -/* ---------------------------------------------------------------- */ -/** @brief Get processor time - ** @return processor time in seconds. - ** @sa ::vl_tic, ::vl_toc - **/ - -double -vl_get_cpu_time () -{ - #ifdef VL_OS_WIN - VlThreadState * threadState = vl_get_thread_specific_state() ; - LARGE_INTEGER mark ; - QueryPerformanceCounter (&mark) ; - return (double)mark.QuadPart / (double)threadState->ticFreq.QuadPart ; -#else - return (double)clock() / (double)CLOCKS_PER_SEC ; -#endif -} - -/** @brief Reset processor time reference - ** The function resets VLFeat TIC/TOC time reference. There is one - ** such reference per thread. - ** @sa ::vl_get_cpu_time, ::vl_toc. - **/ - -void -vl_tic (void) -{ - VlThreadState * threadState = vl_get_thread_specific_state() ; -#ifdef VL_OS_WIN - QueryPerformanceCounter (&threadState->ticMark) ; -#else - threadState->ticMark = clock() ; -#endif -} - -/** @brief Get elapsed time since tic - ** @return elapsed time in seconds. - ** - ** The function - ** returns the processor time elapsed since ::vl_tic was called last. - ** - ** @remark In multi-threaded applications, there is an independent - ** timer for each execution thread. - ** - ** @remark On UNIX, this function uses the @c clock() system call. - ** On Windows, it uses the @c QueryPerformanceCounter() system call, - ** which is more accurate than @c clock() on this platform. - **/ - -double -vl_toc (void) -{ - VlThreadState * threadState = vl_get_thread_specific_state() ; -#ifdef VL_OS_WIN - LARGE_INTEGER tocMark ; - QueryPerformanceCounter(&tocMark) ; - return (double) (tocMark.QuadPart - threadState->ticMark.QuadPart) / - threadState->ticFreq.QuadPart ; -#else - return (double) (clock() - threadState->ticMark) / CLOCKS_PER_SEC ; -#endif -} - -/* ---------------------------------------------------------------- */ -/** @brief Get the default random number generator. - ** @return random number generator. - ** - ** The function returns a pointer to the default - ** random number generator. - ** There is one such generator per thread. - **/ - -VL_EXPORT VlRand * -vl_get_rand (void) -{ - return &vl_get_thread_specific_state()->rand ; -} - -/* ---------------------------------------------------------------- */ -/* Library construction and destruction routines */ -/* --------------------------------------------------------------- */ - -/** @internal@brief Construct a new thread state object - ** @return new state structure. - **/ - -static VlThreadState * -vl_thread_specific_state_new (void) -{ - VlThreadState * self ; -#if defined(DEBUG) - printf("VLFeat DEBUG: thread constructor begins.\n") ; -#endif - self = malloc(sizeof(VlThreadState)) ; - self->lastError = 0 ; - self->lastErrorMessage[0] = 0 ; -#if defined(VL_OS_WIN) - QueryPerformanceFrequency (&self->ticFreq) ; - self->ticMark.QuadPart = 0 ; -#else - self->ticMark = 0 ; -#endif - vl_rand_init (&self->rand) ; - - return self ; -} - -/** @internal@brief Delete a thread state structure - ** @param self thread state object. - **/ - -static void -vl_thread_specific_state_delete (VlThreadState * self) -{ -#if defined(DEBUG) - printf("VLFeat DEBUG: thread destructor begins.\n") ; -#endif - free (self) ; -} - -/* ---------------------------------------------------------------- */ -/* Library constructor and destructor */ -/* ---------------------------------------------------------------- */ - -/** @internal @brief Initialize VLFeat state */ -void -vl_constructor (void) -{ - VlState * state ; -#if defined(DEBUG) - printf("VLFeat DEBUG: constructor begins.\n") ; -#endif - - state = vl_get_state() ; - -#if ! defined(VL_DISABLE_THREADS) -#if defined(DEBUG) - printf("VLFeat DEBUG: constructing thread specific state.\n") ; -#endif -#if defined(VL_THREADS_POSIX) - { - typedef void (*destructorType)(void * ); - pthread_key_create (&state->threadKey, - (destructorType) - vl_thread_specific_state_delete) ; - pthread_mutex_init (&state->mutex, NULL) ; - pthread_cond_init (&state->mutexCondition, NULL) ; - } -#elif defined(VL_THREADS_WIN) - InitializeCriticalSection (&state->mutex) ; - state->tlsIndex = TlsAlloc () ; -#endif -#else - -/* threading support disabled */ -#if defined(DEBUG) - printf("VLFeat DEBUG: constructing the generic thread state instance (threading support disabled).\n") ; -#endif - vl_get_state()->threadState = vl_thread_specific_state_new() ; -#endif - - state->malloc_func = malloc ; - state->realloc_func = realloc ; - state->calloc_func = calloc ; - state->free_func = free ; - state->printf_func = printf ; - - /* on x86 platforms read the CPUID register */ -#if defined(VL_ARCH_IX86) || defined(VL_ARCH_X64) || defined(VL_ARCH_IA64) - _vl_x86cpu_info_init (&state->cpuInfo) ; -#endif - - /* get the number of CPUs */ -#if defined(VL_OS_WIN) - { - SYSTEM_INFO info; - GetSystemInfo (&info) ; - state->numCPUs = info.dwNumberOfProcessors ; - } -#elif defined(_SC_NPROCESSORS_ONLN) - state->numCPUs = sysconf(_SC_NPROCESSORS_ONLN) ; -#else - state->numCPUs = 1 ; -#endif - state->simdEnabled = VL_TRUE ; - - /* get the number of (OpenMP) threads used by the library */ -#if defined(_OPENMP) - state->numThreads = omp_get_max_threads() ; -#else - state->numThreads = 1 ; -#endif - -#if defined(DEBUG) - printf("VLFeat DEBUG: constructor ends.\n") ; -#endif -} - -/** @internal @brief Destruct VLFeat */ -void -vl_destructor () -{ - VlState * state ; -#if defined(DEBUG) - printf("VLFeat DEBUG: destructor begins.\n") ; -#endif - - state = vl_get_state() ; - -#if ! defined(VL_DISABLE_THREADS) -#if defined(DEBUG) - printf("VLFeat DEBUG: destroying a thread specific state instance.\n") ; -#endif -#if defined(VL_THREADS_POSIX) - { - /* Delete the thread state of this thread as the - destructor is not called by pthread_key_delete or after - the key is deleted. When the library - is unloaded, this thread should also be the last one - using the library, so this is fine. - */ - VlThreadState * threadState = - pthread_getspecific(state->threadKey) ; - if (threadState) { - vl_thread_specific_state_delete (threadState) ; - pthread_setspecific(state->threadKey, NULL) ; - } - } - pthread_cond_destroy (&state->mutexCondition) ; - pthread_mutex_destroy (&state->mutex) ; - pthread_key_delete (state->threadKey) ; -#elif defined(VL_THREADS_WIN) - { - /* Delete the thread state of this thread as the - destructor is not called by pthread_key_delete or after - the key is deleted. When the library - is unloaded, this thread should also be the last one - using the library, so this is fine. - */ - VlThreadState * threadState = - TlsGetValue(state->tlsIndex) ; - if (threadState) { - vl_thread_specific_state_delete (threadState) ; - TlsSetValue(state->tlsIndex, NULL) ; - } - } - TlsFree (state->tlsIndex) ; - DeleteCriticalSection (&state->mutex) ; -#endif -#else -#if defined(DEBUG) - printf("VLFeat DEBUG: destroying the generic thread state instance (threading support disabled).\n") ; -#endif - vl_thread_specific_state_delete(vl_get_state()->threadState) ; -#endif - -#if defined(DEBUG) - printf("VLFeat DEBUG: destructor ends.\n") ; -#endif -} - -/* ---------------------------------------------------------------- */ -/* Cross-platform call to constructor/destructor */ -/* ---------------------------------------------------------------- */ - -#ifdef __cplusplus - #define INITIALIZER(f) \ - static void f(void); \ - struct f##_t_ { f##_t_(void) { f(); } }; static f##_t_ f##_; \ - static void f(void) -#elif defined(_MSC_VER) - #pragma section(".CRT$XCU",read) - #define INITIALIZER2_(f,p) \ - static void f(void); \ - __declspec(allocate(".CRT$XCU")) void (*f##_)(void) = f; \ - __pragma(comment(linker,"/include:" p #f "_")) \ - static void f(void) - #ifdef _WIN64 - #define INITIALIZER(f) INITIALIZER2_(f,"") - #else - #define INITIALIZER(f) INITIALIZER2_(f,"_") - #endif -#else - #define INITIALIZER(f) \ - static void f(void) __attribute__((constructor)); \ - static void f(void) -#endif - -INITIALIZER(vl_initialize) -{ - vl_constructor(); - atexit(vl_destructor); -} - diff --git a/opensfm/src/third_party/vlfeat/vl/generic.h b/opensfm/src/third_party/vlfeat/vl/generic.h deleted file mode 100644 index 4a6296e8c..000000000 --- a/opensfm/src/third_party/vlfeat/vl/generic.h +++ /dev/null @@ -1,213 +0,0 @@ -/** @file generic.h - ** @brief Generic (@ref generic) - ** @author Andrea Vedaldi - **/ - -/* -Copyright (C) 2013 Andrea Vedaldi. -Copyright (C) 2007-12 Andrea Vedaldi and Brian Fulkerson. -All rights reserved. - -This file is part of the VLFeat library and is made available under -the terms of the BSD license (see the COPYING file). -*/ - -#ifndef VL_GENERIC_H -#define VL_GENERIC_H - -#include "host.h" -#include "random.h" - -#include -#include -#include -#include - -/** @brief Library version string */ -#define VL_VERSION_STRING "0.9.20" - -/** @brief Maximum length (in characters) of an error message */ -#define VL_ERR_MSG_LEN 1024 - -/** @name Type identifiers for atomic data types - ** @{ */ - -#define VL_TYPE_FLOAT 1 /**< @c float type */ -#define VL_TYPE_DOUBLE 2 /**< @c double type */ -#define VL_TYPE_INT8 3 /**< @c ::vl_int8 type */ -#define VL_TYPE_UINT8 4 /**< @c ::vl_uint8 type */ -#define VL_TYPE_INT16 5 /**< @c ::vl_int16 type */ -#define VL_TYPE_UINT16 6 /**< @c ::vl_uint16 type */ -#define VL_TYPE_INT32 7 /**< @c ::vl_int32 type */ -#define VL_TYPE_UINT32 8 /**< @c ::vl_uint32 type */ -#define VL_TYPE_INT64 9 /**< @c ::vl_int64 type */ -#define VL_TYPE_UINT64 10 /**< @c ::vl_uint64 type */ - -typedef vl_uint32 vl_type ; - -/** @brief Get the name of a data type. - ** @param type data type. - ** @return data name of the data type. - ** - ** @c type is one of ::VL_TYPE_FLOAT, ::VL_TYPE_DOUBLE, - ** ::VL_TYPE_INT8, ::VL_TYPE_INT16, ::VL_TYPE_INT32, ::VL_TYPE_INT64, - ** ::VL_TYPE_UINT8, ::VL_TYPE_UINT16, ::VL_TYPE_UINT32, ::VL_TYPE_UINT64. - **/ - -void vl_constructor(); -void vl_destructor(); - -VL_INLINE char const * -vl_get_type_name (vl_type type) -{ - switch (type) { - case VL_TYPE_FLOAT : return "float" ; - case VL_TYPE_DOUBLE : return "double" ; - case VL_TYPE_INT8 : return "int8" ; - case VL_TYPE_INT16 : return "int16" ; - case VL_TYPE_INT32 : return "int32" ; - case VL_TYPE_INT64 : return "int64" ; - case VL_TYPE_UINT8 : return "int8" ; - case VL_TYPE_UINT16 : return "int16" ; - case VL_TYPE_UINT32 : return "int32" ; - case VL_TYPE_UINT64 : return "int64" ; - default: return NULL ; - } -} - -/** @brief Get data type size. - ** @param type data type. - ** @return size (in byte) - ** - ** @c type is one of ::VL_TYPE_FLOAT, ::VL_TYPE_DOUBLE, - ** ::VL_TYPE_INT8, ::VL_TYPE_INT16, ::VL_TYPE_INT32, ::VL_TYPE_INT64, - ** ::VL_TYPE_UINT8, ::VL_TYPE_UINT16, ::VL_TYPE_UINT32, ::VL_TYPE_UINT64. - **/ - -VL_INLINE vl_size -vl_get_type_size (vl_type type) -{ - vl_size dataSize = 0 ; - switch (type) { - case VL_TYPE_DOUBLE : dataSize = sizeof(double) ; break ; - case VL_TYPE_FLOAT : dataSize = sizeof(float) ; break ; - case VL_TYPE_INT64 : case VL_TYPE_UINT64 : dataSize = sizeof(vl_int64) ; break ; - case VL_TYPE_INT32 : case VL_TYPE_UINT32 : dataSize = sizeof(vl_int32) ; break ; - case VL_TYPE_INT16 : case VL_TYPE_UINT16 : dataSize = sizeof(vl_int16) ; break ; - case VL_TYPE_INT8 : case VL_TYPE_UINT8 : dataSize = sizeof(vl_int8) ; break ; - default: - abort() ; - } - return dataSize ; -} -/** @} */ - -VL_EXPORT char const * vl_get_version_string (void) ; -VL_EXPORT char * vl_configuration_to_string_copy (void) ; -VL_EXPORT void vl_set_simd_enabled (vl_bool x) ; -VL_EXPORT vl_bool vl_get_simd_enabled (void) ; -VL_EXPORT vl_bool vl_cpu_has_avx (void) ; -VL_EXPORT vl_bool vl_cpu_has_sse3 (void) ; -VL_EXPORT vl_bool vl_cpu_has_sse2 (void) ; -VL_EXPORT vl_size vl_get_num_cpus (void) ; -VL_EXPORT VlRand * vl_get_rand (void) ; - -/** @name Multi-thread computations - ** @{ */ -VL_EXPORT vl_size vl_get_max_threads (void) ; -VL_EXPORT void vl_set_num_threads (vl_size n) ; -VL_EXPORT vl_size vl_get_thread_limit (void) ; -/** @} (*/ - -/** ------------------------------------------------------------------ - ** @name Error handling - ** @{ */ -#define VL_ERR_OK 0 /**< No error */ -#define VL_ERR_OVERFLOW 1 /**< Buffer overflow error */ -#define VL_ERR_ALLOC 2 /**< Resource allocation error */ -#define VL_ERR_BAD_ARG 3 /**< Bad argument or illegal data error */ -#define VL_ERR_IO 4 /**< Input/output error */ -#define VL_ERR_EOF 5 /**< End-of-file or end-of-sequence error */ -#define VL_ERR_NO_MORE 5 /**< End-of-sequence @deprecated */ - -VL_EXPORT int vl_get_last_error (void) ; -VL_EXPORT char const * vl_get_last_error_message (void) ; -VL_EXPORT int vl_set_last_error (int error, char const * errorMessage, ...) ; -/** @} */ - -/** ------------------------------------------------------------------ - ** @name Memory allocation - ** @{ */ -VL_EXPORT void -vl_set_alloc_func (void *(*malloc_func) (size_t), - void *(*realloc_func) (void*,size_t), - void *(*calloc_func) (size_t, size_t), - void (*free_func) (void*)) ; -VL_EXPORT void *vl_malloc (size_t n) ; -VL_EXPORT void *vl_realloc (void *ptr, size_t n) ; -VL_EXPORT void *vl_calloc (size_t n, size_t size) ; -VL_EXPORT void *vl_memalign (size_t n, size_t size) ; -VL_EXPORT void vl_free (void* ptr) ; -/** @} */ - -/** ------------------------------------------------------------------ - ** @name Logging - ** @{ */ -/** @brief Customizable printf function pointer type */ -typedef int(*printf_func_t) (char const *format, ...) ; -VL_EXPORT void vl_set_printf_func (printf_func_t printf_func) ; -VL_EXPORT printf_func_t vl_get_printf_func (void) ; - -/** @def VL_PRINTF - ** @brief Call user-customizable @c printf function - ** - ** The function calls the user customizable @c printf. - **/ - -/** @def VL_PRINT - ** @brief Same as ::VL_PRINTF (legacy code) - **/ - -#define VL_PRINTF (*vl_get_printf_func()) -#define VL_PRINT (*vl_get_printf_func()) -/** @} */ - -/** ------------------------------------------------------------------ - ** @name Common operations - ** @{ */ - -/** @brief Compute the minimum between two values - ** @param x value - ** @param y value - ** @return the minimum of @a x and @a y. - **/ -#define VL_MIN(x,y) (((x)<(y))?(x):(y)) - -/** @brief Compute the maximum between two values - ** @param x value. - ** @param y value. - ** @return the maximum of @a x and @a y. - **/ -#define VL_MAX(x,y) (((x)>(y))?(x):(y)) - -/** @brief Signed left shift operation - ** @param x value. - ** @param n number of shift positions. - ** @return @c x << n . - ** The macro is equivalent to the builtin @c << operator, but it - ** supports negative shifts too. - **/ -#define VL_SHIFT_LEFT(x,n) (((n)>=0)?((x)<<(n)):((x)>>-(n))) -/* @} */ - -/** ------------------------------------------------------------------ - ** @name Measuring time - ** @{ - **/ -VL_EXPORT void vl_tic (void) ; -VL_EXPORT double vl_toc (void) ; -VL_EXPORT double vl_get_cpu_time (void) ; -/** @} */ - -/* VL_GENERIC_H */ -#endif diff --git a/opensfm/src/third_party/vlfeat/vl/getopt_long.c b/opensfm/src/third_party/vlfeat/vl/getopt_long.c deleted file mode 100644 index 0e860f386..000000000 --- a/opensfm/src/third_party/vlfeat/vl/getopt_long.c +++ /dev/null @@ -1,326 +0,0 @@ -/** @file getopt_long.c - ** @brief getopt_long - Definition - ** @author Andrea Vedaldi - **/ - -/* -Copyright (C) 2007-12 Andrea Vedaldi and Brian Fulkerson. -All rights reserved. - -This file is part of the VLFeat library and is made available under -the terms of the BSD license (see the COPYING file). -*/ - -/** -@file getopt_long.h -@brief getopt_long -@author Andrea Vedaldi - -This is a drop-in replacament of GNU getopt_long meant to be used -on platforms that do not support such functionality. -**/ - -#include -#include -#include - -#include "generic.h" -#include "getopt_long.h" - -int opterr = 1 ; -int optind = 1 ; -int optopt ; -char * optarg ; -int optreset ; - -#define BADCH '?' -#define BADARG ':' -#define EEND -1 -#define EMSG "" - -/** @brief Parse long options (BSD style) - ** @param argc number of arguments. - ** @param argv pointer to the vector of arguments. - ** @param optstring list of abbreviated options - ** @param longopts list of long options. - ** @param longindex index of current option in @a longopts. - ** @return the code of the next option. - ** - ** This function extract long and short options from the argument - ** list @a argv of @a argc entries. - ** - ** A short options sequence is introduced by a single dash character - ** @c -. Each short option is described by a single character in the - ** string @a optstring, possibly followed by a @c : character to - ** denote a (mandatory) argument of the short option. A short option - ** with an argument cannot appear in the middle of a short option - ** sequence, but only at the end. - ** - ** A long option is introduced by a double dash @c --. Each long - ** option is described by an instance of the ::option structure in - ** the @a longopts table (the last entry must be filled with zeroes - ** to denote the end). - ** - ** Illegal options and missing arguments cause the function to skip - ** the option and return '?'. If ::opterr is @c true (default), the - ** function prints an error message to @a stderr. Finally, if @a - ** optstring has a leading @c :, then error messages are suppressed - ** and a missing argument causes @a : to be returned. - ** - ** @remark The function is currently not thread safe. - **/ - -VL_EXPORT int -getopt_long(int argc, char *const argv[], - const char *optstring, - const struct option * longopts, - int *longindex) -{ - static char *place = EMSG; /* option letter processing */ - static int optbegin = 0 ; - static int optend = 0 ; - char *oli; /* option letter list index */ - int has_colon = 0 ; - int ret_val = 0 ; - - /* - A semicolon at the beginning of optstring has a special meaning. - If we find one, we annote and remove it. - */ - has_colon = optstring && optstring[0] == ':' ; - if (has_colon) ++ optstring ; - - /* - Here we are either processing a short option sequence or - we start processing a new option. This is indicated by optreset. - */ - - if (optreset || *place == '\0') { - - /* --------------------------------------------------------------- - * Look for next short/long option - * ------------------------------------------------------------ */ - optreset = 0 ; - - /* no more arguments ? */ - if (optind >= argc) { - place = EMSG ; - return -1 ; - } - - /* next argument that may hold an option */ - optbegin = optind ; - - /* --------------------------------------------------------------- - * Look for an option to parse - * ------------------------------------------------------------ */ - - parse_option_at_optbegin : - - /* place points to the candidate option */ - place = argv [optbegin] ; - - /* an option is introduced by '-' */ - if (place [0] != '-') { - /* this argument is not an option: try next argument */ - ++ optbegin ; - if (optbegin >= argc) { - /* no more arguments to look for options */ - place = EMSG ; - return -1 ; - } - goto parse_option_at_optbegin ; - } - - /* consume leading `-' */ - ++ place ; - - /* assume the option is composed of one argument only */ - optend = optbegin + 1 ; - - /* assume no argument */ - optarg = 0 ; - - /* --------------------------------------------------------------- - * option `--' - * ------------------------------------------------------------ */ - - /* this special option (void long option) ends the option processing */ - if (place[0] && - place[0] == '-' && - place[1] == '\0') { - - optind = optend ; - place = EMSG ; - ret_val = -1 ; - goto done_option ; - } - - /* --------------------------------------------------------------- - * long option - * ------------------------------------------------------------ */ - - if (place[0] && - place[0] == '-' && - place[1] ) { - - size_t namelen ; - int i ; - - /* consume second `-' */ - ++ place ; - - /* count characters before `=' */ - namelen = strcspn(place, "=") ; - - /* scan longopts for this option */ - for (i = 0 ; longopts[i].name != NULL ; ++ i) { - - if (strlen ( longopts[i].name) == namelen && - strncmp (place, longopts[i].name, namelen) == 0 ) { - - /* save back long option index */ - if (longindex) *longindex = i ; - - /* process long option argument */ - if (longopts[i].has_arg == required_argument || - longopts[i].has_arg == optional_argument) { - - /* --option=value style */ - if (place[namelen] == '=') { - optarg = place + namelen + 1 ; - } - - /* --option value style (only required_argument) */ - else if (longopts[i].has_arg == required_argument) { - /* missing argument ? */ - if (optbegin >= argc - 1) { - if (! has_colon && opterr) - fprintf(stderr, - "%s: option requires an argument -- %s\n", - argv[0], place); - place = EMSG ; - ret_val = has_colon ? BADARG : BADCH ; - goto done_option ; - } - optarg = argv [optend] ; - ++ optend ; - } - } - - /* determine return value */ - if (longopts[i].flag == NULL) { - ret_val = longopts[i].val ; - } - else { - *longopts[i].flag = longopts[i].val; - ret_val = 0 ; - } - - /* mark sequence closed */ - place = EMSG ; - goto done_option ; - } /* if match */ - - } /* scan longoptions */ - - /* no matching option found */ - if (! has_colon && opterr) - fprintf(stderr, - "%s: illegal option -- %s\n", argv[0], place) ; - place = EMSG ; - ret_val = BADCH ; - goto done_option ; - } - } /* end new option */ - - /* ----------------------------------------------------------------- - * Finish short option sequence - * -------------------------------------------------------------- */ - optopt = (int) *place++ ; - - /* search charcater in option list */ - oli = strchr(optstring, optopt); - - /* short option not found */ - if (!oli) { - - if (! has_colon && opterr) - fprintf(stderr, - "%s: illegal option -- %c\n", - argv[0], optopt); - - if (*place) { - /* more short options in the list */ - return BADCH ; - } - - else { - /* error occured as last option in the list */ - place = EMSG ; - ret_val = BADCH ; - goto done_option ; - } - } /* end short option not found */ - - if (oli[1] != ':') { - /* short option with no argument */ - - if (*place) { - /* more short options in the list */ - return optopt ; - } - else { - /* last option in the list */ - place = EMSG ; - ret_val = optopt ; - goto done_option ; - } - - } else { - /* short option with argument */ - - /* -ovalue style */ - if (*place) { - optarg = place ; - place = EMSG ; - ret_val = optopt ; - goto done_option ; - } - /* -o value style: missing argument */ - else if (optbegin >= argc - 1) { - if (! has_colon && opterr) - fprintf(stderr, - "%s: option requires an argument -- %c\n", - argv[0], optopt); - place = EMSG ; - ret_val = has_colon ? BADARG : BADCH ; - goto done_option ; - } - - /* -o value style: process argument */ - optarg = argv [optend] ; - ++ optend ; - place = EMSG ; - ret_val = optopt ; - goto done_option ; - } /* short with argument */ - - done_option : - { - int pos = optend - optbegin ; /* n of circular shifts */ - int c = pos ; - - while (c --) { - int i ; - char *tmp = argv [optend - 1] ; - for (i = optend - 1 ; i > optind ; -- i) { - ((char**)argv) [i] = argv [i-1] ; - } - ((char**)argv) [optind] = tmp ; - } - optind += pos ; - } - - return ret_val ; -} diff --git a/opensfm/src/third_party/vlfeat/vl/getopt_long.h b/opensfm/src/third_party/vlfeat/vl/getopt_long.h deleted file mode 100644 index 421213546..000000000 --- a/opensfm/src/third_party/vlfeat/vl/getopt_long.h +++ /dev/null @@ -1,43 +0,0 @@ -/** @file getopt_long.h - ** @brief getopt_long - ** @author Andrea Vedaldi - **/ - -/* -Copyright (C) 2007-12 Andrea Vedaldi and Brian Fulkerson. -All rights reserved. - -This file is part of the VLFeat library and is made available under -the terms of the BSD license (see the COPYING file). -*/ - -#ifndef VL_GETOPT_LONG_H -#define VL_GETOPT_LONG_H - -#include "generic.h" - -VL_EXPORT int opterr ; /**< code of the last error occured while parsing an option */ -VL_EXPORT int optind ; /**< index of the next option to process in @c argv */ -VL_EXPORT int optopt ; /**< current option */ -VL_EXPORT char * optarg ; /**< argument of the current option */ -VL_EXPORT int optreset ; /**< reset flag */ - -/** @brief ::getopt_long option */ -struct option -{ - const char *name ; /**< option long name */ - int has_arg ; /**< flag indicating whether the option has no, required or optional argument */ - int *flag ; /**< pointer to a variable to set (if @c NULL, the value is returned instead) */ - int val ; /**< value to set or to return */ -} ; - -#define no_argument 0 /**< ::option with no argument */ -#define required_argument 1 /**< ::option with required argument */ -#define optional_argument 2 /**< ::option with optional argument */ - -VL_EXPORT int getopt_long(int argc, char * const argv[], - const char * optstring, - const struct option * longopts, int * longindex); - -/* VL_GETOPT_LONG_H */ -#endif diff --git a/opensfm/src/third_party/vlfeat/vl/gmm.c b/opensfm/src/third_party/vlfeat/vl/gmm.c deleted file mode 100644 index 585044576..000000000 --- a/opensfm/src/third_party/vlfeat/vl/gmm.c +++ /dev/null @@ -1,1709 +0,0 @@ -/** @file gmm.c - ** @brief Gaussian Mixture Models - Implementation - ** @author David Novotny - ** @author Andrea Vedaldi - **/ - -/* -Copyright (C) 2013 David Novotny and Andrea Vedaldi. -All rights reserved. - -This file is part of the VLFeat library and is made available under -the terms of the BSD license (see the COPYING file). -*/ - -/** - -@page gmm Gaussian Mixture Models (GMM) -@author David Novotny -@author Andrea Vedaldi -@tableofcontents - - -@ref gmm.h is an implementation of *Gaussian Mixture Models* (GMMs). -The main functionality provided by this module is learning GMMs from -data by maximum likelihood. Model optimization uses the Expectation -Maximization (EM) algorithm @cite{dempster77maximum}. The -implementation supports @c float or @c double data types, is -parallelized, and is tuned to work reliably and effectively on -datasets of visual features. Stability is obtained in part by -regularizing and restricting the parameters of the GMM. - -@ref gmm-starting demonstreates how to use the C API to compute the FV -representation of an image. For further details refer to: - -- @subpage gmm-fundamentals - - -@section gmm-starting Getting started - - -In order to use @ref gmm.h to learn a GMM from training data, create a -new ::VlGMM object instance, set the parameters as desired, and run -the training code. The following example learns @c numClusters -Gaussian components from @c numData vectors of dimension @c dimension -and storage class @c float using at most 100 EM iterations: - -@code -float * means ; -float * covariances ; -float * priors ; -float * posteriors ; - -double loglikelihood ; - -// create a new instance of a GMM object for float data -gmm = vl_gmm_new (VL_TYPE_FLOAT, dimension, numClusters) ; - -// set the maximum number of EM iterations to 100 -vl_gmm_set_max_num_iterations (gmm, 100) ; - -// set the initialization to random selection -vl_gmm_set_initialization (gmm,VlGMMRand); - -// cluster the data, i.e. learn the GMM -vl_gmm_cluster (gmm, data, numData); - -// get the means, covariances, and priors of the GMM -means = vl_gmm_get_means(gmm); -covariances = vl_gmm_get_covariances(gmm); -priors = vl_gmm_get_priors(gmm); - -// get loglikelihood of the estimated GMM -loglikelihood = vl_gmm_get_loglikelihood(gmm) ; - -// get the soft assignments of the data points to each cluster -posteriors = vl_gmm_get_posteriors(gmm) ; -@endcode - -@note ::VlGMM assumes that the covariance matrices of the GMM are -diagonal. This reduces significantly the number of parameters to learn -and is usually an acceptable compromise in vision applications. If the -data is significantly correlated, it can be beneficial to de-correlate -it by PCA rotation or projection in pre-processing. - -::vl_gmm_get_loglikelihood is used to get the final loglikelihood of -the estimated mixture, ::vl_gmm_get_means and ::vl_gmm_get_covariances -to obtain the means and the diagonals of the covariance matrices of -the estimated Gaussian modes, and ::vl_gmm_get_posteriors to get the -posterior probabilities that a given point is associated to each of -the modes (soft assignments). - -The learning algorithm, which uses EM, finds a local optimum of the -objective function. Therefore the initialization is crucial in -obtaining a good model, measured in term of the final -loglikelihood. ::VlGMM supports a few methods (use -::vl_gmm_set_initialization to choose one) as follows: - -Method | ::VlGMMInitialization enumeration | Description -----------------------|-----------------------------------------|----------------------------------------------- -Random initialization | ::VlGMMRand | Random initialization of the mixture parameters -KMeans | ::VlGMMKMeans | Initialization of the mixture parameters using ::VlKMeans -Custom | ::VlGMMCustom | User specified initialization - -Note that in the case of ::VlGMMKMeans initialization, an object of -type ::VlKMeans object must be created and passed to the ::VlGMM -instance (see @ref kmeans to see how to correctly set up this object). - -When a user wants to use the ::VlGMMCustom method, the initial means, -covariances and priors have to be specified using the -::vl_gmm_set_means, ::vl_gmm_set_covariances and ::vl_gmm_set_priors -methods. -**/ - -/** - -@page gmm-fundamentals GMM fundamentals -@tableofcontents - - -A *Gaussian Mixture Model* (GMM) is a mixture of $K$ multivariate -Gaussian distributions. In order to sample from a GMM, one samples -first the component index $k \in \{1,\dots,K\}$ with *prior -probability* $\pi_k$, and then samples the vector $\bx \in -\mathbb{R}^d$ from the $k$-th Gaussian distribution -$p(\bx|\mu_k,\Sigma_k)$. Here $\mu_k$ and $\Sigma_k$ are respectively -the *mean* and *covariance* of the distribution. The GMM is completely -specified by the parameters $\Theta=\{\pi_k,\mu_k,\Sigma_k; k = -1,\dots,K\}$ - -The density $p(\bx|\Theta)$ induced on the training data is obtained -by marginalizing the component selector $k$, obtaining -\[ -p(\bx|\Theta) -= \sum_{k=1}^{K} \pi_k p( \bx_i |\mu_k,\Sigma_k), -\qquad -p( \bx |\mu_k,\Sigma_k) -= -\frac{1}{\sqrt{(2\pi)^d\det\Sigma_k}} -\exp\left[ --\frac{1}{2} (\bx-\mu_k)^\top\Sigma_k^{-1}(\bx-\mu_k) -\right]. -\] -Learning a GMM to fit a dataset $X=(\bx_1, \dots, \bx_n)$ is usually -done by maximizing the log-likelihood of the data: -@f[ - \ell(\Theta;X) - = E_{\bx\sim\hat p} [ \log p(\bx|\Theta) ] - = \frac{1}{n}\sum_{i=1}^{n} \log \sum_{k=1}^{K} \pi_k p(\bx_i|\mu_k, \Sigma_k) -@f] -where $\hat p$ is the empirical distribution of the data. An algorithm -to solve this problem is introduced next. - - -@section gmm-em Learning a GMM by expectation maximization - - -The direct maximization of the log-likelihood function of a GMM is -difficult due to the fact that the assignments of points to Gaussian -mode is not observable and, as such, must be treated as a latent -variable. - -Usually, GMMs are learned by using the *Expectation Maximization* (EM) -algorithm @cite{dempster77maximum}. Consider in general the problem of -estimating to the maximum likelihood a distribution $p(x|\Theta) = -\int p(x,h|\Theta)\,dh$, where $x$ is a measurement, $h$ is a *latent -variable*, and $\Theta$ are the model parameters. By introducing an -auxiliary distribution $q(h|x)$ on the latent variable, one can use -Jensen inequality to obtain the following lower bound on the -log-likelihood: - -@f{align*} -\ell(\Theta;X) = -E_{x\sim\hat p} \log p(x|\Theta) -&= E_{x\sim\hat p} \log \int p(x,h|\Theta) \,dh \\ -&= E_{x\sim\hat p} \log \int \frac{p(x,h|\Theta)}{q(h|x)} q(h|x)\,dh \\ -&\geq E_{x\sim\hat p} \int q(h) \log \frac{p(x,h|\Theta)}{q(h|x)}\,dh \\ -&= E_{(x,q) \sim q(h|x) \hat p(x)} \log p(x,h|\Theta) - - E_{(x,q) \sim q(h|x) \hat p(x)} \log q(h|x) -@f} - -The first term of the last expression is the log-likelihood of the -model where both the $x$ and $h$ are observed and joinlty distributed -as $q(x|h)\hat p(x)$; the second term is the a average entropy of the -latent variable, which does not depend on $\Theta$. This lower bound -is maximized and becomes tight by setting $q(h|x) = p(h|x,\Theta)$ to -be the posterior distribution on the latent variable $h$ (given the -current estimate of the parameters $\Theta$). In fact: - -\[ -E_{x \sim \hat p} \log p(x|\Theta) -= -E_{(x,h) \sim p(h|x,\Theta) \hat p(x)}\left[ \log \frac{p(x,h|\Theta)}{p(h|x,\Theta)} \right] -= -E_{(x,h) \sim p(h|x,\Theta) \hat p(x)} [ \log p(x|\Theta) ] -= -\ell(\Theta;X). -\] - -EM alternates between updating the latent variable auxiliary -distribution $q(h|x) = p(h|x,\Theta_t)$ (*expectation step*) given the -current estimate of the parameters $\Theta_t$, and then updating the -model parameters $\Theta_{t+1}$ by maximizing the log-likelihood lower -bound derived (*maximization step*). The simplification is that in the -maximization step both $x$ and $h$ are now ``observed'' quantities. -This procedure converges to a local optimum of the model -log-likelihood. - -@subsection gmm-expectation-step Expectation step - -In the case of a GMM, the latent variables are the point-to-cluster -assignments $k_i, i=1,\dots,n$, one for each of $n$ data points. The -auxiliary distribution $q(k_i|\bx_i) = q_{ik}$ is a matrix with $n -\times K$ entries. Each row $q_{i,:}$ can be thought of as a vector of -soft assignments of the data points $\bx_i$ to each of the Gaussian -modes. Setting $q_{ik} = p(k_i | \bx_i, \Theta)$ yields - -\[ - q_{ik} = -\frac -{\pi_k p(\bx_i|\mu_k,\Sigma_k)} -{\sum_{l=1}^K \pi_l p(\bx_i|\mu_l,\Sigma_l)} -\] - -where the Gaussian density $p(\bx_i|\mu_k,\Sigma_k)$ was given above. - -One important point to keep in mind when these probabilities are -computed is the fact that the Gaussian densities may attain very low -values and underflow in a vanilla implementation. Furthermore, VLFeat -GMM implementation restricts the covariance matrices to be -diagonal. In this case, the computation of the determinant of -$\Sigma_k$ reduces to computing the trace of the matrix and the -inversion of $\Sigma_k$ could be obtained by inverting the elements on -the diagonal of the covariance matrix. - -@subsection gmm-maximization-step Maximization step - -The M step estimates the parameters of the Gaussian mixture components -and the prior probabilities $\pi_k$ given the auxiliary distribution -on the point-to-cluster assignments computed in the E step. Since all -the variables are now ``observed'', the estimate is quite simple. For -example, the mean $\mu_k$ of a Gaussian mode is obtained as the mean -of the data points assigned to it (accounting for the strength of the -soft assignments). The other quantities are obtained in a similar -manner, yielding to: - -@f{align*} - \mu_k &= { { \sum_{i=1}^n q_{ik} \bx_{i} } \over { \sum_{i=1}^n q_{ik} } }, -\\ - \Sigma_k &= { { \sum_{i=1}^n { q_{ik} (\bx_{i} - \mu_{k}) {(\bx_{i} - \mu_{k})}^T } } \over { \sum_{i=1}^n q_{ik} } }, -\\ - \pi_k &= { \sum_{i=1}^n { q_{ik} } \over { \sum_{i=1}^n \sum_{l=1}^K q_{il} } }. -@f} - - -@section gmm-fundamentals-init Initialization algorithms - - -The EM algorithm is a local optimization method. As such, the quality -of the solution strongly depends on the quality of the initial values -of the parameters (i.e. of the locations and shapes of the Gaussian -modes). - -@ref gmm.h supports the following cluster initialization algorithms: - -- Random data points. (::vl_gmm_init_with_rand_data) This method - sets the means of the modes by sampling at random a corresponding - number of data points, sets the covariance matrices of all the modes - are to the covariance of the entire dataset, and sets the prior - probabilities of the Gaussian modes to be uniform. This - initialization method is the fastest, simplest, as well as the one - most likely to end in a bad local minimum. - -- KMeans initialization (::vl_gmm_init_with_kmeans) This - method uses KMeans to pre-cluster the points. It then sets the means - and covariances of the Gaussian distributions the sample means and - covariances of each KMeans cluster. It also sets the prior - probabilities to be proportional to the mass of each cluster. In - order to use this initialization method, a user can specify an - instance of ::VlKMeans by using the function - ::vl_gmm_set_kmeans_init_object, or let ::VlGMM create one - automatically. - -Alternatively, one can manually specify a starting point -(::vl_gmm_set_priors, ::vl_gmm_set_means, ::vl_gmm_set_covariances). -**/ - -#include "gmm.h" -#include -#include -#include - -#ifdef _OPENMP -#include -#endif - -#ifndef VL_DISABLE_SSE2 -#include "mathop_sse2.h" -#endif - -#ifndef VL_DISABLE_AVX -#include "mathop_avx.h" -#endif - -/* ---------------------------------------------------------------- */ -#ifndef VL_GMM_INSTANTIATING -/* ---------------------------------------------------------------- */ - -#define VL_GMM_MIN_VARIANCE 1e-6 -#define VL_GMM_MIN_POSTERIOR 1e-2 -#define VL_GMM_MIN_PRIOR 1e-6 - -struct _VlGMM -{ - vl_type dataType ; /**< Data type. */ - vl_size dimension ; /**< Data dimensionality. */ - vl_size numClusters ; /**< Number of clusters */ - vl_size numData ; /**< Number of last time clustered data points. */ - vl_size maxNumIterations ; /**< Maximum number of refinement iterations. */ - vl_size numRepetitions ; /**< Number of clustering repetitions. */ - int verbosity ; /**< Verbosity level. */ - void * means; /**< Means of Gaussian modes. */ - void * covariances; /**< Diagonals of covariance matrices of Gaussian modes. */ - void * priors; /**< Weights of Gaussian modes. */ - void * posteriors; /**< Probabilities of correspondences of points to clusters. */ - double * sigmaLowBound ; /**< Lower bound on the diagonal covariance values. */ - VlGMMInitialization initialization; /**< Initialization option */ - VlKMeans * kmeansInit; /**< Kmeans object for initialization of gaussians */ - double LL ; /**< Current solution loglikelihood */ - vl_bool kmeansInitIsOwner; /**< Indicates whether a user provided the kmeans initialization object */ -} ; - -/* ---------------------------------------------------------------- */ -/* Life-cycle */ -/* ---------------------------------------------------------------- */ - -static void -_vl_gmm_prepare_for_data (VlGMM* self, vl_size numData) -{ - if (self->numData < numData) { - vl_free(self->posteriors) ; - self->posteriors = vl_malloc(vl_get_type_size(self->dataType) * numData * self->numClusters) ; - } - self->numData = numData ; -} - -/** @brief Create a new GMM object - ** @param dataType type of data (::VL_TYPE_FLOAT or ::VL_TYPE_DOUBLE) - ** @param dimension dimension of the data. - ** @param numComponents number of Gaussian mixture components. - ** @return new GMM object instance. - **/ - -VlGMM * -vl_gmm_new (vl_type dataType, vl_size dimension, vl_size numComponents) -{ - vl_index i ; - vl_size size = vl_get_type_size(dataType) ; - VlGMM * self = vl_calloc(1, sizeof(VlGMM)) ; - self->dataType = dataType; - self->numClusters = numComponents ; - self->numData = 0; - self->dimension = dimension ; - self->initialization = VlGMMRand; - self->verbosity = 0 ; - self->maxNumIterations = 50; - self->numRepetitions = 1; - self->sigmaLowBound = NULL ; - self->priors = NULL ; - self->covariances = NULL ; - self->means = NULL ; - self->posteriors = NULL ; - self->kmeansInit = NULL ; - self->kmeansInitIsOwner = VL_FALSE; - - self->priors = vl_calloc (numComponents, size) ; - self->means = vl_calloc (numComponents * dimension, size) ; - self->covariances = vl_calloc (numComponents * dimension, size) ; - self->sigmaLowBound = vl_calloc (dimension, sizeof(double)) ; - - for (i = 0 ; i < (unsigned)self->dimension ; ++i) { self->sigmaLowBound[i] = 1e-4 ; } - return self ; -} - -/** @brief Reset state - ** @param self object. - ** - ** The function reset the state of the GMM object. It deletes - ** any stored posterior and other internal state variables. - **/ - -void -vl_gmm_reset (VlGMM * self) -{ - if (self->posteriors) { - vl_free(self->posteriors) ; - self->posteriors = NULL ; - self->numData = 0 ; - } - if (self->kmeansInit && self->kmeansInitIsOwner) { - vl_kmeans_delete(self->kmeansInit) ; - self->kmeansInit = NULL ; - self->kmeansInitIsOwner = VL_FALSE ; - } -} - -/** @brief Deletes a GMM object - ** @param self GMM object instance. - ** - ** The function deletes the GMM object instance created - ** by ::vl_gmm_new. - **/ - -void -vl_gmm_delete (VlGMM * self) -{ - if(self->means) vl_free(self->means); - if(self->covariances) vl_free(self->covariances); - if(self->priors) vl_free(self->priors); - if(self->posteriors) vl_free(self->posteriors); - if(self->kmeansInit && self->kmeansInitIsOwner) { - vl_kmeans_delete(self->kmeansInit); - } - vl_free(self); -} - -/* ---------------------------------------------------------------- */ -/* Getters and setters */ -/* ---------------------------------------------------------------- */ - -/** @brief Get data type - ** @param self object - ** @return data type. - **/ - -vl_type -vl_gmm_get_data_type (VlGMM const * self) -{ - return self->dataType ; -} - -/** @brief Get the number of clusters - ** @param self object - ** @return number of clusters. - **/ - -vl_size -vl_gmm_get_num_clusters (VlGMM const * self) -{ - return self->numClusters ; -} - -/** @brief Get the number of data points - ** @param self object - ** @return number of data points. - **/ - -vl_size -vl_gmm_get_num_data (VlGMM const * self) -{ - return self->numData ; -} - -/** @brief Get the log likelihood of the current mixture - ** @param self object - ** @return loglikelihood. - **/ - -double -vl_gmm_get_loglikelihood (VlGMM const * self) -{ - return self->LL ; -} - -/** @brief Get verbosity level - ** @param self object - ** @return verbosity level. - **/ - -int -vl_gmm_get_verbosity (VlGMM const * self) -{ - return self->verbosity ; -} - -/** @brief Set verbosity level - ** @param self object - ** @param verbosity verbosity level. - **/ - -void -vl_gmm_set_verbosity (VlGMM * self, int verbosity) -{ - self->verbosity = verbosity ; -} - -/** @brief Get means - ** @param self object - ** @return cluster means. - **/ - -void const * -vl_gmm_get_means (VlGMM const * self) -{ - return self->means ; -} - -/** @brief Get covariances - ** @param self object - ** @return diagonals of cluster covariance matrices. - **/ - -void const * -vl_gmm_get_covariances (VlGMM const * self) -{ - return self->covariances ; -} - -/** @brief Get priors - ** @param self object - ** @return priors of cluster gaussians. - **/ - -void const * -vl_gmm_get_priors (VlGMM const * self) -{ - return self->priors ; -} - -/** @brief Get posteriors - ** @param self object - ** @return posterior probabilities of cluster memberships. - **/ - -void const * -vl_gmm_get_posteriors (VlGMM const * self) -{ - return self->posteriors ; -} - -/** @brief Get maximum number of iterations - ** @param self object - ** @return maximum number of iterations. - **/ - -vl_size -vl_gmm_get_max_num_iterations (VlGMM const * self) -{ - return self->maxNumIterations ; -} - -/** @brief Set maximum number of iterations - ** @param self VlGMM filter. - ** @param maxNumIterations maximum number of iterations. - **/ - -void -vl_gmm_set_max_num_iterations (VlGMM * self, vl_size maxNumIterations) -{ - self->maxNumIterations = maxNumIterations ; -} - -/** @brief Get maximum number of repetitions. - ** @param self object - ** @return current number of repretitions for quantization. - **/ - -vl_size -vl_gmm_get_num_repetitions (VlGMM const * self) -{ - return self->numRepetitions ; -} - -/** @brief Set maximum number of repetitions - ** @param self object - ** @param numRepetitions maximum number of repetitions. - ** The number of repetitions cannot be smaller than 1. - **/ - -void -vl_gmm_set_num_repetitions (VlGMM * self, vl_size numRepetitions) -{ - assert (numRepetitions >= 1) ; - self->numRepetitions = numRepetitions ; -} - -/** @brief Get data dimension - ** @param self object - ** @return data dimension. - **/ - -vl_size -vl_gmm_get_dimension (VlGMM const * self) -{ - return self->dimension ; -} - -/** @brief Get initialization algorithm - ** @param self object - ** @return initialization algorithm. - **/ - -VlGMMInitialization -vl_gmm_get_initialization (VlGMM const * self) -{ - return self->initialization ; -} - -/** @brief Set initialization algorithm. - ** @param self object - ** @param init initialization algorithm. - **/ -void -vl_gmm_set_initialization (VlGMM * self, VlGMMInitialization init) -{ - self->initialization = init; -} - -/** @brief Get KMeans initialization object. - ** @param self object - ** @return kmeans initialization object. - **/ -VlKMeans * vl_gmm_get_kmeans_init_object (VlGMM const * self) -{ - return self->kmeansInit; -} - -/** @brief Set KMeans initialization object. - ** @param self object - ** @param kmeans initialization KMeans object. - **/ -void vl_gmm_set_kmeans_init_object (VlGMM * self, VlKMeans * kmeans) -{ - if (self->kmeansInit && self->kmeansInitIsOwner) { - vl_kmeans_delete(self->kmeansInit) ; - } - self->kmeansInit = kmeans; - self->kmeansInitIsOwner = VL_FALSE; -} - -/** @brief Get the lower bound on the diagonal covariance values. - ** @param self object - ** @return lower bound on covariances. - **/ -double const * vl_gmm_get_covariance_lower_bounds (VlGMM const * self) -{ - return self->sigmaLowBound; -} - -/** @brief Set the lower bounds on diagonal covariance values. - ** @param self object. - ** @param bounds bounds. - ** - ** There is one lower bound per dimension. Use ::vl_gmm_set_covariance_lower_bound - ** to set all of them to a given scalar. - **/ -void vl_gmm_set_covariance_lower_bounds (VlGMM * self, double const * bounds) -{ - memcpy(self->sigmaLowBound, bounds, sizeof(double) * self->dimension) ; -} - -/** @brief Set the lower bounds on diagonal covariance values. - ** @param self object. - ** @param bound bound. - ** - ** While there is one lower bound per dimension, this function sets - ** all of them to the specified scalar. Use ::vl_gmm_set_covariance_lower_bounds - ** to set them individually. - **/ -void vl_gmm_set_covariance_lower_bound (VlGMM * self, double bound) -{ - int i ; - for (i = 0 ; i < (signed)self->dimension ; ++i) { - self->sigmaLowBound[i] = bound ; - } -} - -/* ---------------------------------------------------------------- */ -/* Instantiate shuffle algorithm */ - -#define VL_SHUFFLE_type vl_uindex -#define VL_SHUFFLE_prefix _vl_gmm -#include "shuffle-def.h" - -/* #ifdef VL_GMM_INSTANTITATING */ -#endif - -/* ---------------------------------------------------------------- */ -#ifdef VL_GMM_INSTANTIATING -/* ---------------------------------------------------------------- */ - -/* ---------------------------------------------------------------- */ -/* Posterior assignments */ -/* ---------------------------------------------------------------- */ - -/** @fn vl_get_gmm_data_posterior_f(float*,vl_size,vl_size,float const*,float const*,vl_size,float const*,float const*) - ** @brief Get Gaussian modes posterior probabilities - ** @param posteriors posterior probabilities (output)/ - ** @param numClusters number of modes in the GMM model. - ** @param numData number of data elements. - ** @param priors prior mode probabilities of the GMM model. - ** @param means means of the GMM model. - ** @param dimension data dimension. - ** @param covariances diagonal covariances of the GMM model. - ** @param data data. - ** @return data log-likelihood. - ** - ** This is a helper function that does not require a ::VlGMM object - ** instance to operate. - **/ - -double -VL_XCAT(vl_get_gmm_data_posteriors_, SFX) -(TYPE * posteriors, - vl_size numClusters, - vl_size numData, - TYPE const * priors, - TYPE const * means, - vl_size dimension, - TYPE const * covariances, - TYPE const * data) -{ - vl_index i_d, i_cl; - vl_size dim; - double LL = 0; - - TYPE halfDimLog2Pi = (dimension / 2.0) * log(2.0*VL_PI); - TYPE * logCovariances ; - TYPE * logWeights ; - TYPE * invCovariances ; - -#if (FLT == VL_TYPE_FLOAT) - VlFloatVector3ComparisonFunction distFn = vl_get_vector_3_comparison_function_f(VlDistanceMahalanobis) ; -#else - VlDoubleVector3ComparisonFunction distFn = vl_get_vector_3_comparison_function_d(VlDistanceMahalanobis) ; -#endif - - logCovariances = vl_malloc(sizeof(TYPE) * numClusters) ; - invCovariances = vl_malloc(sizeof(TYPE) * numClusters * dimension) ; - logWeights = vl_malloc(sizeof(TYPE) * numClusters) ; - -#if defined(_OPENMP) -#pragma omp parallel for private(i_cl,dim) num_threads(vl_get_max_threads()) -#endif - for (i_cl = 0 ; i_cl < (signed)numClusters ; ++ i_cl) { - TYPE logSigma = 0 ; - if (priors[i_cl] < VL_GMM_MIN_PRIOR) { - logWeights[i_cl] = - (TYPE) VL_INFINITY_D ; - } else { - logWeights[i_cl] = log(priors[i_cl]); - } - for(dim = 0 ; dim < dimension ; ++ dim) { - logSigma += log(covariances[i_cl*dimension + dim]); - invCovariances [i_cl*dimension + dim] = (TYPE) 1.0 / covariances[i_cl*dimension + dim]; - } - logCovariances[i_cl] = logSigma; - } /* end of parallel region */ - -#if defined(_OPENMP) -#pragma omp parallel for private(i_cl,i_d) reduction(+:LL) \ -num_threads(vl_get_max_threads()) -#endif - for (i_d = 0 ; i_d < (signed)numData ; ++ i_d) { - TYPE clusterPosteriorsSum = 0; - TYPE maxPosterior = (TYPE)(-VL_INFINITY_D) ; - - for (i_cl = 0 ; i_cl < (signed)numClusters ; ++ i_cl) { - TYPE p = - logWeights[i_cl] - - halfDimLog2Pi - - 0.5 * logCovariances[i_cl] - - 0.5 * distFn (dimension, - data + i_d * dimension, - means + i_cl * dimension, - invCovariances + i_cl * dimension) ; - posteriors[i_cl + i_d * numClusters] = p ; - if (p > maxPosterior) { maxPosterior = p ; } - } - - for (i_cl = 0 ; i_cl < (signed)numClusters ; ++i_cl) { - TYPE p = posteriors[i_cl + i_d * numClusters] ; - p = exp(p - maxPosterior) ; - posteriors[i_cl + i_d * numClusters] = p ; - clusterPosteriorsSum += p ; - } - - LL += log(clusterPosteriorsSum) + (double) maxPosterior ; - - for (i_cl = 0 ; i_cl < (signed)numClusters ; ++i_cl) { - posteriors[i_cl + i_d * numClusters] /= clusterPosteriorsSum ; - } - } /* end of parallel region */ - - vl_free(logCovariances); - vl_free(logWeights); - vl_free(invCovariances); - - return LL; -} - -/* ---------------------------------------------------------------- */ -/* Restarts zero-weighted Gaussians */ -/* ---------------------------------------------------------------- */ - -static void -VL_XCAT(_vl_gmm_maximization_, SFX) -(VlGMM * self, - TYPE * posteriors, - TYPE * priors, - TYPE * covariances, - TYPE * means, - TYPE const * data, - vl_size numData) ; - -static vl_size -VL_XCAT(_vl_gmm_restart_empty_modes_, SFX) (VlGMM * self, TYPE const * data) -{ - vl_size dimension = self->dimension; - vl_size numClusters = self->numClusters; - vl_index i_cl, j_cl, i_d, d; - vl_size zeroWNum = 0; - TYPE * priors = (TYPE*)self->priors ; - TYPE * means = (TYPE*)self->means ; - TYPE * covariances = (TYPE*)self->covariances ; - TYPE * posteriors = (TYPE*)self->posteriors ; - - //VlRand * rand = vl_get_rand() ; - - TYPE * mass = vl_calloc(sizeof(TYPE), self->numClusters) ; - - if (numClusters <= 1) { return 0 ; } - - /* compute statistics */ - { - vl_uindex i, k ; - vl_size numNullAssignments = 0 ; - for (i = 0 ; i < self->numData ; ++i) { - for (k = 0 ; k < self->numClusters ; ++k) { - TYPE p = ((TYPE*)self->posteriors)[k + i * self->numClusters] ; - mass[k] += p ; - if (p < VL_GMM_MIN_POSTERIOR) { - numNullAssignments ++ ; - } - } - } - if (self->verbosity) { - VL_PRINTF("gmm: sparsity of data posterior: %.1f%%\n", (double)numNullAssignments / (self->numData * self->numClusters) * 100) ; - } - } - -#if 0 - /* search for cluster with negligible weight and reassign them to fat clusters */ - for (i_cl = 0 ; i_cl < numClusters ; ++i_cl) { - if (priors[i_cl] < 0.00001/numClusters) { - double mass = priors[0] ; - vl_index best = 0 ; - - for (j_cl = 1 ; j_cl < numClusters ; ++j_cl) { - if (priors[j_cl] > mass) { mass = priors[j_cl] ; best = j_cl ; } - } - - if (j_cl == i_cl) { - /* this should never happen */ - continue ; - } - - j_cl = best ; - zeroWNum ++ ; - - VL_PRINTF("gmm: restarting mode %d by splitting mode %d (with prior %f)\n", i_cl,j_cl,mass) ; - - priors[i_cl] = mass/2 ; - priors[j_cl] = mass/2 ; - for (d = 0 ; d < dimension ; ++d) { - TYPE sigma2 = covariances[j_cl*dimension + d] ; - TYPE sigma = VL_XCAT(vl_sqrt_,SFX)(sigma2) ; - means[i_cl*dimension + d] = means[j_cl*dimension + d] + 0.001 * (vl_rand_real1(rand) - 0.5) * sigma ; - covariances[i_cl*dimension + d] = sigma2 ; - } - } - } -#endif - - /* search for cluster with negligible weight and reassign them to fat clusters */ - for (i_cl = 0 ; i_cl < (signed)numClusters ; ++i_cl) { - double size = - VL_INFINITY_D ; - vl_index best = -1 ; - - if (mass[i_cl] >= VL_GMM_MIN_POSTERIOR * - VL_MAX(1.0, (double) self->numData / self->numClusters)) - { - continue ; - } - - if (self->verbosity) { - VL_PRINTF("gmm: mode %d is nearly empty (mass %f)\n", i_cl, mass[i_cl]) ; - } - - /* - Search for the Gaussian components that (approximately) - maximally contribute to make the negative log-likelihood of the data - large. Then split the worst offender. - - To do so, we approximate the exptected log-likelihood of the GMM: - - E[-log(f(x))] = H(f) = - log \int f(x) log f(x) - - where the density f(x) = sum_k pk gk(x) is a GMM. This is intractable - but it is easy to approximate if we suppose that supp gk is disjoint with - supp gq for all components k ~= q. In this canse - - H(f) ~= sum_k [ - pk log(pk) + pk H(gk) ] - - where H(gk) is the entropy of component k taken alone. The entropy of - the latter is given by: - - H(gk) = D/2 (1 + log(2pi) + 1/2 sum_{i=0}^D log sigma_i^2 - - */ - - for (j_cl = 0 ; j_cl < (signed)numClusters ; ++j_cl) { - double size_ ; - if (priors[j_cl] < VL_GMM_MIN_PRIOR) { continue ; } - size_ = + 0.5 * dimension * (1.0 + log(2*VL_PI)) ; - for(d = 0 ; d < (signed)dimension ; d++) { - double sigma2 = covariances[j_cl * dimension + d] ; - size_ += 0.5 * log(sigma2) ; - } - size_ = priors[j_cl] * (size_ - log(priors[j_cl])) ; - - if (self->verbosity > 1) { - VL_PRINTF("gmm: mode %d: prior %f, mass %f, entropy contribution %f\n", - j_cl, priors[j_cl], mass[j_cl], size_) ; - } - - if (size_ > size) { - size = size_ ; - best = j_cl ; - } - } - - j_cl = best ; - - if (j_cl == i_cl || j_cl < 0) { - if (self->verbosity) { - VL_PRINTF("gmm: mode %d is empty, " - "but no other mode to split could be found\n", i_cl) ; - } - continue ; - } - - if (self->verbosity) { - VL_PRINTF("gmm: reinitializing empty mode %d with mode %d (prior %f, mass %f, score %f)\n", - i_cl, j_cl, priors[j_cl], mass[j_cl], size) ; - } - - /* - Search for the dimension with maximum variance. - */ - - size = - VL_INFINITY_D ; - best = - 1 ; - - for(d = 0; d < (signed)dimension; d++) { - double sigma2 = covariances[j_cl * dimension + d] ; - if (sigma2 > size) { - size = sigma2 ; - best = d ; - } - } - - /* - Reassign points j_cl (mode to split) to i_cl (empty mode). - */ - { - TYPE mu = means[best + j_cl * self->dimension] ; - for(i_d = 0 ; i_d < (signed)self->numData ; ++ i_d) { - TYPE p = posteriors[j_cl + self->numClusters * i_d] ; - TYPE q = posteriors[i_cl + self->numClusters * i_d] ; /* ~= 0 */ - if (data[best + i_d * self->dimension] < mu) { - /* assign this point to i_cl */ - posteriors[i_cl + self->numClusters * i_d] = p + q ; - posteriors[j_cl + self->numClusters * i_d] = 0 ; - } else { - /* assign this point to j_cl */ - posteriors[i_cl + self->numClusters * i_d] = 0 ; - posteriors[j_cl + self->numClusters * i_d] = p + q ; - } - } - } - - /* - Re-estimate. - */ - VL_XCAT(_vl_gmm_maximization_, SFX) - (self,posteriors,priors,covariances,means,data,self->numData) ; - } - - return zeroWNum; -} - -/* ---------------------------------------------------------------- */ -/* Helpers */ -/* ---------------------------------------------------------------- */ - -static void -VL_XCAT(_vl_gmm_apply_bounds_, SFX)(VlGMM * self) -{ - vl_uindex dim ; - vl_uindex k ; - vl_size numAdjusted = 0 ; - TYPE * cov = (TYPE*)self->covariances ; - double const * lbs = self->sigmaLowBound ; - - for (k = 0 ; k < self->numClusters ; ++k) { - vl_bool adjusted = VL_FALSE ; - for (dim = 0 ; dim < self->dimension ; ++dim) { - if (cov[k * self->dimension + dim] < lbs[dim] ) { - cov[k * self->dimension + dim] = lbs[dim] ; - adjusted = VL_TRUE ; - } - } - if (adjusted) { numAdjusted ++ ; } - } - - if (numAdjusted > 0 && self->verbosity > 0) { - VL_PRINT("gmm: detected %d of %d modes with at least one dimension " - "with covariance too small (set to lower bound)\n", - numAdjusted, self->numClusters) ; - } -} - -/* ---------------------------------------------------------------- */ -/* EM - Maximization step */ -/* ---------------------------------------------------------------- */ - -static void -VL_XCAT(_vl_gmm_maximization_, SFX) -(VlGMM * self, - TYPE * posteriors, - TYPE * priors, - TYPE * covariances, - TYPE * means, - TYPE const * data, - vl_size numData) -{ - vl_size numClusters = self->numClusters; - vl_index i_d, i_cl; - vl_size dim ; - TYPE * oldMeans ; - double time = 0 ; - - if (self->verbosity > 1) { - VL_PRINTF("gmm: em: entering maximization step\n") ; - time = vl_get_cpu_time() ; - } - - oldMeans = vl_malloc(sizeof(TYPE) * self->dimension * numClusters) ; - memcpy(oldMeans, means, sizeof(TYPE) * self->dimension * numClusters) ; - - memset(priors, 0, sizeof(TYPE) * numClusters) ; - memset(means, 0, sizeof(TYPE) * self->dimension * numClusters) ; - memset(covariances, 0, sizeof(TYPE) * self->dimension * numClusters) ; - -#if defined(_OPENMP) -#pragma omp parallel default(shared) private(i_d, i_cl, dim) \ - num_threads(vl_get_max_threads()) -#endif - { - TYPE * clusterPosteriorSum_, * means_, * covariances_ ; - -#if defined(_OPENMP) -#pragma omp critical -#endif - { - clusterPosteriorSum_ = vl_calloc(sizeof(TYPE), numClusters) ; - means_ = vl_calloc(sizeof(TYPE), self->dimension * numClusters) ; - covariances_ = vl_calloc(sizeof(TYPE), self->dimension * numClusters) ; - } - - /* - Accumulate weighted sums and sum of square differences. Once normalized, - these become the means and covariances of each Gaussian mode. - - The squared differences will be taken w.r.t. the old means however. In this manner, - one avoids doing two passes across the data. Eventually, these are corrected to account - for the new means properly. In principle, one could set the old means to zero, but - this may cause numerical instabilities (by accumulating large squares). - */ - -#if defined(_OPENMP) -#pragma omp for -#endif - for (i_d = 0 ; i_d < (signed)numData ; ++i_d) { - for (i_cl = 0 ; i_cl < (signed)numClusters ; ++i_cl) { - TYPE p = posteriors[i_cl + i_d * self->numClusters] ; - vl_bool calculated = VL_FALSE ; - - /* skip very small associations for speed */ - if (p < VL_GMM_MIN_POSTERIOR / numClusters) { continue ; } - - clusterPosteriorSum_ [i_cl] += p ; - - #ifndef VL_DISABLE_AVX - if (vl_get_simd_enabled() && vl_cpu_has_avx()) { - VL_XCAT(_vl_weighted_mean_avx_, SFX) - (self->dimension, - means_+ i_cl * self->dimension, - data + i_d * self->dimension, - p) ; - - VL_XCAT(_vl_weighted_sigma_avx_, SFX) - (self->dimension, - covariances_ + i_cl * self->dimension, - data + i_d * self->dimension, - oldMeans + i_cl * self->dimension, - p) ; - - calculated = VL_TRUE; - } - #endif - #ifndef VL_DISABLE_SSE2 - if (vl_get_simd_enabled() && vl_cpu_has_sse2() && !calculated) { - VL_XCAT(_vl_weighted_mean_sse2_, SFX) - (self->dimension, - means_+ i_cl * self->dimension, - data + i_d * self->dimension, - p) ; - - VL_XCAT(_vl_weighted_sigma_sse2_, SFX) - (self->dimension, - covariances_ + i_cl * self->dimension, - data + i_d * self->dimension, - oldMeans + i_cl * self->dimension, - p) ; - - calculated = VL_TRUE; - } - #endif - if(!calculated) { - for (dim = 0 ; dim < self->dimension ; ++dim) { - TYPE x = data[i_d * self->dimension + dim] ; - TYPE mu = oldMeans[i_cl * self->dimension + dim] ; - TYPE diff = x - mu ; - means_ [i_cl * self->dimension + dim] += p * x ; - covariances_ [i_cl * self->dimension + dim] += p * (diff*diff) ; - } - } - } - } - - /* accumulate */ -#if defined(_OPENMP) -#pragma omp critical -#endif - { - for (i_cl = 0 ; i_cl < (signed)numClusters ; ++i_cl) { - priors [i_cl] += clusterPosteriorSum_ [i_cl]; - for (dim = 0 ; dim < self->dimension ; ++dim) { - means [i_cl * self->dimension + dim] += means_ [i_cl * self->dimension + dim] ; - covariances [i_cl * self->dimension + dim] += covariances_ [i_cl * self->dimension + dim] ; - } - } - vl_free(means_); - vl_free(covariances_); - vl_free(clusterPosteriorSum_); - } - } /* parallel section */ - - /* at this stage priors[] contains the total mass of each cluster */ - for (i_cl = 0 ; i_cl < (signed)numClusters ; ++ i_cl) { - TYPE mass = priors[i_cl] ; - /* do not update modes that do not recieve mass */ - if (mass >= 1e-6 / numClusters) { - for (dim = 0 ; dim < self->dimension ; ++dim) { - means[i_cl * self->dimension + dim] /= mass ; - covariances[i_cl * self->dimension + dim] /= mass ; - } - } - } - - /* apply old to new means correction */ - for (i_cl = 0 ; i_cl < (signed)numClusters ; ++ i_cl) { - TYPE mass = priors[i_cl] ; - if (mass >= 1e-6 / numClusters) { - for (dim = 0 ; dim < self->dimension ; ++dim) { - TYPE mu = means[i_cl * self->dimension + dim] ; - TYPE oldMu = oldMeans[i_cl * self->dimension + dim] ; - TYPE diff = mu - oldMu ; - covariances[i_cl * self->dimension + dim] -= diff * diff ; - } - } - } - - VL_XCAT(_vl_gmm_apply_bounds_,SFX)(self) ; - - { - TYPE sum = 0; - for (i_cl = 0 ; i_cl < (signed)numClusters ; ++i_cl) { - sum += priors[i_cl] ; - } - sum = VL_MAX(sum, 1e-12) ; - for (i_cl = 0 ; i_cl < (signed)numClusters ; ++i_cl) { - priors[i_cl] /= sum ; - } - } - - if (self->verbosity > 1) { - VL_PRINTF("gmm: em: maximization step completed in %.2f s\n", - vl_get_cpu_time() - time) ; - } - - vl_free(oldMeans); -} - -/* ---------------------------------------------------------------- */ -/* EM iterations */ -/* ---------------------------------------------------------------- */ - - -static double -VL_XCAT(_vl_gmm_em_, SFX) -(VlGMM * self, - TYPE const * data, - vl_size numData) -{ - vl_size iteration, restarted ; - double previousLL = (TYPE)(-VL_INFINITY_D) ; - double LL = (TYPE)(-VL_INFINITY_D) ; - double time = 0 ; - - _vl_gmm_prepare_for_data (self, numData) ; - - VL_XCAT(_vl_gmm_apply_bounds_,SFX)(self) ; - - for (iteration = 0 ; 1 ; ++ iteration) { - double eps ; - - /* - Expectation: assign data to Gaussian modes - and compute log-likelihood. - */ - - if (self->verbosity > 1) { - VL_PRINTF("gmm: em: entering expectation step\n") ; - time = vl_get_cpu_time() ; - } - - LL = VL_XCAT(vl_get_gmm_data_posteriors_,SFX) - (self->posteriors, - self->numClusters, - numData, - self->priors, - self->means, - self->dimension, - self->covariances, - data) ; - - if (self->verbosity > 1) { - VL_PRINTF("gmm: em: expectation step completed in %.2f s\n", - vl_get_cpu_time() - time) ; - } - - /* - Check the termination conditions. - */ - if (self->verbosity) { - VL_PRINTF("gmm: em: iteration %d: loglikelihood = %f (variation = %f)\n", - iteration, LL, LL - previousLL) ; - } - if (iteration >= self->maxNumIterations) { - if (self->verbosity) { - VL_PRINTF("gmm: em: terminating because " - "the maximum number of iterations " - "(%d) has been reached.\n", self->maxNumIterations) ; - } - break ; - } - - eps = vl_abs_d ((LL - previousLL) / (LL)); - if ((iteration > 0) && (eps < 0.00001)) { - if (self->verbosity) { - VL_PRINTF("gmm: em: terminating because the algorithm " - "fully converged (log-likelihood variation = %f).\n", eps) ; - } - break ; - } - previousLL = LL ; - - /* - Restart empty modes. - */ - if (iteration > 1) { - restarted = VL_XCAT(_vl_gmm_restart_empty_modes_, SFX) - (self, data); - if ((restarted > 0) & (self->verbosity > 0)) { - VL_PRINTF("gmm: em: %d Gaussian modes restarted because " - "they had become empty.\n", restarted); - } - } - - /* - Maximization: reestimate the GMM parameters. - */ - VL_XCAT(_vl_gmm_maximization_, SFX) - (self,self->posteriors,self->priors,self->covariances,self->means,data,numData) ; - } - return LL; -} - - -/* ---------------------------------------------------------------- */ -/* Kmeans initialization of mixtures */ -/* ---------------------------------------------------------------- */ - -static void -VL_XCAT(_vl_gmm_init_with_kmeans_, SFX) -(VlGMM * self, - TYPE const * data, - vl_size numData, - VlKMeans * kmeansInit) -{ - vl_size i_d ; - vl_uint32 * assignments = vl_malloc(sizeof(vl_uint32) * numData); - - _vl_gmm_prepare_for_data (self, numData) ; - - memset(self->means,0,sizeof(TYPE) * self->numClusters * self->dimension) ; - memset(self->priors,0,sizeof(TYPE) * self->numClusters) ; - memset(self->covariances,0,sizeof(TYPE) * self->numClusters * self->dimension) ; - memset(self->posteriors,0,sizeof(TYPE) * self->numClusters * numData) ; - - /* setup speified KMeans initialization object if any */ - if (kmeansInit) { vl_gmm_set_kmeans_init_object (self, kmeansInit) ; } - - /* if a KMeans initalization object is still unavailable, create one */ - if(self->kmeansInit == NULL) { - vl_size ncomparisons = VL_MAX(numData / 4, 10) ; - vl_size niter = 5 ; - vl_size ntrees = 1 ; - vl_size nrepetitions = 1 ; - VlKMeansAlgorithm algorithm = VlKMeansANN ; - VlKMeansInitialization initialization = VlKMeansRandomSelection ; - - VlKMeans * kmeansInitDefault = vl_kmeans_new(self->dataType,VlDistanceL2) ; - vl_kmeans_set_initialization(kmeansInitDefault, initialization); - vl_kmeans_set_max_num_iterations (kmeansInitDefault, niter) ; - vl_kmeans_set_max_num_comparisons (kmeansInitDefault, ncomparisons) ; - vl_kmeans_set_num_trees (kmeansInitDefault, ntrees); - vl_kmeans_set_algorithm (kmeansInitDefault, algorithm); - vl_kmeans_set_num_repetitions(kmeansInitDefault, nrepetitions); - vl_kmeans_set_verbosity (kmeansInitDefault, self->verbosity); - - self->kmeansInit = kmeansInitDefault; - self->kmeansInitIsOwner = VL_TRUE ; - } - - /* Use k-means to assign data to clusters */ - vl_kmeans_cluster (self->kmeansInit, data, self->dimension, numData, self->numClusters); - vl_kmeans_quantize (self->kmeansInit, assignments, NULL, data, numData) ; - - /* Transform the k-means assignments in posteriors and estimates the mode parameters */ - for(i_d = 0; i_d < numData; i_d++) { - ((TYPE*)self->posteriors)[assignments[i_d] + i_d * self->numClusters] = (TYPE) 1.0 ; - } - - /* Update cluster parameters */ - VL_XCAT(_vl_gmm_maximization_, SFX) - (self,self->posteriors,self->priors,self->covariances,self->means,data,numData); - vl_free(assignments) ; -} - -/* ---------------------------------------------------------------- */ -/* Random initialization of mixtures */ -/* ---------------------------------------------------------------- */ - -static void -VL_XCAT(_vl_gmm_compute_init_sigma_, SFX) -(VlGMM * self, - TYPE const * data, - TYPE * initSigma, - vl_size dimension, - vl_size numData) -{ - vl_size dim; - vl_uindex i; - - TYPE * dataMean ; - - memset(initSigma,0,sizeof(TYPE)*dimension) ; - if (numData <= 1) return ; - - dataMean = vl_malloc(sizeof(TYPE)*dimension); - memset(dataMean,0,sizeof(TYPE)*dimension) ; - - /* find mean of the whole dataset */ - for(dim = 0 ; dim < dimension ; dim++) { - for(i = 0 ; i < numData ; i++) { - dataMean[dim] += data[i*dimension + dim]; - } - dataMean[dim] /= numData; - } - - /* compute variance of the whole dataset */ - for(dim = 0; dim < dimension; dim++) { - for(i = 0; i < numData; i++) { - TYPE diff = (data[i*self->dimension + dim] - dataMean[dim]) ; - initSigma[dim] += diff*diff ; - } - initSigma[dim] /= numData - 1 ; - } - - vl_free(dataMean) ; -} - -static void -VL_XCAT(_vl_gmm_init_with_rand_data_, SFX) -(VlGMM * self, - TYPE const * data, - vl_size numData) -{ - vl_uindex i, k, dim ; - VlKMeans * kmeans ; - - _vl_gmm_prepare_for_data(self, numData) ; - - /* initilaize priors of gaussians so they are equal and sum to one */ - for (i = 0 ; i < self->numClusters ; ++i) { ((TYPE*)self->priors)[i] = (TYPE) (1.0 / self->numClusters) ; } - - /* initialize diagonals of covariance matrices to data covariance */ - VL_XCAT(_vl_gmm_compute_init_sigma_, SFX) (self, data, self->covariances, self->dimension, numData); - for (k = 1 ; k < self->numClusters ; ++ k) { - for(dim = 0; dim < self->dimension; dim++) { - *((TYPE*)self->covariances + k * self->dimension + dim) = - *((TYPE*)self->covariances + dim) ; - } - } - - /* use kmeans++ initialization to pick points at random */ - kmeans = vl_kmeans_new(self->dataType,VlDistanceL2) ; - vl_kmeans_init_centers_plus_plus(kmeans, data, self->dimension, numData, self->numClusters) ; - memcpy(self->means, vl_kmeans_get_centers(kmeans), sizeof(TYPE) * self->dimension * self->numClusters) ; - vl_kmeans_delete(kmeans) ; -} - -/* ---------------------------------------------------------------- */ -#else /* VL_GMM_INSTANTIATING */ -/* ---------------------------------------------------------------- */ - -#ifndef __DOXYGEN__ -#define FLT VL_TYPE_FLOAT -#define TYPE float -#define SFX f -#define VL_GMM_INSTANTIATING -#include "gmm.c" - -#define FLT VL_TYPE_DOUBLE -#define TYPE double -#define SFX d -#define VL_GMM_INSTANTIATING -#include "gmm.c" -#endif - -/* VL_GMM_INSTANTIATING */ -#endif - -/* ---------------------------------------------------------------- */ -#ifndef VL_GMM_INSTANTIATING -/* ---------------------------------------------------------------- */ - -/** @brief Create a new GMM object by copy - ** @param self object. - ** @return new copy. - ** - ** Most parameters, including the cluster priors, means, and - ** covariances are copied. Data posteriors (available after - ** initalization or EM) are not; nor is the KMeans object used for - ** initialization, if any. - **/ - -VlGMM * -vl_gmm_new_copy (VlGMM const * self) -{ - vl_size size = vl_get_type_size(self->dataType) ; - VlGMM * gmm = vl_gmm_new(self->dataType, self->dimension, self->numClusters); - gmm->initialization = self->initialization; - gmm->maxNumIterations = self->maxNumIterations; - gmm->numRepetitions = self->numRepetitions; - gmm->verbosity = self->verbosity; - gmm->LL = self->LL; - - memcpy(gmm->means, self->means, size*self->numClusters*self->dimension); - memcpy(gmm->covariances, self->covariances, size*self->numClusters*self->dimension); - memcpy(gmm->priors, self->priors, size*self->numClusters); - return gmm ; -} - -/** @brief Initialize mixture before EM takes place using random initialization - ** @param self GMM object instance. - ** @param data data points which should be clustered. - ** @param numData number of data points. - **/ - -void -vl_gmm_init_with_rand_data -(VlGMM * self, - void const * data, - vl_size numData) -{ - vl_gmm_reset (self) ; - switch (self->dataType) { - case VL_TYPE_FLOAT : _vl_gmm_init_with_rand_data_f (self, (float const *)data, numData) ; break ; - case VL_TYPE_DOUBLE : _vl_gmm_init_with_rand_data_d (self, (double const *)data, numData) ; break ; - default: - abort() ; - } -} - -/** @brief Initializes the GMM using KMeans - ** @param self GMM object instance. - ** @param data data points which should be clustered. - ** @param numData number of data points. - ** @param kmeansInit KMeans object to use. - **/ - -void -vl_gmm_init_with_kmeans -(VlGMM * self, - void const * data, - vl_size numData, - VlKMeans * kmeansInit) -{ - vl_gmm_reset (self) ; - switch (self->dataType) { - case VL_TYPE_FLOAT : - _vl_gmm_init_with_kmeans_f - (self, (float const *)data, numData, kmeansInit) ; - break ; - case VL_TYPE_DOUBLE : - _vl_gmm_init_with_kmeans_d - (self, (double const *)data, numData, kmeansInit) ; - break ; - default: - abort() ; - } -} - -#if 0 -#include -#endif - -/** @brief Run GMM clustering - includes initialization and EM - ** @param self GMM object instance. - ** @param data data points which should be clustered. - ** @param numData number of data points. - **/ - -double vl_gmm_cluster (VlGMM * self, - void const * data, - vl_size numData) -{ - void * bestPriors = NULL ; - void * bestMeans = NULL; - void * bestCovariances = NULL; - void * bestPosteriors = NULL; - vl_size size = vl_get_type_size(self->dataType) ; - double bestLL = -VL_INFINITY_D; - vl_uindex repetition; - - assert(self->numRepetitions >=1) ; - - bestPriors = vl_malloc(size * self->numClusters) ; - bestMeans = vl_malloc(size * self->dimension * self->numClusters) ; - bestCovariances = vl_malloc(size * self->dimension * self->numClusters) ; - bestPosteriors = vl_malloc(size * self->numClusters * numData) ; - -#if 0 - feenableexcept(FE_DIVBYZERO | FE_INVALID | FE_OVERFLOW); -#endif - - for (repetition = 0 ; repetition < self->numRepetitions ; ++ repetition) { - double LL ; - double timeRef ; - - if (self->verbosity) { - VL_PRINTF("gmm: clustering: starting repetition %d of %d\n", repetition + 1, self->numRepetitions) ; - } - - /* initialize a new mixture model */ - timeRef = vl_get_cpu_time() ; - switch (self->initialization) { - case VlGMMKMeans : vl_gmm_init_with_kmeans (self, data, numData, NULL) ; break ; - case VlGMMRand : vl_gmm_init_with_rand_data (self, data, numData) ; break ; - case VlGMMCustom : break ; - default: abort() ; - } - if (self->verbosity) { - VL_PRINTF("gmm: model initialized in %.2f s\n", - vl_get_cpu_time() - timeRef) ; - } - - /* fit the model to data by running EM */ - timeRef = vl_get_cpu_time () ; - LL = vl_gmm_em (self, data, numData) ; - if (self->verbosity) { - VL_PRINTF("gmm: optimization terminated in %.2f s with loglikelihood %f\n", - vl_get_cpu_time() - timeRef, LL) ; - } - - if (LL > bestLL || repetition == 0) { - void * temp ; - - temp = bestPriors ; - bestPriors = self->priors ; - self->priors = temp ; - - temp = bestMeans ; - bestMeans = self->means ; - self->means = temp ; - - temp = bestCovariances ; - bestCovariances = self->covariances ; - self->covariances = temp ; - - temp = bestPosteriors ; - bestPosteriors = self->posteriors ; - self->posteriors = temp ; - - bestLL = LL; - } - } - - vl_free (self->priors) ; - vl_free (self->means) ; - vl_free (self->covariances) ; - vl_free (self->posteriors) ; - - self->priors = bestPriors ; - self->means = bestMeans ; - self->covariances = bestCovariances ; - self->posteriors = bestPosteriors ; - self->LL = bestLL; - - if (self->verbosity) { - VL_PRINTF("gmm: all repetitions terminated with final loglikelihood %f\n", self->LL) ; - } - - return bestLL ; -} - -/** @brief Invoke the EM algorithm. - ** @param self GMM object instance. - ** @param data data points which should be clustered. - ** @param numData number of data points. - **/ - -double vl_gmm_em (VlGMM * self, void const * data, vl_size numData) -{ - switch (self->dataType) { - case VL_TYPE_FLOAT: - return _vl_gmm_em_f (self, (float const *)data, numData) ; break ; - case VL_TYPE_DOUBLE: - return _vl_gmm_em_d (self, (double const *)data, numData) ; break ; - default: - abort() ; - } - return 0 ; -} - -/** @brief Explicitly set the initial means for EM. - ** @param self GMM object instance. - ** @param means initial values of means. - **/ - -void -vl_gmm_set_means (VlGMM * self, void const * means) -{ - memcpy(self->means,means, - self->dimension * self->numClusters * vl_get_type_size(self->dataType)); -} - -/** @brief Explicitly set the initial sigma diagonals for EM. - ** @param self GMM object instance. - ** @param covariances initial values of covariance matrix diagonals. - **/ - -void vl_gmm_set_covariances (VlGMM * self, void const * covariances) -{ - memcpy(self->covariances,covariances, - self->dimension * self->numClusters * vl_get_type_size(self->dataType)); -} - -/** @brief Explicitly set the initial priors of the gaussians. - ** @param self GMM object instance. - ** @param priors initial values of the gaussian priors. - **/ - -void vl_gmm_set_priors (VlGMM * self, void const * priors) -{ - memcpy(self->priors,priors, - self->numClusters * vl_get_type_size(self->dataType)); -} - -/* VL_GMM_INSTANTIATING */ -#endif - -#undef SFX -#undef TYPE -#undef FLT -#undef VL_GMM_INSTANTIATING diff --git a/opensfm/src/third_party/vlfeat/vl/gmm.h b/opensfm/src/third_party/vlfeat/vl/gmm.h deleted file mode 100644 index 3562d74c2..000000000 --- a/opensfm/src/third_party/vlfeat/vl/gmm.h +++ /dev/null @@ -1,149 +0,0 @@ -/** @file gmm.h - ** @brief GMM (@ref gmm) - ** @author David Novotny - ** @author Andrea Vedaldi - **/ - -/* -Copyright (C) 2013 David Novotny and Andrea Vedaldi. -All rights reserved. - -This file is part of the VLFeat library and is made available under -the terms of the BSD license (see the COPYING file). -*/ - -#ifndef VL_GMM_H -#define VL_GMM_H - -#include "kmeans.h" - -/** @brief GMM initialization algorithms */ -typedef enum _VlGMMInitialization -{ - VlGMMKMeans, /**< Initialize GMM from KMeans clustering. */ - VlGMMRand, /**< Initialize GMM parameters by selecting points at random. */ - VlGMMCustom /**< User specifies the initial GMM parameters. */ -} VlGMMInitialization ; - - -#ifndef __DOXYGEN__ -struct _VlGMM ; -typedef struct _VlGMM VlGMM ; -#else -/** @brief GMM quantizer */ -typedef OPAQUE VlGMM ; -#endif - -/** @name Create and destroy - ** @{ - **/ -VL_EXPORT VlGMM * vl_gmm_new (vl_type dataType, vl_size dimension, vl_size numComponents) ; -VL_EXPORT VlGMM * vl_gmm_new_copy (VlGMM const * gmm) ; -VL_EXPORT void vl_gmm_delete (VlGMM * self) ; -VL_EXPORT void vl_gmm_reset (VlGMM * self); -/** @} */ - -/** @name Basic data processing - ** @{ - **/ -VL_EXPORT double -vl_gmm_cluster -(VlGMM * self, - void const * data, - vl_size numData); -/** @} */ - -/** @name Fine grained data processing - ** @{ */ - -VL_EXPORT void -vl_gmm_init_with_rand_data -(VlGMM * self, - void const * data, - vl_size numData) ; - -VL_EXPORT void -vl_gmm_init_with_kmeans -(VlGMM * self, - void const * data, - vl_size numData, - VlKMeans * kmeansInit); - -VL_EXPORT double -vl_gmm_em -(VlGMM * self, - void const * data, - vl_size numData); -/** @} */ - -VL_EXPORT void -vl_gmm_set_means -(VlGMM * self, - void const * means); - -VL_EXPORT void -vl_gmm_set_covariances -(VlGMM * self, - void const * covariances); - -VL_EXPORT void -vl_gmm_set_priors -(VlGMM * self, - void const * priors); - -VL_EXPORT double -vl_get_gmm_data_posteriors_f(float * posteriors, - vl_size numClusters, - vl_size numData, - float const * priors, - float const * means, - vl_size dimension, - float const * covariances, - float const * data) ; - -VL_EXPORT double -vl_get_gmm_data_posteriors_d(double * posteriors, - vl_size numClusters, - vl_size numData, - double const * priors, - double const * means, - vl_size dimension, - double const * covariances, - double const * data) ; -/** @} */ - -/** @name Set parameters - ** @{ - **/ -VL_EXPORT void vl_gmm_set_num_repetitions (VlGMM * self, vl_size numRepetitions) ; -VL_EXPORT void vl_gmm_set_max_num_iterations (VlGMM * self, vl_size maxNumIterations) ; -VL_EXPORT void vl_gmm_set_verbosity (VlGMM * self, int verbosity) ; -VL_EXPORT void vl_gmm_set_initialization (VlGMM * self, VlGMMInitialization init); -VL_EXPORT void vl_gmm_set_kmeans_init_object (VlGMM * self, VlKMeans * kmeans); -VL_EXPORT void vl_gmm_set_covariance_lower_bounds (VlGMM * self, double const * bounds); -VL_EXPORT void vl_gmm_set_covariance_lower_bound (VlGMM * self, double bound) ; -/** @} */ - -/** @name Get parameters - ** @{ - **/ -VL_EXPORT void const * vl_gmm_get_means (VlGMM const * self); -VL_EXPORT void const * vl_gmm_get_covariances (VlGMM const * self); -VL_EXPORT void const * vl_gmm_get_priors (VlGMM const * self); -VL_EXPORT void const * vl_gmm_get_posteriors (VlGMM const * self); -VL_EXPORT vl_type vl_gmm_get_data_type (VlGMM const * self); -VL_EXPORT vl_size vl_gmm_get_dimension (VlGMM const * self); -VL_EXPORT vl_size vl_gmm_get_num_repetitions (VlGMM const * self); -VL_EXPORT vl_size vl_gmm_get_num_data (VlGMM const * self); -VL_EXPORT vl_size vl_gmm_get_num_clusters (VlGMM const * self); -VL_EXPORT double vl_gmm_get_loglikelihood (VlGMM const * self); -VL_EXPORT int vl_gmm_get_verbosity (VlGMM const * self); -VL_EXPORT vl_size vl_gmm_get_max_num_iterations (VlGMM const * self); -VL_EXPORT vl_size vl_gmm_get_num_repetitions (VlGMM const * self); -VL_EXPORT VlGMMInitialization vl_gmm_get_initialization (VlGMM const * self); -VL_EXPORT VlKMeans * vl_gmm_get_kmeans_init_object (VlGMM const * self); -VL_EXPORT double const * vl_gmm_get_covariance_lower_bounds (VlGMM const * self); -/** @} */ - -/* VL_GMM_H */ -#endif diff --git a/opensfm/src/third_party/vlfeat/vl/heap-def.h b/opensfm/src/third_party/vlfeat/vl/heap-def.h deleted file mode 100644 index bb56c6ceb..000000000 --- a/opensfm/src/third_party/vlfeat/vl/heap-def.h +++ /dev/null @@ -1,464 +0,0 @@ -/** @file heap-def.h - ** @brief Heap preprocessor metaprogram - ** @author Andrea Vedaldi - **/ - -/* -Copyright (C) 2007-12 Andrea Vedaldi and Brian Fulkerson. -All rights reserved. - -This file is part of the VLFeat library and is made available under -the terms of the BSD license (see the COPYING file). -*/ - -/** @file heap-def.h - - A heap organizes an array of objects in a priority queue. This module - is a template metaprogram that defines heap operations on array of - generic objects, or even generic object containers. - - - @ref heap-def-overview "Overview" - - @ref heap-def-overview-general "General usage" - - @ref heap-def-tech "Technical details" - - - @section heap-def-overview Overview - - - To use @ref heap-def.h one must specify at least a prefix and the data - type for the heap elements: - - @code - #define VL_HEAP_prefix my_heap - #define VL_HEAP_type float - #include - @endcode - - This code fragment defines a number of functions prefixed by - ::VL_HEAP_prefix, such as @c my_heap_push (::VL_HEAP_push) and @c - my_heap_pop (::VL_HEAP_pop), that implement the heap operations. - These functions operate on an array that has type ::VL_HEAP_array. - By default, this is defined to be: - - @code - #define VL_HEAP_array VL_HEAP_type* - #define VL_HEAP_array_const VL_HEAP_type const* - @endcode - - The array itself is accessed uniquely by means of two functions: - - - ::VL_HEAP_cmp, that compares two array elements. The default - implementation assumes that ::VL_HEAP_type is numeric. - - ::VL_HEAP_swap, that swaps two array elements. The default - implementation assumes that ::VL_HEAP_type can be copied by the @c - = operator. - - The heap state is a integer @c numElements (of type ::vl_size) counting - the number of elements of the array that are currently part of the heap - and the content of the first @c numElements elements of the array. The - portion of the array that constitutes the heap satisfies a certain - invariant property (heap property, @ref heap-def-tech). From a user - viewpoint, the most important consequence is that the first element - of the array (the one of index 0) is also the smallest (according to - ::VL_HEAP_cmp). - - Elements are added to the heap by ::VL_HEAP_push and removed from the - heap by ::VL_HEAP_pop. A push operation adds to the heap the array - element immediately after the last element already in the heap - (i.e. the element of index @c numElements) and increases the number of - heap elements @c numElements. Elements in the heap are swapped as required in - order to maintain the heap consistency. Similarly, a pop operation - removes the first (smaller) element from the heap and decreases the - number of heap elements @c numElements. - - The values of nodes currently in the heap can be updated by - ::VL_HEAP_update. Notice however that using this function requires - knowing the index of the element that needs to be updated up to the - swapping operations that the heap performs to maintain - consistency. Typically, this requires redefining ::VL_HEAP_swap to - keep track of such changes (@ref heap-def-overview-general). - - - @subsection heap-def-overview-general General usage - - - The heap container may be mapped to any type by reimplementing - ::VL_HEAP_cmp and ::VL_HEAP_swap explicitly. For instance - the following code redefines ::VL_HEAP_cmp to deal with the case - in which the heap is an array of structures: - - @code - typedef struct _S { int x ; } S ; - int s_cmp (S const * v, vl_uindex a, vl_uindex b) { - return v[a].x - v[b].x ; - } - #define VL_HEAP_prefix s_heap - #define VL_HEAP_type S - #define VL_HEAP_cmp s_cmp - #include - @endcode - - In the following example, the heap itself is an arbitrary structure: - - @code - typedef struct _H { int* array ; } H ; - int h_cmp (H const * h, vl_uindex a, vl_uindex b) { - return h->array[a] - h->array[b] ; - } - int h_swap (H * h, vl_uindex a, vl_uindex b) { - int t = h->array[a] ; - h->array[a] = h->array[b] ; - h->array[b] = t ; - } - #define VL_HEAP_prefix h_heap - #define VL_HEAP_swap h_swap - #define VL_HEAP_cmp h_cmp - #include - @endcode - - - @section heap-def-tech Technical details - - - The heap is organised as a binary tree with the property (heap - property) that any node is not larger than any of its - children. In particular, the root is the smallest node. - - @ref heap-def.h uses the standard binary tree representation as a linear - array. Tree nodes are mapped to array elements as follows: - array[0] corresponds to the root, array[1] - and array[2] to the root left and right children and so - on. In this way, the tree structure is fully specified by the total - number of nodes N. - - Assuming that the heap has N nodes (from - array[0] to array[N-1]), adding the node - array[N] to the heap is done by a push down - operation: if the node array[N] is smaller than its - parent (violating the heap property) it is pushed down by swapping it - with the parent, and so on recursively. - - Removing the smallest element array[0] with an heap of - N nodes is done by swapping array[0] with - array[N-1]. If then array[0] is larger than - any of its children, it is swapped with the smallest of the two and - so on recursively (push up operation). - - Restoring the heap property after an element array[i] - has been modified can be done by a push up or push down operation on - that node. - - **/ - -#include "host.h" -#include - -#ifndef VL_HEAP_prefix -#error "VL_HEAP_prefix must be defined" -#endif - -#ifndef VL_HEAP_array -#ifndef VL_HEAP_type -#error "VL_HEAP_type must be defined if VL_HEAP_array is not" -#endif -#define VL_HEAP_array VL_HEAP_type* -#define VL_HEAP_array_const VL_HEAP_type const* -#endif - -#ifndef VL_HEAP_array_const -#define VL_HEAP_array_const VL_HEAP_array -#endif - -#ifdef __DOXYGEN__ -#define VL_HEAP_prefix HeapObject /**< Prefix of the heap functions */ -#define VL_HEAP_type HeapType /**< Data type of the heap elements */ -#define VL_HEAP_array HeapType* /**< Data type of the heap container */ -#define VL_HEAP_array HeapType const* /**< Const data type of the heap container */ -#endif - -/* ---------------------------------------------------------------- */ - -#ifndef VL_HEAP_DEF_H -#define VL_HEAP_DEF_H - -/** @internal @brief Get index of parent node - ** @param index a node index. - ** @return index of the parent node. - **/ - -VL_INLINE vl_uindex -vl_heap_parent (vl_uindex index) -{ - if (index == 0) return 0 ; - return (index - 1) / 2 ; -} - -/** @internal @brief Get index of left child - ** @param index a node index. - ** @return index of the left child. - **/ - -VL_INLINE vl_uindex -vl_heap_left_child (vl_uindex index) -{ - return 2 * index + 1 ; -} - -/** @internal @brief Get index of right child - ** @param index a node index. - ** @return index of the right child. - **/ - -VL_INLINE vl_uindex -vl_heap_right_child (vl_uindex index) -{ - return vl_heap_left_child (index) + 1 ; -} - -/* VL_HEAP_DEF_H */ -#endif - -/* ---------------------------------------------------------------- */ - -#if ! defined(VL_HEAP_cmp) || defined(__DOXYGEN__) -#define VL_HEAP_cmp VL_XCAT(VL_HEAP_prefix, _cmp) - -/** @brief Compare two heap elements - ** @param array heap array. - ** @param indexA index of the first element @c A to compare. - ** @param indexB index of the second element @c B to comapre. - ** @return a negative number if @c AB. - **/ - -VL_INLINE VL_HEAP_type -VL_HEAP_cmp -(VL_HEAP_array_const array, - vl_uindex indexA, - vl_uindex indexB) -{ - return array[indexA] - array[indexB] ; -} - -/* VL_HEAP_cmp */ -#endif - -/* ---------------------------------------------------------------- */ - -#if ! defined(VL_HEAP_swap) || defined(__DOXYGEN__) -#define VL_HEAP_swap VL_XCAT(VL_HEAP_prefix, _swap) - -/** @brief Swap two heap elements - ** @param array array of nodes. - ** @param array heap array. - ** @param indexA index of the first node to swap. - ** @param indexB index of the second node to swap. - ** - ** The function swaps the two heap elements @a a and @ b. The function - ** uses a temporary element and the copy operator, which must be - ** well defined for the heap elements. - **/ - -VL_INLINE void -VL_HEAP_swap -(VL_HEAP_array array, - vl_uindex indexA, - vl_uindex indexB) -{ - VL_HEAP_type t = array [indexA] ; - array [indexA] = array [indexB] ; - array [indexB] = t ; -} - -/* VL_HEAP_swap */ -#endif - -/* ---------------------------------------------------------------- */ - -#if ! defined(VL_HEAP_up) || defined(__DOXYGEN__) -#define VL_HEAP_up VL_XCAT(VL_HEAP_prefix, _up) - -/** @brief Heap up operation - ** @param array pointer to the heap array. - ** @param heapSize size of the heap. - ** @param index index of the node to push up. - **/ - -VL_INLINE void -VL_HEAP_up -(VL_HEAP_array array, vl_size heapSize, vl_uindex index) -{ - vl_uindex leftIndex = vl_heap_left_child (index) ; - vl_uindex rightIndex = vl_heap_right_child (index) ; - - /* no childer: stop */ - if (leftIndex >= heapSize) return ; - - /* only left childer: easy */ - if (rightIndex >= heapSize) { - if (VL_HEAP_cmp (array, index, leftIndex) > 0) { - VL_HEAP_swap (array, index, leftIndex) ; - } - return ; - } - - /* both childern */ - { - if (VL_HEAP_cmp (array, leftIndex, rightIndex) < 0) { - /* swap with left */ - if (VL_HEAP_cmp (array, index, leftIndex) > 0) { - VL_HEAP_swap (array, index, leftIndex) ; - VL_HEAP_up (array, heapSize, leftIndex) ; - } - } else { - /* swap with right */ - if (VL_HEAP_cmp (array, index, rightIndex) > 0) { - VL_HEAP_swap (array, index, rightIndex) ; - VL_HEAP_up (array, heapSize, rightIndex) ; - } - } - } -} - -/* VL_HEAP_up */ -#endif - -/* ---------------------------------------------------------------- */ - -#if ! defined(VL_HEAP_down) || defined(__DOXYGEN__) -#define VL_HEAP_down VL_XCAT(VL_HEAP_prefix, _down) - -/** @brief Heap down operation - ** @param array pointer to the heap node array. - ** @param index index of the node to push up. - **/ - -VL_INLINE void -VL_HEAP_down -(VL_HEAP_array array, vl_uindex index) -{ - vl_uindex parentIndex ; - - if (index == 0) return ; - - parentIndex = vl_heap_parent (index) ; - - if (VL_HEAP_cmp (array, index, parentIndex) < 0) { - VL_HEAP_swap (array, index, parentIndex) ; - VL_HEAP_down (array, parentIndex) ; - } -} - -/* VL_HEAP_down */ -#endif - -/* ---------------------------------------------------------------- */ - -#if ! defined(VL_HEAP_push) || defined(__DOXYGEN__) -#define VL_HEAP_push VL_XCAT(VL_HEAP_prefix, _push) - -/** @brief Heap push operation - ** @param array pointer to the heap array. - ** @param heapSize (in/out) size of the heap. - ** - ** The function adds to the heap the element of index @c heapSize - ** and increments @c heapSize. - **/ - -VL_INLINE void -VL_HEAP_push -(VL_HEAP_array array, vl_size *heapSize) -{ - VL_HEAP_down (array, *heapSize) ; - *heapSize += 1 ; -} - -/* VL_HEAP_push */ -#endif - -/* ---------------------------------------------------------------- */ - -#if ! defined(VL_HEAP_pop) || defined(__DOXYGEN__) -#define VL_HEAP_pop VL_XCAT(VL_HEAP_prefix, _pop) - -/** @brief Heap pop operation - ** @param array pointer to the heap array. - ** @param heapSize (in/out) size of the heap. - ** @return index of the popped element. - ** - ** The function extracts from the heap the element of index 0 - ** (the smallest element) and decreases @c heapSize. - ** - ** The element extracted is moved as the first element after - ** the heap end (thus it has index @c heapSize). For convenience, - ** this index is returned by the function. - ** - ** Popping from an empty heap is undefined. - **/ - -VL_INLINE vl_uindex -VL_HEAP_pop -(VL_HEAP_array array, vl_size *heapSize) -{ - assert (*heapSize) ; - - *heapSize -= 1 ; - - VL_HEAP_swap (array, 0, *heapSize) ; - - if (*heapSize > 1) { - VL_HEAP_up (array, *heapSize, 0) ; - } - - return *heapSize ; -} - -/* VL_HEAP_pop */ -#endif - -/* ---------------------------------------------------------------- */ - -#if ! defined(VL_HEAP_update) || defined(__DOXYGEN__) -#define VL_HEAP_update VL_XCAT(VL_HEAP_prefix, _update) - -/** @brief Heap update operation - ** @param array pointer to the heap array. - ** @param heapSize size of the heap. - ** @param index index of the node to update. - ** - ** The function updates the heap to account for a change to the - ** element of index @c index in the heap. - ** - ** Notice that using this - ** function requires knowing the index of the heap index of - ** element that was changed. Since the heap swaps elements in the - ** array, this is in general different from the index that that - ** element had originally. - **/ - -VL_INLINE void -VL_HEAP_update -(VL_HEAP_array array, - vl_size heapSize, - vl_uindex index) -{ - VL_HEAP_up (array, heapSize, index) ; - VL_HEAP_down (array, index) ; -} - -/* VL_HEAP_update */ -#endif - -/* ---------------------------------------------------------------- */ - -#undef VL_HEAP_cmp -#undef VL_HEAP_swap -#undef VL_HEAP_up -#undef VL_HEAP_down -#undef VL_HEAP_push -#undef VL_HEAP_pop -#undef VL_HEAP_update -#undef VL_HEAP_prefix -#undef VL_HEAP_type -#undef VL_HEAP_array -#undef VL_HEAP_array_const diff --git a/opensfm/src/third_party/vlfeat/vl/hikmeans.c b/opensfm/src/third_party/vlfeat/vl/hikmeans.c deleted file mode 100644 index c72720831..000000000 --- a/opensfm/src/third_party/vlfeat/vl/hikmeans.c +++ /dev/null @@ -1,371 +0,0 @@ -/** @file hikmeans.c - ** @brief Hierarchical Integer K-Means Clustering - Declaration - ** @author Brian Fulkerson - ** @author Andrea Vedaldi - **/ - -/* -Copyright (C) 2007-12 Andrea Vedaldi and Brian Fulkerson. -All rights reserved. - -This file is part of the VLFeat library and is made available under -the terms of the BSD license (see the COPYING file). -*/ - -/** @file hikmeans.h - ** @brief Hierarchical integer K-Means clustering - ** - ** Hierarchical integer K-Means clustering (HIKM) is a simple - ** hierarchical version of integer K-Means (@ref ikmeans.h - ** "IKM"). The algorithm recursively applies integer K-means to create - ** more refined partitions of the data. - ** - ** Create a tree with ::vl_hikm_new() and delete it with - ** ::vl_hikm_delete(). Use ::vl_hikm_train() to build the tree - ** from training data and ::vl_hikm_push() to project new data down - ** a HIKM tree. - ** - ** @section hikm-tree HIKM tree - ** - ** The HIKM tree is represented by a ::VlHIKMTree structure, which - ** contains a tree composed of ::VlHIKMNode. Each node is an - ** integer K-means filter which partitions the data into @c K - ** clusters. - **/ - -#include -#include -#include -#include - -#include "hikmeans.h" - -/** ------------------------------------------------------------------ - ** @internal - ** @brief Copy a subset of the data to a buffer - ** @param data Data - ** @param ids Data labels - ** @param N Number of indices - ** @param M Data dimensionality - ** @param id Label of data to copy - ** @param N2 Number of data copied (out) - ** @return a new buffer with a copy of the selected data. - **/ - -vl_uint8* -vl_hikm_copy_subset (vl_uint8 const * data, - vl_uint32 *ids, - vl_size N, vl_size M, - vl_uint32 id, vl_size *N2) -{ - vl_uindex i ; - vl_size count = 0; - - /* count how many data points with this label there are */ - for (i = 0 ; i < N ; i++) { - if (ids[i] == id) { - count ++ ; - } - } - *N2 = count ; - - /* copy each datum to the buffer */ - { - vl_uint8 *new_data = vl_malloc (sizeof(*new_data) * M * count); - count = 0; - for (i = 0 ; i < N ; i ++) { - if (ids[i] == id) { - memcpy(new_data + count * M, - data + i * M, - sizeof(*new_data) * M); - count ++ ; - } - } - *N2 = count ; - return new_data ; - } -} - -/** ------------------------------------------------------------------ - ** @brief Compute HIKM clustering. - ** - ** @param tree HIKM tree to initialize. - ** @param data Data to cluster. - ** @param N Number of data points. - ** @param K Number of clusters for this node. - ** @param height Tree height. - ** - ** @remark height cannot be smaller than 1. - ** - ** @return a new HIKM node representing a sub-clustering. - **/ - -static VlHIKMNode * -xmeans (VlHIKMTree *tree, - vl_uint8 const *data, - vl_size N, vl_size K, vl_size height) -{ - VlHIKMNode *node = vl_malloc (sizeof(*node)) ; - vl_uint32 *ids = vl_malloc (sizeof(*ids) * N) ; - - node->filter = vl_ikm_new (tree -> method) ; - node->children = (height == 1) ? 0 : vl_malloc (sizeof(*node->children) * K) ; - - vl_ikm_set_max_niters (node->filter, tree->max_niters) ; - vl_ikm_set_verbosity (node->filter, tree->verb - 1 ) ; - vl_ikm_init_rand_data (node->filter, data, tree->M, N, K) ; - vl_ikm_train (node->filter, data, N) ; - vl_ikm_push (node->filter, ids, data, N) ; - - /* recursively process each child */ - if (height > 1) { - vl_uindex k ; - for (k = 0 ; k < K ; ++k) { - vl_size partition_N ; - vl_size partition_K ; - vl_uint8 *partition ; - - partition = vl_hikm_copy_subset - (data, ids, N, tree->M, (vl_uint32)k, &partition_N) ; - - partition_K = VL_MIN (K, partition_N) ; - - node->children [k] = xmeans - (tree, partition, partition_N, partition_K, height - 1) ; - - vl_free (partition) ; - - if (tree->verb > (signed)tree->depth - (signed)height) { - VL_PRINTF("hikmeans: branch at depth %d: %6.1f %% completed\n", - tree->depth - height, - (double) (k+1) / K * 100) ; - } - } - } - - vl_free (ids) ; - return node ; -} - -/** ------------------------------------------------------------------ - ** @internal - ** @brief Delete node - ** - ** @param node to delete. - ** - ** The function deletes recursively @a node and all its descendent. - **/ - -static void -xdelete (VlHIKMNode *node) -{ - if(node) { - vl_uindex k ; - if (node->children) { - for(k = 0 ; k < vl_ikm_get_K (node->filter) ; ++k) - xdelete (node->children[k]) ; - vl_free (node->children) ; - } - if (node->filter) { - vl_ikm_delete (node->filter) ; - } - vl_free(node); - } -} - -/** ------------------------------------------------------------------ - ** @brief New HIKM tree - ** @param method clustering method. - ** @return new HIKM tree. - **/ - -VlHIKMTree * -vl_hikm_new (int method) -{ - VlHIKMTree *f = vl_calloc (sizeof(VlHIKMTree), 1) ; - f->max_niters = 200 ; - f->method = method ; - return f ; -} - -/** ------------------------------------------------------------------ - ** @brief Delete HIKM tree - ** @param f HIKM tree. - **/ - -void -vl_hikm_delete (VlHIKMTree *f) -{ - if (f) { - xdelete (f->root) ; - vl_free (f) ; - } -} - -/** ------------------------------------------------------------------ - ** @brief Initialize HIKM tree - ** @param f HIKM tree. - ** @param M Data dimensionality. - ** @param K Number of clusters per node. - ** @param depth Tree depth. - ** @return a new HIKM tree representing the clustering. - ** - ** @remark @a depth cannot be smaller than 1. - **/ - -void -vl_hikm_init (VlHIKMTree *f, vl_size M, vl_size K, vl_size depth) -{ - assert(depth > 0) ; - assert(M > 0) ; - assert(K > 0) ; - - xdelete (f -> root) ; - f->root = 0; - f->M = M ; - f->K = K ; - f->depth = depth ; -} - -/** ------------------------------------------------------------------ - ** @brief Train HIKM tree - ** @param f HIKM tree. - ** @param data Data to cluster. - ** @param N Number of data. - **/ - -void -vl_hikm_train (VlHIKMTree *f, vl_uint8 const *data, vl_size N) -{ - f->root= xmeans (f, data, N, VL_MIN(f->K, N), f->depth) ; -} - -/** ------------------------------------------------------------------ - ** @brief Project data down HIKM tree - ** @param f HIKM tree. - ** @param asgn Path down the tree (out). - ** @param data Data to project. - ** @param N Number of data. - ** - ** The function writes to @a asgn the path of the data @a data - ** down the HIKM tree @a f. The parameter @a asgn must point to - ** an array of @c M by @c N elements, where @c M is the depth of - ** the HIKM tree and @c N is the number of data point to process. - **/ - -void -vl_hikm_push (VlHIKMTree *f, vl_uint32 *asgn, vl_uint8 const *data, vl_size N) -{ - vl_uindex i, d ; - vl_size M = vl_hikm_get_ndims (f) ; - vl_size depth = vl_hikm_get_depth (f) ; - - /* for each datum */ - for(i = 0 ; i < N ; i++) { - VlHIKMNode *node = f->root ; - d = 0 ; - while (node) { - vl_uint32 best ; - vl_ikm_push (node->filter, - &best, - data + i * M, 1) ; - asgn[i * depth + d] = best ; - ++ d ; - if (!node->children) break ; - node = node->children [best] ; - } - } -} - -/* ---------------------------------------------------------------- */ -/* Setters and getters */ -/* ---------------------------------------------------------------- */ - -/** @brief Get data dimensionality - ** @param f HIKM tree. - ** @return data dimensionality. - **/ - -vl_size -vl_hikm_get_ndims (VlHIKMTree const* f) -{ - return f->M ; -} - -/** @brief Get K - ** @param f HIKM tree. - ** @return K. - **/ - -vl_size -vl_hikm_get_K (VlHIKMTree const *f) -{ - return f->K ; -} - -/** @brief Get depth - ** @param f HIKM tree. - ** @return depth. - **/ - -vl_size -vl_hikm_get_depth (VlHIKMTree const *f) -{ - return f->depth ; -} - - -/** @brief Get verbosity level - ** @param f HIKM tree. - ** @return verbosity level. - **/ - -int -vl_hikm_get_verbosity (VlHIKMTree const *f) -{ - return f->verb ; -} - -/** @brief Get maximum number of iterations - ** @param f HIKM tree. - ** @return maximum number of iterations. - **/ - -vl_size -vl_hikm_get_max_niters (VlHIKMTree const *f) -{ - return f-> max_niters ; -} - -/** @brief Get maximum number of iterations - ** @param f HIKM tree. - ** @return maximum number of iterations. - **/ - -VlHIKMNode const * -vl_hikm_get_root (VlHIKMTree const *f) -{ - return f->root ; -} - -/** @brief Set verbosity level - ** @param f HIKM tree. - ** @param verb verbosity level. - **/ - -void -vl_hikm_set_verbosity (VlHIKMTree *f, int verb) -{ - f->verb = verb ; -} - -/** @brief Set maximum number of iterations - ** @param f HIKM tree. - ** @param max_niters maximum number of iterations. - **/ - -void -vl_hikm_set_max_niters (VlHIKMTree *f, int max_niters) -{ - f->max_niters = max_niters ; -} diff --git a/opensfm/src/third_party/vlfeat/vl/hikmeans.h b/opensfm/src/third_party/vlfeat/vl/hikmeans.h deleted file mode 100644 index 5da4f5ec8..000000000 --- a/opensfm/src/third_party/vlfeat/vl/hikmeans.h +++ /dev/null @@ -1,80 +0,0 @@ -/** @file hikmeans.h - ** @brief Hierarchical Integer K-Means Clustering - ** @author Brian Fulkerson - **/ - -/* -Copyright (C) 2007-12 Andrea Vedaldi and Brian Fulkerson. -All rights reserved. - -This file is part of the VLFeat library and is made available under -the terms of the BSD license (see the COPYING file). -*/ - -#ifndef VL_HIKMEANS_H -#define VL_HIKMEANS_H - -#include "generic.h" -#include "ikmeans.h" - -struct _VLHIKMTree ; -struct _VLHIKMNode ; - -/** @brief HIKM tree node - ** - ** The number of children @a K is not bigger than the @a K parameter - ** of the HIKM tree. - **/ -typedef struct _VlHIKMNode -{ - VlIKMFilt *filter ; /**< IKM filter for this node*/ - struct _VlHIKMNode **children ; /**< Node children (if any) */ -} VlHIKMNode ; - -/** @brief HIKM tree */ -typedef struct _VlHIKMTree { - vl_size M ; /**< IKM: data dimensionality */ - vl_size K ; /**< IKM: K */ - vl_size depth ; /**< Depth of the tree */ - vl_size max_niters ; /**< IKM: maximum # of iterations */ - int method ; /**< IKM: method */ - int verb ; /**< Verbosity level */ - VlHIKMNode * root; /**< Tree root node */ -} VlHIKMTree ; - -/** @name Create and destroy - ** @{ - **/ -VL_EXPORT VlHIKMTree *vl_hikm_new (int method) ; -VL_EXPORT void vl_hikm_delete (VlHIKMTree *f) ; -/** @} */ - -/** @name Retrieve data and parameters - ** @{ - **/ -VL_EXPORT vl_size vl_hikm_get_ndims (VlHIKMTree const *f) ; -VL_EXPORT vl_size vl_hikm_get_K (VlHIKMTree const *f) ; -VL_EXPORT vl_size vl_hikm_get_depth (VlHIKMTree const *f) ; -VL_EXPORT int vl_hikm_get_verbosity (VlHIKMTree const *f) ; -VL_EXPORT vl_size vl_hikm_get_max_niters (VlHIKMTree const *f) ; -VL_EXPORT VlHIKMNode const * vl_hikm_get_root (VlHIKMTree const *f) ; -/** @} */ - -/** @name Set parameters - ** @{ - **/ -VL_EXPORT void vl_hikm_set_verbosity (VlHIKMTree *f, int verb) ; -VL_EXPORT void vl_hikm_set_max_niters (VlHIKMTree *f, int max_niters) ; -/** @} */ - -/** @name Process data - ** @{ - **/ -VL_EXPORT void vl_hikm_init (VlHIKMTree *f, vl_size M, vl_size K, vl_size depth) ; -VL_EXPORT void vl_hikm_train (VlHIKMTree *f, vl_uint8 const *data, vl_size N) ; -VL_EXPORT void vl_hikm_push (VlHIKMTree *f, vl_uint32 *asgn, vl_uint8 const *data, vl_size N) ; -/** @} */ - - -/* VL_HIKMEANS_H */ -#endif diff --git a/opensfm/src/third_party/vlfeat/vl/hog.c b/opensfm/src/third_party/vlfeat/vl/hog.c deleted file mode 100644 index 0a1487541..000000000 --- a/opensfm/src/third_party/vlfeat/vl/hog.c +++ /dev/null @@ -1,1072 +0,0 @@ -/** @file hog.c - ** @brief Histogram of Oriented Gradients (HOG) - Definition - ** @author Andrea Vedaldi - **/ - -/* - Copyright (C) 2007-12 Andrea Vedaldi and Brian Fulkerson. - All rights reserved. - - This file is part of the VLFeat library and is made available under - the terms of the BSD license (see the COPYING file). -*/ - -#include "hog.h" -#include "mathop.h" -#include - -/** - - -@page hog Histogram of Oriented Gradients (HOG) features -@author Andrea Vedaldi - - -@ref hog.h implements the Histogram of Oriented Gradients (HOG) features -in the variants of Dalal Triggs @cite{dalal05histograms} and of UOCTTI -@cite{felzenszwalb09object}. Applications include object detection -and deformable object detection. - -- @ref hog-overview -- @ref hog-tech - - -@section hog-overview Overview - - -HOG is a standard image feature used, among others, in object detection -and deformable object detection. It decomposes the image into square cells -of a given size (typically eight pixels), compute a histogram of oriented -gradient in each cell (similar to @ref sift), and then renormalizes -the cells by looking into adjacent blocks. - -VLFeat implements two HOG variants: the original one of Dalal-Triggs -@cite{dalal05histograms} and the one proposed in Felzenszwalb et al. -@cite{felzenszwalb09object}. - -In order to use HOG, start by creating a new HOG object, set the desired -parameters, pass a (color or grayscale) image, and read off the results. - -@code -VlHog * hog = vl_hog_new(VlHogVariantDalalTriggs, numOrientations, VL_FALSE) ; -vl_hog_put_image(hog, image, height, width, numChannels, cellSize) ; -hogWidth = vl_hog_get_width(hog) ; -hogHeight = vl_hog_get_height(hog) ; -hogDimenison = vl_hog_get_dimension(hog) ; -hogArray = vl_malloc(hogWidth*hogHeight*hogDimension*sizeof(float)) ; -vl_hog_extract(hog, hogArray) ; -vl_hog_delete(hog) ; -@endcode - -HOG is a feature array of the dimension returned by ::vl_hog_get_width, -::vl_hog_get_height, with each feature (histogram) having -dimension ::vl_hog_get_dimension. The array is stored in row major order, -with the slowest varying dimension beying the dimension indexing the histogram -elements. - -The number of entreis in the histogram as well as their meaning depends -on the HOG variant and is detailed later. However, it is usually -unnecessary to know such details. @ref hog.h provides support for -creating an inconic representation of a HOG feature array: - -@code -glyphSize = vl_hog_get_glyph_size(hog) ; -imageHeight = glyphSize * hogArrayHeight ; -imageWidth = glyphSize * hogArrayWidth ; -image = vl_malloc(sizeof(float)*imageWidth*imageHeight) ; -vl_hog_render(hog, image, hogArray) ; -@endcode - -It is often convenient to mirror HOG features from left to right. This -can be obtained by mirroring an array of HOG cells, but the content -of each cell must also be rearranged. This can be done by -the permutation obtaiend by ::vl_hog_get_permutation. - -Furthermore, @ref hog.h suppots computing HOG features not from -images but from vector fields. - - -@section hog-tech Technical details - - -HOG divdes the input image into square cells of size @c cellSize, -fitting as many cells as possible, filling the image domain from -the upper-left corner down to the right one. For each row and column, -the last cell is at least half contained in the image. -More precisely, the number of cells obtained in this manner is: - -@code -hogWidth = (width + cellSize/2) / cellSize ; -hogHeight = (height + cellSize/2) / cellSize ; -@endcode - -Then the image gradient @f$ \nabla \ell(x,y) @f$ -is computed by using central difference (for colour image -the channel with the largest gradient at that pixel is used). -The gradient @f$ \nabla \ell(x,y) @f$ is assigned to one of @c 2*numOrientations orientation in the -range @f$ [0,2\pi) @f$ (see @ref hog-conventions for details). -Contributions are then accumulated by using bilinear interpolation -to four neigbhour cells, as in @ref sift. -This results in an histogram @f$h_d@f$ of dimension -2*numOrientations, called of @e directed orientations -since it accounts for the direction as well as the orientation -of the gradient. A second histogram @f$h_u@f$ of undirected orientations -of half the size is obtained by folding @f$ h_d @f$ into two. - -Let a block of cell be a @f$ 2\times 2 @f$ sub-array of cells. -Let the norm of a block be the @f$ l^2 @f$ norm of the stacking of the -respective unoriented histogram. Given a HOG cell, four normalisation -factors are then obtained as the inverse of the norm of the four -blocks that contain the cell. - -For the Dalal-Triggs variant, each histogram @f$ h_d @f$ is copied -four times, normalised using the four different normalisation factors, -the four vectors are stacked, saturated at 0.2, and finally stored as the descriptor -of the cell. This results in a @c numOrientations * 4 dimensional -cell descriptor. Blocks are visited from left to right and top to bottom -when forming the final descriptor. - -For the UOCCTI descriptor, the same is done for both the undirected -as well as the directed orientation histograms. This would yield -a dimension of @c 4*(2+1)*numOrientations elements, but the resulting -vector is projected down to @c (2+1)*numOrientations elements -by averaging corresponding histogram dimensions. This was shown to -be an algebraic approximation of PCA for descriptors computed on natural -images. - -In addition, for the UOCTTI variant the l1 norm of each of the -four l2 normalised undirected histograms is computed and stored -as additional four dimensions, for a total of -@c 4+3*numOrientations dimensions. - - -@subsection hog-conventions Conventions - - -The orientation of a gradient is expressed as the angle it forms with the -horizontal axis of the image. Angles are measured clock-wise (as the vertical -image axis points downards), and the null angle corresponds to -an horizontal vector pointing right. The quantized directed -orientations are @f$ \mathrm{k} \pi / \mathrm{numOrientations} @f$, where -@c k is an index that varies in the ingeger -range @f$ \{0, \dots, 2\mathrm{numOrientations} - 1\} @f$. - -Note that the orientations capture the orientation of the gradeint; -image edges would be oriented at 90 degrees from these. - -**/ - -/* ---------------------------------------------------------------- */ -/** @brief Create a new HOG object - ** @param variant HOG descriptor variant. - ** @param numOrientations number of distinguished orientations. - ** @param transposed wether images are transposed (column major). - ** @return the new HOG object. - ** - ** The function creates a new HOG object to extract descriptors of - ** the prescribed @c variant. The angular resolution is set by - ** @a numOrientations, which specifies the number of undirected - ** orientations. The object can work with column major images - ** by setting @a transposed to true. - **/ - -VlHog * -vl_hog_new (VlHogVariant variant, vl_size numOrientations, vl_bool transposed) -{ - vl_index o, k ; - VlHog * self = vl_calloc(1, sizeof(VlHog)) ; - - assert(numOrientations >= 1) ; - - self->variant = variant ; - self->numOrientations = numOrientations ; - self->glyphSize = 21 ; - self->transposed = transposed ; - self->useBilinearOrientationAssigment = VL_FALSE ; - self->orientationX = vl_malloc(sizeof(float) * self->numOrientations) ; - self->orientationY = vl_malloc(sizeof(float) * self->numOrientations) ; - - /* - Create a vector along the center of each orientation bin. These - are used to map gradients to bins. If the image is transposed, - then this can be adjusted here by swapping X and Y in these - vectors. - */ - for(o = 0 ; o < (signed)self->numOrientations ; ++o) { - double angle = o * VL_PI / self->numOrientations ; - if (!self->transposed) { - self->orientationX[o] = (float) cos(angle) ; - self->orientationY[o] = (float) sin(angle) ; - } else { - self->orientationX[o] = (float) sin(angle) ; - self->orientationY[o] = (float) cos(angle) ; - } - } - - /* - If the number of orientation is equal to 9, one gets: - - Uoccti:: 18 directed orientations + 9 undirected orientations + 4 texture - DalalTriggs:: 9 undirected orientations x 4 blocks. - */ - switch (self->variant) { - case VlHogVariantUoctti: - self->dimension = 3*self->numOrientations + 4 ; - break ; - - case VlHogVariantDalalTriggs: - self->dimension = 4*self->numOrientations ; - break ; - - default: - assert(0) ; - } - - /* - A permutation specifies how to permute elements in a HOG - descriptor to flip it horizontally. Since the first orientation - of index 0 points to the right, this must be swapped with orientation - self->numOrientation that points to the left (for the directed case, - and to itself for the undirected one). - */ - - self->permutation = vl_malloc(self->dimension * sizeof(vl_index)) ; - switch (self->variant) { - case VlHogVariantUoctti: - for(o = 0 ; o < (signed)self->numOrientations ; ++o) { - vl_index op = self->numOrientations - o ; - self->permutation[o] = op ; - self->permutation[o + self->numOrientations] = (op + self->numOrientations) % (2*self->numOrientations) ; - self->permutation[o + 2*self->numOrientations] = (op % self->numOrientations) + 2*self->numOrientations ; - } - for (k = 0 ; k < 4 ; ++k) { - /* The texture features correspond to four displaced block around - a cell. These permute with a lr flip as for DalalTriggs. */ - vl_index blockx = k % 2 ; - vl_index blocky = k / 2 ; - vl_index q = (1 - blockx) + blocky * 2 ; - self->permutation[k + self->numOrientations * 3] = q + self->numOrientations * 3 ; - } - break ; - - case VlHogVariantDalalTriggs: - for(k = 0 ; k < 4 ; ++k) { - /* Find the corresponding block. Blocks are listed in order 1,2,3,4,... - from left to right and top to bottom */ - vl_index blockx = k % 2 ; - vl_index blocky = k / 2 ; - vl_index q = (1 - blockx) + blocky * 2 ; - for(o = 0 ; o < (signed)self->numOrientations ; ++o) { - vl_index op = self->numOrientations - o ; - self->permutation[o + k*self->numOrientations] = (op % self->numOrientations) + q*self->numOrientations ; - } - } - break ; - - default: - assert(0) ; - } - - /* - Create glyphs for representing the HOG features/ filters. The glyphs - are simple bars, oriented orthogonally to the gradients to represent - image edges. If the object is configured to work on transposed image, - the glyphs images are also stored in column-major. - */ - self->glyphs = vl_calloc(self->glyphSize * self->glyphSize * self->numOrientations, sizeof(float)) ; -#define atglyph(x,y,k) self->glyphs[(x) + self->glyphSize * (y) + self->glyphSize * self->glyphSize * (k)] - for (o = 0 ; o < (signed)self->numOrientations ; ++o) { - double angle = fmod(o * VL_PI / self->numOrientations + VL_PI/2, VL_PI) ; - double x2 = self->glyphSize * cos(angle) / 2 ; - double y2 = self->glyphSize * sin(angle) / 2 ; - - if (angle <= VL_PI / 4 || angle >= VL_PI * 3 / 4) { - /* along horizontal direction */ - double slope = y2 / x2 ; - double offset = (1 - slope) * (self->glyphSize - 1) / 2 ; - vl_index skip = (1 - fabs(cos(angle))) / 2 * self->glyphSize ; - vl_index i, j ; - for (i = skip ; i < (signed)self->glyphSize - skip ; ++i) { - j = vl_round_d(slope * i + offset) ; - if (! self->transposed) { - atglyph(i,j,o) = 1 ; - } else { - atglyph(j,i,o) = 1 ; - } - } - } else { - /* along vertical direction */ - double slope = x2 / y2 ; - double offset = (1 - slope) * (self->glyphSize - 1) / 2 ; - vl_index skip = (1 - sin(angle)) / 2 * self->glyphSize ; - vl_index i, j ; - for (j = skip ; j < (signed)self->glyphSize - skip; ++j) { - i = vl_round_d(slope * j + offset) ; - if (! self->transposed) { - atglyph(i,j,o) = 1 ; - } else { - atglyph(j,i,o) = 1 ; - } - } - } - } - return self ; -} - -/* ---------------------------------------------------------------- */ -/** @brief Delete a HOG object - ** @param self HOG object to delete. - **/ - -void -vl_hog_delete (VlHog * self) -{ - if (self->orientationX) { - vl_free(self->orientationX) ; - self->orientationX = NULL ; - } - - if (self->orientationY) { - vl_free(self->orientationY) ; - self->orientationY = NULL ; - } - - if (self->glyphs) { - vl_free(self->glyphs) ; - self->glyphs = NULL ; - } - - if (self->permutation) { - vl_free(self->permutation) ; - self->permutation = NULL ; - } - - if (self->hog) { - vl_free(self->hog) ; - self->hog = NULL ; - } - - if (self->hogNorm) { - vl_free(self->hogNorm) ; - self->hogNorm = NULL ; - } - - vl_free(self) ; -} - - -/* ---------------------------------------------------------------- */ -/** @brief Get HOG glyph size - ** @param self HOG object. - ** @return size (height and width) of a glyph. - **/ - -vl_size -vl_hog_get_glyph_size (VlHog const * self) -{ - return self->glyphSize ; -} - -/* ---------------------------------------------------------------- */ -/** @brief Get HOG left-right flip permutation - ** @param self HOG object. - ** @return left-right permutation. - ** - ** The function returns a pointer to an array @c permutation of ::vl_hog_get_dimension - ** elements. Given a HOG descriptor (for a cell) @c hog, which is also - ** a vector of ::vl_hog_get_dimension elements, the - ** descriptor obtained for the same image flipped horizotnally is - ** given by flippedHog[i] = hog[permutation[i]]. - **/ - -vl_index const * -vl_hog_get_permutation (VlHog const * self) -{ - return self->permutation ; -} - -/* ---------------------------------------------------------------- */ -/** @brief Turn bilinear interpolation of assignments on or off - ** @param self HOG object. - ** @param x @c true if orientations should be assigned with bilinear interpolation. - **/ - -void -vl_hog_set_use_bilinear_orientation_assignments (VlHog * self, vl_bool x) { - self->useBilinearOrientationAssigment = x ; -} - -/** @brief Tell whether assignments use bilinear interpolation or not - ** @param self HOG object. - ** @return @c true if orientations are be assigned with bilinear interpolation. - **/ - -vl_bool -vl_hog_get_use_bilinear_orientation_assignments (VlHog const * self) { - return self->useBilinearOrientationAssigment ; -} - -/* ---------------------------------------------------------------- */ -/** @brief Render a HOG descriptor to a glyph image - ** @param self HOG object. - ** @param image glyph image (output). - ** @param descriptor HOG descriptor. - ** @param width HOG descriptor width. - ** @param height HOG descriptor height. - ** - ** The function renders the HOG descriptor or filter - ** @a descriptor as an image (for visualization) and stores the result in - ** the buffer @a image. This buffer - ** must be an array of dimensions @c width*glyphSize - ** by @c height*glyphSize elements, where @c glyphSize is - ** obtained from ::vl_hog_get_glyph_size and is the size in pixels - ** of the image element used to represent the descriptor of one - ** HOG cell. - **/ - -void -vl_hog_render (VlHog const * self, - float * image, - float const * descriptor, - vl_size width, - vl_size height) -{ - vl_index x, y, k, cx, cy ; - vl_size hogStride = width * height ; - - assert(self) ; - assert(image) ; - assert(descriptor) ; - assert(width > 0) ; - assert(height > 0) ; - - for (y = 0 ; y < (signed)height ; ++y) { - for (x = 0 ; x < (signed)width ; ++x) { - float minWeight = 0 ; - float maxWeight = 0 ; - - for (k = 0 ; k < (signed)self->numOrientations ; ++k) { - float weight ; - float const * glyph = self->glyphs + k * (self->glyphSize*self->glyphSize) ; - float * glyphImage = image + self->glyphSize * x + y * width * (self->glyphSize*self->glyphSize) ; - - switch (self->variant) { - case VlHogVariantUoctti: - weight = - descriptor[k * hogStride] + - descriptor[(k + self->numOrientations) * hogStride] + - descriptor[(k + 2 * self->numOrientations) * hogStride] ; - break ; - case VlHogVariantDalalTriggs: - weight = - descriptor[k * hogStride] + - descriptor[(k + self->numOrientations) * hogStride] + - descriptor[(k + 2 * self->numOrientations) * hogStride] + - descriptor[(k + 3 * self->numOrientations) * hogStride] ; - break ; - default: - abort() ; - } - maxWeight = VL_MAX(weight, maxWeight) ; - minWeight = VL_MIN(weight, minWeight); - - for (cy = 0 ; cy < (signed)self->glyphSize ; ++cy) { - for (cx = 0 ; cx < (signed)self->glyphSize ; ++cx) { - *glyphImage++ += weight * (*glyph++) ; - } - glyphImage += (width - 1) * self->glyphSize ; - } - } /* next orientation */ - - { - float * glyphImage = image + self->glyphSize * x + y * width * (self->glyphSize*self->glyphSize) ; - for (cy = 0 ; cy < (signed)self->glyphSize ; ++cy) { - for (cx = 0 ; cx < (signed)self->glyphSize ; ++cx) { - float value = *glyphImage ; - *glyphImage++ = VL_MAX(minWeight, VL_MIN(maxWeight, value)) ; - } - glyphImage += (width - 1) * self->glyphSize ; - } - } - - ++ descriptor ; - } /* next column of cells (x) */ - } /* next row of cells (y) */ -} - -/* ---------------------------------------------------------------- */ -/** @brief Get the dimension of the HOG features - ** @param self HOG object. - ** @return imension of a HOG cell descriptors. - **/ - -vl_size -vl_hog_get_dimension (VlHog const * self) -{ - return self->dimension ; -} - -/** @brief Get the width of the HOG cell array - ** @param self HOG object. - ** @return number of HOG cells in the horizontal direction. - **/ - -vl_size -vl_hog_get_width (VlHog * self) -{ - return self->hogWidth ; -} - -/** @brief Get the height of the HOG cell array - ** @param self HOG object. - ** @return number of HOG cells in the vertical direction. - **/ - -vl_size -vl_hog_get_height (VlHog * self) -{ - return self->hogHeight ; -} - -/* ---------------------------------------------------------------- */ -/** @internal @brief Prepare internal buffers - ** @param self HOG object. - ** @param width image width. - ** @param height image height. - ** @param cellSize size of a HOG cell. - **/ - -static void -vl_hog_prepare_buffers (VlHog * self, vl_size width, vl_size height, vl_size cellSize) -{ - vl_size hogWidth = (width + cellSize/2) / cellSize ; - vl_size hogHeight = (height + cellSize/2) / cellSize ; - - assert(width > 3) ; - assert(height > 3) ; - assert(hogWidth > 0) ; - assert(hogHeight > 0) ; - - if (self->hog && - self->hogWidth == hogWidth && - self->hogHeight == hogHeight) { - /* a suitable buffer is already allocated */ - memset(self->hog, 0, sizeof(float) * hogWidth * hogHeight * self->numOrientations * 2) ; - memset(self->hogNorm, 0, sizeof(float) * hogWidth * hogHeight) ; - return ; - } - - if (self->hog) { - vl_free(self->hog) ; - self->hog = NULL ; - } - - if (self->hogNorm) { - vl_free(self->hogNorm) ; - self->hogNorm = NULL ; - } - - self->hog = vl_calloc(hogWidth * hogHeight * self->numOrientations * 2, sizeof(float)) ; - self->hogNorm = vl_calloc(hogWidth * hogHeight, sizeof(float)) ; - self->hogWidth = hogWidth ; - self->hogHeight = hogHeight ; -} - -/* ---------------------------------------------------------------- */ -/** @brief Process features starting from an image - ** @param self HOG object. - ** @param image image to process. - ** @param width image width. - ** @param height image height. - ** @param numChannels number of image channles. - ** @param cellSize size of a HOG cell. - ** - ** The buffer @c hog must be a three-dimensional array. - ** The first two dimensions are @c (width + cellSize/2)/cellSize and - ** @c (height + cellSize/2)/cellSize, where divisions are integer. - ** This is approximately @c width/cellSize and @c height/cellSize, - ** adjusted so that the last cell is at least half contained in the - ** image. - ** - ** The image @c width and @c height must be not smaller than three - ** pixels and not smaller than @c cellSize. - **/ - -void -vl_hog_put_image (VlHog * self, - float const * image, - vl_size width, vl_size height, vl_size numChannels, - vl_size cellSize) -{ - vl_size hogStride ; - vl_size channelStride = width * height ; - vl_index x, y ; - vl_uindex k ; - - assert(self) ; - assert(image) ; - - /* clear features */ - vl_hog_prepare_buffers(self, width, height, cellSize) ; - hogStride = self->hogWidth * self->hogHeight ; - -#define at(x,y,k) (self->hog[(x) + (y) * self->hogWidth + (k) * hogStride]) - - /* compute gradients and map the to HOG cells by bilinear interpolation */ - for (y = 1 ; y < (signed)height - 1 ; ++y) { - for (x = 1 ; x < (signed)width - 1 ; ++x) { - float gradx = 0 ; - float grady = 0 ; - float gradNorm ; - float orientationWeights [2] = {-1, -1} ; - vl_index orientationBins [2] = {-1, -1} ; - vl_index orientation = 0 ; - float hx, hy, wx1, wx2, wy1, wy2 ; - vl_index binx, biny, o ; - - /* - Compute the gradient at (x,y). The image channel with - the maximum gradient at each location is selected. - */ - { - float const * iter = image + y * width + x ; - float gradNorm2 = 0 ; - for (k = 0 ; k < numChannels ; ++k) { - float gradx_ = *(iter + 1) - *(iter - 1) ; - float grady_ = *(iter + width) - *(iter - width) ; - float gradNorm2_ = gradx_ * gradx_ + grady_ * grady_ ; - if (gradNorm2_ > gradNorm2) { - gradx = gradx_ ; - grady = grady_ ; - gradNorm2 = gradNorm2_ ; - } - iter += channelStride ; - } - gradNorm = sqrtf(gradNorm2) ; - } - - /* - Map the gradient to the closest and second closets orientation bins. - There are numOrientations orientation in the interval [0,pi). - The next numOriantations are the symmetric ones, for a total - of 2*numOrientation directed orientations. - */ - for (k = 0 ; k < self->numOrientations ; ++k) { - float orientationScore_ = gradx * self->orientationX[k] + grady * self->orientationY[k] ; - vl_index orientationBin_ = k ; - if (orientationScore_ < 0) { - orientationScore_ = - orientationScore_ ; - orientationBin_ += self->numOrientations ; - } - if (orientationScore_ > orientationWeights[0]) { - orientationBins[1] = orientationBins[0] ; - orientationWeights[1] = orientationWeights[0] ; - orientationBins[0] = orientationBin_ ; ; - orientationWeights[0] = orientationScore_ ; - } else if (orientationScore_ > orientationWeights[1]) { - orientationBins[1] = orientationBin_ ; - orientationWeights[1] = orientationScore_ ; - } - } - - if (self->useBilinearOrientationAssigment) { - /* min(1.0,...) guards against small overflows causing NaNs */ - float angle0 = acosf(VL_MIN(orientationWeights[0] / VL_MAX(gradNorm, 1e-10),1.0)) ; - orientationWeights[1] = angle0 / (VL_PI / self->numOrientations) ; - orientationWeights[0] = 1 - orientationWeights[1] ; - } else { - orientationWeights[0] = 1 ; - orientationBins[1] = -1 ; - } - - for (o = 0 ; o < 2 ; ++o) { - float ow ; - /* - Accumulate the gradient. hx is the distance of the - pixel x to the cell center at its left, in units of cellSize. - With this parametrixation, a pixel on the cell center - has hx = 0, which gradually increases to 1 moving to the next - center. - */ - - orientation = orientationBins[o] ; - if (orientation < 0) continue ; - - /* (x - (w-1)/2) / w = (x + 0.5)/w - 0.5 */ - hx = (x + 0.5) / cellSize - 0.5 ; - hy = (y + 0.5) / cellSize - 0.5 ; - binx = vl_floor_f(hx) ; - biny = vl_floor_f(hy) ; - wx2 = hx - binx ; - wy2 = hy - biny ; - wx1 = 1.0 - wx2 ; - wy1 = 1.0 - wy2 ; - - ow = orientationWeights[o] ; - - /*VL_PRINTF("%d %d - %d %d %f %f - %f %f %f %f - %d \n ",x,y,binx,biny,hx,hy,wx1,wx2,wy1,wy2,o);*/ - - if (binx >= 0 && biny >=0) { - at(binx,biny,orientation) += gradNorm * ow * wx1 * wy1 ; - } - if (binx < (signed)self->hogWidth - 1 && biny >=0) { - at(binx+1,biny,orientation) += gradNorm * ow * wx2 * wy1 ; - } - if (binx < (signed)self->hogWidth - 1 && biny < (signed)self->hogHeight - 1) { - at(binx+1,biny+1,orientation) += gradNorm * ow * wx2 * wy2 ; - } - if (binx >= 0 && biny < (signed)self->hogHeight - 1) { - at(binx,biny+1,orientation) += gradNorm * ow * wx1 * wy2 ; - } - } /* next o */ - } /* next x */ - } /* next y */ -} - -/* ---------------------------------------------------------------- */ -/** @brief Process features starting from a field in polar notation - ** @param self HOG object. - ** @param modulus image gradient modulus. - ** @param angle image gradient angle. - ** @param directed wrap the gradient angles at 2pi (directed) or pi (undirected). - ** @param width image width. - ** @param height image height. - ** @param cellSize size of a HOG cell. - ** - ** The function behaves like ::vl_hog_put_image, but foregoes the internal - ** computation of the gradient field, allowing the user to specify - ** their own. Angles are measure clockwise, the y axis pointing downwards, - ** starting from the x axis (pointing to the right). - **/ - -void vl_hog_put_polar_field (VlHog * self, - float const * modulus, - float const * angle, - vl_bool directed, - vl_size width, vl_size height, - vl_size cellSize) -{ - vl_size hogStride ; - vl_index x, y, o ; - vl_index period = self->numOrientations * (directed ? 2 : 1) ; - double angleStep = VL_PI / self->numOrientations ; - - assert(self) ; - assert(modulus) ; - assert(angle) ; - - /* clear features */ - vl_hog_prepare_buffers(self, width, height, cellSize) ; - hogStride = self->hogWidth * self->hogHeight ; - -#define at(x,y,k) (self->hog[(x) + (y) * self->hogWidth + (k) * hogStride]) -#define atNorm(x,y) (self->hogNorm[(x) + (y) * self->hogWidth]) - - /* fill HOG cells from gradient field */ - for (y = 0 ; y < (signed)height ; ++y) { - for (x = 0 ; x < (signed)width ; ++x) { - float ho, hx, hy, wo1, wo2, wx1, wx2, wy1, wy2 ; - vl_index bino, binx, biny ; - float orientationWeights [2] = {0,0} ; - vl_index orientationBins [2] = {-1,-1} ; - vl_index orientation = 0 ; - float thisAngle = *angle++ ; - float thisModulus = *modulus++ ; - - if (thisModulus <= 0.0f) continue ; - - /* (x - (w-1)/2) / w = (x + 0.5)/w - 0.5 */ - - ho = (float)thisAngle / angleStep ; - bino = vl_floor_f(ho) ; - wo2 = ho - bino ; - wo1 = 1.0f - wo2 ; - - while (bino < 0) { bino += self->numOrientations * 2 ; } - - if (self->useBilinearOrientationAssigment) { - orientationBins[0] = bino % period ; - orientationBins[1] = (bino + 1) % period ; - orientationWeights[0] = wo1 ; - orientationWeights[1] = wo2 ; - } else { - orientationBins[0] = (bino + ((wo1 > wo2) ? 0 : 1)) % period ; - orientationWeights[0] = 1 ; - orientationBins[1] = -1 ; - } - - for (o = 0 ; o < 2 ; ++o) { - /* - Accumulate the gradient. hx is the distance of the - pixel x to the cell center at its left, in units of cellSize. - With this parametrixation, a pixel on the cell center - has hx = 0, which gradually increases to 1 moving to the next - center. - */ - - orientation = orientationBins[o] ; - if (orientation < 0) continue ; - - hx = (x + 0.5) / cellSize - 0.5 ; - hy = (y + 0.5) / cellSize - 0.5 ; - binx = vl_floor_f(hx) ; - biny = vl_floor_f(hy) ; - wx2 = hx - binx ; - wy2 = hy - biny ; - wx1 = 1.0 - wx2 ; - wy1 = 1.0 - wy2 ; - - wx1 *= orientationWeights[o] ; - wx2 *= orientationWeights[o] ; - wy1 *= orientationWeights[o] ; - wy2 *= orientationWeights[o] ; - - /*VL_PRINTF("%d %d - %d %d %f %f - %f %f %f %f - %d \n ",x,y,binx,biny,hx,hy,wx1,wx2,wy1,wy2,o);*/ - - if (binx >= 0 && biny >=0) { - at(binx,biny,orientation) += thisModulus * wx1 * wy1 ; - } - if (binx < (signed)self->hogWidth - 1 && biny >=0) { - at(binx+1,biny,orientation) += thisModulus * wx2 * wy1 ; - } - if (binx < (signed)self->hogWidth - 1 && biny < (signed)self->hogHeight - 1) { - at(binx+1,biny+1,orientation) += thisModulus * wx2 * wy2 ; - } - if (binx >= 0 && biny < (signed)self->hogHeight - 1) { - at(binx,biny+1,orientation) += thisModulus * wx1 * wy2 ; - } - } /* next o */ - } /* next x */ - } /* next y */ -} - -/* ---------------------------------------------------------------- */ -/** @brief Extract HOG features - ** @param self HOG object. - ** @param features HOG features (output). - ** - ** This method is called after ::vl_hog_put_image or ::vl_hog_put_polar_field - ** in order to retrieve the computed HOG features. The buffer @c features must have the dimensions returned by - ** ::vl_hog_get_width, ::vl_hog_get_height, and ::vl_hog_get_dimension. - **/ - -void -vl_hog_extract (VlHog * self, float * features) -{ - vl_index x, y ; - vl_uindex k ; - vl_size hogStride = self->hogWidth * self->hogHeight ; - - assert(features) ; - -#define at(x,y,k) (self->hog[(x) + (y) * self->hogWidth + (k) * hogStride]) -#define atNorm(x,y) (self->hogNorm[(x) + (y) * self->hogWidth]) - - /* - Compute the squared L2 norm of the unoriented version of each HOG - cell histogram. The unoriented version is obtained by folding - the 2*numOrientations compotnent into numOrientations only. - */ - { - float const * iter = self->hog ; - for (k = 0 ; k < self->numOrientations ; ++k) { - float * niter = self->hogNorm ; - float * niterEnd = self->hogNorm + self->hogWidth * self->hogHeight ; - vl_size stride = self->hogWidth*self->hogHeight*self->numOrientations ; - while (niter != niterEnd) { - float h1 = *iter ; - float h2 = *(iter + stride) ; - float h = h1 + h2 ; - *niter += h * h ; - niter++ ; - iter++ ; - } - } - } - - /* - HOG block-normalisation. - - The Dalal-Triggs implementation computes a normalized descriptor for - each block of 2x2 cells, by stacking the histograms of each cell - into a vector and L2-normalizing and truncating the result. - - Each block-level descriptor is then decomposed back into cells - and corresponding parts are stacked into cell-level descritpors. - Each HOG cell is contained in exactly - four 2x2 cell blocks. For example, the cell number 5 in the following - figure is contained in blocks 1245, 2356, 4578, 5689: - - +---+---+---+ - | 1 | 2 | 3 | - +---+---+---+ - | 4 | 5 | 6 | - +---+---+---+ - | 7 | 8 | 9 | - +---+---+---+ - - Hence, when block-level descriptors are decomposed back - into cells, each cell receives contributions from four blocks. So, - if each cell started with a D-dimensional histogram, it - ends up with a 4D dimesional descriptor vector. - - Note however that this is just a convenient way of rewriting the - blocks as per-cell contributions, but the block information - is unchanged. In particular, barring boundary effects, - in an array of H x W cells there are approximately HW blocks; - hence the L2 norm of all the blocks stacked is approximately HW - (because individual blocks are L2-normalized). Since this does - not change in the final HOG descriptor, - the L2 norm of the HOG descriptor of an image should be approximately - the same as the area of the image divided by the - area of a HOG cell. This can be used as a sanity check. - - The UoCTTI variant differs in some non-negligible ways. First, - it includes both oriented and unoriented histograms, as well - as four components capturing texture. Second, and most importantly, - it merges the four chunks of block-level descirptors landing in - each cell into one by taking their average. This makes sense - because, ultimately, these four sub-descriptors are identical - to the original cell histogram, just with four different normalisations - applied. - */ - { - float const * iter = self->hog ; - for (y = 0 ; y < (signed)self->hogHeight ; ++y) { - for (x = 0 ; x < (signed)self->hogWidth ; ++x) { - - /* norm of upper-left, upper-right, ... cells */ - vl_index xm = VL_MAX(x - 1, 0) ; - vl_index xp = VL_MIN(x + 1, (signed)self->hogWidth - 1) ; - vl_index ym = VL_MAX(y - 1, 0) ; - vl_index yp = VL_MIN(y + 1, (signed)self->hogHeight - 1) ; - - double norm1 = atNorm(xm,ym) ; - double norm2 = atNorm(x,ym) ; - double norm3 = atNorm(xp,ym) ; - double norm4 = atNorm(xm,y) ; - double norm5 = atNorm(x,y) ; - double norm6 = atNorm(xp,y) ; - double norm7 = atNorm(xm,yp) ; - double norm8 = atNorm(x,yp) ; - double norm9 = atNorm(xp,yp) ; - - double factor1, factor2, factor3, factor4 ; - - double t1 = 0 ; - double t2 = 0 ; - double t3 = 0 ; - double t4 = 0 ; - - float * oiter = features + x + self->hogWidth * y ; - - /* each factor is the inverse of the l2 norm of one of the 2x2 blocks surrounding - cell x,y */ -#if 0 - if (self->transposed) { - /* if the image is transposed, y and x are swapped */ - factor1 = 1.0 / VL_MAX(sqrt(norm1 + norm2 + norm4 + norm5), 1e-10) ; - factor3 = 1.0 / VL_MAX(sqrt(norm2 + norm3 + norm5 + norm6), 1e-10) ; - factor2 = 1.0 / VL_MAX(sqrt(norm4 + norm5 + norm7 + norm8), 1e-10) ; - factor4 = 1.0 / VL_MAX(sqrt(norm5 + norm6 + norm8 + norm9), 1e-10) ; - } else { - factor1 = 1.0 / VL_MAX(sqrt(norm1 + norm2 + norm4 + norm5), 1e-10) ; - factor2 = 1.0 / VL_MAX(sqrt(norm2 + norm3 + norm5 + norm6), 1e-10) ; - factor3 = 1.0 / VL_MAX(sqrt(norm4 + norm5 + norm7 + norm8), 1e-10) ; - factor4 = 1.0 / VL_MAX(sqrt(norm5 + norm6 + norm8 + norm9), 1e-10) ; - } -#else - /* as implemented in UOCTTI code */ - if (self->transposed) { - /* if the image is transposed, y and x are swapped */ - factor1 = 1.0 / sqrt(norm1 + norm2 + norm4 + norm5 + 1e-4) ; - factor3 = 1.0 / sqrt(norm2 + norm3 + norm5 + norm6 + 1e-4) ; - factor2 = 1.0 / sqrt(norm4 + norm5 + norm7 + norm8 + 1e-4) ; - factor4 = 1.0 / sqrt(norm5 + norm6 + norm8 + norm9 + 1e-4) ; - } else { - factor1 = 1.0 / sqrt(norm1 + norm2 + norm4 + norm5 + 1e-4) ; - factor2 = 1.0 / sqrt(norm2 + norm3 + norm5 + norm6 + 1e-4) ; - factor3 = 1.0 / sqrt(norm4 + norm5 + norm7 + norm8 + 1e-4) ; - factor4 = 1.0 / sqrt(norm5 + norm6 + norm8 + norm9 + 1e-4) ; - } -#endif - - for (k = 0 ; k < self->numOrientations ; ++k) { - double ha = iter[hogStride * k] ; - double hb = iter[hogStride * (k + self->numOrientations)] ; - double hc ; - - double ha1 = factor1 * ha ; - double ha2 = factor2 * ha ; - double ha3 = factor3 * ha ; - double ha4 = factor4 * ha ; - - double hb1 = factor1 * hb ; - double hb2 = factor2 * hb ; - double hb3 = factor3 * hb ; - double hb4 = factor4 * hb ; - - double hc1 = ha1 + hb1 ; - double hc2 = ha2 + hb2 ; - double hc3 = ha3 + hb3 ; - double hc4 = ha4 + hb4 ; - - ha1 = VL_MIN(0.2, ha1) ; - ha2 = VL_MIN(0.2, ha2) ; - ha3 = VL_MIN(0.2, ha3) ; - ha4 = VL_MIN(0.2, ha4) ; - - hb1 = VL_MIN(0.2, hb1) ; - hb2 = VL_MIN(0.2, hb2) ; - hb3 = VL_MIN(0.2, hb3) ; - hb4 = VL_MIN(0.2, hb4) ; - - hc1 = VL_MIN(0.2, hc1) ; - hc2 = VL_MIN(0.2, hc2) ; - hc3 = VL_MIN(0.2, hc3) ; - hc4 = VL_MIN(0.2, hc4) ; - - t1 += hc1 ; - t2 += hc2 ; - t3 += hc3 ; - t4 += hc4 ; - - switch (self->variant) { - case VlHogVariantUoctti : - ha = 0.5 * (ha1 + ha2 + ha3 + ha4) ; - hb = 0.5 * (hb1 + hb2 + hb3 + hb4) ; - hc = 0.5 * (hc1 + hc2 + hc3 + hc4) ; - *oiter = ha ; - *(oiter + hogStride * self->numOrientations) = hb ; - *(oiter + 2 * hogStride * self->numOrientations) = hc ; - break ; - - case VlHogVariantDalalTriggs : - *oiter = hc1 ; - *(oiter + hogStride * self->numOrientations) = hc2 ; - *(oiter + 2 * hogStride * self->numOrientations) = hc3 ; - *(oiter + 3 * hogStride * self->numOrientations) = hc4 ; - break ; - } - oiter += hogStride ; - - } /* next orientation */ - - switch (self->variant) { - case VlHogVariantUoctti : - oiter += 2 * hogStride * self->numOrientations ; - *oiter = (1.0f/sqrtf(18.0f)) * t1 ; oiter += hogStride ; - *oiter = (1.0f/sqrtf(18.0f)) * t2 ; oiter += hogStride ; - *oiter = (1.0f/sqrtf(18.0f)) * t3 ; oiter += hogStride ; - *oiter = (1.0f/sqrtf(18.0f)) * t4 ; oiter += hogStride ; - break ; - - case VlHogVariantDalalTriggs : - break ; - } - ++iter ; - } /* next x */ - } /* next y */ - } /* block normalization */ -} - diff --git a/opensfm/src/third_party/vlfeat/vl/hog.h b/opensfm/src/third_party/vlfeat/vl/hog.h deleted file mode 100644 index 0a513d41e..000000000 --- a/opensfm/src/third_party/vlfeat/vl/hog.h +++ /dev/null @@ -1,89 +0,0 @@ -/** @file hog.h - ** @brief Histogram of Oriented Gradients (@ref hog) - ** @author Andrea Vedaldi - **/ - -/* - Copyright (C) 2007-12 Andrea Vedaldi and Brian Fulkerson. - All rights reserved. - - This file is part of the VLFeat library and is made available under - the terms of the BSD license (see the COPYING file). -*/ - -#ifndef VL_HOG_H -#define VL_HOG_H - -#include "generic.h" - -enum VlHogVariant_ { VlHogVariantDalalTriggs, VlHogVariantUoctti } ; - -typedef enum VlHogVariant_ VlHogVariant ; - -struct VlHog_ -{ - VlHogVariant variant ; - vl_size dimension ; - vl_size numOrientations ; - vl_bool transposed ; - vl_bool useBilinearOrientationAssigment ; - - /* left-right flip permutation */ - vl_index * permutation ; - - /* glyphs */ - float * glyphs ; - vl_size glyphSize ; - - /* helper vectors */ - float * orientationX ; - float * orientationY ; - - /* buffers */ - float * hog ; - float * hogNorm ; - vl_size hogWidth ; - vl_size hogHeight ; -} ; - -typedef struct VlHog_ VlHog ; - -VL_EXPORT VlHog * vl_hog_new (VlHogVariant variant, vl_size numOrientations, vl_bool transposed) ; -VL_EXPORT void vl_hog_delete (VlHog * self) ; -VL_EXPORT void vl_hog_process (VlHog * self, - float * features, - float const * image, - vl_size width, vl_size height, vl_size numChannels, - vl_size cellSize) ; - -VL_EXPORT void vl_hog_put_image (VlHog * self, - float const * image, - vl_size width, vl_size height, vl_size numChannels, - vl_size cellSize) ; - -VL_EXPORT void vl_hog_put_polar_field (VlHog * self, - float const * modulus, - float const * angle, - vl_bool directed, - vl_size width, vl_size height, vl_size cellSize) ; - -VL_EXPORT void vl_hog_extract (VlHog * self, float * features) ; -VL_EXPORT vl_size vl_hog_get_height (VlHog * self) ; -VL_EXPORT vl_size vl_hog_get_width (VlHog * self) ; - - -VL_EXPORT void vl_hog_render (VlHog const * self, - float * image, - float const * features, - vl_size width, - vl_size height) ; - -VL_EXPORT vl_size vl_hog_get_dimension (VlHog const * self) ; -VL_EXPORT vl_index const * vl_hog_get_permutation (VlHog const * self) ; -VL_EXPORT vl_size vl_hog_get_glyph_size (VlHog const * self) ; - -VL_EXPORT vl_bool vl_hog_get_use_bilinear_orientation_assignments (VlHog const * self) ; -VL_EXPORT void vl_hog_set_use_bilinear_orientation_assignments (VlHog * self, vl_bool x) ; - -/* VL_HOG_H */ -#endif diff --git a/opensfm/src/third_party/vlfeat/vl/homkermap.c b/opensfm/src/third_party/vlfeat/vl/homkermap.c deleted file mode 100644 index 9113990fb..000000000 --- a/opensfm/src/third_party/vlfeat/vl/homkermap.c +++ /dev/null @@ -1,580 +0,0 @@ -/** @file homkermap.c - ** @brief Homogeneous kernel map - Definition - ** @author Andrea Vedaldi - **/ - -/* -Copyright (C) 2007-12 Andrea Vedaldi and Brian Fulkerson. -Copyright (C) 2013 Andrea Vedaldi. -All rights reserved. - -This file is part of the VLFeat library and is made available under -the terms of the BSD license (see the COPYING file). -*/ - -/** @file homkermap.h - - -@page homkermap Homogeneous kernel map -@author Andrea Vedaldi -@tableofcontents - - -@ref homkermap.h implements the homogeneous kernel maps introduced in -@cite{vedaldi10efficient},@cite{vedaldi12efficient}. Such maps are -efficient linear representations of popular kernels such as the -intersection, $\chi^2$, and Jensen-Shannon ones. - - -@section homkermap-starting Getting started - - -The homogeneous kernel map is implemented as an object of type -::VlHomogeneousKernelMap. To use thois object, first create an -instance by using ::vl_homogeneouskernelmap_new, then use -::vl_homogeneouskernelmap_evaluate_d or -::vl_homogeneouskernelmap_evaluate_f (depdening on whether the data is -@c double or @c float) to compute the feature map $ \Psi(x) -$. When done, dispose of the object by calling -::vl_homogeneouskernelmap_delete. - -@code -double gamma = 1.0 ; -int order = 1 ; -double period = -1 ; // use default -double psi [3] ; -vl_size psiStride = 1 ; -double x = 0.5 ; -VlHomogeneousKernelMap * hom = vl_homogeneouskernelmap_new( - VlHomogeneousKernelChi2, gamma, order, period, - VlHomogeneousKernelMapWindowRectangular) ; -vl_homogeneouskernelmap_evaluate_d(hom, psi, psiStride, x) ; -vl_homogeneouskernelmap_delete(x) ; -@endcode - -The constructor ::vl_homogeneouskernelmap_new takes the kernel type @c -kernel (see ::VlHomogeneousKernelType), the homogeneity order @c gamma -(use one for the standard $1$-homogeneous kernels), the approximation -order @c order (usually order one is enough), the period @a period -(use a negative value to use the default period), and a window type @c -window (use ::VlHomogeneousKernelMapWindowRectangular if unsure). The -approximation order trades off the quality and dimensionality of the -approximation. The resulting feature map $ \Psi(x) $, computed by -::vl_homogeneouskernelmap_evaluate_d or -::vl_homogeneouskernelmap_evaluate_f , is 2*order+1 -dimensional. - -The code pre-computes the map $ \Psi(x) $ for efficient -evaluation. The table spans values of $ x $ in the range -$[2^{-20}, 2^{8}) $. In particular, values smaller than $ -2^{-20} $ are treated as zeroes (which results in a null feature). - - -@section homkermap-fundamentals Fundamentals - - -The homogeneous kernel map is a finite dimensional linear -approximation of homogeneous kernels, including the intersection, -$\chi^2$, and Jensen-Shannon kernels. These kernels are frequently -used in computer vision applications because they are particular -suited to data in the format of histograms, which includes many common -visual descriptors. - -Let $x,y \in \mathbb{R}_+$ be non-negative scalars and let $k(x,y) \in -\mathbb{R}$ be an homogeneous kernel such as the $\chi^2$ and or the -intersection ones: - -@f[ - k_{\mathrm{inters}}(x,y) = \min\{x, y\}, - \quad - k_{\chi^2}(x,y) = 2 \frac{(x - y)^2}{x+y}. -@f] - -For vectorial data $ \mathbf{x},\mathbf{y} \in \mathbb{R}_+^d $, the -homogeneous kernels is defined as an additive combination of -scalar kernels $K(\mathbf{x},\mathbf{y}) = \sum_{i=1}^d k(x_i,y_i)$. - -The homogeneous kernel map of order $n$ is a vector function -$\Psi(x) \in \mathbb{R}^{2n+1}$ such that, for any choice of $x, y \in -\mathbb{R}_+$, the following approximation holds: - -@f[ - k(x,y) \approx \langle \Psi(x), \Psi(y) \rangle. -@f] - -Given the feature map for the scalar case, the corresponding feature -map $\Psi(\mathbf{x})$ for the vectorial case is obtained by stacking -$[\Psi(x_1), \dots, \Psi(x_n)]$. Note that the stacked feature -$\Psi(\mathbf{x})$ has dimension $d(2n+1)$. - -Using linear analysis tools (e.g. a linear support vector machine) -on top of dataset that has been encoded by the homogeneous kernel map -is therefore approximately equivalent to using a method based -on the corresponding non-linear kernel. - - -@subsection homkermap-overview-negative Extension to the negative reals - - -Any positive (semi-)definite kernel $k(x,y)$ defined on the -non-negative reals $x,y \in \mathbb{R}_+$ can be extended to the -entire real line by using the definition: - -@f[ -k_\pm(x,y) = \operatorname{sign}(x) \operatorname{sign}(y) k(|x|,|y|). -@f] - -The homogeneous kernel map implements this extension by defining -$\Psi_\pm(x) = \operatorname{sign}(x) \Psi(|x|)$. Note that other -extensions are possible, such as - -@f[ -k_\pm(x,y) = H(xy) \operatorname{sign}(y) k(|x|,|y|) -@f] - -where $H$ is the Heaviside function, but may result in higher -dimensional feature maps. - - -@subsection homkermap-overview-homogeneity Homogeneity degree - - -Any (1-)homogeneous kernel $k_1(x,y)$ can be extended to a so called -$\gamma$-homgeneous kernel $k_\gamma(x,y)$ by the definition - -@f[ - k_\gamma(x,y) = (xy)^{\frac{\gamma}{2}} \frac{k_1(x,y)}{\sqrt{xy}} -@f] - -Smaller values of $\gamma$ enhance the kernel non-linearity and are -sometimes beneficial in applications (see -@cite{vedaldi10efficient},@cite{vedaldi12efficient} for details). - - -@subsection homkermap-overview-window Windowing and period - - -This section discusses aspects of the homogeneous kernel map which are -more technical and may be skipped. The homogeneous kernel map -approximation is based on periodizing the kernel; given the kernel -signature - -@f[ - \mathcal{K}(\lambda) = k(e^{\frac{\lambda}{2}}, e^{-\frac{\lambda}{2}}) -@f] - -the homogeneous kernel map is a feature map for the windowed and -periodized kernel whose signature is given by - -@f[ - \hat{\mathcal{K}}(\lambda) - = - \sum_{i=-\infty}^{+\infty} \mathcal{K}(\lambda + k \Lambda) W(\lambda + k \Lambda) -@f] - -where $W(\lambda)$ is a windowing function and $\Lambda$ is the -period. This implementation of the homogeneous kernel map supports the -use of a uniform window ($ W(\lambda) = 1 $) or of a -rectangular window ($ W(\lambda) = -\operatorname{rect}(\lambda/\Lambda) $). Note that $ \lambda = -\log(y/x) $ is equal to the logarithmic ratio of the arguments of the -kernel. Empirically, the rectangular window seems to have a slight -edge in applications. - - -@section homkermap-details Implementation details - - -This implementation uses the expressions given in -@cite{vedaldi10efficient},@cite{vedaldi11efficient} to compute in -closed form the maps $\Psi(x)$ for the supported kernel types. For -efficiency reasons, it precomputes $\Psi(x)$ for a large range of -values of the argument when the homogeneous kernel map object is -created. - -The internal table stores $\Psi(x) \in \mathbb{R}^{2n+1}$ by sampling -$x\geq 0$. This uses the internal decomposition of IEEE floating point -representations (@c float and @c double) in mantissa and exponent: -
-  x = mantissa * (2**exponent),
-  minExponent <= exponent <= maxExponent,
-  1 <= matnissa < 2.
-
-Each octave is further sampled in @c numSubdivisions sublevels. - -When the map $\Psi(x)$ is evaluated, @c x is decomposed again into -exponent and mantissa to index the table. The output is obtained by -bilinear interpolation from the appropriate table entries. - -**/ - -/* ---------------------------------------------------------------- */ -#ifndef VL_HOMKERMAP_INSTANTIATING -/* ---------------------------------------------------------------- */ - -#include "homkermap.h" -#include "mathop.h" -#include - -struct _VlHomogeneousKernelMap -{ - VlHomogeneousKernelType kernelType ; - double gamma ; - VlHomogeneousKernelMapWindowType windowType ; - vl_size order ; - double period ; - vl_size numSubdivisions ; - double subdivision ; - vl_index minExponent ; - vl_index maxExponent ; - double * table ; -} ; - -/** @internal @brief Sample the kernel specturm - ** @param self homogeneous kernel map. - ** @param omega sampling frequency. - ** @return the spectrum sampled at @a omega. - **/ - -VL_INLINE double -vl_homogeneouskernelmap_get_spectrum (VlHomogeneousKernelMap const * self, double omega) -{ - assert (self) ; - switch (self->kernelType) { - case VlHomogeneousKernelIntersection: - return (2.0 / VL_PI) / (1 + 4 * omega*omega) ; - case VlHomogeneousKernelChi2: - return 2.0 / (exp(VL_PI * omega) + exp(-VL_PI * omega)) ; - case VlHomogeneousKernelJS: - return (2.0 / log(4.0)) * - 2.0 / (exp(VL_PI * omega) + exp(-VL_PI * omega)) / - (1 + 4 * omega*omega) ; - default: - abort() ; - } -} - -/* helper */ -VL_INLINE double sinc(double x) -{ - if (x == 0.0) return 1.0 ; - return sin(x) / x ; -} - -/** @internal @brief Sample the smoothed kernel spectrum - ** @param self homogeneous kernel map. - ** @param omega sampling frequency. - ** @return the spectrum sampled at @a omega after smoothing. - **/ - -VL_INLINE double -vl_homogeneouskernelmap_get_smooth_spectrum (VlHomogeneousKernelMap const * self, double omega) -{ - double kappa_hat = 0 ; - double omegap ; - double epsilon = 1e-2 ; - double const omegaRange = 2.0 / (self->period * epsilon) ; - double const domega = 2 * omegaRange / (2 * 1024.0 + 1) ; - assert (self) ; - switch (self->windowType) { - case VlHomogeneousKernelMapWindowUniform: - kappa_hat = vl_homogeneouskernelmap_get_spectrum(self, omega) ; - break ; - case VlHomogeneousKernelMapWindowRectangular: - for (omegap = - omegaRange ; omegap <= omegaRange ; omegap += domega) { - double win = sinc((self->period/2.0) * omegap) ; - win *= (self->period/(2.0*VL_PI)) ; - kappa_hat += win * vl_homogeneouskernelmap_get_spectrum(self, omegap + omega) ; - } - kappa_hat *= domega ; - /* project on the postivie orthant (see PAMI) */ - kappa_hat = VL_MAX(kappa_hat, 0.0) ; - break ; - default: - abort() ; - } - return kappa_hat ; -} - -/* ---------------------------------------------------------------- */ -/* Constructors and destructors */ -/* ---------------------------------------------------------------- */ - -/** @brief Create a new homgeneous kernel map - ** @param kernelType type of homogeneous kernel. - ** @param gamma kernel homogeneity degree. - ** @param order approximation order. - ** @param period kernel period. - ** @param windowType type of window used to truncate the kernel. - ** @return the new homogeneous kernel map. - ** - ** The function intializes a new homogeneous kernel map for the - ** specified kernel type, homogeneity degree, approximation order, - ** period, and truncation window. See @ref homkermap-fundamentals for - ** details. - ** - ** The homogeneity degree @c gamma must be positive (the standard - ** kernels are obtained by setting @c gamma to 1). When unsure, set - ** @c windowType to ::VlHomogeneousKernelMapWindowRectangular. The @c - ** period should be non-negative; specifying a negative or null value - ** causes the function to switch to a default value. - ** - ** The function returns @c NULL if there is not enough free memory. - **/ - -VlHomogeneousKernelMap * -vl_homogeneouskernelmap_new (VlHomogeneousKernelType kernelType, - double gamma, - vl_size order, - double period, - VlHomogeneousKernelMapWindowType windowType) -{ - int tableWidth, tableHeight ; - VlHomogeneousKernelMap * self = vl_malloc(sizeof(VlHomogeneousKernelMap)) ; - if (! self) return NULL ; - - assert(gamma > 0) ; - - assert(kernelType == VlHomogeneousKernelIntersection || - kernelType == VlHomogeneousKernelChi2 || - kernelType == VlHomogeneousKernelJS) ; - - assert(windowType == VlHomogeneousKernelMapWindowUniform || - windowType == VlHomogeneousKernelMapWindowRectangular) ; - - if (period < 0) { - switch (windowType) { - case VlHomogeneousKernelMapWindowUniform: - switch (kernelType) { - case VlHomogeneousKernelChi2: period = 5.86 * sqrt(order + 0) + 3.65 ; break ; - case VlHomogeneousKernelJS: period = 6.64 * sqrt(order + 0) + 7.24 ; break ; - case VlHomogeneousKernelIntersection: period = 2.38 * log(order + 0.8) + 5.6 ; break ; - } - break ; - case VlHomogeneousKernelMapWindowRectangular: - switch (kernelType) { - case VlHomogeneousKernelChi2: period = 8.80 * sqrt(order + 4.44) - 12.6 ; break ; - case VlHomogeneousKernelJS: period = 9.63 * sqrt(order + 1.00) - 2.93; break ; - case VlHomogeneousKernelIntersection: period = 2.00 * log(order + 0.99) + 3.52 ; break ; - } - break ; - } - period = VL_MAX(period, 1.0) ; - } - - self->kernelType = kernelType ; - self->windowType = windowType ; - self->gamma = gamma ; - self->order = order ; - self->period = period ; - self->numSubdivisions = 8 + 8*order ; - self->subdivision = 1.0 / self->numSubdivisions ; - self->minExponent = -20 ; - self->maxExponent = 8 ; - - tableHeight = (int) (2*self->order + 1) ; - tableWidth = (int) (self->numSubdivisions * (self->maxExponent - self->minExponent + 1)) ; - self->table = vl_malloc (sizeof(double) * - (tableHeight * tableWidth + 2*(1+self->order))) ; - if (! self->table) { - vl_free(self) ; - return NULL ; - } - - { - vl_index exponent ; - vl_uindex i, j ; - double * tablep = self->table ; - double * kappa = self->table + tableHeight * tableWidth ; - double * freq = kappa + (1+self->order) ; - double L = 2.0 * VL_PI / self->period ; - - /* precompute the sampled periodicized spectrum */ - j = 0 ; - i = 0 ; - while (i <= self->order) { - freq[i] = j ; - kappa[i] = vl_homogeneouskernelmap_get_smooth_spectrum(self, j * L) ; - ++ j ; - if (kappa[i] > 0 || j >= 3*i) ++ i ; - } - - /* fill table */ - for (exponent = self->minExponent ; - exponent <= self->maxExponent ; ++ exponent) { - - double x, Lxgamma, Llogx, xgamma ; - double sqrt2kappaLxgamma ; - double mantissa = 1.0 ; - - for (i = 0 ; i < self->numSubdivisions ; - ++i, mantissa += self->subdivision) { - x = ldexp(mantissa, (int)exponent) ; - xgamma = pow(x, self->gamma) ; - Lxgamma = L * xgamma ; - Llogx = L * log(x) ; - - *tablep++ = sqrt(Lxgamma * kappa[0]) ; - for (j = 1 ; j <= self->order ; ++j) { - sqrt2kappaLxgamma = sqrt(2.0 * Lxgamma * kappa[j]) ; - *tablep++ = sqrt2kappaLxgamma * cos(freq[j] * Llogx) ; - *tablep++ = sqrt2kappaLxgamma * sin(freq[j] * Llogx) ; - } - } /* next mantissa */ - } /* next exponent */ - } - return self ; -} - -/** @brief Delete an object instance. - ** @param self object. - ** The function deletes the specified map object. - **/ - -void -vl_homogeneouskernelmap_delete (VlHomogeneousKernelMap * self) -{ - vl_free(self->table) ; - self->table = NULL ; - vl_free(self) ; -} - -/* ---------------------------------------------------------------- */ -/* Retrieve data and parameters */ -/* ---------------------------------------------------------------- */ - -/** @brief Get the map order. - ** @param self object. - ** @return the map order. - **/ - -vl_size -vl_homogeneouskernelmap_get_order (VlHomogeneousKernelMap const * self) -{ - assert(self) ; - return self->order ; -} - -/** @brief Get the map dimension. - ** @param self object. - ** @return the map dimension (2 @c order +1). - **/ - -vl_size -vl_homogeneouskernelmap_get_dimension (VlHomogeneousKernelMap const * self) -{ - assert(self) ; - return 2 * self->order + 1 ; -} - -/** @brief Get the kernel type. - ** @param self object. - ** @return kernel type. - **/ - -VlHomogeneousKernelType -vl_homogeneouskernelmap_get_kernel_type (VlHomogeneousKernelMap const * self) -{ - assert(self) ; - return self->kernelType ; -} - -/** @brief Get the window type. - ** @param self object. - ** @return window type. - **/ - -VlHomogeneousKernelMapWindowType -vl_homogeneouskernelmap_get_window_type (VlHomogeneousKernelMap const * self) -{ - assert(self) ; - return self->windowType ; -} - -/* ---------------------------------------------------------------- */ -/* Process data */ -/* ---------------------------------------------------------------- */ - -/** @fn ::vl_homogeneouskernelmap_evaluate_d(VlHomogeneousKernelMap const*,double*,vl_size,double) - ** @brief Evaluate map - ** @param self map object. - ** @param destination output buffer. - ** @param stride stride of the output buffer. - ** @param x value to expand. - ** - ** The function evaluates the feature map on @a x and stores the - ** resulting 2*order+1 dimensional vector to - ** @a destination[0], @a destination[stride], @a destination[2*stride], .... - **/ - -/** @fn ::vl_homogeneouskernelmap_evaluate_f(VlHomogeneousKernelMap const*,float*,vl_size,double) - ** @copydetails ::vl_homogeneouskernelmap_evaluate_d(VlHomogeneousKernelMap const*,double*,vl_size,double) - **/ - -#define FLT VL_TYPE_FLOAT -#define VL_HOMKERMAP_INSTANTIATING -#include "homkermap.c" - -#define FLT VL_TYPE_DOUBLE -#define VL_HOMKERMAP_INSTANTIATING -#include "homkermap.c" - -/* VL_HOMKERMAP_INSTANTIATING */ -#endif - -/* ---------------------------------------------------------------- */ -#ifdef VL_HOMKERMAP_INSTANTIATING -/* ---------------------------------------------------------------- */ - -#include "float.h" - -void -VL_XCAT(vl_homogeneouskernelmap_evaluate_,SFX) -(VlHomogeneousKernelMap const * self, - T * destination, - vl_size stride, - double x) -{ - /* break value into exponent and mantissa */ - int exponent ; - int unsigned j ; - double mantissa = frexp(x, &exponent) ; - double sign = (mantissa >= 0.0) ? +1.0 : -1.0 ; - mantissa *= 2*sign ; - exponent -- ; - - if (mantissa == 0 || - exponent <= self->minExponent || - exponent >= self->maxExponent) { - for (j = 0 ; j < 2*self->order+1 ; ++j) { - *destination = (T) 0.0 ; - destination += stride ; - } - return ; - } - { - vl_size featureDimension = 2*self->order + 1 ; - double const * v1 = self->table + - (exponent - self->minExponent) * self->numSubdivisions * featureDimension ; - double const * v2 ; - double f1, f2 ; - - mantissa -= 1.0 ; - while (mantissa >= self->subdivision) { - mantissa -= self->subdivision ; - v1 += featureDimension ; - } - v2 = v1 + featureDimension ; - for (j = 0 ; j < featureDimension ; ++j) { - f1 = *v1++ ; - f2 = *v2++ ; - *destination = (T) sign * ((f2 - f1) * (self->numSubdivisions * mantissa) + f1) ; - destination += stride ; - } - } -} - -#undef FLT -#undef VL_HOMKERMAP_INSTANTIATING -/* VL_HOMKERMAP_INSTANTIATING */ -#endif diff --git a/opensfm/src/third_party/vlfeat/vl/homkermap.h b/opensfm/src/third_party/vlfeat/vl/homkermap.h deleted file mode 100644 index e16a7167e..000000000 --- a/opensfm/src/third_party/vlfeat/vl/homkermap.h +++ /dev/null @@ -1,86 +0,0 @@ -/** @file homkermap.h - ** @brief Homogeneous kernel map (@ref homkermap) - ** @author Andrea Vedaldi - **/ - -/* -Copyright (C) 2007-12 Andrea Vedaldi and Brian Fulkerson. -All rights reserved. - -This file is part of the VLFeat library and is made available under -the terms of the BSD license (see the COPYING file). -*/ - -#ifndef VL_HOMKERMAP_H -#define VL_HOMKERMAP_H - -#include "generic.h" - -#include - -/** @brief Type of kernel */ -typedef enum { - VlHomogeneousKernelIntersection = 0, /**< intersection kernel */ - VlHomogeneousKernelChi2, /**< Chi2 kernel */ - VlHomogeneousKernelJS /**< Jensen-Shannon kernel */ -} VlHomogeneousKernelType ; - -/** @brief Type of spectral windowing function */ -typedef enum { - VlHomogeneousKernelMapWindowUniform = 0, /**< uniform window */ - VlHomogeneousKernelMapWindowRectangular = 1, /**< rectangular window */ -} VlHomogeneousKernelMapWindowType ; - -#ifndef __DOXYGEN__ -struct _VlHomogeneousKernelMap ; -typedef struct _VlHomogeneousKernelMap VlHomogeneousKernelMap ; -#else -/** @brief Homogeneous kernel map object */ -typedef OPAQUE VlHomogeneousKernelMap ; -#endif - -/** @name Create and destroy - ** @{ */ -VL_EXPORT VlHomogeneousKernelMap * -vl_homogeneouskernelmap_new (VlHomogeneousKernelType kernelType, - double gamma, - vl_size order, - double period, - VlHomogeneousKernelMapWindowType windowType) ; -VL_EXPORT void -vl_homogeneouskernelmap_delete (VlHomogeneousKernelMap * self) ; -/** @} */ - -/** @name Process data - ** @{ */ -VL_EXPORT void -vl_homogeneouskernelmap_evaluate_d (VlHomogeneousKernelMap const * self, - double * destination, - vl_size stride, - double x) ; - -VL_EXPORT void -vl_homogeneouskernelmap_evaluate_f (VlHomogeneousKernelMap const * self, - float * destination, - vl_size stride, - double x) ; -/** @} */ - - -/** @name Retrieve data and parameters - ** @{ */ -VL_EXPORT vl_size -vl_homogeneouskernelmap_get_order (VlHomogeneousKernelMap const * self) ; - -VL_EXPORT vl_size -vl_homogeneouskernelmap_get_dimension (VlHomogeneousKernelMap const * self) ; - -VL_EXPORT VlHomogeneousKernelType -vl_homogeneouskernelmap_get_kernel_type (VlHomogeneousKernelMap const * self) ; - -VL_EXPORT VlHomogeneousKernelMapWindowType -vl_homogeneouskernelmap_get_window_type (VlHomogeneousKernelMap const * self) ; -/** @} */ - -/* VL_HOMKERMAP_H */ -#endif diff --git a/opensfm/src/third_party/vlfeat/vl/host.c b/opensfm/src/third_party/vlfeat/vl/host.c deleted file mode 100644 index 50a0f0f40..000000000 --- a/opensfm/src/third_party/vlfeat/vl/host.c +++ /dev/null @@ -1,586 +0,0 @@ -/** @file host.c - ** @brief Host - Definition - ** @author Andrea Vedaldi - ** @see @ref portability - **/ - -/* -Copyright (C) 2007-12 Andrea Vedaldi and Brian Fulkerson. -All rights reserved. - -This file is part of the VLFeat library and is made available under -the terms of the BSD license (see the COPYING file). -*/ - -/** - -@page portability Portability features -@author Andrea Vedaldi -@tableofcontents - - -Platform dependent details are isolated in the @ref host.h. This -module provides functionalities to identify the host operating system, -C compiler, and CPU architecture. It also provides a few features to -abstract from such details. - -@see http://predef.sourceforge.net/index.php -@see http://en.wikipedia.org/wiki/64-bit_computing - -@section host-os Host operating system - -The module defines a symbol to identify the host operating system: -::VL_OS_WIN for Windows, ::VL_OS_LINUX for Linux, ::VL_OS_MACOSX for -Mac OS X, and so on. - -@section host-compiler Host compiler - -The module defines a symbol to identify the host compiler: -::VL_COMPILER_MSC for Microsoft Visual C++, ::VL_COMPILER_GNUC for -GNU C, and so on. The (integer) value of such symbols corresponds the -version of the compiler. - -The module defines a symbol to identify the data model of the -compiler: ::VL_COMPILER_ILP32, ::VL_COMPILER_LP64, or -::VL_COMPILER_LLP64 (see Sect. @ref host-compiler-data-model). For -convenience, it also defines a number of atomic types of prescribed -width (::vl_int8, ::vl_int16, ::vl_int32, etc.). - -@remark While some of such functionalities are provided by the -standard header @c stdint.h, the latter is not supported by all -platforms. - -@subsection host-compiler-data-model Data models - -The C language defines a number of atomic data types (such as @c char, -@c short, @c int and so on). The number of bits (width) used to -represent each data type depends on the compiler data model. The -different models are *ILP32* (@c int, @c long, and pointer 32 bit), -*LP64* (@c int 32 bit, @c long and pointer 64 bit), *ILP64* (@c int, -@c long, and pointer 64 bit), and *LLP64* (@c int, @c long 32 bit and -pointer 64 -- and `long long` -- 64 bit). Note in particular that -`long long` is 64 bit in all models of interest. The following table -summarizes them: - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
Compiler data models.
Data modelshortintlonglong longvoid*Compiler
ILP321632326432Most 32 bit architectures.
LP641632646464UNIX-64 (Linux, Mac OS X)
ILP641664646464Alpha, Cray
SLIP646464646464
LLP641632326464Windows-64
- -Macros such as ::VL_UINT32_C can be used to generate integer literal -with the correct suffix for a type of a given width. - -@subsection host-compiler-other Other compiler-specific features - -The module provides the macro ::VL_EXPORT to declare symbols exported -from the library and the macro ::VL_INLINE to declare inline -functions. Such features are not part of the C89 standard, and -change depending on the compiler. - -@par "Example:" -The following header file declares a function @c f that -should be visible from outside the library. -@code -#include -VL_EXPORT void f () ; -VL_EXPORT int i ; -@endcode -Notice that the macro ::VL_EXPORT needs not to be included again -when the function is defined. - -@par "Example:" -The following header file declares an inline function @c f: -@code -#include -VL_INLINE int f() ; - -VL_INLINE int f() { return 1 ; } -@endcode - -Here the first instruction defines the function @c f, where the -second declares it. Notice that since this is an inline function, its -definition must be found in the header file rather than in an -implementation file. Notice also that definition and declaration can -be merged. - -These macros translate according to the following tables: - - - - - - - - - - - - - - - - - - - - - -
Macros for exporting library symbols
PlatformMacro nameValue when building the libraryValue when importing the library
Unix/GCC::VL_EXPORTempty (assumes -visibility=hidden GCC option)__attribute__((visibility ("default")))
Win/Visual C++::VL_EXPORT@c __declspec(dllexport)@c __declspec(dllimport)
- - - - - - - - - - - - - - - - - - -
Macros for declaring inline functions
PlatformMacro nameValue
Unix/GCC::VL_INLINEstatic inline
Win/Visual C++::VL_INLINEstatic __inline
- -@section host-arch Host CPU architecture - -The module defines a symbol to identify the host CPU architecture: -::VL_ARCH_IX86 for Intel x86, ::VL_ARCH_IA64 for Intel 64, and so on. - -@subsection host-arch-endianness Endianness - -The module defines a symbol to identify the host CPU endianness: -::VL_ARCH_BIG_ENDIAN for big endian and ::VL_ARCH_LITTLE_ENDIAN for -little endian. The functions ::vl_swap_host_big_endianness_8(), -::vl_swap_host_big_endianness_4(), ::vl_swap_host_big_endianness_2() -to change the endianness of data (from/to host and network order). - -Recall that endianness concerns the way multi-byte data -types (such as 16, 32 and 64 bits integers) are stored into the -addressable memory. All CPUs uses a contiguous address range to -store atomic data types (e.g. a 16-bit integer could be assigned to -the addresses 0x10001 and 0x10002), but the order may -differ. - -- The convention is big endian, or in network - order, if the most significant byte of the multi-byte data - types is assigned to the smaller memory address. This is the - convention used for instance by the PPC architecture. - -- The convention is little endian if the least significant - byte is assigned to the smaller memory address. This is the - convention used for instance by the x86 architecture. - -@remark The names “big endian” and “little -endian” are a little confusing. “Big endian” means -“big endian first”, i.e. the address of the most -significant byte comes first. Similarly, “little endian” -means “little endian first”, in the sense that the -address of the least significant byte comes first. - -Endianness is a concern when data is either exchanged with processors -that use different conventions, transmitted over a network, or stored -to a file. For the latter two cases, one usually saves data in big -endian (network) order regardless of the host CPU. - -@section host-threads Multi-threading - -The file defines #VL_THREADS_WIN if multi-threading support is -enabled and the host supports Windows threads and #VL_THREADS_POSIX if -it supports POSIX threads. -**/ - -/** @def VL_OS_LINUX - ** @brief Defined if the host operating system is Linux. - **/ - -/** @def VL_OS_MACOSX - ** @brief Defined if the host operating system is Mac OS X. - **/ - -/** @def VL_OS_WIN - ** @brief Defined if the host operating system is Windows (32 or 64) - **/ - -/** @def VL_OS_WIN64 - ** @brief Defined if the host operating system is Windows-64. - **/ - -/** @def VL_COMPILER_GNUC - ** @brief Defined if the host compiler is GNU C. - ** - ** This macro is defined if the compiler is GNUC. - ** Its value is calculated as - ** @code - ** 10000 * MAJOR + 100 * MINOR + PATCHLEVEL - ** @endcode - ** @see @ref host-compiler - **/ - -/** @def VL_COMPILER_MSC - ** @brief Defined if the host compiler is Microsoft Visual C++. - ** @see @ref host-compiler - **/ - -/** @def VL_COMPILER_LCC - ** @brief Defined if the host compiler is LCC. - ** @deprecated The LCC is not supported anymore. - ** @see @ref host-compiler - **/ - -/** @def VL_COMPILER_LLP64 - ** @brief Defined if the host compiler data model is LLP64. - ** @see @ref host-compiler-data-model - **/ - -/** @def VL_COMPILER_LP64 - ** @brief Defined if the host compiler data model is LP64. - ** @see @ref host-compiler-data-model - **/ - -/** @def VL_COMPILER_ILP32 - ** @brief Defined if the host compiler data model is ILP32. - ** @see @ref host-compiler-data-model - **/ - -/** @def VL_INT8_C(x) - ** @brief Create an integer constant of the specified width and sign - ** @param x integer constant. - ** @return @a x with the correct suffix for the given sign and size. - ** The suffix used depends on the @ref host-compiler-data-model. - ** @par "Example:" - ** The macro VL_INT64_C(1234) is expanded as @c 123L in - ** a LP64 system and as @c 123LL in a LLP64 system. - **/ - -/** @def VL_INT16_C(x) - ** @copydoc VL_INT8_C */ - -/** @def VL_INT32_C(x) - ** @copydoc VL_INT8_C */ - -/** @def VL_INT64_C(x) - ** @copydoc VL_INT8_C */ - -/** @def VL_UINT8_C(x) - ** @copydoc VL_INT8_C */ - -/** @def VL_UINT16_C(x) - ** @copydoc VL_INT8_C */ - -/** @def VL_UINT32_C(x) - ** @copydoc VL_INT8_C */ - -/** @def VL_UINT64_C(x) - ** @copydoc VL_INT8_C */ - -/** @def VL_ARCH_IX86 - ** @brief Defined if the host CPU is of the Intel x86 family. - ** @see @ref host-arch - **/ - -/** @def VL_ARCH_IA64 - ** @brief Defined if the host CPU is of the Intel Architecture-64 family. - ** @see @ref host-arch - **/ - -/** @def VL_ARCH_LITTLE_ENDIAN - ** @brief Defined if the host CPU is little endian - ** @see @ref host-arch-endianness - **/ - -/** @def VL_ARCH_BIG_ENDIAN - ** @brief Defined if the host CPU is big endian - ** @see @ref host-arch-endianness - **/ - -/** @def VL_INLINE - ** @brief Adds appropriate inline function qualifier - ** @see @ref host-compiler-other - **/ - -/** @def VL_EXPORT - ** @brief Declares a DLL exported symbol - ** @see @ref host-compiler-other - **/ - -/** @def VL_DISABLE_SSE2 - ** @brief Defined if SSE2 support if disabled - ** - ** Define this symbol during compliation of the library and linking - ** to another project to disable VLFeat SSE2 support. - **/ - -/** @def VL_DISABLE_THREADS - ** @brief Defined if multi-threading support is disabled - ** - ** Define this symbol during compilation of the library and linking - ** to another project to disable VLFeat multi-threading support. - **/ - -/** @def VL_DISABLE_OPENMP - ** @brief Defined if OpenMP support is disabled - ** - ** Define this symbol during compilation of the library and linking - ** to another project to disable VLFeat OpenMP support. - **/ - -/** @def VL_THREADS_WIN - ** @brief Defined if the host uses Windows threads. - ** @see @ref host-threads - **/ - -/** @def VL_THREADS_POSIX - ** @brief Defiend if the host uses POISX threads. - ** @see @ref host-threads - **/ - -/** --------------------------------------------------------------- */ - -#include "host.h" -#include "generic.h" -#include - -#if defined(VL_ARCH_IX86) || defined(VL_ARCH_IA64) || defined(VL_ARCH_X64) -#define HAS_CPUID -#else -#undef HAS_CPUID -#endif - -#if defined(HAS_CPUID) & defined(VL_COMPILER_MSC) -#include -VL_INLINE void -_vl_cpuid (vl_int32* info, int function) -{ - __cpuid(info, function) ; -} -#endif - -#if defined(HAS_CPUID) & defined(VL_COMPILER_GNUC) -VL_INLINE void -_vl_cpuid (vl_int32* info, int function) -{ -#if defined(VL_ARCH_IX86) && (defined(__PIC__) || defined(__pic__)) - /* This version is compatible with -fPIC on x386 targets. This special - * case is required becaus - * on such platform -fPIC alocates ebx as global offset table pointer. - * Note that =r below will be mapped to a register different from ebx, - * so the code is sound. */ - __asm__ __volatile__ - ("pushl %%ebx \n" /* save %ebx */ - "cpuid \n" - "movl %%ebx, %1 \n" /* save what cpuid just put in %ebx */ - "popl %%ebx \n" /* restore the old %ebx */ - : "=a"(info[0]), "=r"(info[1]), "=c"(info[2]), "=d"(info[3]) - : "a"(function) - : "cc") ; /* clobbered (cc=condition codes) */ -#else /* no -fPIC or -fPIC with a 64-bit target */ - __asm__ __volatile__ - ("cpuid" - : "=a"(info[0]), "=b"(info[1]), "=c"(info[2]), "=d"(info[3]) - : "a"(function) - : "cc") ; -#endif -} - -#endif - -#if defined(HAS_CPUID) - -void -_vl_x86cpu_info_init (VlX86CpuInfo *self) -{ - vl_int32 info [4] ; - int max_func = 0 ; - _vl_cpuid(info, 0) ; - max_func = info[0] ; - self->vendor.words[0] = info[1] ; - self->vendor.words[1] = info[3] ; - self->vendor.words[2] = info[2] ; - - if (max_func >= 1) { - _vl_cpuid(info, 1) ; - self->hasMMX = info[3] & (1 << 23) ; - self->hasSSE = info[3] & (1 << 25) ; - self->hasSSE2 = info[3] & (1 << 26) ; - self->hasSSE3 = info[2] & (1 << 0) ; - self->hasSSE41 = info[2] & (1 << 19) ; - self->hasSSE42 = info[2] & (1 << 20) ; - self->hasAVX = info[2] & (1 << 28) ; - } -} - -#endif - -char * -_vl_x86cpu_info_to_string_copy (VlX86CpuInfo const *self) -{ - char * string = 0 ; - int length = 0 ; - while (string == 0) { - if (length > 0) { - string = vl_malloc(sizeof(char) * length) ; - if (string == NULL) break ; - } - length = snprintf(string, length, "%s%s%s%s%s%s%s%s", - self->vendor.string, - self->hasMMX ? " MMX" : "", - self->hasSSE ? " SSE" : "", - self->hasSSE2 ? " SSE2" : "", - self->hasSSE3 ? " SSE3" : "", - self->hasSSE41 ? " SSE41" : "", - self->hasSSE42 ? " SSE42" : "", - self->hasAVX ? " AVX" : "") ; - length += 1 ; - } - return string ; -} - -/** ------------------------------------------------------------------ - ** @brief Human readable static library configuration - ** @return a new string with the static configuration. - ** - ** The string includes information about the compiler, the host, and - ** other static configuration parameters. The string must be released - ** by ::vl_free. - **/ - -VL_EXPORT char * -vl_static_configuration_to_string_copy () -{ - char const * hostString = -#ifdef VL_ARCH_X64 - "X64" -#endif -#ifdef VL_ARCH_IA64 - "IA64" -#endif -#ifdef VL_ARCH_IX86 - "IX86" -#endif -#ifdef VL_ARCH_PPC - "PPC" -#endif - ", " -#ifdef VL_ARCH_BIG_ENDIAN - "big_endian" -#endif -#ifdef VL_ARCH_LITTLE_ENDIAN - "little_endian" -#endif - ; - - char compilerString [1024] ; - - char const * libraryString = -#ifndef VL_DISABLE_THREADS -#ifdef VL_THREADS_WIN - "Windows_threads" -#elif VL_THREADS_POSIX - "POSIX_threads" -#endif -#else - "No_threads" -#endif -#ifndef VL_DISABLE_SSE2 - ", SSE2" -#endif -#if defined(_OPENMP) - ", OpenMP" -#endif - ; - -snprintf(compilerString, 1024, -#ifdef VL_COMPILER_MSC - "Microsoft Visual C++ %d" -#define v VL_COMPILER_MSC -#endif -#ifdef VL_COMPILER_GNUC - "GNU C %d" -#define v VL_COMPILER_GNUC -#endif - " " -#ifdef VL_COMPILER_LP64 - "LP64" -#endif -#ifdef VL_COMPILER_LLP64 - "LP64" -#endif -#ifdef VL_COMPILER_ILP32 - "ILP32" -#endif - , v) ; - - { - char * string = 0 ; - int length = 0 ; - while (string == 0) { - if (length > 0) { - string = vl_malloc(sizeof(char) * length) ; - if (string == NULL) break ; - } - length = snprintf(string, length, "%s, %s, %s", - hostString, - compilerString, - libraryString) ; - length += 1 ; - } - return string ; - } -} diff --git a/opensfm/src/third_party/vlfeat/vl/host.h b/opensfm/src/third_party/vlfeat/vl/host.h deleted file mode 100644 index fb2700c77..000000000 --- a/opensfm/src/third_party/vlfeat/vl/host.h +++ /dev/null @@ -1,662 +0,0 @@ -/** @file host.h - ** @brief Host - ** @author Andrea Vedaldi - ** @sa @ref portability - **/ - -/* -Copyright (C) 2007-12 Andrea Vedaldi and Brian Fulkerson. -All rights reserved. - -This file is part of the VLFeat library and is made available under -the terms of the BSD license (see the COPYING file). -*/ - -#ifndef VL_HOST_H -#define VL_HOST_H - -/** ------------------------------------------------------------------ - ** @name Configuration options - ** @{ */ - -#if defined(__DOXYGEN__) -#define VL_DISABLE_THREADS -#define VL_DISABLE_SSE2 -#define VL_DISABLE_OPENMP -#endif - -/** @} */ - -/** ------------------------------------------------------------------ - ** @name Defining functions - ** @{ */ - -#if defined(__DOXYGEN__) -#define VL_EXPORT -#define VL_INLINE -#endif - -/** @} */ - -/** ------------------------------------------------------------------ - ** @name C preprocessor helper macros - ** @{ */ - -/** @brief Convert the argument to a string - ** @param x value to be stringified. - ** - ** This macro stringifies the argument @a x by means of the - ** # prerpocessor operator. - ** - ** The standard C preprocessor does not prescan arguments which are - ** stringified, so - ** - ** @code - ** #define A B - ** char const * str = VL_STRINGIFY(A) ; - ** @endcode - ** - ** initializes str with a pointer to the string - ** "A", which mihgt be unexpected. To fix this issue, - ** you can use ::VL_XSTRINGIFY. - ** - ** @sa ::VL_XSTRINGIFY - **/ - -#define VL_STRINGIFY(x) # x - -/** @brief Expand and then convert the argument to a string - ** @param x value to be macro-expanded and converted. - ** - ** This macro macro-expands the argument @a x and stringifies the - ** result of the expansion. For instance - ** - ** @code - ** #define A B - ** char const * str = VL_STRINGIFY(A) ; - ** @endcode - ** - ** initializes str with a pointer to the string - ** "B". - ** - ** @sa ::VL_STRINGIFY - **/ - -#define VL_XSTRINGIFY(x) VL_STRINGIFY(x) - -/** @brief Concatenate two arguments into a lexical unit - ** @param x first argument to be concatenated. - ** @param y second argument to be concatenated. - ** - ** This macro concatenates its arguments into a single lexical unit - ** by means of the ## preprocessor operator. Notice that - ** arguments concatenated by ## are not pre-expanded by - ** the C preprocessor. To macro-expand the arguments and then - ** concatenate them,use ::VL_XCAT. - ** - ** @see ::VL_XCAT - **/ - -#define VL_CAT(x,y) x ## y - -/** @brief Expand and then concatenate two arguments into a lexical unit - ** @param x first argument to be concatenated. - ** @param y second argument to be concatenated. - ** - ** This macro is the same as ::VL_CAT, except that the arguments are - ** macro expanded before being concatenated. - ** - ** @see ::VL_CAT - **/ - -#define VL_XCAT(x,y) VL_CAT(x,y) - -/** @brief Expand and then concatenate three arguments into a lexical unit - ** @param x first argument to be concatenated. - ** @param y second argument to be concatenated. - ** @param z third argument to be concatenated. - ** - ** This macro is the same as ::VL_XCAT, except that it has three arguments. - ** - ** @see ::VL_XCAT - **/ - -#define VL_XCAT3(x,y,z) VL_XCAT(VL_XCAT(x,y),z) - -/** @brief Expand and then concatenate four arguments into a lexical unit - ** @param x first argument to be concatenated. - ** @param y second argument to be concatenated. - ** @param z third argument to be concatenated. - ** @param u fourth argument to be concatenated. - ** - ** This macro is the same as ::VL_XCAT, except that it has four arguments. - ** - ** @see ::VL_XCAT - **/ - -#define VL_XCAT4(x,y,z,u) VL_XCAT(VL_XCAT3(x,y,z),u) - -/** @brief Expand and then concatenate five arguments into a lexical unit - ** @param x first argument to be concatenated. - ** @param y second argument to be concatenated. - ** @param z third argument to be concatenated. - ** @param u fourth argument to be concatenated. - ** @param v fifth argument to be concatenated. - ** - ** This macro is the same as ::VL_XCAT, except that it has five arguments. - ** - ** @see ::VL_XCAT - **/ - -#define VL_XCAT5(x,y,z,u,v) VL_XCAT(VL_XCAT4(x,y,z,u),v) - -/** @brief Convert a boolean to "yes" or "no" strings - ** @param x boolean to convert. - ** - ** A pointer to either the string "yes" (if @a x is true) - ** or the string "no". - ** - ** @par Example - ** @code - ** VL_PRINTF("Is x true? %s.", VL_YESNO(x)) - ** @endcode - **/ - -#define VL_YESNO(x) ((x)?"yes":"no") - -/** @} */ - -/* - The following macros identify the host OS, architecture and compiler. - They are derived from http://predef.sourceforge.net/ - */ - -/** @name Identifying the host operating system - ** @{ */ -#if defined(linux) || \ - defined(__linux) || \ - defined(__linux__) || \ - defined(__DOXYGEN__) -#define VL_OS_LINUX 1 -#endif - -#if (defined(__APPLE__) & defined(__MACH__)) || \ - defined(__DOXYGEN__) -#define VL_OS_MACOSX 1 -#endif - -#if defined(__WIN32__) || \ - defined(_WIN32) || \ - defined(__DOXYGEN__) -#define VL_OS_WIN 1 -#endif - -#if defined(_WIN64) || \ - defined(__DOXYGEN__) -#define VL_OS_WIN64 1 -#endif -/** @} */ - -/** @name Identifying the host threading library - ** @{ */ -#if !defined(VL_OS_WIN) && !defined(VL_OS_WIN64) || \ -defined(__DOXYGEN__) -#define VL_THREADS_POSIX 1 -#endif - -#if defined(VL_OS_WIN) || defined(VL_OS_WIN64) || \ -defined(__DOXYGEN__) -#define VL_THREADS_WIN 1 -#endif -/** @} */ - -/** @name Identifying the host compiler - ** @{ */ -#if defined(__GNUC__) || defined(__DOXYGEN__) -# if defined(__GNUC_PATCHLEVEL__) -# define VL_COMPILER_GNUC (__GNUC__ * 10000 \ -+ __GNUC_MINOR__ * 100 \ -+ __GNUC_PATCHLEVEL__) -# else -# define VL_COMPILER_GNUC (__GNUC__ * 10000 \ -+ __GNUC_MINOR__ * 100) -# endif -#endif - -#if defined(_MSC_VER) || defined(__DOXYGEN__) -#define VL_COMPILER_MSC _MSC_VER -#endif - -#if defined(__LCC__) || defined(__DOXYGEN__) -#warning "LCC support is experimental!" -#define VL_COMPILER_LCC 1 -#endif - -/** @} */ - -/** @name Identifying the host CPU architecture - ** @{ */ -#if defined(i386) || \ - defined(__i386__) || \ - defined(__DOXYGEN__) -#define VL_ARCH_IX86 300 -#elif defined(__i486__) -#define VL_ARCH_IX86 400 -#elif defined(__i586__) -#define VL_ARCH_IX86 500 -#elif defined(__i686__) -#define VL_ARCH_IX86 600 -#elif defined(_M_IX86) -#define VL_ARCH_IX86 _M_IX86 -#endif - -#if defined(_M_X64) || \ - defined(__amd64__) || \ - defined(__amd64) || \ - defined(__x86_64) || \ - defined(__x86_64) -#define VL_ARCH_X64 -#endif - -#if defined(__ia64__) || \ - defined(_IA64) || \ - defined(__IA64) || \ - defined(__ia64) || \ - defined(_M_IA64) || \ - defined(__DOXYGEN__) -#define VL_ARCH_IA64 -#endif -/** @} */ - -/** @name Identifying the host data model - ** @{ */ -#if defined(__LLP64__) || \ - defined(__LLP64) || \ - defined(__LLP64) || \ - (defined(VL_COMPILER_MSC) & defined(VL_OS_WIN64)) || \ - (defined(VL_COMPILER_LCC) & defined(VL_OS_WIN64)) || \ - defined(__DOXYGEN__) -#define VL_COMPILER_LLP64 -#endif - -#if defined(__LP64__) || \ - defined(__LP64) || \ - defined(__LP64) || \ - (defined(VL_OS_MACOSX) & defined(VL_ARCH_IA64)) || \ - defined(__DOXYGEN__) -#define VL_COMPILER_LP64 -#endif - -#if (!defined(VL_COMPILER_LLP64) & !defined(VL_COMPILER_LP64)) || \ - defined(__DOXYGEN__) -#define VL_COMPILER_ILP32 -#endif -/** @} */ - -/** @name Identifying the host endianness - ** @{ */ -#if defined(__LITTLE_ENDIAN__) || \ - defined(VL_ARCH_IX86) || \ - defined(VL_ARCH_IA64) || \ - defined(VL_ARCH_X64) || \ - defined(__DOXYGEN__) -#define VL_ARCH_LITTLE_ENDIAN -#endif - -#if defined(__DOXYGEN__) || \ - !defined(VL_ARCH_LITTLE_ENDIAN) -#define VL_ARCH_BIG_ENDIAN -#endif -/** @} */ - -#if defined(VL_COMPILER_MSC) & ! defined(__DOXYGEN__) -# define VL_UNUSED -# define VL_INLINE static __inline -#if defined _MSC_VER && _MSC_VER < 1900 -# define snprintf _snprintf -#endif -# define isnan _isnan -# ifdef VL_BUILD_DLL -# ifdef __cplusplus -# define VL_EXPORT extern "C" __declspec(dllexport) -# else -# define VL_EXPORT extern __declspec(dllexport) -# endif -# else -# ifdef __cplusplus -# define VL_EXPORT extern "C" -# else -# define VL_EXPORT extern -# endif -# endif -#endif - -#if defined(VL_COMPILER_LCC) & ! defined(__DOXYGEN__) -# define VL_UNUSED -# define VL_INLINE static __inline -# define snprintf _snprintf -# define isnan _isnan -VL_INLINE float fabsf(float x) { return (float) fabs((double) x) ; } -# ifdef VL_BUILD_DLL -# define VL_EXPORT extern __declspec(dllexport) -# else -# define VL_EXPORT extern -# endif -#endif - -#if defined(VL_COMPILER_GNUC) & ! defined(__DOXYGEN__) -# define VL_UNUSED __attribute__((unused)) -# define VL_INLINE static __inline__ -# ifdef VL_BUILD_DLL -# ifdef __cplusplus -# define VL_EXPORT __attribute__((visibility ("default"))) extern "C" -# else -# define VL_EXPORT __attribute__((visibility ("default"))) extern -# endif -# else -# ifdef __cplusplus -# define VL_EXPORT extern "C" -# else -# define VL_EXPORT extern -# endif -# endif -#endif - -VL_EXPORT char * vl_static_configuration_to_string_copy () ; - -/** ------------------------------------------------------------------ - ** @name Atomic data types - ** @{ - **/ - -#define VL_TRUE 1 /**< @brief @c true (1) constant */ -#define VL_FALSE 0 /**< @brief @c false (0) constant */ - -#if defined(VL_COMPILER_LP64) || defined(VL_COMPILER_LLP64) -typedef long long vl_int64 ; /**< @brief Signed 64-bit integer. */ -typedef int vl_int32 ; /**< @brief Signed 32-bit integer. */ -typedef short vl_int16 ; /**< @brief Signed 16-bit integer. */ -typedef char vl_int8 ; /**< @brief Signed 8-bit integer. */ - -typedef long long unsigned vl_uint64 ; /**< @brief Unsigned 64-bit integer. */ -typedef int unsigned vl_uint32 ; /**< @brief Unsigned 32-bit integer. */ -typedef short unsigned vl_uint16 ; /**< @brief Unsigned 16-bit integer. */ -typedef char unsigned vl_uint8 ; /**< @brief Unsigned 8-bit integer. */ - -typedef int vl_int ; /**< @brief Same as @c int. */ -typedef unsigned int vl_uint ; /**< @brief Same as unsigned int. */ - -typedef int vl_bool ; /**< @brief Boolean. */ -typedef vl_int64 vl_intptr ; /**< @brief Integer holding a pointer. */ -typedef vl_uint64 vl_uintptr ; /**< @brief Unsigned integer holding a pointer. */ -typedef vl_int64 vl_size ; /**< @brief Signed integer holding the size of a memory block. */ -typedef vl_int64 vl_index ; /**< @brief Signed version of ::vl_size and ::vl_uindex */ -typedef vl_uint64 vl_uindex ; /**< @brief Same as ::vl_size */ -#endif - -#if defined(VL_COMPILER_ILP32) - -#ifdef VL_COMPILER_MSC -typedef __int64 vl_int64 ; -#else -typedef long long vl_int64 ; -#endif - -typedef int vl_int32 ; -typedef short vl_int16 ; -typedef char vl_int8 ; - -#ifdef VL_COMPILER_MSC -typedef __int64 unsigned vl_uint64 ; -#else -typedef long long unsigned vl_uint64 ; -#endif -typedef int unsigned vl_uint32 ; -typedef short unsigned vl_uint16 ; -typedef char unsigned vl_uint8 ; - -typedef int vl_int ; -typedef unsigned int vl_uint ; - -typedef int vl_bool ; -typedef vl_int32 vl_intptr ; -typedef vl_uint32 vl_uintptr ; -typedef vl_uint32 vl_size ; -typedef vl_int32 vl_index ; -typedef vl_uint32 vl_uindex ; -#endif -/** @} */ - -/** @name Creating integer constants - ** @{ */ -#if defined(VL_COMPILER_LP64) || defined(__DOXYGEN__) -#define VL_INT8_C(x) x -#define VL_INT16_C(x) x -#define VL_INT32_C(x) x -#define VL_INT64_C(x) x ## L - -#define VL_UINT8_C(x) x -#define VL_UINT16_C(x) x -#define VL_UINT32_C(x) x ## U -#define VL_UINT64_C(x) x ## UL -#endif - -#if (defined(VL_COMPILER_LLP64) || defined(VL_COMPILER_ILP32)) \ - & !defined(__DOXYGEN__) -#define VL_INT8_C(x) x -#define VL_INT16_C(x) x -#define VL_INT32_C(x) x -#define VL_INT64_C(x) x ## LL - -#define VL_UINT8_C(x) x -#define VL_UINT16_C(x) x -#define VL_UINT32_C(x) x ## U -#define VL_UINT64_C(x) x ## ULL -#endif -/** @} */ - -/** ------------------------------------------------------------------ - ** @name Printing the atomic data types - ** @{ */ - -/* Lengths only: */ - -/** @def VL_FL_INT64 - ** @brief @c printf length flag for ::vl_int64 and ::vl_uint64. - **/ - -/** @def VL_FL_INT32 - ** @brief @c printf length flag for ::vl_int32 and ::vl_uint32. - **/ - -/** @def VL_FL_INT16 - ** @brief @c printf length flag for ::vl_int16 and ::vl_uint16. - **/ - -/** @def VL_FL_INT8 - ** @brief @c printf length flag for ::vl_int8 and ::vl_uint8. - **/ - -/** @def VL_FL_INDEX - ** @brief @c printf length flag for ::vl_index and ::vl_uindex - **/ - -#ifdef VL_COMPILER_MSC -#define VL_FL_INT64 "I64" -#else -#define VL_FL_INT64 "ll" -#endif -#define VL_FL_INT32 "" -#define VL_FL_INT16 "h" -#define VL_FL_INT8 "hh" - -#if defined(VL_COMPILER_LP64) || defined(VL_COMPILER_LLP64) -#define VL_FL_INDEX VL_FL_INT64 -#endif - -#if defined(VL_COMPILER_ILP32) -#define VL_FL_INDEX VL_FL_INT32 -#endif - -/* Formats (but not conversions!): */ - -/** @def VL_FMT_SIZE - ** @brief @c printf flag for ::vl_size - **/ - -/** @def VL_FMT_INDEX - ** @brief @c printf flag for ::vl_index - **/ - -/** @def VL_FMT_UINDEX - ** @brief @c printf flag for ::vl_uindex - **/ - -/** @def VL_FMT_INTPTR - ** @brief @c printf flag for ::vl_intptr - **/ - -/** @def VL_FMT_UINTPTR - ** @brief @c printf flag for ::vl_uintptr - **/ - -#define VL_FMT_INDEX VL_FL_INDEX "d" -#define VL_FMT_INTPTR VL_FMT_INDEX -#define VL_FMT_UINDEX VL_FL_INDEX "u" -#define VL_FMT_SIZE VL_FMT_UINDEX -#define VL_FMT_UINTPTR VL_FMT_UINDEX - -/** @} */ - -/** ------------------------------------------------------------------ - ** @name Atomic data types limits - ** @{ */ - -/** @brief Largest integer (math constant) */ -#define VL_BIG_INT 0x7FFFFFFFL - -/** @brief Smallest integer (math constant) */ -#define VL_SMALL_INT (- VL_BIG_INT - 1) - -/** @brief Largest unsigned integer (math constant) */ -#define VL_BIG_UINT 0xFFFFFFFFUL - -/** @} */ - -/** ------------------------------------------------------------------ - ** @name Endianness detection and conversion - ** @{ - **/ -VL_INLINE void vl_swap_host_big_endianness_8 (void *dst, void* src) ; -VL_INLINE void vl_swap_host_big_endianness_4 (void *dst, void* src) ; -VL_INLINE void vl_swap_host_big_endianness_2 (void *dst, void* src) ; -/** @} */ - -/** ------------------------------------------------------------------ - ** @name Obtaining host info at run time - ** @{ */ - -typedef struct _VlX86CpuInfo -{ - union { - char string [0x20] ; - vl_uint32 words [0x20 / 4] ; - } vendor ; - vl_bool hasAVX ; - vl_bool hasSSE42 ; - vl_bool hasSSE41 ; - vl_bool hasSSE3 ; - vl_bool hasSSE2 ; - vl_bool hasSSE ; - vl_bool hasMMX ; -} VlX86CpuInfo ; - -void _vl_x86cpu_info_init (VlX86CpuInfo *self) ; -char * _vl_x86cpu_info_to_string_copy (VlX86CpuInfo const *self) ; - -/** @} */ - -/** ------------------------------------------------------------------ - ** @brief Host <-> big endian transformation for 8-bytes value - ** - ** @param dst destination 8-byte buffer. - ** @param src source 8-byte bufffer. - ** @see @ref host-arch-endianness. - **/ - -VL_INLINE void -vl_swap_host_big_endianness_8 (void *dst, void* src) -{ - char *dst_ = (char*) dst ; - char *src_ = (char*) src ; -#if defined(VL_ARCH_BIG_ENDIAN) - dst_ [0] = src_ [0] ; - dst_ [1] = src_ [1] ; - dst_ [2] = src_ [2] ; - dst_ [3] = src_ [3] ; - dst_ [4] = src_ [4] ; - dst_ [5] = src_ [5] ; - dst_ [6] = src_ [6] ; - dst_ [7] = src_ [7] ; -#else - dst_ [0] = src_ [7] ; - dst_ [1] = src_ [6] ; - dst_ [2] = src_ [5] ; - dst_ [3] = src_ [4] ; - dst_ [4] = src_ [3] ; - dst_ [5] = src_ [2] ; - dst_ [6] = src_ [1] ; - dst_ [7] = src_ [0] ; -#endif -} - -/** ------------------------------------------------------------------ - ** @brief Host <-> big endian transformation for 4-bytes value - ** - ** @param dst destination 4-byte buffer. - ** @param src source 4-byte bufffer. - ** @sa @ref host-arch-endianness. - **/ - -VL_INLINE void -vl_swap_host_big_endianness_4 (void *dst, void* src) -{ - char *dst_ = (char*) dst ; - char *src_ = (char*) src ; -#if defined(VL_ARCH_BIG_ENDIAN) - dst_ [0] = src_ [0] ; - dst_ [1] = src_ [1] ; - dst_ [2] = src_ [2] ; - dst_ [3] = src_ [3] ; -#else - dst_ [0] = src_ [3] ; - dst_ [1] = src_ [2] ; - dst_ [2] = src_ [1] ; - dst_ [3] = src_ [0] ; -#endif -} - -/** ------------------------------------------------------------------ - ** @brief Host <-> big endian transformation for 2-bytes value - ** - ** @param dst destination 2-byte buffer. - ** @param src source 2-byte bufffer. - ** @see @ref host-arch-endianness. - **/ - -VL_INLINE void -vl_swap_host_big_endianness_2 (void *dst, void* src) -{ - char *dst_ = (char*) dst ; - char *src_ = (char*) src ; -#if defined(VL_ARCH_BIG_ENDIAN) - dst_ [0] = src_ [0] ; - dst_ [1] = src_ [1] ; -#else - dst_ [0] = src_ [1] ; - dst_ [1] = src_ [0] ; -#endif -} - -/* VL_HOST_H */ -#endif diff --git a/opensfm/src/third_party/vlfeat/vl/ikmeans.c b/opensfm/src/third_party/vlfeat/vl/ikmeans.c deleted file mode 100644 index 4eb7c4687..000000000 --- a/opensfm/src/third_party/vlfeat/vl/ikmeans.c +++ /dev/null @@ -1,297 +0,0 @@ -/** @file ikmeans.c - ** @brief Integer K-Means clustering - Definition - ** @author Brian Fulkerson - ** @author Andrea Vedaldi - **/ - -/* -Copyright (C) 2007-12 Andrea Vedaldi and Brian Fulkerson. -All rights reserved. - -This file is part of the VLFeat library and is made available under -the terms of the BSD license (see the COPYING file). -*/ - -/** @file ikmeans.h - ** - ** Integer K-means (IKM) is an implementation of K-means clustering - ** (or Vector Quantization, VQ) for integer data. This is - ** particularly useful for clustering large collections of visual - ** descriptors. - ** - ** Use the function ::vl_ikm_new() to create a IKM - ** quantizer. Initialize the IKM quantizer with @c K clusters by - ** ::vl_ikm_init() or similar function. Use ::vl_ikm_train() to train - ** the quantizer. Use ::vl_ikm_push() or ::vl_ikm_push_one() to - ** quantize new data. - ** - ** Given data @f$x_1,\dots,x_N\in R^d@f$ and a number of clusters - ** @f$K@f$, the goal is to find assignments @f$a_i\in\{1,\dots,K\},@f$ - ** and centers @f$c_1,\dots,c_K\in R^d@f$ so that the expected - ** distortion - ** - ** @f[ - ** E(\{a_{i}, c_j\}) = \frac{1}{N} \sum_{i=1}^N d(x_i, c_{a_i}) - ** @f] - ** - ** is minimized. Here @f$d(x_i, c_{a_i})@f$ is the - ** distortion, i.e. the cost we pay for representing @f$ x_i - ** @f$ by @f$ c_{a_i} @f$. IKM uses the squared distortion - ** @f$d(x,y)=\|x-y\|^2_2@f$. - ** - ** @section ikmeans-algo Algorithms - ** - ** @subsection ikmeans-alg-init Initialization - ** - ** Most K-means algorithms are iterative and needs an initialization - ** in the form of an initial choice of the centers - ** @f$c_1,\dots,c_K@f$. We include the following options: - ** - ** - User specified centers (::vl_ikm_init); - ** - Random centers (::vl_ikm_init_rand); - ** - Centers from @c K randomly selected data points (::vl_ikm_init_rand_data). - ** - ** @subsection ikmeans-alg-lloyd Lloyd - ** - ** The Lloyd (also known as Lloyd-Max and LBG) algorithm iteratively: - ** - ** - Fixes the centers, optimizing the assignments (minimizing by - ** exhaustive search the association of each data point to the - ** centers); - ** - Fixes the assignments and optimizes the centers (by descending - ** the distortion error function). For the squared distortion, this - ** step is in closed form. - ** - ** This algorithm is not particularly efficient because all data - ** points need to be compared to all centers, for a complexity - ** @f$O(dNKT)@f$, where T is the total number of iterations. - ** - ** @subsection ikmeans-alg-elkan Elkan - ** - ** The Elkan algorithm is an optimized variant of Lloyd. By making - ** use of the triangle inequality, many comparisons of data points - ** and centers are avoided, especially at later iterations. - ** Usually 4-5 times less comparisons than Lloyd are preformed, - ** providing a dramatic speedup in the execution time. - ** - **/ - -#include "ikmeans.h" - -#include -#include -#include /* memset */ -#include "assert.h" - -static void vl_ikm_init_lloyd (VlIKMFilt*) ; -static void vl_ikm_init_elkan (VlIKMFilt*) ; -static int vl_ikm_train_lloyd (VlIKMFilt*, vl_uint8 const*, vl_size) ; -static int vl_ikm_train_elkan (VlIKMFilt*, vl_uint8 const*, vl_size) ; -static void vl_ikm_push_lloyd (VlIKMFilt*, vl_uint32*, vl_uint8 const*, vl_size) ; -static void vl_ikm_push_elkan (VlIKMFilt*, vl_uint32*, vl_uint8 const*, vl_size) ; - -/** @brief Create a new IKM quantizer - ** @param method Clustering algorithm. - ** @return new IKM quantizer. - ** - ** The function allocates initializes a new IKM quantizer to - ** operate based algorithm @a method. - ** - ** @a method has values in the enumerations ::VlIKMAlgorithms. - **/ - -VlIKMFilt * -vl_ikm_new (int method) -{ - VlIKMFilt *f = vl_calloc (sizeof(VlIKMFilt), 1) ; - f -> method = method ; - f -> max_niters = 200 ; - return f ; -} - -/** @brief Delete IKM quantizer - ** @param f IKM quantizer. - **/ - -void -vl_ikm_delete (VlIKMFilt* f) -{ - if (f) { - if (f->centers) vl_free(f->centers) ; - if (f->inter_dist) vl_free(f->inter_dist) ; - vl_free(f) ; - } -} - -/** @brief Train clusters - ** @param f IKM quantizer. - ** @param data data. - ** @param N number of data (@a N @c >= 1). - ** @return -1 if an overflow may have occurred. - **/ - -int -vl_ikm_train (VlIKMFilt *f, vl_uint8 const *data, vl_size N) -{ - int err ; - - if (f-> verb) { - VL_PRINTF ("ikm: training with %d data\n", N) ; - VL_PRINTF ("ikm: %d clusters\n", f -> K) ; - } - - switch (f -> method) { - case VL_IKM_LLOYD : err = vl_ikm_train_lloyd (f, data, N) ; break ; - case VL_IKM_ELKAN : err = vl_ikm_train_elkan (f, data, N) ; break ; - default : - abort() ; - } - return err ; -} - -/** @brief Project data to clusters - ** @param f IKM quantizer. - ** @param asgn Assignments (out). - ** @param data data. - ** @param N number of data (@a N @c >= 1). - ** - ** The function projects the data @a data on the integer K-means - ** clusters specified by the IKM quantizer @a f. Notice that the - ** quantizer must be initialized. - **/ - -void -vl_ikm_push (VlIKMFilt *f, vl_uint32 *asgn, vl_uint8 const *data, vl_size N) { - switch (f -> method) { - case VL_IKM_LLOYD : vl_ikm_push_lloyd (f, asgn, data, N) ; break ; - case VL_IKM_ELKAN : vl_ikm_push_elkan (f, asgn, data, N) ; break ; - default : - abort() ; - } -} - -/** @brief Project one datum to clusters - ** @param centers centers. - ** @param data datum to project. - ** @param K number of centers. - ** @param M dimensionality of the datum. - ** @return the cluster index. - ** - ** The function projects the specified datum @a data on the clusters - ** specified by the centers @a centers. - **/ - -vl_uint32 -vl_ikm_push_one (vl_ikmacc_t const *centers, - vl_uint8 const *data, - vl_size M, vl_size K) -{ - vl_uindex i,k ; - - /* assign data to centers */ - vl_uindex best = (vl_uindex) -1 ; - vl_ikmacc_t best_dist = 0 ; - - for(k = 0 ; k < K ; ++k) { - vl_ikmacc_t dist = 0 ; - - /* compute distance with this center */ - for(i = 0 ; i < M ; ++i) { - vl_ikmacc_t delta = (vl_ikmacc_t)data[i] - centers[k*M + i] ; - dist += delta * delta ; - } - - /* compare with current best */ - if (best == (vl_uindex) -1 || dist < best_dist) { - best = k ; - best_dist = dist ; - } - } - return (vl_uint32)best; -} - -/* ---------------------------------------------------------------- */ -/* Getters and setters */ -/* ---------------------------------------------------------------- */ - -/** @brief Get data dimensionality - ** @param f IKM filter. - ** @return data dimensionality. - **/ - -vl_size -vl_ikm_get_ndims (VlIKMFilt const* f) -{ - return f->M ; -} - - -/** @brief Get the number of centers K - ** @param f IKM filter. - ** @return number of centers K. - **/ - -vl_size -vl_ikm_get_K (VlIKMFilt const* f) -{ - return f->K ; -} - -/** @brief Get verbosity level - ** @param f IKM filter. - ** @return verbosity level. - **/ - -int -vl_ikm_get_verbosity (VlIKMFilt const* f) -{ - return f->verb ; -} - -/** @brief Get maximum number of iterations - ** @param f IKM filter. - ** @return maximum number of iterations. - **/ - -vl_size -vl_ikm_get_max_niters (VlIKMFilt const* f) -{ - return f->max_niters ; -} - -/** @brief Get maximum number of iterations - ** @param f IKM filter. - ** @return maximum number of iterations. - **/ - -vl_ikmacc_t const * -vl_ikm_get_centers (VlIKMFilt const* f) -{ - return f-> centers ; -} - -/** @brief Set verbosity level - ** @param f IKM filter. - ** @param verb verbosity level. - **/ - -void -vl_ikm_set_verbosity (VlIKMFilt *f, int verb) -{ - f-> verb = VL_MAX(0,verb) ; -} - -/** @brief Set maximum number of iterations - ** @param f IKM filter. - ** @param max_niters maximum number of iterations. - **/ - -void -vl_ikm_set_max_niters (VlIKMFilt *f, vl_size max_niters) -{ - f-> max_niters = max_niters ; -} - -#include "ikmeans_init.tc" -#include "ikmeans_lloyd.tc" -#include "ikmeans_elkan.tc" diff --git a/opensfm/src/third_party/vlfeat/vl/ikmeans.h b/opensfm/src/third_party/vlfeat/vl/ikmeans.h deleted file mode 100644 index e79908056..000000000 --- a/opensfm/src/third_party/vlfeat/vl/ikmeans.h +++ /dev/null @@ -1,87 +0,0 @@ -/** @file ikmeans.h - ** @brief Integer K-Means clustering - ** @author Brian Fulkerson - ** @author Andrea Vedaldi - **/ - -/* -Copyright (C) 2014 Andrea Vedaldi. -Copyright (C) 2007-12 Andrea Vedaldi and Brian Fulkerson. -All rights reserved. - -This file is part of the VLFeat library and is made available under -the terms of the BSD license (see the COPYING file). -*/ - -#ifndef VL_IKMEANS_H -#define VL_IKMEANS_H - -#include "generic.h" -#include "random.h" - -#if 0 -typedef vl_int64 vl_ikmacc_t ; /**< IKM accumulator data type */ -#define VL_IKMACC_MAX 0x7fffffffffffffffULL -#else -typedef vl_int32 vl_ikmacc_t ; /**< IKM accumulator data type */ -#define VL_IKMACC_MAX 0x7fffffffUL -#endif - - -/** ------------------------------------------------------------------ - ** @brief IKM algorithms - **/ - -enum VlIKMAlgorithms { - VL_IKM_LLOYD, /**< Lloyd algorithm */ - VL_IKM_ELKAN, /**< Elkan algorithm */ -} ; - -/** ------------------------------------------------------------------ - ** @brief IKM quantizer - **/ - -typedef struct _VlIKMFilt -{ - vl_size M ; /**< data dimensionality */ - vl_size K ; /**< number of centers */ - vl_size max_niters ; /**< Lloyd: maximum number of iterations */ - int method ; /**< Learning method */ - int verb ; /**< verbosity level */ - vl_ikmacc_t *centers ; /**< centers */ - vl_ikmacc_t *inter_dist ; /**< centers inter-distances */ -} VlIKMFilt ; - -/** @name Create and destroy - ** @{ */ -VL_EXPORT VlIKMFilt *vl_ikm_new (int method) ; -VL_EXPORT void vl_ikm_delete (VlIKMFilt *f) ; -/** @} */ - -/** @name Process data - ** @{ */ -VL_EXPORT void vl_ikm_init (VlIKMFilt *f, vl_ikmacc_t const *centers, vl_size M, vl_size K) ; -VL_EXPORT void vl_ikm_init_rand (VlIKMFilt *f, vl_size M, vl_size K) ; -VL_EXPORT void vl_ikm_init_rand_data (VlIKMFilt *f, vl_uint8 const *data, vl_size M, vl_size N, vl_size K) ; -VL_EXPORT int vl_ikm_train (VlIKMFilt *f, vl_uint8 const *data, vl_size N) ; -VL_EXPORT void vl_ikm_push (VlIKMFilt *f, vl_uint32 *asgn, vl_uint8 const *data, vl_size N) ; -VL_EXPORT vl_uint vl_ikm_push_one (vl_ikmacc_t const *centers, vl_uint8 const *data, vl_size M, vl_size K) ; -/** @} */ - -/** @name Retrieve data and parameters - ** @{ */ -VL_EXPORT vl_size vl_ikm_get_ndims (VlIKMFilt const *f) ; -VL_EXPORT vl_size vl_ikm_get_K (VlIKMFilt const *f) ; -VL_EXPORT int vl_ikm_get_verbosity (VlIKMFilt const *f) ; -VL_EXPORT vl_size vl_ikm_get_max_niters (VlIKMFilt const *f) ; -VL_EXPORT vl_ikmacc_t const *vl_ikm_get_centers (VlIKMFilt const *f) ; -/** @} */ - -/** @name Set parameters - ** @{ */ -VL_EXPORT void vl_ikm_set_verbosity (VlIKMFilt *f, int verb) ; -VL_EXPORT void vl_ikm_set_max_niters (VlIKMFilt *f, vl_size max_niters) ; -/** @} */ - -/* VL_IKMEANS_H */ -#endif diff --git a/opensfm/src/third_party/vlfeat/vl/imopv.c b/opensfm/src/third_party/vlfeat/vl/imopv.c deleted file mode 100644 index 984b5061a..000000000 --- a/opensfm/src/third_party/vlfeat/vl/imopv.c +++ /dev/null @@ -1,1074 +0,0 @@ -/** @file imopv.c - ** @brief Vectorized image operations - Definition - ** @author Andrea Vedaldi - **/ - -/* -Copyright (C) 2007-12 Andrea Vedaldi and Brian Fulkerson. -All rights reserved. - -This file is part of the VLFeat library and is made available under -the terms of the BSD license (see the COPYING file). -*/ - -/** @file imopv.h - ** - ** This module provides the following image operations: - ** - ** - Separable convolution. The function ::vl_imconvcol_vf() - ** can be used to compute separable convolutions. - ** - ** - Convolution by a triangular kernel. The function - ** vl_imconvcoltri_vf() is an optimized convolution routine for - ** triangular kernels. - ** - ** - Distance transform. ::vl_image_distance_transform_f() is - ** a linear algorithm to compute the distance transform of an - ** image. - ** - ** @remark Some operations are optimized to exploit possible SIMD - ** instructions. This requires image data to be properly aligned (typically - ** to 16 bytes). Similalry, the image stride (the number of bytes to skip to move - ** to the next image row), must be aligned. - **/ - -#ifndef VL_IMOPV_INSTANTIATING - -#include "imopv.h" -#include "imopv_sse2.h" -#include "mathop.h" - -#define FLT VL_TYPE_FLOAT -#define VL_IMOPV_INSTANTIATING -#include "imopv.c" - -#define FLT VL_TYPE_DOUBLE -#define VL_IMOPV_INSTANTIATING -#include "imopv.c" - -#define FLT VL_TYPE_UINT32 -#define VL_IMOPV_INSTANTIATING -#include "imopv.c" - -#define FLT VL_TYPE_INT32 -#define VL_IMOPV_INSTANTIATING -#include "imopv.c" - -/* VL_IMOPV_INSTANTIATING */ -#endif - -#if defined(VL_IMOPV_INSTANTIATING) || defined(__DOXYGEN__) - -#include "float.h" - -/* ---------------------------------------------------------------- */ -/* Image Convolution */ -/* ---------------------------------------------------------------- */ - -#if (FLT == VL_TYPE_FLOAT || FLT == VL_TYPE_DOUBLE) - -/** @fn vl_imconvcol_vd(double*,vl_size,double const*,vl_size,vl_size,vl_size,double const*,vl_index,vl_index,int,unsigned int) - ** @brief Convolve image along columns - ** - ** @param dst destination image. - ** @param dst_stride width of the destination image including padding. - ** @param src source image. - ** @param src_width width of the source image. - ** @param src_height height of the source image. - ** @param src_stride width of the source image including padding. - ** @param filt filter kernel. - ** @param filt_begin coordinate of the first filter element. - ** @param filt_end coordinate of the last filter element. - ** @param step sub-sampling step. - ** @param flags operation modes. - ** - ** The function convolves the column of the image @a src by the - ** filter @a filt and saves the result to the image @a dst. The size - ** of @a dst must be equal to the size of @a src. Formally, this - ** results in the calculation - ** - ** @f[ - ** \mathrm{dst} [x,y] = \sum_{p=y-\mathrm{filt\_end}}^{y-\mathrm{filt\_begin}} - ** \mathrm{src}[x,y] \mathrm{filt}[y - p - \mathrm{filt\_begin}] - ** @f] - ** - ** The function subsamples the image along the columns according to - ** the parameter @a step. Setting @a step to 1 (one) computes the - ** elements @f$\mathrm{dst}[x,y]@f$ for all pairs (x,0), (x,1), (x,2) - ** and so on. Setting @a step two 2 (two) computes only (x,0), (x,2) - ** and so on (in this case the height of the destination image is - ** floor(src_height/step)+1). - ** - ** Calling twice the function can be used to compute 2-D separable - ** convolutions. Use the flag ::VL_TRANSPOSE to transpose the result - ** (in this case @a dst has transposed dimension as well). - ** - ** The function allows the support of the filter to be any range. - ** Usually the support is @a filt_end = -@a filt_begin. - ** - ** The convolution operation may pick up values outside the image - ** boundary. To cope with this edge cases, the function either pads - ** the image by zero (::VL_PAD_BY_ZERO) or with the values at the - ** boundary (::VL_PAD_BY_CONTINUITY). - **/ - -/** @fn vl_imconvcol_vf(float*,vl_size,float const*,vl_size,vl_size,vl_size,float const*,vl_index,vl_index,int,unsigned int) - ** @see ::vl_imconvcol_vd - **/ - -VL_EXPORT void -VL_XCAT(vl_imconvcol_v, SFX) -(T* dst, vl_size dst_stride, - T const* src, - vl_size src_width, vl_size src_height, vl_size src_stride, - T const* filt, vl_index filt_begin, vl_index filt_end, - int step, unsigned int flags) -{ - vl_index x = 0 ; - vl_index y ; - vl_index dheight = (src_height - 1) / step + 1 ; - vl_bool transp = flags & VL_TRANSPOSE ; - vl_bool zeropad = (flags & VL_PAD_MASK) == VL_PAD_BY_ZERO ; - - /* dispatch to accelerated version */ -#ifndef VL_DISABLE_SSE2 - if (vl_cpu_has_sse2() && vl_get_simd_enabled()) { - VL_XCAT3(_vl_imconvcol_v,SFX,_sse2) - (dst,dst_stride, - src,src_width,src_height,src_stride, - filt,filt_begin,filt_end, - step,flags) ; - return ; - } -#endif - - /* let filt point to the last sample of the filter */ - filt += filt_end - filt_begin ; - - while (x < (signed)src_width) { - /* Calculate dest[x,y] = sum_p image[x,p] filt[y - p] - * where supp(filt) = [filt_begin, filt_end] = [fb,fe]. - * - * CHUNK_A: y - fe <= p < 0 - * completes VL_MAX(fe - y, 0) samples - * CHUNK_B: VL_MAX(y - fe, 0) <= p < VL_MIN(y - fb, height - 1) - * completes fe - VL_MAX(fb, height - y) + 1 samples - * CHUNK_C: completes all samples - */ - T const *filti ; - vl_index stop ; - - for (y = 0 ; y < (signed)src_height ; y += step) { - T acc = 0 ; - T v = 0, c ; - T const* srci ; - - filti = filt ; - stop = filt_end - y ; - srci = src + x - stop * src_stride ; - - if (stop > 0) { - if (zeropad) { - v = 0 ; - } else { - v = *(src + x) ; - } - while (filti > filt - stop) { - c = *filti-- ; - acc += v * c ; - srci += src_stride ; - } - } - - stop = filt_end - VL_MAX(filt_begin, y - (signed)src_height + 1) + 1 ; - while (filti > filt - stop) { - v = *srci ; - c = *filti-- ; - acc += v * c ; - srci += src_stride ; - } - - if (zeropad) v = 0 ; - - stop = filt_end - filt_begin + 1 ; - while (filti > filt - stop) { - c = *filti-- ; - acc += v * c ; - } - - if (transp) { - *dst = acc ; dst += 1 ; - } else { - *dst = acc ; dst += dst_stride ; - } - } /* next y */ - if (transp) { - dst += 1 * dst_stride - dheight * 1 ; - } else { - dst += 1 * 1 - dheight * dst_stride ; - } - x += 1 ; - } /* next x */ -} - -/* VL_TYPE_FLOAT, VL_TYPE_DOUBLE */ -#endif - -/* ---------------------------------------------------------------- */ -/* Image distance transform */ -/* ---------------------------------------------------------------- */ - -#if (FLT == VL_TYPE_FLOAT || FLT == VL_TYPE_DOUBLE) - -/** @fn ::vl_image_distance_transform_d(double const*,vl_size,vl_size,vl_size,vl_size,double*,vl_uindex*,double,double) - ** @brief Compute the distance transform of an image - ** @param image image. - ** @param numColumns number of columns of the image. - ** @param numRows number of rows of the image. - ** @param columnStride offset from one column to the next. - ** @param rowStride offset from one row to the next. - ** @param distanceTransform distance transform (out). - ** @param indexes nearest neighbor indexes (in/out). - ** @param coeff quadratic cost coefficient (non-negative). - ** @param offset quadratic cost offset. - ** - ** The function computes the distance transform along the first - ** dimension of the image @a image. Let @f$ I(u,v) @f$ be @a image. - ** Its distance transfrom @f$ D(u,v) @f$ is given by: - ** - ** @f[ - ** u^*(u,v) = \min_{u'} I(u',v) + \mathtt{coeff} (u' - u - \mathtt{offset})^2, - ** \quad D(u,v) = I(u^*(u,v),v). - ** @f] - ** - ** Notice that @a coeff must be non negative. - ** - ** The function fills in the buffer @a distanceTransform with @f$ D - ** @f$. This buffer must have the same size as @a image. - ** - ** If @a indexes is not @c NULL, it must be a matrix of the same size - ** o the image. The function interprets the value of this matrix as - ** indexes of the pixels, i.e @f$ \mathtt{indexes}(u,v) @f$ is the - ** index of pixel @f$ (u,v) @f$. On output, the matrix @a indexes - ** contains @f$ \mathtt{indexes}(u^*(u,v),v) @f$. This information - ** can be used to determine for each pixel @f$ (u,v) @f$ its - ** “nearest neighbor&rdquo. - ** - ** Notice that by swapping @a numRows and @a numColumns and @a - ** columnStride and @a rowStride, the function can be made to operate - ** along the other image dimension. Specifically, to compute the - ** distance transform along columns and rows, call the functinon - ** twice: - *** - ** @code - ** for (i = 0 ; i < numColumns * numRows ; ++i) indexes[i] = i ; - ** vl_image_distance_transform_d(image,numColumns,numRows,1,numColumns, - ** distanceTransform,indexes,u_coeff,u_offset) ; - ** vl_image_distance_transform_d(distanceTransform,numRows,numColumns,numColumns,1, - ** distanceTransform,indexes,u_coeff,u_offset) ; - ** @endcode - ** - ** @par Algorithm - ** - ** The function implements the algorithm described in: - ** P. F. Felzenszwalb and D. P. Huttenlocher, Distance Transforms - ** of Sampled Functions, Technical Report, Cornell University, - ** 2004. - ** - ** Since the algorithm operates along one dimension per time, - ** consider the 1D version of the problem for simplicity: - ** - ** @f[ - ** d(y) = \min_{x} g(y;x), \quad g(y;x) = f(x) + \alpha (y - x - \beta)^2, - ** \quad x,y \in \{0,1,\dots,N-1\}. - ** @f] - ** - ** Hence the distance transform @f$ d(y) @f$ is the lower envelope of - ** the family of parabolas @f$ g(y;x) @f$ indexed by @f$ x - ** @f$. Notice that all parabolas have the same curvature and that - ** their centers are located at @f$ x + \beta, @f$ @f$ x=0,\dots,N-1 - ** @f$. The algorithm considers one parabola per time, from left to - ** right, and finds the interval for which the parabola belongs to - ** the lower envelope (if any). - ** - ** Initially, only the leftmost parabola @f$ g(y;0) @f$ has been - ** considered, and its validity interval is @f$(-\infty, \infty) @f$. - ** Then the second parabola @f$ g(y;1) @f$ is considered. As long as - ** @f$ \alpha > 0 @f$, the two parabolas @f$ g(y;0),\ g(y;1) @f$ - ** intersect at a unique point @f$ \bar y @f$. Then the first - ** parabola belongs to the envelope in the interval @f$ (-\infty, - ** \bar y] @f$ and the second one in the interval @f$ (\bar y, - ** +\infty] @f$. When the third parabola @f$ g(y;2) @f$ is - ** considered, the intersection point @f$ \hat y @f$ with the - ** previously added parabola @f$ g(y;1) @f$ is found. Now two cases - ** may arise: - ** - ** - @f$ \hat y > \bar y @f$, in which case all three parabolas - ** belong to the envelope in the intervals @f$ (-\infty,\bar y], - ** (\bar y, \hat y], (\hat y, +\infty] @f$. - ** - ** - @f$ \hat y \leq \bar y @f$, in which case the second parabola - ** @f$ g(y;1) @f$ has no point beloning to the envelope, and it is - ** removed. One then remains with the two parabolas @f$ g(y;0),\ - ** g(y;2) @f$ and the algorithm is re-iterated. - ** - ** The algorithm proceeds in this fashion. Every time a new parabola - ** is considered, its intersection point with the previously added - ** parabola on the left is computed, and that parabola is potentially - ** removed. The cost of an iteration is 1 plus the number of deleted - ** parabolas. Since there are @f$ N @f$ iterations and at most @f$ N - ** @f$ parabolas to delete overall, the complexity is linear, - ** i.e. @f$ O(N) @f$. - **/ - -/** @fn ::vl_image_distance_transform_f(float const*,vl_size,vl_size,vl_size,vl_size,float*,vl_uindex*,float,float) - ** @see ::vl_image_distance_transform_d - **/ - -VL_EXPORT void -VL_XCAT(vl_image_distance_transform_,SFX) -(T const * image, - vl_size numColumns, - vl_size numRows, - vl_size columnStride, - vl_size rowStride, - T * distanceTransform, - vl_uindex * indexes, - T coeff, - T offset) -{ - /* Each image pixel corresponds to a parabola. The algorithm scans - such parabolas from left to right, keeping track of which - parabolas belong to the lower envelope and in which interval. There are - NUM active parabolas, FROM stores the beginning of the interval - for which a certain parabola is part of the envoelope, and WHICH store - the index of the parabola (that is, the pixel x from which the parabola - originated). - */ - vl_uindex x, y ; - T * from = vl_malloc (sizeof(T) * (numColumns + 1)) ; - T * base = vl_malloc (sizeof(T) * numColumns) ; - vl_uindex * baseIndexes = vl_malloc (sizeof(vl_uindex) * numColumns) ; - vl_uindex * which = vl_malloc (sizeof(vl_uindex) * numColumns) ; - vl_uindex num = 0 ; - - for (y = 0 ; y < numRows ; ++y) { - num = 0 ; - for (x = 0 ; x < numColumns ; ++x) { - T r = image[x * columnStride + y * rowStride] ; - T x2 = x * x ; -#if (FLT == VL_TYPE_FLOAT) - T from_ = - VL_INFINITY_F ; -#else - T from_ = - VL_INFINITY_D ; -#endif - - /* - Add next parabola (there are NUM so far). The algorithm finds - intersection INTERS with the previously added parabola. If - the intersection is on the right of the "starting point" of - this parabola, then the previous parabola is kept, and the - new one is added to its right. Otherwise the new parabola - "eats" the old one, which gets deleted and the check is - repeated with the parabola added before the deleted one. - */ - - while (num >= 1) { - vl_uindex x_ = which[num - 1] ; - T x2_ = x_ * x_ ; - T r_ = image[x_ * columnStride + y * rowStride] ; - T inters ; - if (r == r_) { - /* handles the case r = r_ = \pm inf */ - inters = (x + x_) / 2.0 + offset ; - } -#if (FLT == VL_TYPE_FLOAT) - else if (coeff > VL_EPSILON_F) -#else - else if (coeff > VL_EPSILON_D) -#endif - { - inters = ((r - r_) + coeff * (x2 - x2_)) / (x - x_) / (2*coeff) + offset ; - } else { - /* If coeff is very small, the parabolas are flat (= lines). - In this case the previous parabola should be deleted if the current - pixel has lower score */ -#if (FLT == VL_TYPE_FLOAT) - inters = (r < r_) ? - VL_INFINITY_F : VL_INFINITY_F ; -#else - inters = (r < r_) ? - VL_INFINITY_D : VL_INFINITY_D ; -#endif - } - if (inters <= from [num - 1]) { - /* delete a previous parabola */ - -- num ; - } else { - /* accept intersection */ - from_ = inters ; - break ; - } - } - - /* add a new parabola */ - which[num] = x ; - from[num] = from_ ; - base[num] = r ; - if (indexes) baseIndexes[num] = indexes[x * columnStride + y * rowStride] ; - num ++ ; - } /* next column */ - -#if (FLT == VL_TYPE_FLOAT) - from[num] = VL_INFINITY_F ; -#else - from[num] = VL_INFINITY_D ; -#endif - - /* fill in */ - num = 0 ; - for (x = 0 ; x < numColumns ; ++x) { - double delta ; - while (x >= from[num + 1]) ++ num ; - delta = (double) x - (double) which[num] - offset ; - distanceTransform[x * columnStride + y * rowStride] - = base[num] + coeff * delta * delta ; - if (indexes) { - indexes[x * columnStride + y * rowStride] - = baseIndexes[num] ; - } - } - } /* next row */ - - vl_free (from) ; - vl_free (which) ; - vl_free (base) ; - vl_free (baseIndexes) ; -} - -/* VL_TYPE_FLOAT, VL_TYPE_DOUBLE */ -#endif - -/* ---------------------------------------------------------------- */ -/* Image convolution by a triangular kernel */ -/* ---------------------------------------------------------------- */ - -#if (FLT == VL_TYPE_FLOAT || FLT == VL_TYPE_DOUBLE) - -/** @fn vl_imconvcoltri_d(double*,vl_size,double const*,vl_size,vl_size,vl_size,vl_size,vl_size,int unsigned) - ** @brief Convolve an image along the columns with a triangular kernel - ** @param dest destination image. - ** @param destStride destination image stride. - ** @param image image to convolve. - ** @param imageWidth width of the image. - ** @param imageHeight height of the image. - ** @param imageStride width of the image including padding. - ** @param filterSize size of the triangular filter. - ** @param step sub-sampling step. - ** @param flags operation modes. - ** - ** The function convolves the columns of the image @a image with the - ** triangular kernel - ** - ** @f[ - ** k(t) = \frac{1}{\Delta^2} \max\{ \Delta - |t|, 0 \}, - ** \quad t \in \mathbb{Z} - ** @f] - ** - ** The paramter @f$ \Delta @f$, equal to the function argument @a - ** filterSize, controls the width of the kernel. Notice that the - ** support of @f$ k(x) @f$ as a continuous function of @f$ x @f$ is - ** the open interval @f$ (-\Delta,\Delta) @f$, which has length @f$ - ** 2\Delta @f$. However, @f$ k(x) @f$ restricted to the ingeter - ** domain @f$ x \in \mathcal{Z} @f$ has support @f$ \{ -\Delta + 1, - ** \Delta +2, \dots, \Delta-1 \} @f$, which counts @f$ 2 \Delta - 1 - ** @f$ elements only. In particular, the discrete kernel is symmetric - ** about the origin for all values of @f$ \Delta @f$. - ** - ** The normalization factor @f$ 1 / \Delta^2 @f$ guaratnees that the - ** filter is normalized to one, i.e.: - ** - ** @f[ - ** \sum_{t=-\infty}^{+\infty} k(t) = 1 - ** @f] - ** - ** @par Algorithm - ** - ** The function exploits the fact that convolution by a triangular - ** kernel can be expressed as the repeated convolution by a - ** rectangular kernel, and that the latter can be performed in time - ** indepenedent on the fiter width by using an integral-image type - ** trick. Overall, the algorithm complexity is independent on the - ** parameter @a filterSize and linear in the nubmer of image pixels. - ** - ** @see ::vl_imconvcol_vd for details on the meaning of the other parameters. - **/ - -/** @fn vl_imconvcoltri_f(float*,vl_size,float const*,vl_size,vl_size,vl_size,vl_size,vl_size,int unsigned) - ** @brief Convolve an image along the columns with a triangular kernel - ** @see ::vl_imconvcoltri_d() - **/ - -VL_EXPORT void -VL_XCAT(vl_imconvcoltri_, SFX) -(T * dest, vl_size destStride, - T const * image, - vl_size imageWidth, vl_size imageHeight, vl_size imageStride, - vl_size filterSize, - vl_size step, unsigned int flags) -{ - vl_index x, y, dheight ; - vl_bool transp = flags & VL_TRANSPOSE ; - vl_bool zeropad = (flags & VL_PAD_MASK) == VL_PAD_BY_ZERO ; - T scale = (T) (1.0 / ((double)filterSize * (double)filterSize)) ; - T * buffer = vl_malloc (sizeof(T) * (imageHeight + filterSize)) ; - buffer += filterSize ; - - if (imageHeight == 0) { - return ; - } - - x = 0 ; - dheight = (imageHeight - 1) / step + 1 ; - - while (x < (signed)imageWidth) { - T const * imagei ; - imagei = image + x + imageStride * (imageHeight - 1) ; - - /* We decompose the convolution by a triangluar signal as the convolution - * by two rectangular signals. The rectangular convolutions are computed - * quickly by computing the integral signals. Each rectangular convolution - * introduces a delay, which is compensated by convolving each in opposite - * directions. - */ - - /* integrate backward the column */ - buffer[imageHeight - 1] = *imagei ; - for (y = (signed)imageHeight - 2 ; y >= 0 ; --y) { - imagei -= imageStride ; - buffer[y] = buffer[y + 1] + *imagei ; - } - if (zeropad) { - for ( ; y >= - (signed)filterSize ; --y) { - buffer[y] = buffer[y + 1] ; - } - } else { - for ( ; y >= - (signed)filterSize ; --y) { - buffer[y] = buffer[y + 1] + *imagei ; - } - } - - /* compute the filter forward */ - for (y = - (signed)filterSize ; - y < (signed)imageHeight - (signed)filterSize ; ++y) { - buffer[y] = buffer[y] - buffer[y + filterSize] ; - } - if (! zeropad) { - for (y = (signed)imageHeight - (signed)filterSize ; - y < (signed)imageHeight ; - ++y) { - buffer[y] = buffer[y] - buffer[imageHeight - 1] * - ((signed)imageHeight - (signed)filterSize - y) ; - } - } - - /* integrate forward the column */ - for (y = - (signed)filterSize + 1 ; - y < (signed)imageHeight ; ++y) { - buffer[y] += buffer[y - 1] ; - } - - /* compute the filter backward */ - { - vl_size stride = transp ? 1 : destStride ; - dest += dheight * stride ; - for (y = step * (dheight - 1) ; y >= 0 ; y -= step) { - dest -= stride ; - *dest = scale * (buffer[y] - buffer[y - (signed)filterSize]) ; - } - dest += transp ? destStride : 1 ; - } - x += 1 ; - } /* next x */ - vl_free (buffer - filterSize) ; -} - -/* VL_TYPE_FLOAT, VL_TYPE_DOUBLE */ -#endif - -/* ---------------------------------------------------------------- */ -/* Gaussian Smoothing */ -/* ---------------------------------------------------------------- */ - -#if (FLT == VL_TYPE_FLOAT || FLT == VL_TYPE_DOUBLE) - -/** @fn vl_imsmooth_d(double*,vl_size,double const*,vl_size,vl_size,vl_size,double,double) - ** @brief Smooth an image with a Gaussian filter - ** @param smoothed - ** @param smoothedStride - ** @param image - ** @param width - ** @param height - ** @param stride - ** @param sigmax - ** @param sigmay - **/ - -/** @fn vl_imsmooth_f(float*,vl_size,float const*,vl_size,vl_size,vl_size,double,double) - ** @brief Smooth an image with a Gaussian filter - ** @see ::vl_imsmooth_d - **/ - -static T* -VL_XCAT(_vl_new_gaussian_fitler_,SFX)(vl_size *size, double sigma) -{ - T* filter ; - T mass = (T)1.0 ; - vl_index i ; - vl_size width = vl_ceil_d(sigma * 3.0) ; - *size = 2 * width + 1 ; - - assert(size) ; - - filter = vl_malloc((*size) * sizeof(T)) ; - filter[width] = 1.0 ; - for (i = 1 ; i <= (signed)width ; ++i) { - double x = (double)i / sigma ; - double g = exp(-0.5 * x * x) ; - mass += g + g ; - filter[width-i] = g ; - filter[width+i] = g ; - } - for (i = 0 ; i < (signed)(*size) ; ++i) {filter[i] /= mass ;} - return filter ; -} - -VL_EXPORT void -VL_XCAT(vl_imsmooth_, SFX) -(T * smoothed, vl_size smoothedStride, - T const *image, vl_size width, vl_size height, vl_size stride, - double sigmax, double sigmay) -{ - T *filterx, *filtery, *buffer ; - vl_size sizex, sizey ; - - filterx = VL_XCAT(_vl_new_gaussian_fitler_,SFX)(&sizex,sigmax) ; - if (sigmax == sigmay) { - filtery = filterx ; - sizey = sizex ; - } else { - filtery = VL_XCAT(_vl_new_gaussian_fitler_,SFX)(&sizey,sigmay) ; - } - buffer = vl_malloc(width*height*sizeof(T)) ; - - VL_XCAT(vl_imconvcol_v,SFX) (buffer, height, - image, width, height, stride, - filtery, - -((signed)sizey-1)/2, ((signed)sizey-1)/2, - 1, VL_PAD_BY_CONTINUITY | VL_TRANSPOSE) ; - - VL_XCAT(vl_imconvcol_v,SFX) (smoothed, smoothedStride, - buffer, height, width, height, - filterx, - -((signed)sizex-1)/2, ((signed)sizex-1)/2, - 1, VL_PAD_BY_CONTINUITY | VL_TRANSPOSE) ; - - vl_free(buffer) ; - vl_free(filterx) ; - if (sigmax != sigmay) { - vl_free(filtery) ; - } -} - -/* VL_TYPE_FLOAT, VL_TYPE_DOUBLE */ -#endif - -/* ---------------------------------------------------------------- */ -/* Image Gradient */ -/* ---------------------------------------------------------------- */ - -#if (FLT == VL_TYPE_FLOAT || FLT == VL_TYPE_DOUBLE) - -/** @fn vl_imgradient_d(double*,double*,vl_size,vl_size,double*,vl_size,vl_size,vl_size) - ** @brief Compute image gradient - ** @param xGradient Pointer to amplitude gradient plane - ** @param yGradient Pointer to angle gradient plane - ** @param gradWidthStride Width of the gradient plane including padding - ** @param gradHeightStride Height of the gradient plane including padding - ** @param image Pointer to the source image - ** @param imageWidth Source image width - ** @param imageHeight Source image height - ** @param imageStride Width of the image including padding. - ** - ** This functions computes the amplitudes and angles of input image gradient. - ** - ** Gradient is computed simple by gradient kernel \f$ (-1 ~ 1) \f$, - ** \f$ (-1 ~ 1)^T \f$ for border pixels and with sobel filter kernel - ** \f$ (-0.5 ~ 0 ~ 0.5) \f$, \f$ (-0.5 ~ 0 ~ 0.5)^T \f$ otherwise on the input - ** image @a image yielding x-gradient \f$ dx \f$, stored in @a xGradient and - ** y-gradient \f$ dy \f$, stored in @a yGradient, respectively. - ** - ** This function also allows to process only part of the input image - ** defining the @a imageStride as original image width and @a width as - ** width of the sub-image. - ** - ** Also it allows to easily align the output data by definition - ** of the @a gradWidthStride and @a gradHeightStride . - **/ - -/** @fn vl_imgradient_f(float*,float*,vl_size,vl_size,float*,vl_size,vl_size,vl_size) - ** @brief Compute image gradient - ** @see ::vl_imgradient_d - **/ - -VL_EXPORT void -VL_XCAT(vl_imgradient_, SFX) -(T * xGradient, T * yGradient, - vl_size gradWidthStride, vl_size gradHeightStride, - T const * image, - vl_size imageWidth, vl_size imageHeight, - vl_size imageStride) -{ - /* Shortcuts */ - vl_index const xo = 1 ; - vl_index const yo = imageStride ; - vl_size const w = imageWidth; - vl_size const h = imageHeight; - - T const *src, *end ; - T *pgrad_x, *pgrad_y; - vl_size y; - - src = image ; - pgrad_x = xGradient ; - pgrad_y = yGradient ; - - /* first pixel of the first row */ - *pgrad_x = src[+xo] - src[0] ; - pgrad_x += gradWidthStride; - *pgrad_y = src[+yo] - src[0] ; - pgrad_y += gradWidthStride; - src++; - - /* middle pixels of the first row */ - end = (src - 1) + w - 1 ; - while (src < end) { - *pgrad_x = 0.5 * (src[+xo] - src[-xo]) ; - pgrad_x += gradWidthStride; - *pgrad_y = src[+yo] - src[0] ; - pgrad_y += gradWidthStride; - src++; - } - - /* last pixel of the first row */ - *pgrad_x = src[0] - src[-xo] ; - pgrad_x += gradWidthStride; - *pgrad_y = src[+yo] - src[0] ; - pgrad_y += gradWidthStride; - src++; - - xGradient += gradHeightStride; - pgrad_x = xGradient; - yGradient += gradHeightStride; - pgrad_y = yGradient; - image += yo; - src = image; - - for (y = 1 ; y < h -1 ; ++y) { - - /* first pixel of the middle rows */ - *pgrad_x = src[+xo] - src[0] ; - pgrad_x += gradWidthStride; - *pgrad_y = 0.5 * (src[+yo] - src[-yo]) ; - pgrad_y += gradWidthStride; - src++; - - /* middle pixels of the middle rows */ - end = (src - 1) + w - 1 ; - while (src < end) { - *pgrad_x = 0.5 * (src[+xo] - src[-xo]) ; - pgrad_x += gradWidthStride; - *pgrad_y = 0.5 * (src[+yo] - src[-yo]) ; - pgrad_y += gradWidthStride; - src++; - } - - /* last pixel of the middle row */ - *pgrad_x = src[0] - src[-xo] ; - pgrad_x += gradWidthStride; - *pgrad_y = 0.5 * (src[+yo] - src[-yo]) ; - pgrad_y += gradWidthStride; - src++; - - xGradient += gradHeightStride; - pgrad_x = xGradient; - yGradient += gradHeightStride; - pgrad_y = yGradient; - image += yo; - src = image; - } - - /* first pixel of the last row */ - *pgrad_x = src[+xo] - src[0] ; - pgrad_x += gradWidthStride; - *pgrad_y = src[ 0] - src[-yo] ; - pgrad_y += gradWidthStride; - src++; - - /* middle pixels of the last row */ - end = (src - 1) + w - 1 ; - while (src < end) { - *pgrad_x = 0.5 * (src[+xo] - src[-xo]) ; - pgrad_x += gradWidthStride; - *pgrad_y = src[0] - src[-yo] ; - pgrad_y += gradWidthStride; - src++; - } - - /* last pixel of the last row */ - *pgrad_x = src[0] - src[-xo] ; - *pgrad_y = src[0] - src[-yo] ; -} -/* VL_TYPE_FLOAT, VL_TYPE_DOUBLE */ -#endif - - -/** @fn vl_imgradient_polar_d(double*,double*,vl_size,vl_size,double const*,vl_size,vl_size,vl_size) - ** @brief Compute gradient mangitudes and directions of an image. - ** @param amplitudeGradient Pointer to amplitude gradient plane - ** @param angleGradient Pointer to angle gradient plane - ** @param gradWidthStride Width of the gradient plane including padding - ** @param gradHeightStride Height of the gradient plane including padding - ** @param image Pointer to the source image - ** @param imageWidth Source image width - ** @param imageHeight Source image height - ** @param imageStride Width of the source image including padding. - ** - ** This functions computes the amplitudes and angles of input image gradient. - ** - ** Gradient is computed simple by gradient kernel \f$ (-1 ~ 1) \f$, - ** \f$ (-1 ~ 1)^T \f$ for border pixels and with sobel filter kernel - ** \f$ (-0.5 ~ 0 ~ 0.5) \f$, \f$ (-0.5 ~ 0 ~ 0.5)^T \f$ otherwise on - ** the input image @a image yielding x-gradient \f$ dx \f$, stored in - ** @a xGradient and y-gradient \f$ dy \f$, stored in @a yGradient, - ** respectively. - ** - ** The amplitude of the gradient, stored in plane @a - ** amplitudeGradient, is then calculated as \f$ \sqrt(dx^2+dy^2) \f$ - ** and the angle of the gradient, stored in @a angleGradient is \f$ - ** atan(\frac{dy}{dx}) \f$ normalised into interval 0 and @f$ 2\pi - ** @f$. - ** - ** This function also allows to process only part of the input image - ** defining the @a imageStride as original image width and @a width - ** as width of the sub-image. - ** - ** Also it allows to easily align the output data by definition - ** of the @a gradWidthStride and @a gradHeightStride . - **/ - -/** @fn vl_imgradient_polar_f(float*,float*,vl_size,vl_size,float const*,vl_size,vl_size,vl_size) - ** @see ::vl_imgradient_polar_d - **/ - -#if (FLT == VL_TYPE_FLOAT || FLT == VL_TYPE_DOUBLE) - -VL_EXPORT void -VL_XCAT(vl_imgradient_polar_, SFX) -(T * gradientModulus, T * gradientAngle, - vl_size gradientHorizontalStride, vl_size gradHeightStride, - T const* image, - vl_size imageWidth, vl_size imageHeight, vl_size imageStride) -{ - /* Shortcuts */ - vl_index const xo = 1 ; - vl_index const yo = imageStride ; - vl_size const w = imageWidth; - vl_size const h = imageHeight; - - T const *src, *end; - T *pgrad_angl, *pgrad_ampl; - T gx, gy ; - vl_size y; - -#define SAVE_BACK \ -*pgrad_ampl = vl_fast_sqrt_f (gx*gx + gy*gy) ; \ -pgrad_ampl += gradientHorizontalStride ; \ -*pgrad_angl = vl_mod_2pi_f (vl_fast_atan2_f (gy, gx) + 2*VL_PI) ; \ -pgrad_angl += gradientHorizontalStride ; \ -++src ; \ - - src = image ; - pgrad_angl = gradientAngle ; - pgrad_ampl = gradientModulus ; - - /* first pixel of the first row */ - gx = src[+xo] - src[0] ; - gy = src[+yo] - src[0] ; - SAVE_BACK ; - - /* middle pixels of the first row */ - end = (src - 1) + w - 1 ; - while (src < end) { - gx = 0.5 * (src[+xo] - src[-xo]) ; - gy = src[+yo] - src[0] ; - SAVE_BACK ; - } - - /* last pixel of the first row */ - gx = src[0] - src[-xo] ; - gy = src[+yo] - src[0] ; - SAVE_BACK ; - - gradientModulus += gradHeightStride; - pgrad_ampl = gradientModulus; - gradientAngle += gradHeightStride; - pgrad_angl = gradientAngle; - image += imageStride; - src = image; - - for (y = 1 ; y < h -1 ; ++y) { - - /* first pixel of the middle rows */ - gx = src[+xo] - src[0] ; - gy = 0.5 * (src[+yo] - src[-yo]) ; - SAVE_BACK ; - - /* middle pixels of the middle rows */ - end = (src - 1) + w - 1 ; - while (src < end) { - gx = 0.5 * (src[+xo] - src[-xo]) ; - gy = 0.5 * (src[+yo] - src[-yo]) ; - SAVE_BACK ; - } - - /* last pixel of the middle row */ - gx = src[0] - src[-xo] ; - gy = 0.5 * (src[+yo] - src[-yo]) ; - SAVE_BACK ; - - gradientModulus += gradHeightStride; - pgrad_ampl = gradientModulus; - gradientAngle += gradHeightStride; - pgrad_angl = gradientAngle; - image += imageStride; - src = image; - } - - /* first pixel of the last row */ - gx = src[+xo] - src[0] ; - gy = src[ 0] - src[-yo] ; - SAVE_BACK ; - - /* middle pixels of the last row */ - end = (src - 1) + w - 1 ; - while (src < end) { - gx = 0.5 * (src[+xo] - src[-xo]) ; - gy = src[0] - src[-yo] ; - SAVE_BACK ; - } - - /* last pixel of the last row */ - gx = src[0] - src[-xo] ; - gy = src[0] - src[-yo] ; - SAVE_BACK ; - -} -/* VL_TYPE_FLOAT, VL_TYPE_DOUBLE */ -#endif - -/* ---------------------------------------------------------------- */ -/* Integral Image */ -/* ---------------------------------------------------------------- */ - -/** @fn vl_imintegral_d(double*,vl_size,double const*,vl_size,vl_size,vl_size) - ** @brief Compute integral image - ** - ** @param integral integral image. - ** @param integralStride integral image stride. - ** @param image source image. - ** @param imageWidth source image width. - ** @param imageHeight source image height. - ** @param imageStride source image stride. - ** - ** Let @f$ I(x,y), (x,y) \in [0, W-1] \times [0, H-1] @f$. The - ** function computes the integral image @f$ J(x,y) @f$ of @f$ I(x,g) - ** @f$: - ** - ** @f[ - ** J(x,y) = \sum_{x'=0}^{x} \sum_{y'=0}^{y} I(x',y') - ** @f] - ** - ** The integral image @f$ J(x,y) @f$ can be used to compute quickly - ** the integral of of @f$ I(x,y) @f$ in a rectangular region @f$ R = - ** [x',x'']\times[y',y''] @f$: - ** - ** @f[ - ** \sum_{(x,y)\in[x',x'']\times[y',y'']} I(x,y) = - ** (J(x'',y'') - J(x'-1, y'')) - (J(x'',y'-1) - J(x'-1,y'-1)). - ** @f] - ** - ** Note that the order of operations is important when the integral image - ** has an unsigned data type (e.g. ::vl_uint32). The formula - ** is easily derived as follows: - ** - ** @f{eqnarray*} - ** \sum_{(x,y)\in R} I(x,y) - ** &=& \sum_{x=x'}^{x''} \sum_{y=y'}^{y''} I(x,y)\\ - ** &=& \sum_{x=0}^{x''} \sum_{y=y'}^{y''} I(x,y) - ** - \sum_{x=0}^{x'-1} \sum_{y=y'}^{y''} I(x,y)\\ - ** &=& \sum_{x=0}^{x''} \sum_{y=0}^{y''} I(x,y) - ** - \sum_{x=0}^{x''} \sum_{y=0}^{y'-1} I(x,y) - ** - \sum_{x=0}^{x'-1} \sum_{y=0}^{y''} I(x,y) - ** + \sum_{x=0}^{x'-1} \sum_{y=0}^{y'-1} I(x,y)\\ - ** &=& J(x'',y'') - J(x'-1,y'') - J(x'',y'-1) + J(x'-1,y'-1). - ** @f} - **/ - -/** @fn vl_imintegral_f(float*,vl_size,float const*,vl_size,vl_size,vl_size) - ** @brief Compute integral image - ** @see ::vl_imintegral_d. - **/ - -/** @fn vl_imintegral_ui32(vl_uint32*,vl_size,vl_uint32 const*,vl_size,vl_size,vl_size) - ** @brief Compute integral image - ** @see ::vl_imintegral_d. - **/ - -/** @fn vl_imintegral_i32(vl_int32*,vl_size,vl_int32 const*,vl_size,vl_size,vl_size) - ** @brief Compute integral image - ** @see ::vl_imintegral_d. - **/ - -VL_EXPORT void -VL_XCAT(vl_imintegral_, SFX) -(T * integral, vl_size integralStride, - T const * image, - vl_size imageWidth, vl_size imageHeight, vl_size imageStride) -{ - vl_uindex x, y ; - T temp = 0 ; - - if (imageHeight > 0) { - for (x = 0 ; x < imageWidth ; ++ x) { - temp += *image++ ; - *integral++ = temp ; - } - } - - for (y = 1 ; y < imageHeight ; ++ y) { - T * integralPrev ; - integral += integralStride - imageWidth ; - image += imageStride - imageWidth ; - integralPrev = integral - integralStride ; - - temp = 0 ; - for (x = 0 ; x < imageWidth ; ++ x) { - temp += *image++ ; - *integral++ = *integralPrev++ + temp ; - } - } -} - -/* endif VL_IMOPV_INSTANTIATING */ -#undef FLT -#undef VL_IMOPV_INSTANTIATING -#endif diff --git a/opensfm/src/third_party/vlfeat/vl/imopv.h b/opensfm/src/third_party/vlfeat/vl/imopv.h deleted file mode 100644 index ca127ca3c..000000000 --- a/opensfm/src/third_party/vlfeat/vl/imopv.h +++ /dev/null @@ -1,164 +0,0 @@ -/** @file imopv.h - ** @brief Vectorized image operations - ** @author Andrea Vedaldi - **/ - -/* -Copyright (C) 2007-12 Andrea Vedaldi and Brian Fulkerson. -All rights reserved. - -This file is part of the VLFeat library and is made available under -the terms of the BSD license (see the COPYING file). -*/ - -#ifndef VL_IMOPV_H -#define VL_IMOPV_H - -#include "generic.h" - -/** @name Image convolution flags - ** @{ */ -#define VL_PAD_BY_ZERO (0x0 << 0) /**< @brief Pad with zeroes. */ -#define VL_PAD_BY_CONTINUITY (0x1 << 0) /**< @brief Pad by continuity. */ -#define VL_PAD_MASK (0x3) /**< @brief Padding field selector. */ -#define VL_TRANSPOSE (0x1 << 2) /**< @brief Transpose result. */ -/** @} */ - -/** @name Image convolution - ** @{ */ -VL_EXPORT -void vl_imconvcol_vf (float* dst, vl_size dst_stride, - float const* src, - vl_size src_width, vl_size src_height, vl_size src_stride, - float const* filt, vl_index filt_begin, vl_index filt_end, - int step, unsigned int flags) ; - -VL_EXPORT -void vl_imconvcol_vd (double* dst, vl_size dst_stride, - double const* src, - vl_size src_width, vl_size src_height, vl_size src_stride, - double const* filt, vl_index filt_begin, vl_index filt_end, - int step, unsigned int flags) ; - -VL_EXPORT -void vl_imconvcoltri_f (float * dest, vl_size destStride, - float const * image, - vl_size imageWidth, vl_size imageHeight, vl_size imageStride, - vl_size filterSize, - vl_size step, int unsigned flags) ; - -VL_EXPORT -void vl_imconvcoltri_d (double * dest, vl_size destStride, - double const * image, - vl_size imageWidth, vl_size imageHeight, vl_size imageStride, - vl_size filterSize, - vl_size step, int unsigned flags) ; -/** @} */ - -/** @name Integral image - ** @{ */ -VL_EXPORT -void vl_imintegral_f (float * integral, vl_size integralStride, - float const * image, - vl_size imageWidth, vl_size imageHeight, vl_size imageStride) ; - -VL_EXPORT -void vl_imintegral_d (double * integral, vl_size integralStride, - double const * image, - vl_size imageWidth, vl_size imageHeight, vl_size imageStride) ; - -VL_EXPORT -void vl_imintegral_i32 (vl_int32 * integral, vl_size integralStride, - vl_int32 const * image, - vl_size imageWidth, vl_size imageHeight, vl_size imageStride) ; - -VL_EXPORT -void vl_imintegral_ui32 (vl_uint32 * integral, vl_size integralStride, - vl_uint32 const * image, - vl_size imageWidth, vl_size imageHeight, vl_size imageStride) ; -/** @} */ - -/** @name Distance transform */ -/** @{ */ - -VL_EXPORT void -vl_image_distance_transform_d (double const * image, - vl_size numColumns, - vl_size numRows, - vl_size columnStride, - vl_size rowStride, - double * distanceTransform, - vl_uindex * indexes, - double coeff, - double offset) ; - -VL_EXPORT void -vl_image_distance_transform_f (float const * image, - vl_size numColumns, - vl_size numRows, - vl_size columnStride, - vl_size rowStride, - float * distanceTransform, - vl_uindex * indexes, - float coeff, - float offset) ; - -/** @} */ - -/* ---------------------------------------------------------------- */ -/** @name Image smoothing */ -/** @{ */ - -VL_EXPORT void -vl_imsmooth_f (float *smoothed, vl_size smoothedStride, - float const *image, vl_size width, vl_size height, vl_size stride, - double sigmax, double sigmay) ; - -VL_EXPORT void -vl_imsmooth_d (double *smoothed, vl_size smoothedStride, - double const *image, vl_size width, vl_size height, vl_size stride, - double sigmax, double sigmay) ; - -/** @} */ - -/* ---------------------------------------------------------------- */ -/** @name Image gradients */ -/** @{ */ -VL_EXPORT void -vl_imgradient_polar_f (float* amplitudeGradient, float* angleGradient, - vl_size gradWidthStride, vl_size gradHeightStride, - float const* image, - vl_size imageWidth, vl_size imageHeight, - vl_size imageStride); - -VL_EXPORT void -vl_imgradient_polar_d (double* amplitudeGradient, double* angleGradient, - vl_size gradWidthStride, vl_size gradHeightStride, - double const* image, - vl_size imageWidth, vl_size imageHeight, - vl_size imageStride); - -VL_EXPORT void -vl_imgradient_f (float* xGradient, float* yGradient, - vl_size gradWidthStride, vl_size gradHeightStride, - float const *image, - vl_size imageWidth, vl_size imageHeight, vl_size imageStride); - -VL_EXPORT void -vl_imgradient_d(double* xGradient, double* yGradient, - vl_size gradWidthStride, vl_size gradHeightStride, - double const *image, - vl_size imageWidth, vl_size imageHeight, vl_size imageStride); - -VL_EXPORT void -vl_imgradient_polar_f_callback(float const *sourceImage, - int sourceImageWidth, int sourceImageHeight, - float *dstImage, - int dstWidth, int dstHeight, - int octave, int level, - void *params); - -/** @} */ - -/* VL_IMOPV_H */ -#endif diff --git a/opensfm/src/third_party/vlfeat/vl/imopv_sse2.c b/opensfm/src/third_party/vlfeat/vl/imopv_sse2.c deleted file mode 100644 index 11df6d858..000000000 --- a/opensfm/src/third_party/vlfeat/vl/imopv_sse2.c +++ /dev/null @@ -1,289 +0,0 @@ -/** @file imopv_sse2.c - ** @brief Vectorized image operations - SSE2 - Definition - ** @author Andrea Vedaldi - **/ - -/* -Copyright (C) 2007-12 Andrea Vedaldi and Brian Fulkerson. -All rights reserved. - -This file is part of the VLFeat library and is made available under -the terms of the BSD license (see the COPYING file). -*/ - -#if ! defined(VL_DISABLE_SSE2) & ! defined(__SSE2__) -#error "Compiling with SSE2 enabled, but no __SSE2__ defined" -#endif - -#if ! defined(VL_DISABLE_SSE2) - -#ifndef VL_IMOPV_SSE2_INSTANTIATING - -#include - -#include "imopv.h" -#include "imopv_sse2.h" - -#define FLT VL_TYPE_FLOAT -#define VL_IMOPV_SSE2_INSTANTIATING -#include "imopv_sse2.c" - -#define FLT VL_TYPE_DOUBLE -#define VL_IMOPV_SSE2_INSTANTIATING -#include "imopv_sse2.c" - -/* ---------------------------------------------------------------- */ -/* VL_IMOPV_SSE2_INSTANTIATING */ -#else - -#include "float.h" - -/* ---------------------------------------------------------------- */ -void -VL_XCAT3(_vl_imconvcol_v, SFX, _sse2) -(T* dst, vl_size dst_stride, - T const* src, - vl_size src_width, vl_size src_height, vl_size src_stride, - T const* filt, vl_index filt_begin, vl_index filt_end, - int step, unsigned int flags) -{ - vl_index x = 0 ; - vl_index y ; - vl_index dheight = (src_height - 1) / step + 1 ; - vl_bool use_simd = VALIGNED(src_stride) ; - vl_bool transp = flags & VL_TRANSPOSE ; - vl_bool zeropad = (flags & VL_PAD_MASK) == VL_PAD_BY_ZERO ; - double totcol = 0 ; - double simdcol = 0 ; - - /* let filt point to the last sample of the filter */ - filt += filt_end - filt_begin ; - - while (x < (signed)src_width) { - /* Calculate dest[x,y] = sum_p image[x,p] filt[y - p] - * where supp(filt) = [filt_begin, filt_end] = [fb,fe]. - * - * CHUNK_A: y - fe <= p < 0 - * completes VL_MAX(fe - y, 0) samples - * CHUNK_B: VL_MAX(y - fe, 0) <= p < VL_MIN(y - fb, height - 1) - * completes fe - VL_MAX(fb, height - y) + 1 samples - * CHUNK_C: completes all samples - */ - - T const *filti ; - vl_index stop ; - - if ((x + VSIZE < (signed)src_width) & - VALIGNED(src + x) & use_simd) - { - /* ---------------------------------------------- Vectorized */ - for (y = 0 ; y < (signed)src_height ; y += step) { - union {VTYPE v ; T x [VSIZE] ; } acc ; - VTYPE v, c ; - T const *srci ; - acc.v = VSTZ () ; - v = VSTZ() ; - - filti = filt ; - stop = filt_end - y ; - srci = src + x - stop * src_stride ; - - if (stop > 0) { - if (zeropad) { - v = VSTZ () ; - } else { - v = * (VTYPE*) (src + x) ; - } - while (filti > filt - stop) { - c = VLD1 (filti--) ; - acc.v = VADD (acc.v, VMUL (v, c)) ; - srci += src_stride ; - } - } - - stop = filt_end - VL_MAX(filt_begin, y - (signed)src_height + 1) + 1 ; - while (filti > filt - stop) { - v = * (VTYPE*) srci ; - c = VLD1 (filti--) ; - acc.v = VADD (acc.v, VMUL (v, c)) ; - srci += src_stride ; - } - - if (zeropad) v = VSTZ () ; - - stop = filt_end - filt_begin + 1; - while (filti > filt - stop) { - c = VLD1 (filti--) ; - acc.v = VADD (acc.v, VMUL (v, c)) ; - } - - if (transp) { - *dst = acc.x[0] ; dst += dst_stride ; - *dst = acc.x[1] ; dst += dst_stride ; -#if(VSIZE == 4) - *dst = acc.x[2] ; dst += dst_stride ; - *dst = acc.x[3] ; dst += dst_stride ; -#endif - dst += 1 * 1 - VSIZE * dst_stride ; - } else { - *dst = acc.x[0] ; dst += 1 ; - *dst = acc.x[1] ; dst += 1 ; -#if(VSIZE == 4) - *dst = acc.x[2] ; dst += 1 ; - *dst = acc.x[3] ; dst += 1 ; -#endif - dst += 1 * dst_stride - VSIZE * 1 ; - } - } /* next y */ - if (transp) { - dst += VSIZE * dst_stride - dheight * 1 ; - } else { - dst += VSIZE * 1 - dheight * dst_stride ; - } - x += VSIZE ; - simdcol += VSIZE ; - totcol += VSIZE ; - } else { - /* ------------------------------------------------- Vanilla */ - for (y = 0 ; y < (signed)src_height ; y += step) { - T acc = 0 ; - T v = 0, c ; - T const* srci ; - - filti = filt ; - stop = filt_end - y ; - srci = src + x - stop * src_stride ; - - if (stop > 0) { - if (zeropad) { - v = 0 ; - } else { - v = *(src + x) ; - } - while (filti > filt - stop) { - c = *filti-- ; - acc += v * c ; - srci += src_stride ; - } - } - - stop = filt_end - VL_MAX(filt_begin, y - (signed)src_height + 1) + 1 ; - while (filti > filt - (signed)stop) { - v = *srci ; - c = *filti-- ; - acc += v * c ; - srci += src_stride ; - } - - if (zeropad) v = 0 ; - - stop = filt_end - filt_begin + 1 ; - while (filti > filt - stop) { - c = *filti-- ; - acc += v * c ; - } - - if (transp) { - *dst = acc ; dst += 1 ; - } else { - *dst = acc ; dst += dst_stride ; - } - } /* next y */ - if (transp) { - dst += 1 * dst_stride - dheight * 1 ; - } else { - dst += 1 * 1 - dheight * dst_stride ; - } - x += 1 ; - totcol += 1 ; - } /* next x */ - } -} - -/* ---------------------------------------------------------------- */ -#if 0 -void -VL_XCAT(_vl_imconvcoltri_v, SFX, sse2) -(T* dst, int dst_stride, - T const* src, - int src_width, int src_height, int src_stride, - int filt_size, - int step, unsigned int flags) -{ - int x = 0 ; - int y ; - int dheight = (src_height - 1) / step + 1 ; - vl_bool use_simd = ((src_stride & ALIGNSTRIDE) == 0) && - (! (flags & VL_NO_SIMD)) ; - vl_bool transp = flags & VL_TRANSPOSE ; - vl_bool zeropad = (flags & VL_PAD_MASK) == VL_PAD_BY_ZERO ; - - T * buff = vl_malloc(sizeof(T) * (src_height + filt_size)) ; -#define fa (1.0 / (double) (filt_size + 1)) - T scale = fa*fa*fa*fa ; - buff += filt_size ; - - while (x < src_width) { - T const *srci ; - - use_simd = 0 ; - if ((x + VSIZE < src_width) & - (((vl_ptrint)(src + x) & ALIGNPTR) == 0) & - use_simd) - { - - } else { - int stridex = transp ? dst_stride : 1 ; - int stridey = transp ? 1 : dst_stride ; - srci = src + x + src_stride * (src_height - 1) ; - - /* integrate backward the column */ - buff [src_height - 1] = *srci ; - for (y = src_height-2 ; y >= 0 ; --y) { - srci -= src_stride ; - buff [y] = buff [y+1] + *srci ; - } - if (zeropad) { - for ( ; y >= - filt_size ; --y) { - buff [y] = buff [y+1] ; - } - } else { - for ( ; y >= - filt_size ; --y) { - buff [y] = buff[y+1] + *srci ; - } - } - - /* compute the filter forward */ - for (y = - filt_size ; y < src_height - filt_size ; ++y) { - buff [y] = buff [y] - buff [y + filt_size] ; - } - if (! zeropad) { - for (y = src_height - filt_size ; y < src_height ; ++y) { - buff [y] = buff [y] - buff [src_height-1] * - (src_height - filt_size - y) ; - } - } - - /* integrate forward the column */ - for (y = - filt_size + 1 ; y < src_height ; ++y) { - buff [y] += buff [y - 1] ; - } - - /* compute the filter backward */ - for (y = src_height - 1 ; y >= 0 ; --y) { - dst [x*stridex + y*stridey] - = scale * (buff [y] - buff [y - filt_size]) ; - } - } /* next y */ - x += 1 ; - } - vl_free (buff - filt_size) ; -} -#endif - -#undef FLT -#undef VL_IMOPV_SSE2_INSTANTIATING -#endif - -/* ! VL_DISABLE_SSE2 */ -#endif diff --git a/opensfm/src/third_party/vlfeat/vl/imopv_sse2.h b/opensfm/src/third_party/vlfeat/vl/imopv_sse2.h deleted file mode 100644 index 0f8da374e..000000000 --- a/opensfm/src/third_party/vlfeat/vl/imopv_sse2.h +++ /dev/null @@ -1,54 +0,0 @@ -/** @file imopv_sse2.h - ** @brief Vectorized image operations - SSE2 - ** @author Andrea Vedaldi - **/ - -/* -Copyright (C) 2007-12 Andrea Vedaldi and Brian Fulkerson. -All rights reserved. - -This file is part of the VLFeat library and is made available under -the terms of the BSD license (see the COPYING file). -*/ - -#ifndef VL_IMOPV_SSE2_H -#define VL_IMOPV_SSE2_H - -#include "generic.h" - -#ifndef VL_DISABLE_SSE2 - -VL_EXPORT -void _vl_imconvcol_vf_sse2 (float* dst, vl_size dst_stride, - float const* src, - vl_size src_width, vl_size src_height, vl_size src_stride, - float const* filt, vl_index filt_begin, vl_index filt_end, - int step, unsigned int flags) ; - -VL_EXPORT -void _vl_imconvcol_vd_sse2 (double* dst, vl_size dst_stride, - double const* src, - vl_size src_width, vl_size src_height, vl_size src_stride, - double const* filt, vl_index filt_begin, vl_index filt_end, - int step, unsigned int flags) ; - -/* -VL_EXPORT -void _vl_imconvcoltri_vf_sse2 (float* dst, int dst_stride, - float const* src, - int src_width, int src_height, int src_stride, - int filt_size, - int step, unsigned int flags) ; - -VL_EXPORT -void _vl_imconvcoltri_vd_sse2 (double* dst, int dst_stride, - double const* src, - int src_width, int src_height, int src_stride, - int filt_size, - int step, unsigned int flags) ; -*/ - -#endif - -/* VL_IMOPV_SSE2_H */ -#endif diff --git a/opensfm/src/third_party/vlfeat/vl/kdtree.c b/opensfm/src/third_party/vlfeat/vl/kdtree.c deleted file mode 100644 index 889cc7dc3..000000000 --- a/opensfm/src/third_party/vlfeat/vl/kdtree.c +++ /dev/null @@ -1,1082 +0,0 @@ -/** @file kdtree.c - ** @brief KD-tree - Definition - ** @author Andrea Vedaldi, David Novotny - **/ - -/* -Copyright (C) 2007-12 Andrea Vedaldi and Brian Fulkerson. -All rights reserved. - -This file is part of the VLFeat library and is made available under -the terms of the BSD license (see the COPYING file). -*/ - -/** - - -@page kdtree KD-trees and forests -@author Andrea Vedaldi -@author David Novotny - - -@ref kdtree.h implements a KD-tree object, a data structure that can -efficiently index moderately dimensional vector spaces. Both -best-bin-first @cite{beis97shape} and randomized KD-tree forests are -implemented -@cite{silpa-anan08optimised},@cite{muja09fast}. Applications include -fast matching of feature descriptors. - -- @ref kdtree-overview -- @ref kdtree-tech - - -@section kdtree-overview Overview - - -To create a ::VlKDForest object use ::vl_kdforest_new specifying the -dimensionality of the data and the number of trees in the forest. -With one tree only, the algorithm is analogous to @cite{beis97shape} -(best-bin KDTree). Multiple trees correspond to the randomized KDTree -forest as in @cite{silpa-anan08optimised},@cite{muja09fast}. - -To let the KD-tree index some data use ::vl_kdforest_build. Note that -for efficiency KD-tree does not copy the data but retains a pointer to -it. Therefore the data must exist (and not change) until the KD-tree -is deleted. To delete the KD-tree object, use ::vl_kdforest_delete. - -To find the N nearest neighbors to a query point first instantiate -a ::VlKDForestSearcher and then start search using a ::vl_kdforest_query -with the searcher object as an argument. To set a maximum number of -comparisons per query and calculate approximate nearest neighbors use -::vl_kdforest_set_max_num_comparisons. - - -@section kdtree-tech Technical details - - -::VlKDForest implements the best-bin-first kd-tree of @cite{beis97shape}. - -Construction. Given a set of points @f$ x_1,\dots,x_n \in -\mathbb{R}^d @f$, the algorithm recursively partitions the @e d -dimensional Euclidean space @f$ \mathbb{R}^d @f$ into (hyper-) -rectangles. - -Partitions are organized into a binary tree with the root -corresponding to the whole space @f$ \mathbb{R}^d @f$. The algorithm -refines each partition by dividing it into two halves by thresholding -along a given dimension. Both the splitting dimension and the -threshold are determined as a statistic of the data points contained -in the partition. The splitting dimension is the one which has largest -sample variance and the splitting threshold is either the sample mean -or the median. Leaves are atomic partitions and they contain a list of -zero or more data points (typically one). - -Querying. Querying amounts to finding the N data points closer -to a given query point @f$ x_q \in \mathbb{R}^d @f$. This is done by -branch-and-bound. A search state is an active partition (initially the -root) and it is weighed by the lower bound on the distance of any -point in the partition and the query point. Such a lower bound is -trivial to compute because partitions are hyper-rectangles. - -Querying usage. As said before a user has to create an instance -::VlKDForestSearcher using ::vl_kdforest_new_searcher in order to be able -to make queries. When a user wants to delete a KD-Tree all the searchers -bound to the given KD-Forest are erased automatically. If a user wants to -delete some of the searchers before the KD-Tree erase, he could do it -using the vl_kdforest_delete_searcher method. -**/ - -#include "kdtree.h" -#include "generic.h" -#include "random.h" -#include "mathop.h" -#include - -#if defined(_OPENMP) -#include -#endif - -#define VL_HEAP_prefix vl_kdforest_search_heap -#define VL_HEAP_type VlKDForestSearchState -#define VL_HEAP_cmp(v,x,y) (v[x].distanceLowerBound - v[y].distanceLowerBound) -#include "heap-def.h" - -#define VL_HEAP_prefix vl_kdtree_split_heap -#define VL_HEAP_type VlKDTreeSplitDimension -#define VL_HEAP_cmp(v,x,y) (v[x].variance - v[y].variance) -#include "heap-def.h" - -#define VL_HEAP_prefix vl_kdforest_neighbor_heap -#define VL_HEAP_type VlKDForestNeighbor -#define VL_HEAP_cmp(v,x,y) (v[y].distance - v[x].distance) -#include "heap-def.h" - -/** ------------------------------------------------------------------ - ** @internal - ** @brief Allocate a new node from the tree pool - **/ - -static vl_uindex -vl_kdtree_node_new (VlKDTree * tree, vl_uindex parentIndex) -{ - VlKDTreeNode * node = NULL ; - vl_uindex nodeIndex = tree->numUsedNodes ; - tree -> numUsedNodes += 1 ; - - assert (tree->numUsedNodes <= tree->numAllocatedNodes) ; - - node = tree->nodes + nodeIndex ; - node -> parent = parentIndex ; - node -> lowerChild = 0 ; - node -> upperChild = 0 ; - node -> splitDimension = 0 ; - node -> splitThreshold = 0 ; - return nodeIndex ; -} - -/** ------------------------------------------------------------------ - ** @internal - ** @brief Compare KDTree index entries for sorting - **/ - -VL_INLINE int -vl_kdtree_compare_index_entries (void const * a, - void const * b) -{ - double delta = - ((VlKDTreeDataIndexEntry const*)a) -> value - - ((VlKDTreeDataIndexEntry const*)b) -> value ; - if (delta < 0) return -1 ; - if (delta > 0) return +1 ; - return 0 ; -} - -/** ------------------------------------------------------------------ - ** @internal - ** @brief Build KDTree recursively - ** @param forest forest to which the tree belongs. - ** @param tree tree being built. - ** @param nodeIndex node to process. - ** @param dataBegin begin of data for this node. - ** @param dataEnd end of data for this node. - ** @param depth depth of this node. - **/ - -static void -vl_kdtree_build_recursively -(VlKDForest * forest, - VlKDTree * tree, vl_uindex nodeIndex, - vl_uindex dataBegin, vl_uindex dataEnd, - unsigned int depth) -{ - vl_uindex d, i, medianIndex, splitIndex ; - VlKDTreeNode * node = tree->nodes + nodeIndex ; - VlKDTreeSplitDimension * splitDimension ; - - /* base case: there is only one data point */ - if (dataEnd - dataBegin <= 1) { - if (tree->depth < depth) tree->depth = depth ; - node->lowerChild = - dataBegin - 1; - node->upperChild = - dataEnd - 1 ; - return ; - } - - /* compute the dimension with largest variance > 0 */ - forest->splitHeapNumNodes = 0 ; - for (d = 0 ; d < forest->dimension ; ++ d) { - double mean = 0 ; /* unnormalized */ - double secondMoment = 0 ; - double variance = 0 ; - vl_size numSamples = VL_KDTREE_VARIANCE_EST_NUM_SAMPLES; - vl_bool useAllData = VL_FALSE; - - if(dataEnd - dataBegin <= VL_KDTREE_VARIANCE_EST_NUM_SAMPLES) { - useAllData = VL_TRUE; - numSamples = dataEnd - dataBegin; - } - - for (i = 0; i < numSamples ; ++ i) { - vl_uint32 sampleIndex; - vl_index di; - double datum ; - - if(useAllData == VL_TRUE) { - sampleIndex = (vl_uint32)i; - } else { - sampleIndex = (vl_rand_uint32(forest->rand) % VL_KDTREE_VARIANCE_EST_NUM_SAMPLES); - } - sampleIndex += dataBegin; - - di = tree->dataIndex[sampleIndex].index ; - - switch(forest->dataType) { - case VL_TYPE_FLOAT: datum = ((float const*)forest->data) - [di * forest->dimension + d] ; - break ; - case VL_TYPE_DOUBLE: datum = ((double const*)forest->data) - [di * forest->dimension + d] ; - break ; - default: - abort() ; - } - mean += datum ; - secondMoment += datum * datum ; - } - - mean /= numSamples ; - secondMoment /= numSamples ; - variance = secondMoment - mean * mean ; - - if (variance <= 0) continue ; - - /* keep splitHeapSize most varying dimensions */ - if (forest->splitHeapNumNodes < forest->splitHeapSize) { - VlKDTreeSplitDimension * splitDimension - = forest->splitHeapArray + forest->splitHeapNumNodes ; - splitDimension->dimension = (unsigned int)d ; - splitDimension->mean = mean ; - splitDimension->variance = variance ; - vl_kdtree_split_heap_push (forest->splitHeapArray, &forest->splitHeapNumNodes) ; - } else { - VlKDTreeSplitDimension * splitDimension = forest->splitHeapArray + 0 ; - if (splitDimension->variance < variance) { - splitDimension->dimension = (unsigned int)d ; - splitDimension->mean = mean ; - splitDimension->variance = variance ; - vl_kdtree_split_heap_update (forest->splitHeapArray, forest->splitHeapNumNodes, 0) ; - } - } - } - - /* additional base case: the maximum variance is equal to 0 (overlapping points) */ - if (forest->splitHeapNumNodes == 0) { - node->lowerChild = - dataBegin - 1 ; - node->upperChild = - dataEnd - 1 ; - return ; - } - - /* toss a dice to decide the splitting dimension (variance > 0) */ - splitDimension = forest->splitHeapArray - + (vl_rand_uint32(forest->rand) % VL_MIN(forest->splitHeapSize, forest->splitHeapNumNodes)) ; - - node->splitDimension = splitDimension->dimension ; - - /* sort data along largest variance dimension */ - for (i = dataBegin ; i < dataEnd ; ++ i) { - vl_index di = tree->dataIndex[i].index ; - double datum ; - switch (forest->dataType) { - case VL_TYPE_FLOAT: datum = ((float const*)forest->data) - [di * forest->dimension + splitDimension->dimension] ; - break ; - case VL_TYPE_DOUBLE: datum = ((double const*)forest->data) - [di * forest->dimension + splitDimension->dimension] ; - break ; - default: - abort() ; - } - tree->dataIndex [i] .value = datum ; - } - qsort (tree->dataIndex + dataBegin, - dataEnd - dataBegin, - sizeof (VlKDTreeDataIndexEntry), - vl_kdtree_compare_index_entries) ; - - /* determine split threshold */ - switch (forest->thresholdingMethod) { - case VL_KDTREE_MEAN : - node->splitThreshold = splitDimension->mean ; - for (splitIndex = dataBegin ; - splitIndex < dataEnd && tree->dataIndex[splitIndex].value <= node->splitThreshold ; - ++ splitIndex) ; - splitIndex -= 1 ; - /* If the mean does not provide a proper partition, fall back to - * median. This usually happens if all points have the same - * value and the zero variance test fails for numerical accuracy - * reasons. In this case, also due to numerical accuracy, the - * mean value can be smaller, equal, or larger than all - * points. */ - if (dataBegin <= splitIndex && splitIndex + 1 < dataEnd) break ; - - case VL_KDTREE_MEDIAN : - medianIndex = (dataBegin + dataEnd - 1) / 2 ; - splitIndex = medianIndex ; - node -> splitThreshold = tree->dataIndex[medianIndex].value ; - break ; - - default: - abort() ; - } - - /* divide subparts */ - node->lowerChild = vl_kdtree_node_new (tree, nodeIndex) ; - vl_kdtree_build_recursively (forest, tree, node->lowerChild, dataBegin, splitIndex + 1, depth + 1) ; - - node->upperChild = vl_kdtree_node_new (tree, nodeIndex) ; - vl_kdtree_build_recursively (forest, tree, node->upperChild, splitIndex + 1, dataEnd, depth + 1) ; -} - -/** ------------------------------------------------------------------ - ** @brief Create new KDForest object - ** @param dataType type of data (::VL_TYPE_FLOAT or ::VL_TYPE_DOUBLE) - ** @param dimension data dimensionality. - ** @param numTrees number of trees in the forest. - ** @param distance type of distance norm (::VlDistanceL1 or ::VlDistanceL2). - ** @return new KDForest. - ** - ** The data dimension @a dimension and the number of trees @a - ** numTrees must not be smaller than one. - **/ - -VlKDForest * -vl_kdforest_new (vl_type dataType, - vl_size dimension, vl_size numTrees, VlVectorComparisonType distance) -{ - VlKDForest * self = vl_calloc (sizeof(VlKDForest), 1) ; - - assert(dataType == VL_TYPE_FLOAT || dataType == VL_TYPE_DOUBLE) ; - assert(dimension >= 1) ; - assert(numTrees >= 1) ; - - self -> rand = vl_get_rand () ; - self -> dataType = dataType ; - self -> numData = 0 ; - self -> data = 0 ; - self -> dimension = dimension ; - self -> numTrees = numTrees ; - self -> trees = 0 ; - self -> thresholdingMethod = VL_KDTREE_MEDIAN ; - self -> splitHeapSize = VL_MIN(numTrees, VL_KDTREE_SPLIT_HEAP_SIZE) ; - self -> splitHeapNumNodes = 0 ; - self -> distance = distance; - self -> maxNumNodes = 0 ; - self -> numSearchers = 0 ; - self -> headSearcher = 0 ; - - switch (self->dataType) { - case VL_TYPE_FLOAT: - self -> distanceFunction = (void(*)(void)) - vl_get_vector_comparison_function_f (distance) ; - break; - case VL_TYPE_DOUBLE : - self -> distanceFunction = (void(*)(void)) - vl_get_vector_comparison_function_d (distance) ; - break ; - default : - abort() ; - } - - return self ; -} - -/** ------------------------------------------------------------------ - ** @brief Create a KDForest searcher object, used for processing queries - ** @param kdforest a forest to which the queries should be pointing. - ** @return KDForest searcher object. - ** - ** A searcher is an object attached to the forest which must be created - ** before running the queries. Each query has to be invoked with the - ** searcher as its argument. - ** - ** When using a multi-threaded approach a user should at first instantiate - ** a correct number of searchers - each used in one thread. - ** Then in each thread a query to the given searcher could be run. - ** - **/ - -VlKDForestSearcher * -vl_kdforest_new_searcher (VlKDForest * kdforest) -{ - VlKDForestSearcher * self = vl_calloc(sizeof(VlKDForestSearcher), 1); - if(kdforest->numSearchers == 0) { - kdforest->headSearcher = self; - self->previous = NULL; - self->next = NULL; - } else { - VlKDForestSearcher * lastSearcher = kdforest->headSearcher; - while (1) { - if(lastSearcher->next) { - lastSearcher = lastSearcher->next; - } else { - lastSearcher->next = self; - self->previous = lastSearcher; - self->next = NULL; - break; - } - } - } - - kdforest->numSearchers++; - - self->forest = kdforest; - self->searchHeapArray = vl_malloc (sizeof(VlKDForestSearchState) * kdforest->maxNumNodes) ; - self->searchIdBook = vl_calloc (sizeof(vl_uindex), kdforest->numData) ; - return self ; -} - -/** ------------------------------------------------------------------ - ** @brief Delete object - ** @param self object. - **/ - -void -vl_kdforestsearcher_delete (VlKDForestSearcher * self) -{ - if (self->previous && self->next) { - self->previous->next = self->next; - self->next->previous = self->previous; - } else if (self->previous && !self->next) { - self->previous->next = NULL; - } else if (!self->previous && self->next) { - self->next->previous = NULL; - self->forest->headSearcher = self->next; - } else { - self->forest->headSearcher = NULL; - } - self->forest->numSearchers -- ; - vl_free(self->searchHeapArray) ; - vl_free(self->searchIdBook) ; - vl_free(self) ; -} - -VlKDForestSearcher * -vl_kdforest_get_searcher (VlKDForest const * self, vl_uindex pos) -{ - VlKDForestSearcher * lastSearcher = self->headSearcher ; - vl_uindex i ; - - for(i = 0; (i < pos) & (lastSearcher != NULL) ; ++i) { - lastSearcher = lastSearcher->next ; - } - return lastSearcher ; -} - -/** ------------------------------------------------------------------ - ** @brief Delete KDForest object - ** @param self KDForest object to delete - ** @sa ::vl_kdforest_new - **/ - -void -vl_kdforest_delete (VlKDForest * self) -{ - vl_uindex ti ; - VlKDForestSearcher * searcher ; - - while ((searcher = vl_kdforest_get_searcher(self, 0))) { - vl_kdforestsearcher_delete(searcher) ; - } - - if (self->trees) { - for (ti = 0 ; ti < self->numTrees ; ++ ti) { - if (self->trees[ti]) { - if (self->trees[ti]->nodes) vl_free (self->trees[ti]->nodes) ; - if (self->trees[ti]->dataIndex) vl_free (self->trees[ti]->dataIndex) ; - vl_free (self->trees[ti]) ; - } - } - vl_free (self->trees) ; - } - vl_free (self) ; -} - -/** ------------------------------------------------------------------ - ** @internal @brief Compute tree bounds recursively - ** @param tree KDTree object instance. - ** @param nodeIndex node index to start from. - ** @param searchBounds 2 x numDimension array of bounds. - **/ - -static void -vl_kdtree_calc_bounds_recursively (VlKDTree * tree, - vl_uindex nodeIndex, double * searchBounds) -{ - VlKDTreeNode * node = tree->nodes + nodeIndex ; - vl_uindex i = node->splitDimension ; - double t = node->splitThreshold ; - - node->lowerBound = searchBounds [2 * i + 0] ; - node->upperBound = searchBounds [2 * i + 1] ; - - //VL_PRINT("%f %f\n",node->lowerBound,node->upperBound); - - if (node->lowerChild > 0) { - searchBounds [2 * i + 1] = t ; - vl_kdtree_calc_bounds_recursively (tree, node->lowerChild, searchBounds) ; - searchBounds [2 * i + 1] = node->upperBound ; - } - if (node->upperChild > 0) { - searchBounds [2 * i + 0] = t ; - vl_kdtree_calc_bounds_recursively (tree, node->upperChild, searchBounds) ; - searchBounds [2 * i + 0] = node->lowerBound ; - } -} - -/** ------------------------------------------------------------------ - ** @brief Build KDTree from data - ** @param self KDTree object - ** @param numData number of data points. - ** @param data pointer to the data. - ** - ** The function builds the KDTree by processing the data @a data. For - ** efficiency, KDTree does not make a copy the data, but retains a - ** pointer to it. Therefore the data buffer must be valid and - ** unchanged for the lifespan of the object. - ** - ** The number of data points @c numData must not be smaller than one. - **/ - -void -vl_kdforest_build (VlKDForest * self, vl_size numData, void const * data) -{ - vl_uindex di, ti ; - vl_size maxNumNodes ; - double * searchBounds; - - assert(data) ; - assert(numData >= 1) ; - - /* need to check: if alredy built, clean first */ - self->data = data ; - self->numData = numData ; - self->trees = vl_malloc (sizeof(VlKDTree*) * self->numTrees) ; - maxNumNodes = 0 ; - - for (ti = 0 ; ti < self->numTrees ; ++ ti) { - self->trees[ti] = vl_malloc (sizeof(VlKDTree)) ; - self->trees[ti]->dataIndex = vl_malloc (sizeof(VlKDTreeDataIndexEntry) * self->numData) ; - for (di = 0 ; di < self->numData ; ++ di) { - self->trees[ti]->dataIndex[di].index = di ; - } - self->trees[ti]->numUsedNodes = 0 ; - /* num. nodes of a complete binary tree with numData leaves */ - self->trees[ti]->numAllocatedNodes = 2 * self->numData - 1 ; - self->trees[ti]->nodes = vl_malloc (sizeof(VlKDTreeNode) * self->trees[ti]->numAllocatedNodes) ; - self->trees[ti]->depth = 0 ; - vl_kdtree_build_recursively (self, self->trees[ti], - vl_kdtree_node_new(self->trees[ti], 0), 0, - self->numData, 0) ; - maxNumNodes += self->trees[ti]->numUsedNodes ; - } - - searchBounds = vl_malloc(sizeof(double) * 2 * self->dimension); - - for (ti = 0 ; ti < self->numTrees ; ++ ti) { - double * iter = searchBounds ; - double * end = iter + 2 * self->dimension ; - while (iter < end) { - *iter++ = - VL_INFINITY_F ; - *iter++ = + VL_INFINITY_F ; - } - - vl_kdtree_calc_bounds_recursively (self->trees[ti], 0, searchBounds) ; - } - - vl_free(searchBounds); - self -> maxNumNodes = maxNumNodes; -} - - -/** ------------------------------------------------------------------ - ** @internal @brief - **/ - -vl_uindex -vl_kdforest_query_recursively (VlKDForestSearcher * searcher, - VlKDTree * tree, - vl_uindex nodeIndex, - VlKDForestNeighbor * neighbors, - vl_size numNeighbors, - vl_size * numAddedNeighbors, - double dist, - void const * query) -{ - - VlKDTreeNode const * node = tree->nodes + nodeIndex ; - vl_uindex i = node->splitDimension ; - vl_index nextChild, saveChild ; - double delta, saveDist ; - double x ; - double x1 = node->lowerBound ; - double x2 = node->splitThreshold ; - double x3 = node->upperBound ; - VlKDForestSearchState * searchState ; - - searcher->searchNumRecursions ++ ; - - switch (searcher->forest->dataType) { - case VL_TYPE_FLOAT : - x = ((float const*) query)[i] ; - break ; - case VL_TYPE_DOUBLE : - x = ((double const*) query)[i] ; - break ; - default : - abort() ; - } - - /* base case: this is a leaf node */ - if (node->lowerChild < 0) { - - vl_index begin = - node->lowerChild - 1 ; - vl_index end = - node->upperChild - 1 ; - vl_index iter ; - - for (iter = begin ; - iter < end && - (searcher->forest->searchMaxNumComparisons == 0 || - searcher->searchNumComparisons < searcher->forest->searchMaxNumComparisons) ; - ++ iter) { - - vl_index di = tree->dataIndex [iter].index ; - - /* multiple KDTrees share the database points and we must avoid - * adding the same point twice */ - if (searcher->searchIdBook[di] == searcher->searchId) continue ; - searcher->searchIdBook[di] = searcher->searchId ; - - /* compare the query to this point */ - switch (searcher->forest->dataType) { - case VL_TYPE_FLOAT: - dist = ((VlFloatVectorComparisonFunction)searcher->forest->distanceFunction) - (searcher->forest->dimension, - ((float const *)query), - ((float const*)searcher->forest->data) + di * searcher->forest->dimension) ; - break ; - case VL_TYPE_DOUBLE: - dist = ((VlDoubleVectorComparisonFunction)searcher->forest->distanceFunction) - (searcher->forest->dimension, - ((double const *)query), - ((double const*)searcher->forest->data) + di * searcher->forest->dimension) ; - break ; - default: - abort() ; - } - searcher->searchNumComparisons += 1 ; - - /* see if it should be added to the result set */ - if (*numAddedNeighbors < numNeighbors) { - VlKDForestNeighbor * newNeighbor = neighbors + *numAddedNeighbors ; - newNeighbor->index = di ; - newNeighbor->distance = dist ; - vl_kdforest_neighbor_heap_push (neighbors, numAddedNeighbors) ; - } else { - VlKDForestNeighbor * largestNeighbor = neighbors + 0 ; - if (largestNeighbor->distance > dist) { - largestNeighbor->index = di ; - largestNeighbor->distance = dist ; - vl_kdforest_neighbor_heap_update (neighbors, *numAddedNeighbors, 0) ; - } - } - } /* next data point */ - - - return nodeIndex ; - } - -#if 0 - assert (x1 <= x2 && x2 <= x3) ; - assert (node->lowerChild >= 0) ; - assert (node->upperChild >= 0) ; -#endif - - /* - * x1 x2 x3 - * x (---|---] - * (--x|---] - * (---|x--] - * (---|---] x - */ - - delta = x - x2 ; - saveDist = dist + delta*delta ; - - if (x <= x2) { - nextChild = node->lowerChild ; - saveChild = node->upperChild ; - if (x <= x1) { - delta = x - x1 ; - saveDist -= delta*delta ; - } - } else { - nextChild = node->upperChild ; - saveChild = node->lowerChild ; - if (x > x3) { - delta = x - x3 ; - saveDist -= delta*delta ; - } - } - - if (*numAddedNeighbors < numNeighbors || neighbors[0].distance > saveDist) { - searchState = searcher->searchHeapArray + searcher->searchHeapNumNodes ; - searchState->tree = tree ; - searchState->nodeIndex = saveChild ; - searchState->distanceLowerBound = saveDist ; - vl_kdforest_search_heap_push (searcher->searchHeapArray , - &searcher->searchHeapNumNodes) ; - } - - return vl_kdforest_query_recursively (searcher, - tree, - nextChild, - neighbors, - numNeighbors, - numAddedNeighbors, - dist, - query) ; -} - -/** ------------------------------------------------------------------ - ** @brief Query the forest - ** @param self object. - ** @param neighbors list of nearest neighbors found (output). - ** @param numNeighbors number of nearest neighbors to find. - ** @param query query point. - ** @return number of tree leaves visited. - ** - ** A neighbor is represented by an instance of the structure - ** ::VlKDForestNeighbor. Each entry contains the index of the - ** neighbor (this is an index into the KDTree data) and its distance - ** to the query point. Neighbors are sorted by increasing distance. - **/ - -vl_size -vl_kdforest_query (VlKDForest * self, - VlKDForestNeighbor * neighbors, - vl_size numNeighbors, - void const * query) -{ - VlKDForestSearcher * searcher = vl_kdforest_get_searcher(self, 0) ; - if (searcher == NULL) { - searcher = vl_kdforest_new_searcher(self) ; - } - return vl_kdforestsearcher_query(searcher, - neighbors, - numNeighbors, - query) ; -} - -/** ------------------------------------------------------------------ - ** @brief Query the forest - ** @param self object. - ** @param neighbors list of nearest neighbors found (output). - ** @param numNeighbors number of nearest neighbors to find. - ** @param query query point. - ** @return number of tree leaves visited. - ** - ** A neighbor is represented by an instance of the structure - ** ::VlKDForestNeighbor. Each entry contains the index of the - ** neighbor (this is an index into the KDTree data) and its distance - ** to the query point. Neighbors are sorted by increasing distance. - **/ - -vl_size -vl_kdforestsearcher_query (VlKDForestSearcher * self, - VlKDForestNeighbor * neighbors, - vl_size numNeighbors, - void const * query) -{ - - vl_uindex i, ti ; - vl_bool exactSearch = self->forest->searchMaxNumComparisons == 0 ; - - VlKDForestSearchState * searchState ; - vl_size numAddedNeighbors = 0 ; - - assert (neighbors) ; - assert (numNeighbors > 0) ; - assert (query) ; - - /* this number is used to differentiate a query from the next */ - self -> searchId += 1 ; - self -> searchNumRecursions = 0 ; - - self->searchNumComparisons = 0 ; - self->searchNumSimplifications = 0 ; - - /* put the root node into the search heap */ - self->searchHeapNumNodes = 0 ; - for (ti = 0 ; ti < self->forest->numTrees ; ++ ti) { - searchState = self->searchHeapArray + self->searchHeapNumNodes ; - searchState -> tree = self->forest->trees[ti] ; - searchState -> nodeIndex = 0 ; - searchState -> distanceLowerBound = 0 ; - - vl_kdforest_search_heap_push (self->searchHeapArray, &self->searchHeapNumNodes) ; - } - - /* branch and bound */ - while (exactSearch || self->searchNumComparisons < self->forest->searchMaxNumComparisons) - { - /* pop the next optimal search node */ - VlKDForestSearchState * searchState ; - - /* break if search space completed */ - if (self->searchHeapNumNodes == 0) { - break ; - } - searchState = self->searchHeapArray + - vl_kdforest_search_heap_pop (self->searchHeapArray, &self->searchHeapNumNodes) ; - /* break if no better solution may exist */ - if (numAddedNeighbors == numNeighbors && - neighbors[0].distance < searchState->distanceLowerBound) { - self->searchNumSimplifications ++ ; - break ; - } - vl_kdforest_query_recursively (self, - searchState->tree, - searchState->nodeIndex, - neighbors, - numNeighbors, - &numAddedNeighbors, - searchState->distanceLowerBound, - query) ; - } - - /* sort neighbors by increasing distance */ - for (i = numAddedNeighbors ; i < numNeighbors ; ++ i) { - neighbors[i].index = -1 ; - neighbors[i].distance = VL_NAN_F ; - } - - while (numAddedNeighbors) { - vl_kdforest_neighbor_heap_pop (neighbors, &numAddedNeighbors) ; - } - - return self->searchNumComparisons ; -} - -/** ------------------------------------------------------------------ - ** @brief Run multiple queries - ** @param self object. - ** @param indexes assignments of points. - ** @param numNeighbors number of nearest neighbors to be found for each data point - ** @param numQueries number of query points. - ** @param distances distances of query points. - ** @param queries lisf of vectors to use as queries. - ** - ** @a indexes and @a distances are @a numNeighbors by @a numQueries - ** matrices containing the indexes and distances of the nearest neighbours - ** for each of the @a numQueries queries @a queries. - ** - ** This function is similar to ::vl_kdforest_query. The main - ** difference is that the function can use multiple cores to query - ** large amounts of data. - ** - ** @sa ::vl_kdforest_query. - **/ - -vl_size -vl_kdforest_query_with_array (VlKDForest * self, - vl_uint32 * indexes, - vl_size numNeighbors, - vl_size numQueries, - void * distances, - void const * queries) -{ - vl_size numComparisons = 0; - vl_type dataType = vl_kdforest_get_data_type(self) ; - vl_size dimension = vl_kdforest_get_data_dimension(self) ; - -#ifdef _OPENMP -#pragma omp parallel default(shared) num_threads(vl_get_max_threads()) -#endif - { - vl_index qi ; - vl_size thisNumComparisons = 0 ; - VlKDForestSearcher * searcher ; - VlKDForestNeighbor * neighbors ; - -#ifdef _OPENMP -#pragma omp critical -#endif - { - searcher = vl_kdforest_new_searcher(self) ; - neighbors = vl_calloc (sizeof(VlKDForestNeighbor), numNeighbors) ; - } - -#ifdef _OPENMP -#pragma omp for -#endif - for(qi = 0 ; qi < (signed)numQueries; ++ qi) { - switch (dataType) { - case VL_TYPE_FLOAT: { - vl_size ni; - thisNumComparisons += vl_kdforestsearcher_query (searcher, neighbors, numNeighbors, - (float const *) (queries) + qi * dimension) ; - for (ni = 0 ; ni < numNeighbors ; ++ni) { - indexes [qi*numNeighbors + ni] = (vl_uint32) neighbors[ni].index ; - if (distances){ - *((float*)distances + qi*numNeighbors + ni) = neighbors[ni].distance ; - } - } - break ; - } - case VL_TYPE_DOUBLE: { - vl_size ni; - thisNumComparisons += vl_kdforestsearcher_query (searcher, neighbors, numNeighbors, - (double const *) (queries) + qi * dimension) ; - for (ni = 0 ; ni < numNeighbors ; ++ni) { - indexes [qi*numNeighbors + ni] = (vl_uint32) neighbors[ni].index ; - if (distances){ - *((double*)distances + qi*numNeighbors + ni) = neighbors[ni].distance ; - } - } - break ; - } - default: - abort() ; - } - } - -#ifdef _OPENMP -#pragma omp critical -#endif - { - numComparisons += thisNumComparisons ; - vl_kdforestsearcher_delete (searcher) ; - vl_free (neighbors) ; - } - } - return numComparisons ; -} - -/** ------------------------------------------------------------------ - ** @brief Get the number of nodes of a given tree - ** @param self KDForest object. - ** @param treeIndex index of the tree. - ** @return number of trees. - **/ - -vl_size -vl_kdforest_get_num_nodes_of_tree (VlKDForest const * self, vl_uindex treeIndex) -{ - assert (treeIndex < self->numTrees) ; - return self->trees[treeIndex]->numUsedNodes ; -} - -/** ------------------------------------------------------------------ - ** @brief Get the detph of a given tree - ** @param self KDForest object. - ** @param treeIndex index of the tree. - ** @return number of trees. - **/ - -vl_size -vl_kdforest_get_depth_of_tree (VlKDForest const * self, vl_uindex treeIndex) -{ - assert (treeIndex < self->numTrees) ; - return self->trees[treeIndex]->depth ; -} - -/** ------------------------------------------------------------------ - ** @brief Get the number of trees in the forest - ** - ** @param self KDForest object. - ** @return number of trees. - **/ - -vl_size -vl_kdforest_get_num_trees (VlKDForest const * self) -{ - return self->numTrees ; -} - -/** ------------------------------------------------------------------ - ** @brief Set the maximum number of comparisons for a search - ** - ** @param self KDForest object. - ** @param n maximum number of leaves. - ** - ** This function sets the maximum number of comparisons for a - ** nearest neighbor search. Setting it to 0 means unbounded comparisons. - ** - ** @sa ::vl_kdforest_query, ::vl_kdforest_get_max_num_comparisons. - **/ - -void -vl_kdforest_set_max_num_comparisons (VlKDForest * self, vl_size n) -{ - self->searchMaxNumComparisons = n ; -} - -/** ------------------------------------------------------------------ - ** @brief Get the maximum number of comparisons for a search - ** - ** @param self KDForest object. - ** @return maximum number of leaves. - ** - ** @sa ::vl_kdforest_set_max_num_comparisons. - **/ - -vl_size -vl_kdforest_get_max_num_comparisons (VlKDForest * self) -{ - return self->searchMaxNumComparisons ; -} - -/** ------------------------------------------------------------------ - ** @brief Set the thresholding method - ** @param self KDForest object. - ** @param method one of ::VlKDTreeThresholdingMethod. - ** - ** @sa ::vl_kdforest_get_thresholding_method - **/ - - void -vl_kdforest_set_thresholding_method (VlKDForest * self, VlKDTreeThresholdingMethod method) -{ - assert(method == VL_KDTREE_MEDIAN || method == VL_KDTREE_MEAN) ; - self->thresholdingMethod = method ; -} - -/** ------------------------------------------------------------------ - ** @brief Get the thresholding method - ** - ** @param self KDForest object. - ** @return thresholding method. - ** - ** @sa ::vl_kdforest_set_thresholding_method - **/ - - VlKDTreeThresholdingMethod -vl_kdforest_get_thresholding_method (VlKDForest const * self) -{ - return self->thresholdingMethod ; -} - -/** ------------------------------------------------------------------ - ** @brief Get the dimension of the data - ** @param self KDForest object. - ** @return dimension of the data. - **/ - - vl_size -vl_kdforest_get_data_dimension (VlKDForest const * self) -{ - return self->dimension ; -} - -/** ------------------------------------------------------------------ - ** @brief Get the data type - ** @param self KDForest object. - ** @return data type (one of ::VL_TYPE_FLOAT, ::VL_TYPE_DOUBLE). - **/ - -vl_type -vl_kdforest_get_data_type (VlKDForest const * self) -{ - return self->dataType ; -} - -/** ------------------------------------------------------------------ - ** @brief Get the forest linked to the searcher - ** @param self object. - ** @return correspoinding KD-Forest. - **/ - -VlKDForest * -vl_kdforestsearcher_get_forest (VlKDForestSearcher const * self) -{ - return self->forest; -} diff --git a/opensfm/src/third_party/vlfeat/vl/kdtree.h b/opensfm/src/third_party/vlfeat/vl/kdtree.h deleted file mode 100644 index 8c8f212be..000000000 --- a/opensfm/src/third_party/vlfeat/vl/kdtree.h +++ /dev/null @@ -1,185 +0,0 @@ -/** @file kdtree.h - ** @brief KD-tree (@ref kdtree) - ** @author Andrea Vedaldi, David Novotny - **/ - -/* -Copyright (C) 2007-12 Andrea Vedaldi and Brian Fulkerson. -All rights reserved. - -This file is part of the VLFeat library and is made available under -the terms of the BSD license (see the COPYING file). -*/ - -#ifndef VL_KDTREE_H -#define VL_KDTREE_H - -#include "generic.h" -#include "mathop.h" - -#define VL_KDTREE_SPLIT_HEAP_SIZE 5 -#define VL_KDTREE_VARIANCE_EST_NUM_SAMPLES 1024 - -typedef struct _VlKDTreeNode VlKDTreeNode ; -typedef struct _VlKDTreeSplitDimension VlKDTreeSplitDimension ; -typedef struct _VlKDTreeDataIndexEntry VlKDTreeDataIndexEntry ; -typedef struct _VlKDForestSearchState VlKDForestSearchState ; - -struct _VlKDTreeNode -{ - vl_uindex parent ; - vl_index lowerChild ; - vl_index upperChild ; - unsigned int splitDimension ; - double splitThreshold ; - double lowerBound ; - double upperBound ; -} ; - -struct _VlKDTreeSplitDimension -{ - unsigned int dimension ; - double mean ; - double variance ; -} ; - -struct _VlKDTreeDataIndexEntry -{ - vl_index index ; - double value ; -} ; - -/** @brief Thresholding method */ -typedef enum _VlKDTreeThresholdingMethod -{ - VL_KDTREE_MEDIAN, - VL_KDTREE_MEAN -} VlKDTreeThresholdingMethod ; - -/** @brief Neighbor of a query point */ -typedef struct _VlKDForestNeighbor { - double distance ; /**< distance to the query point */ - vl_uindex index ; /**< index of the neighbor in the KDTree data */ -} VlKDForestNeighbor ; - -typedef struct _VlKDTree -{ - VlKDTreeNode * nodes ; - vl_size numUsedNodes ; - vl_size numAllocatedNodes ; - VlKDTreeDataIndexEntry * dataIndex ; - unsigned int depth ; -} VlKDTree ; - -struct _VlKDForestSearchState -{ - VlKDTree * tree ; - vl_uindex nodeIndex ; - double distanceLowerBound ; -} ; - -struct _VlKDForestSearcher; - -/** @brief KDForest object */ -typedef struct _VlKDForest -{ - vl_size dimension ; - - /* random number generator */ - VlRand * rand ; - - /* indexed data */ - vl_type dataType ; - void const * data ; - vl_size numData ; - VlVectorComparisonType distance; - void (*distanceFunction)(void) ; - - /* tree structure */ - VlKDTree ** trees ; - vl_size numTrees ; - - /* build */ - VlKDTreeThresholdingMethod thresholdingMethod ; - VlKDTreeSplitDimension splitHeapArray [VL_KDTREE_SPLIT_HEAP_SIZE] ; - vl_size splitHeapNumNodes ; - vl_size splitHeapSize ; - vl_size maxNumNodes; - - /* query */ - vl_size searchMaxNumComparisons ; - vl_size numSearchers; - struct _VlKDForestSearcher * headSearcher ; /* head of the double linked list with searchers */ - -} VlKDForest ; - -/** @brief ::VlKDForest searcher object */ -typedef struct _VlKDForestSearcher -{ - /* maintain a linked list of searchers for later disposal*/ - struct _VlKDForestSearcher * next; - struct _VlKDForestSearcher * previous; - - vl_uindex * searchIdBook ; - VlKDForestSearchState * searchHeapArray ; - VlKDForest * forest; - - vl_size searchNumComparisons; - vl_size searchNumRecursions ; - vl_size searchNumSimplifications ; - - vl_size searchHeapNumNodes ; - vl_uindex searchId ; -} VlKDForestSearcher ; - -/** @name Creating, copying and disposing - ** @{ */ -VL_EXPORT VlKDForest * vl_kdforest_new (vl_type dataType, - vl_size dimension, vl_size numTrees, VlVectorComparisonType normType) ; -VL_EXPORT VlKDForestSearcher * vl_kdforest_new_searcher (VlKDForest * kdforest); -VL_EXPORT void vl_kdforest_delete (VlKDForest * self) ; -VL_EXPORT void vl_kdforestsearcher_delete (VlKDForestSearcher * searcher) ; -/** @} */ - -/** @name Building and querying - ** @{ */ -VL_EXPORT void vl_kdforest_build (VlKDForest * self, - vl_size numData, - void const * data) ; - -VL_EXPORT vl_size vl_kdforest_query (VlKDForest * self, - VlKDForestNeighbor * neighbors, - vl_size numNeighbors, - void const * query) ; - -VL_EXPORT vl_size vl_kdforest_query_with_array (VlKDForest * self, - vl_uint32 * index, - vl_size numNeighbors, - vl_size numQueries, - void * distance, - void const * queries) ; - -VL_EXPORT vl_size vl_kdforestsearcher_query (VlKDForestSearcher * self, - VlKDForestNeighbor * neighbors, - vl_size numNeighbors, - void const * query) ; -/** @} */ - -/** @name Retrieving and setting parameters - ** @{ */ -VL_EXPORT vl_size vl_kdforest_get_depth_of_tree (VlKDForest const * self, vl_uindex treeIndex) ; -VL_EXPORT vl_size vl_kdforest_get_num_nodes_of_tree (VlKDForest const * self, vl_uindex treeIndex) ; -VL_EXPORT vl_size vl_kdforest_get_num_trees (VlKDForest const * self) ; -VL_EXPORT vl_size vl_kdforest_get_data_dimension (VlKDForest const * self) ; -VL_EXPORT vl_type vl_kdforest_get_data_type (VlKDForest const * self) ; -VL_EXPORT void vl_kdforest_set_max_num_comparisons (VlKDForest * self, vl_size n) ; -VL_EXPORT vl_size vl_kdforest_get_max_num_comparisons (VlKDForest * self) ; -VL_EXPORT void vl_kdforest_set_thresholding_method (VlKDForest * self, VlKDTreeThresholdingMethod method) ; -VL_EXPORT VlKDTreeThresholdingMethod vl_kdforest_get_thresholding_method (VlKDForest const * self) ; -VL_EXPORT VlKDForest * vl_kdforest_searcher_get_forest (VlKDForestSearcher const * self) ; -VL_EXPORT VlKDForestSearcher * vl_kdforest_get_searcher (VlKDForest const * self, vl_uindex pos) ; -/** @} */ - - -/* VL_KDTREE_H */ -#endif diff --git a/opensfm/src/third_party/vlfeat/vl/kmeans.c b/opensfm/src/third_party/vlfeat/vl/kmeans.c deleted file mode 100644 index b7c93088b..000000000 --- a/opensfm/src/third_party/vlfeat/vl/kmeans.c +++ /dev/null @@ -1,2101 +0,0 @@ -/** @file kmeans.c - ** @brief K-means - Declaration - ** @author Andrea Vedaldi, David Novotny - **/ - -/* -Copyright (C) 2007-12 Andrea Vedaldi and Brian Fulkerson. -Copyright (C) 2013 Andrea Vedaldi and David Novotny. -All rights reserved. - -This file is part of the VLFeat library and is made available under -the terms of the BSD license (see the COPYING file). -*/ - -/** - -@page kmeans K-means clustering -@author Andrea Vedaldi -@author David Novotny -@tableofcontents - - -@ref kmeans.h implements a number of algorithm for **K-means -quantization**: Lloyd @cite{lloyd82least}, an accelerated version by -Elkan @cite{elkan03using}, and a large scale algorithm based on -Approximate Nearest Neighbors (ANN). All algorithms support @c float -or @c double data and can use the $l^1$ or the $l^2$ distance for -clustering. Furthermore, all algorithms can take advantage of multiple -CPU cores. - -Please see @subpage kmeans-fundamentals for a technical description of -K-means and of the algorithms implemented here. - - -@section kmeans-starting Getting started - - -The goal of K-means is to partition a dataset into $K$ -“compact” clusters. The following example demonstrates -using @ref kmeans.h in the C programming language to partition @c -numData @c float vectors into compute @c numCenters clusters using -Lloyd's algorithm: - -@code -#include -double energy ; -double * centers ; - -// Use float data and the L2 distance for clustering -KMeans * kmeans = vl_kmeans_new (VLDistanceL2, VL_TYPE_FLOAT) ; - -// Use Lloyd algorithm -vl_kmeans_set_algorithm (kmeans, VlKMeansLloyd) ; - -// Initialize the cluster centers by randomly sampling the data -vl_kmeans_init_centers_with_rand_data (kmeans, data, dimension, numData, numCenters) ; - -// Run at most 100 iterations of cluster refinement using Lloyd algorithm -vl_kmeans_set_max_num_iterations (kmeans, 100) ; -vl_kmeans_refine_centers (kmeans, data, numData) ; - -// Obtain the energy of the solution -energy = vl_kmeans_get_energy(kmeans) ; - -// Obtain the cluster centers -centers = vl_kmeans_get_centers(kmeans) ; -@endcode - -Once the centers have been obtained, new data points can be assigned -to clusters by using the ::vl_kmeans_quantize function: - -@code -vl_uint32 * assignments = vl_malloc(sizeof(vl_uint32) * numData) ; -float * distances = vl_malloc(sizeof(float) * numData) ; -vl_kmeans_quantize(kmeans, assignments, distances, data, numData) ; -@endcode - -Alternatively, one can directly assign new pointers to the closest -centers, without bothering with a ::VlKMeans object. - -There are several considerations that may impact the performance of -KMeans. First, since K-means is usually based local optimization -algorithm, the **initialization method** is important. The following -initialization methods are supported: - -Method | Function | Description ----------------|-----------------------------------------|----------------------------------------------- -Random samples | ::vl_kmeans_init_centers_with_rand_data | Random data points -K-means++ | ::vl_kmeans_init_centers_plus_plus | Random selection biased towards diversity -Custom | ::vl_kmeans_set_centers | Choose centers (useful to run quantization only) - -See @ref kmeans-init for further details. The initialization methods -use a randomized selection of the data points; the random number -generator init is controlled by ::vl_rand_init. - -The second important choice is the **optimization algorithm**. The -following optimization algorithms are supported: - -Algorithm | Symbol | See | Description -------------|------------------|-------------------|----------------------------------------------- -Lloyd | ::VlKMeansLloyd | @ref kmeans-lloyd | Alternate EM-style optimization -Elkan | ::VlKMeansElkan | @ref kmeans-elkan | A speedup using triangular inequalities -ANN | ::VlKMeansANN | @ref kmeans-ann | A speedup using approximated nearest neighbors - -See the relative sections for further details. These algorithm are -iterative, and stop when either a **maximum number of iterations** -(::vl_kmeans_set_max_num_iterations) is reached, or when the energy -changes sufficiently slowly in one iteration (::vl_kmeans_set_min_energy_variation). - - -All the three algorithms support multithreaded computations. The number -of threads used is usually controlled globally by ::vl_set_num_threads. -**/ - -/** - -@page kmeans-fundamentals K-means fundamentals -@tableofcontents - - -Given $n$ points $\bx_1,\dots,\bx_n \in \real^d$, the goal of K-means -is find $K$ `centers` $\bc_1,\dots,\bc_m \in \real^d$ and -`assignments` $q_1,\dots,q_n \in \{1,\dots,K\}$ of the points to the -centers such that the sum of distances - -\[ - E(\bc_1,\dots,\bc_k,q_1,\dots,q_n) - = \sum_{i=1}^n \|\bx_i - \bc_{q_i} \|_p^p -\] - -is minimized. $K$-means is obtained for the case $p=2$ ($l^2$ norm), -because in this case the optimal centers are the means of the input -vectors assigned to them. Here the generalization $p=1$ ($l^1$ norm) -will also be considered. - -Up to normalization, the K-means objective $E$ is also the average -reconstruction error if the original points are approximated with the -cluster centers. Thus K-means is used not only to group the input -points into cluster, but also to `quantize` their values. - -K-means is widely used in computer vision, for example in the -construction of vocabularies of visual features (visual words). In -these applications the number $n$ of points to cluster and/or the -number $K$ of clusters is often large. Unfortunately, minimizing the -objective $E$ is in general a difficult combinatorial problem, so -locally optimal or approximated solutions are sought instead. - -The basic K-means algorithm alternate between re-estimating the -centers and the assignments (@ref kmeans-lloyd). Combined with a good -initialization strategy (@ref kmeans-init) and, potentially, by -re-running the optimization from a number of randomized starting -states, this algorithm may attain satisfactory solutions in practice. - -However, despite its simplicity, Lloyd's algorithm is often too slow. -A good replacement is Elkan's algorithm (@ref kmeans-elkan), which -uses the triangular inequality to cut down significantly the cost of -Lloyd's algorithm. Since this algorithm is otherwise equivalent, it -should often be preferred. - -For very large problems (millions of point to clusters and hundreds, -thousands, or more clusters to find), even Elkan's algorithm is not -sufficiently fast. In these cases, one can resort to a variant of -Lloyd's algorithm that uses an approximated nearest neighbors routine -(@ref kmeans-ann). - - -@section kmeans-init Initialization methods - - -All the $K$-means algorithms considered here find locally optimal -solutions; as such the way they are initialized is important. @ref -kmeans.h supports the following initialization algorithms: - -@par Random data samples - -The simplest initialization method is to sample $K$ points at random -from the input data and use them as initial values for the cluster -centers. - -@par K-means++ - -@cite{arthur07k-means} proposes a randomized initialization of the -centers which improves upon random selection. The first center $\bc_1$ -is selected at random from the data points $\bx_1, \dots, \bx_n $ and -the distance from this center to all points $\|\bx_i - \bc_1\|_p^p$ is -computed. Then the second center $\bc_2$ is selected at random from -the data points with probability proportional to the distance. The -procedure is repeated to obtain the other centers by using the minimum -distance to the centers collected so far. - - -@section kmeans-lloyd Lloyd's algorithm - - -The most common K-means method is Lloyd's algorithm -@cite{lloyd82least}. This algorithm is based on the observation that, -while jointly optimizing clusters and assignment is difficult, -optimizing one given the other is easy. Lloyd's algorithm alternates -the steps: - -1. **Quantization.** Each point $\bx_i$ is reassigned to the center - $\bc_{q_j}$ closer to it. This requires finding for each point the - closest among $K$ other points, which is potentially slow. -2. **Center estimation.** Each center $\bc_q$ is updated to minimize - its average distances to the points assigned to it. It is easy to - show that the best center is the mean or median of the points, - respectively if the $l^2$ or $l^1$ norm is considered. - -A naive implementation of the assignment step requires $O(dnK)$ -operations, where $d$ is the dimensionality of the data, $n$ the -number of data points, and $K$ the number of centers. Updating the -centers is much cheaper: $O(dn)$ operations suffice to compute the $K$ -means and a slightly higher cost is required for the medians. Clearly, -the bottleneck is the assignment computation, and this is what the -other K-means algorithm try to improve. - -During the iterations, it can happen that a cluster becomes empty. In -this case, K-means automatically **“restarts” the -cluster** center by selecting a training point at random. - - -@section kmeans-elkan Elkan's algorithm - - -Elkan's algorithm @cite{elkan03using} is a variation of Lloyd -alternate optimization algorithm (@ref kmeans-lloyd) that uses the -triangular inequality to avoid many distance calculations when -assigning points to clusters. While much faster than Lloyd, Elkan's -method uses storage proportional to the umber of clusters by data -points, which makes it unpractical for a very large number of -clusters. - -The idea of this algorithm is that, if a center update does not move -them much, then most of the point-to-center computations can be -avoided when the point-to-center assignments are recomputed. To detect -which distances need evaluation, the triangular inequality is used to -lower and upper bound distances after a center update. - -Elkan algorithms uses two key observations. First, one has - -\[ -\|\bx_i - \bc_{q_i}\|_p \leq \|\bc - \bc_{q_i}\|_p / 2 -\quad\Rightarrow\quad -\|\bx_i - \bc_{q_i}\|_p \leq \|\bx_i - \bc\|_p. -\] - -Thus if the distance between $\bx_i$ and its current center -$\bc_{q_i}$ is less than half the distance of the center $\bc_{q_i}$ -to another center $\bc$, then $\bc$ can be skipped when the new -assignment for $\bx_i$ is searched. Checking this requires keeping -track of all the inter-center distances, but centers are typically a -small fraction of the training data, so overall this can be a -significant saving. In particular, if this condition is satisfied for -all the centers $\bc \not= \bc_{q_i}$, the point $\bx_i$ can be -skipped completely. Furthermore, the condition can be tested also -based on an upper bound $UB_i$ of $\|\bx_i - \bc_{q_i}\|_p$. - -Second, if a center $\bc$ is updated to $\hat{\bc}$, then the new -distance from $\bx$ to $\hat{\bc}$ is bounded from below and above by - -\[ -\|\bx - \bc\|_p - \|bc - \hat\bc\|_p -\leq -\|\bx - \hat{\bc}\|_p -\leq -\|\bx - \hat{\bc}\|_p + \|\bc + \hat{\bc}\|_p. -\] - -This allows to maintain an upper bound on the distance of $\bx_i$ to -its current center $\bc_{q_i}$ and a lower bound to any other center -$\bc$: - -@f{align*} - UB_i & \leftarrow UB_i + \|\bc_{q_i} - \hat{\bc}_{q_i} \|_p \\ - LB_i(\bc) & \leftarrow LB_i(\bc) - \|\bc -\hat \bc\|_p. -@f} - -Thus the K-means algorithm becomes: - -1. **Initialization.** Compute $LB_i(\bc) = \|\bx_i -\hat \bc\|_p$ for - all points and centers. Find the current assignments $q_i$ and - bounds $UB_i$ by finding the closest centers to each point: $UB_i = - \min_{\bc} LB_i(\bc)$. -2. **Center estimation.** - 1. Recompute all the centers based on the new means; call the updated - version $\hat{\bc}$. - 2. Update all the bounds based on the distance $\|\bc - \hat\bc\|_p$ - as explained above. - 3. Set $\bc \leftarrow \hat\bc$ for all the centers and go to the next - iteration. -3. **Quantization.** - 1. Skip any point $\bx_i$ such that $UB_i \leq \frac{1}{2} \|\bc_{q_i} - \bc\|_p$ - for all centers $\bc \not= \bc_{q_i}$. - 2. For each remaining point $\bx_i$ and center $\bc \not= \bc_{q_i}$: - 1. Skip $\bc$ if - \[ - UB_i \leq \frac{1}{2} \| \bc_{q_i} - \bc \| - \quad\text{or}\quad - UB_i \leq LB_i(\bc). - \] - The first condition reflects the first observation above; the - second uses the bounds to decide if $\bc$ can be closer than the - current center $\bc_{q_i}$ to the point $\bx_i$. If the center - cannot be skipped, continue as follows. - 3. Skip $\bc$ if the condition above is satisfied after making the - upper bound tight: - \[ - UB_i = LB_i(\bc_{q_i}) = \| \bx_i - \bc_{q_i} \|_p. - \] - Note that the latter calculation can be done only once for $\bx_i$. - If the center cannot be skipped still, continue as follows. - 4. Tighten the lower bound too: - \[ - LB_i(\bc) = \| \bx_i - \bc \|_p. - \] - At this point both $UB_i$ and $LB_i(\bc)$ are tight. If $LB_i < - UB_i$, then the point $\bx_i$ should be reassigned to - $\bc$. Update $q_i$ to the index of center $\bc$ and reset $UB_i - = LB_i(\bc)$. - - -@section kmeans-ann ANN algorithm - - -The *Approximate Nearest Neighbor* (ANN) K-means algorithm -@cite{beis97shape} @cite{silpa-anan08optimised} @cite{muja09fast} is a -variant of Lloyd's algorithm (@ref kmeans-lloyd) uses a best-bin-first -randomized KD-tree algorithm to approximately (and quickly) find the -closest cluster center to each point. The KD-tree implementation is -based on @ref kdtree. - -The algorithm can be summarized as follows: - -1. **Quantization.** Each point $\bx_i$ is reassigned to the center - $\bc_{q_j}$ closer to it. This starts by indexing the $K$ centers - by a KD-tree and then using the latter to quickly find the closest - center for every training point. The search is approximated to - further improve speed. This opens up the possibility that a data - point may receive an assignment that is *worse* than the current - one. This is avoided by checking that the new assignment estimated - by using ANN is an improvement; otherwise the old assignment is - kept. -2. **Center estimation.** Each center $\bc_q$ is updated to minimize - its average distances to the points assigned to it. It is easy to - show that the best center is the mean or median of the points, - respectively if the $l^2$ or $l^1$ norm is considered. - -The key is to trade-off carefully the speedup obtained by using the -ANN algorithm and the loss in accuracy when retrieving neighbors. Due -to the curse of dimensionality, KD-trees become less effective for -higher dimensional data, so that the search cost, which in the best -case is logarithmic with this data structure, may become effectively -linear. This is somehow mitigated by the fact that new a new KD-tree -is computed at each iteration, reducing the likelihood that points may -get stuck with sub-optimal assignments. - -Experiments with the quantization of 128-dimensional SIFT features -show that the ANN algorithm may use one quarter of the comparisons of -Elkan's while retaining a similar solution accuracy. - -*/ - -#include "kmeans.h" -#include "generic.h" -#include "mathop.h" -#include - -#ifdef _OPENMP -#include -#endif - -/* ================================================================ */ -#ifndef VL_KMEANS_INSTANTIATING - - -/** ------------------------------------------------------------------ - ** @brief Reset state - ** - ** The function reset the state of the KMeans object. It deletes - ** any stored centers, releasing the corresponding memory. This - ** cancels the effect of seeding or setting the centers, but - ** does not change the other configuration parameters. - **/ - -VL_EXPORT void -vl_kmeans_reset (VlKMeans * self) -{ - self->numCenters = 0 ; - self->dimension = 0 ; - - if (self->centers) vl_free(self->centers) ; - if (self->centerDistances) vl_free(self->centerDistances) ; - - self->centers = NULL ; - self->centerDistances = NULL ; -} - -/** ------------------------------------------------------------------ - ** @brief Create a new KMeans object - ** @param dataType type of data (::VL_TYPE_FLOAT or ::VL_TYPE_DOUBLE) - ** @param distance distance. - ** @return new KMeans object instance. -**/ - -VL_EXPORT VlKMeans * -vl_kmeans_new (vl_type dataType, - VlVectorComparisonType distance) -{ - VlKMeans * self = vl_calloc(1, sizeof(VlKMeans)) ; - - self->algorithm = VlKMeansLloyd ; - self->distance = distance ; - self->dataType = dataType ; - self->verbosity = 0 ; - self->maxNumIterations = 100 ; - self->minEnergyVariation = 1e-4 ; - self->numRepetitions = 1 ; - self->centers = NULL ; - self->centerDistances = NULL ; - self->numTrees = 3; - self->maxNumComparisons = 100; - - vl_kmeans_reset (self) ; - return self ; -} - -/** ------------------------------------------------------------------ - ** @brief Create a new KMeans object by copy - ** @param kmeans KMeans object to copy. - ** @return new copy. - **/ - -VL_EXPORT VlKMeans * -vl_kmeans_new_copy (VlKMeans const * kmeans) -{ - VlKMeans * self = vl_malloc(sizeof(VlKMeans)) ; - - self->algorithm = kmeans->algorithm ; - self->distance = kmeans->distance ; - self->dataType = kmeans->dataType ; - - self->verbosity = kmeans->verbosity ; - self->maxNumIterations = kmeans->maxNumIterations ; - self->numRepetitions = kmeans->numRepetitions ; - - self->dimension = kmeans->dimension ; - self->numCenters = kmeans->numCenters ; - self->centers = NULL ; - self->centerDistances = NULL ; - - self->numTrees = kmeans->numTrees; - self->maxNumComparisons = kmeans->maxNumComparisons; - - if (kmeans->centers) { - vl_size dataSize = vl_get_type_size(self->dataType) * self->dimension * self->numCenters ; - self->centers = vl_malloc(dataSize) ; - memcpy (self->centers, kmeans->centers, dataSize) ; - } - - if (kmeans->centerDistances) { - vl_size dataSize = vl_get_type_size(self->dataType) * self->numCenters * self->numCenters ; - self->centerDistances = vl_malloc(dataSize) ; - memcpy (self->centerDistances, kmeans->centerDistances, dataSize) ; - } - - return self ; -} - -/** ------------------------------------------------------------------ - ** @brief Deletes a KMeans object - ** @param self KMeans object instance. - ** - ** The function deletes the KMeans object instance created - ** by ::vl_kmeans_new. - **/ - -VL_EXPORT void -vl_kmeans_delete (VlKMeans * self) -{ - vl_kmeans_reset (self) ; - vl_free (self) ; -} - -/* an helper structure */ -typedef struct _VlKMeansSortWrapper { - vl_uint32 * permutation ; - void const * data ; - vl_size stride ; -} VlKMeansSortWrapper ; - - -/* ---------------------------------------------------------------- */ -/* Instantiate shuffle algorithm */ - -#define VL_SHUFFLE_type vl_uindex -#define VL_SHUFFLE_prefix _vl_kmeans -#include "shuffle-def.h" - -/* #ifdef VL_KMEANS_INSTANTITATING */ -#endif - -/* ================================================================ */ -#ifdef VL_KMEANS_INSTANTIATING - -/* ---------------------------------------------------------------- */ -/* Set centers */ -/* ---------------------------------------------------------------- */ - -static void -VL_XCAT(_vl_kmeans_set_centers_, SFX) -(VlKMeans * self, - TYPE const * centers, - vl_size dimension, - vl_size numCenters) -{ - self->dimension = dimension ; - self->numCenters = numCenters ; - self->centers = vl_malloc (sizeof(TYPE) * dimension * numCenters) ; - memcpy ((TYPE*)self->centers, centers, - sizeof(TYPE) * dimension * numCenters) ; -} - -/* ---------------------------------------------------------------- */ -/* Random seeding */ -/* ---------------------------------------------------------------- */ - -static void -VL_XCAT(_vl_kmeans_init_centers_with_rand_data_, SFX) -(VlKMeans * self, - TYPE const * data, - vl_size dimension, - vl_size numData, - vl_size numCenters) -{ - vl_uindex i, j, k ; - VlRand * rand = vl_get_rand () ; - - self->dimension = dimension ; - self->numCenters = numCenters ; - self->centers = vl_malloc (sizeof(TYPE) * dimension * numCenters) ; - - { - vl_uindex * perm = vl_malloc (sizeof(vl_uindex) * numData) ; -#if (FLT == VL_TYPE_FLOAT) - VlFloatVectorComparisonFunction distFn = vl_get_vector_comparison_function_f(self->distance) ; -#else - VlDoubleVectorComparisonFunction distFn = vl_get_vector_comparison_function_d(self->distance) ; -#endif - TYPE * distances = vl_malloc (sizeof(TYPE) * numCenters) ; - - /* get a random permutation of the data point */ - for (i = 0 ; i < numData ; ++i) perm[i] = i ; - _vl_kmeans_shuffle (perm, numData, rand) ; - - for (k = 0, i = 0 ; k < numCenters ; ++ i) { - - /* compare the next data point to all centers collected so far - to detect duplicates (if there are enough left) - */ - if (numCenters - k < numData - i) { - vl_bool duplicateDetected = VL_FALSE ; - VL_XCAT(vl_eval_vector_comparison_on_all_pairs_, SFX)(distances, - dimension, - data + dimension * perm[i], 1, - (TYPE*)self->centers, k, - distFn) ; - for (j = 0 ; j < k ; ++j) { - duplicateDetected |= (distances[j] == 0) ; - } - if (duplicateDetected) continue ; - } - - /* ok, it is not a duplicate so we can accept it! */ - memcpy ((TYPE*)self->centers + dimension * k, - data + dimension * perm[i], - sizeof(TYPE) * dimension) ; - k ++ ; - } - vl_free(distances) ; - vl_free(perm) ; - } -} - -/* ---------------------------------------------------------------- */ -/* kmeans++ seeding */ -/* ---------------------------------------------------------------- */ - -static void -VL_XCAT(_vl_kmeans_init_centers_plus_plus_, SFX) -(VlKMeans * self, - TYPE const * data, - vl_size dimension, - vl_size numData, - vl_size numCenters) -{ - vl_uindex x, c ; - VlRand * rand = vl_get_rand () ; - TYPE * distances = vl_malloc (sizeof(TYPE) * numData) ; - TYPE * minDistances = vl_malloc (sizeof(TYPE) * numData) ; -#if (FLT == VL_TYPE_FLOAT) - VlFloatVectorComparisonFunction distFn = vl_get_vector_comparison_function_f(self->distance) ; -#else - VlDoubleVectorComparisonFunction distFn = vl_get_vector_comparison_function_d(self->distance) ; -#endif - - self->dimension = dimension ; - self->numCenters = numCenters ; - self->centers = vl_malloc (sizeof(TYPE) * dimension * numCenters) ; - - for (x = 0 ; x < numData ; ++x) { - minDistances[x] = (TYPE) VL_INFINITY_D ; - } - - /* select the first point at random */ - x = vl_rand_uindex (rand, numData) ; - c = 0 ; - while (1) { - TYPE energy = 0 ; - TYPE acc = 0 ; - TYPE thresh = (TYPE) vl_rand_real1 (rand) ; - - memcpy ((TYPE*)self->centers + c * dimension, - data + x * dimension, - sizeof(TYPE) * dimension) ; - - c ++ ; - if (c == numCenters) break ; - - VL_XCAT(vl_eval_vector_comparison_on_all_pairs_, SFX) - (distances, - dimension, - (TYPE*)self->centers + (c - 1) * dimension, 1, - data, numData, - distFn) ; - - for (x = 0 ; x < numData ; ++x) { - minDistances[x] = VL_MIN(minDistances[x], distances[x]) ; - energy += minDistances[x] ; - } - - for (x = 0 ; x < numData - 1 ; ++x) { - acc += minDistances[x] ; - if (acc >= thresh * energy) break ; - } - } - - vl_free(distances) ; - vl_free(minDistances) ; -} - -/* ---------------------------------------------------------------- */ -/* Quantization */ -/* ---------------------------------------------------------------- */ - -static void -VL_XCAT(_vl_kmeans_quantize_, SFX) -(VlKMeans * self, - vl_uint32 * assignments, - TYPE * distances, - TYPE const * data, - vl_size numData) -{ - vl_index i ; - -#if (FLT == VL_TYPE_FLOAT) - VlFloatVectorComparisonFunction distFn = vl_get_vector_comparison_function_f(self->distance) ; -#else - VlDoubleVectorComparisonFunction distFn = vl_get_vector_comparison_function_d(self->distance) ; -#endif - -#ifdef _OPENMP -#pragma omp parallel \ - shared(self, distances, assignments, numData, distFn, data) \ - num_threads(vl_get_max_threads()) -#endif - { - /* vl_malloc cannot be used here if mapped to MATLAB malloc */ - TYPE * distanceToCenters = malloc(sizeof(TYPE) * self->numCenters) ; - -#ifdef _OPENMP -#pragma omp for -#endif - for (i = 0 ; i < (signed)numData ; ++i) { - vl_uindex k ; - TYPE bestDistance = (TYPE) VL_INFINITY_D ; - VL_XCAT(vl_eval_vector_comparison_on_all_pairs_, SFX)(distanceToCenters, - self->dimension, - data + self->dimension * i, 1, - (TYPE*)self->centers, self->numCenters, - distFn) ; - for (k = 0 ; k < self->numCenters ; ++k) { - if (distanceToCenters[k] < bestDistance) { - bestDistance = distanceToCenters[k] ; - assignments[i] = (vl_uint32)k ; - } - } - if (distances) distances[i] = bestDistance ; - } - - free(distanceToCenters) ; - } -} - -/* ---------------------------------------------------------------- */ -/* ANN quantization */ -/* ---------------------------------------------------------------- */ - -static void -VL_XCAT(_vl_kmeans_quantize_ann_, SFX) -(VlKMeans * self, - vl_uint32 * assignments, - TYPE * distances, - TYPE const * data, - vl_size numData, - vl_bool update) -{ -#if (FLT == VL_TYPE_FLOAT) - VlFloatVectorComparisonFunction distFn = vl_get_vector_comparison_function_f(self->distance) ; -#else - VlDoubleVectorComparisonFunction distFn = vl_get_vector_comparison_function_d(self->distance) ; -#endif - - VlKDForest * forest = vl_kdforest_new(self->dataType,self->dimension,self->numTrees, self->distance) ; - vl_kdforest_set_max_num_comparisons(forest,self->maxNumComparisons); - vl_kdforest_set_thresholding_method(forest,VL_KDTREE_MEDIAN); - vl_kdforest_build(forest,self->numCenters,self->centers); - -#ifdef _OPENMP -#pragma omp parallel default(none) \ - num_threads(vl_get_max_threads()) \ - shared(self, forest, update, assignments, distances, data, numData, distFn) -#endif - { - VlKDForestNeighbor neighbor ; - VlKDForestSearcher * searcher ; - vl_index x; - -#ifdef _OPENMP -#pragma omp critical -#endif - searcher = vl_kdforest_new_searcher (forest) ; - -#ifdef _OPENMP -#pragma omp for -#endif - for(x = 0 ; x < (signed)numData ; ++x) { - vl_kdforestsearcher_query (searcher, &neighbor, 1, (TYPE const *) (data + x*self->dimension)); - - if (distances) { - if(!update) { - distances[x] = (TYPE) neighbor.distance; - assignments[x] = (vl_uint32) neighbor.index ; - } else { - TYPE prevDist = (TYPE) distFn(self->dimension, - data + self->dimension * x, - (TYPE*)self->centers + self->dimension *assignments[x]); - if (prevDist > (TYPE) neighbor.distance) { - distances[x] = (TYPE) neighbor.distance ; - assignments[x] = (vl_uint32) neighbor.index ; - } else { - distances[x] = prevDist ; - } - } - } else { - assignments[x] = (vl_uint32) neighbor.index ; - } - } /* end for */ - } /* end of parallel region */ - - vl_kdforest_delete(forest); -} - -/* ---------------------------------------------------------------- */ -/* Helper functions */ -/* ---------------------------------------------------------------- */ - -/* The sorting routine is used to find increasing permutation of each - * data dimension. This is used to quickly find the median for l1 - * distance clustering. */ - -VL_INLINE TYPE -VL_XCAT3(_vl_kmeans_, SFX, _qsort_cmp) -(VlKMeansSortWrapper * array, vl_uindex indexA, vl_uindex indexB) -{ - return - ((TYPE*)array->data) [array->permutation[indexA] * array->stride] - - - ((TYPE*)array->data) [array->permutation[indexB] * array->stride] ; -} - -VL_INLINE void -VL_XCAT3(_vl_kmeans_, SFX, _qsort_swap) -(VlKMeansSortWrapper * array, vl_uindex indexA, vl_uindex indexB) -{ - vl_uint32 tmp = array->permutation[indexA] ; - array->permutation[indexA] = array->permutation[indexB] ; - array->permutation[indexB] = tmp ; -} - -#define VL_QSORT_prefix VL_XCAT3(_vl_kmeans_, SFX, _qsort) -#define VL_QSORT_array VlKMeansSortWrapper* -#define VL_QSORT_cmp VL_XCAT3(_vl_kmeans_, SFX, _qsort_cmp) -#define VL_QSORT_swap VL_XCAT3(_vl_kmeans_, SFX, _qsort_swap) -#include "qsort-def.h" - -static void -VL_XCAT(_vl_kmeans_sort_data_helper_, SFX) -(VlKMeans * self, vl_uint32 * permutations, TYPE const * data, vl_size numData) -{ - vl_uindex d, x ; - - for (d = 0 ; d < self->dimension ; ++d) { - VlKMeansSortWrapper array ; - array.permutation = permutations + d * numData ; - array.data = data + d ; - array.stride = self->dimension ; - for (x = 0 ; x < numData ; ++x) { - array.permutation[x] = (vl_uint32)x ; - } - VL_XCAT3(_vl_kmeans_, SFX, _qsort_sort)(&array, numData) ; - } -} - -/* ---------------------------------------------------------------- */ -/* Lloyd refinement */ -/* ---------------------------------------------------------------- */ - -static double -VL_XCAT(_vl_kmeans_refine_centers_lloyd_, SFX) -(VlKMeans * self, - TYPE const * data, - vl_size numData) -{ - vl_size c, d, x, iteration ; - double previousEnergy = VL_INFINITY_D ; - double initialEnergy = VL_INFINITY_D ; - double energy ; - TYPE * distances = vl_malloc (sizeof(TYPE) * numData) ; - - vl_uint32 * assignments = vl_malloc (sizeof(vl_uint32) * numData) ; - vl_size * clusterMasses = vl_malloc (sizeof(vl_size) * numData) ; - vl_uint32 * permutations = NULL ; - vl_size * numSeenSoFar = NULL ; - VlRand * rand = vl_get_rand () ; - vl_size totNumRestartedCenters = 0 ; - vl_size numRestartedCenters = 0 ; - - if (self->distance == VlDistanceL1) { - permutations = vl_malloc(sizeof(vl_uint32) * numData * self->dimension) ; - numSeenSoFar = vl_malloc(sizeof(vl_size) * self->numCenters) ; - VL_XCAT(_vl_kmeans_sort_data_helper_, SFX)(self, permutations, data, numData) ; - } - - for (energy = VL_INFINITY_D, - iteration = 0; - 1 ; - ++ iteration) { - - /* assign data to cluters */ - VL_XCAT(_vl_kmeans_quantize_, SFX)(self, assignments, distances, data, numData) ; - - /* compute energy */ - energy = 0 ; - for (x = 0 ; x < numData ; ++x) energy += distances[x] ; - if (self->verbosity) { - VL_PRINTF("kmeans: Lloyd iter %d: energy = %g\n", iteration, - energy) ; - } - - /* check termination conditions */ - if (iteration >= self->maxNumIterations) { - if (self->verbosity) { - VL_PRINTF("kmeans: Lloyd terminating because maximum number of iterations reached\n") ; - } - break ; - } - if (energy == previousEnergy) { - if (self->verbosity) { - VL_PRINTF("kmeans: Lloyd terminating because the algorithm fully converged\n") ; - } - break ; - } - - if (iteration == 0) { - initialEnergy = energy ; - } else { - double eps = (previousEnergy - energy) / (initialEnergy - energy) ; - if (eps < self->minEnergyVariation) { - if (self->verbosity) { - VL_PRINTF("kmeans: ANN terminating because the energy relative variation was less than %f\n", self->minEnergyVariation) ; - } - break ; - } - } - - /* begin next iteration */ - previousEnergy = energy ; - - /* update clusters */ - memset(clusterMasses, 0, sizeof(vl_size) * numData) ; - for (x = 0 ; x < numData ; ++x) { - clusterMasses[assignments[x]] ++ ; - } - - numRestartedCenters = 0 ; - switch (self->distance) { - case VlDistanceL2: - memset(self->centers, 0, sizeof(TYPE) * self->dimension * self->numCenters) ; - for (x = 0 ; x < numData ; ++x) { - TYPE * cpt = (TYPE*)self->centers + assignments[x] * self->dimension ; - TYPE const * xpt = data + x * self->dimension ; - for (d = 0 ; d < self->dimension ; ++d) { - cpt[d] += xpt[d] ; - } - } - for (c = 0 ; c < self->numCenters ; ++c) { - TYPE * cpt = (TYPE*)self->centers + c * self->dimension ; - if (clusterMasses[c] > 0) { - TYPE mass = clusterMasses[c] ; - for (d = 0 ; d < self->dimension ; ++d) { - cpt[d] /= mass ; - } - } else { - vl_uindex x = vl_rand_uindex(rand, numData) ; - numRestartedCenters ++ ; - for (d = 0 ; d < self->dimension ; ++d) { - cpt[d] = data[x * self->dimension + d] ; - } - } - } - break ; - case VlDistanceL1: - for (d = 0 ; d < self->dimension ; ++d) { - vl_uint32 * perm = permutations + d * numData ; - memset(numSeenSoFar, 0, sizeof(vl_size) * self->numCenters) ; - for (x = 0; x < numData ; ++x) { - c = assignments[perm[x]] ; - if (2 * numSeenSoFar[c] < clusterMasses[c]) { - ((TYPE*)self->centers) [d + c * self->dimension] = - data [d + perm[x] * self->dimension] ; - } - numSeenSoFar[c] ++ ; - } - /* restart the centers as required */ - for (c = 0 ; c < self->numCenters ; ++c) { - if (clusterMasses[c] == 0) { - TYPE * cpt = (TYPE*)self->centers + c * self->dimension ; - vl_uindex x = vl_rand_uindex(rand, numData) ; - numRestartedCenters ++ ; - for (d = 0 ; d < self->dimension ; ++d) { - cpt[d] = data[x * self->dimension + d] ; - } - } - } - } - break ; - default: - abort(); - } /* done compute centers */ - - totNumRestartedCenters += numRestartedCenters ; - if (self->verbosity && numRestartedCenters) { - VL_PRINTF("kmeans: Lloyd iter %d: restarted %d centers\n", iteration, - numRestartedCenters) ; - } - } /* next Lloyd iteration */ - - if (permutations) { - vl_free(permutations) ; - } - if (numSeenSoFar) { - vl_free(numSeenSoFar) ; - } - vl_free(distances) ; - vl_free(assignments) ; - vl_free(clusterMasses) ; - return energy ; -} - -static double -VL_XCAT(_vl_kmeans_update_center_distances_, SFX) -(VlKMeans * self) -{ -#if (FLT == VL_TYPE_FLOAT) - VlFloatVectorComparisonFunction distFn = vl_get_vector_comparison_function_f(self->distance) ; -#else - VlDoubleVectorComparisonFunction distFn = vl_get_vector_comparison_function_d(self->distance) ; -#endif - - if (! self->centerDistances) { - self->centerDistances = vl_malloc (sizeof(TYPE) * - self->numCenters * - self->numCenters) ; - } - VL_XCAT(vl_eval_vector_comparison_on_all_pairs_, SFX)(self->centerDistances, - self->dimension, - self->centers, self->numCenters, - NULL, 0, - distFn) ; - return self->numCenters * (self->numCenters - 1) / 2 ; -} - -static double -VL_XCAT(_vl_kmeans_refine_centers_ann_, SFX) -(VlKMeans * self, - TYPE const * data, - vl_size numData) -{ - vl_size c, d, x, iteration ; - double initialEnergy = VL_INFINITY_D ; - double previousEnergy = VL_INFINITY_D ; - double energy ; - - vl_uint32 * permutations = NULL ; - vl_size * numSeenSoFar = NULL ; - VlRand * rand = vl_get_rand () ; - vl_size totNumRestartedCenters = 0 ; - vl_size numRestartedCenters = 0 ; - - vl_uint32 * assignments = vl_malloc (sizeof(vl_uint32) * numData) ; - vl_size * clusterMasses = vl_malloc (sizeof(vl_size) * numData) ; - TYPE * distances = vl_malloc (sizeof(TYPE) * numData) ; - - if (self->distance == VlDistanceL1) { - permutations = vl_malloc(sizeof(vl_uint32) * numData * self->dimension) ; - numSeenSoFar = vl_malloc(sizeof(vl_size) * self->numCenters) ; - VL_XCAT(_vl_kmeans_sort_data_helper_, SFX)(self, permutations, data, numData) ; - } - - for (energy = VL_INFINITY_D, - iteration = 0; - 1 ; - ++ iteration) { - - /* assign data to cluters */ - VL_XCAT(_vl_kmeans_quantize_ann_, SFX)(self, assignments, distances, data, numData, iteration > 0) ; - - /* compute energy */ - energy = 0 ; - for (x = 0 ; x < numData ; ++x) energy += distances[x] ; - if (self->verbosity) { - VL_PRINTF("kmeans: ANN iter %d: energy = %g\n", iteration, - energy) ; - } - - /* check termination conditions */ - if (iteration >= self->maxNumIterations) { - if (self->verbosity) { - VL_PRINTF("kmeans: ANN terminating because the maximum number of iterations has been reached\n") ; - } - break ; - } - if (energy == previousEnergy) { - if (self->verbosity) { - VL_PRINTF("kmeans: ANN terminating because the algorithm fully converged\n") ; - } - break ; - } - - if (iteration == 0) { - initialEnergy = energy ; - } else { - double eps = (previousEnergy - energy) / (initialEnergy - energy) ; - if (eps < self->minEnergyVariation) { - if (self->verbosity) { - VL_PRINTF("kmeans: ANN terminating because the energy relative variation was less than %f\n", self->minEnergyVariation) ; - } - break ; - } - } - - /* begin next iteration */ - previousEnergy = energy ; - - /* update clusters */ - memset(clusterMasses, 0, sizeof(vl_size) * numData) ; - for (x = 0 ; x < numData ; ++x) { - clusterMasses[assignments[x]] ++ ; - } - - numRestartedCenters = 0 ; - switch (self->distance) { - case VlDistanceL2: - memset(self->centers, 0, sizeof(TYPE) * self->dimension * self->numCenters) ; - for (x = 0 ; x < numData ; ++x) { - TYPE * cpt = (TYPE*)self->centers + assignments[x] * self->dimension ; - TYPE const * xpt = data + x * self->dimension ; - for (d = 0 ; d < self->dimension ; ++d) { - cpt[d] += xpt[d] ; - } - } - for (c = 0 ; c < self->numCenters ; ++c) { - TYPE * cpt = (TYPE*)self->centers + c * self->dimension ; - if (clusterMasses[c] > 0) { - TYPE mass = clusterMasses[c] ; - for (d = 0 ; d < self->dimension ; ++d) { - cpt[d] /= mass ; - } - } else { - vl_uindex x = vl_rand_uindex(rand, numData) ; - numRestartedCenters ++ ; - for (d = 0 ; d < self->dimension ; ++d) { - cpt[d] = data[x * self->dimension + d] ; - } - } - } - break ; - case VlDistanceL1: - for (d = 0 ; d < self->dimension ; ++d) { - vl_uint32 * perm = permutations + d * numData ; - memset(numSeenSoFar, 0, sizeof(vl_size) * self->numCenters) ; - for (x = 0; x < numData ; ++x) { - c = assignments[perm[x]] ; - if (2 * numSeenSoFar[c] < clusterMasses[c]) { - ((TYPE*)self->centers) [d + c * self->dimension] = - data [d + perm[x] * self->dimension] ; - } - numSeenSoFar[c] ++ ; - } - /* restart the centers as required */ - for (c = 0 ; c < self->numCenters ; ++c) { - if (clusterMasses[c] == 0) { - TYPE * cpt = (TYPE*)self->centers + c * self->dimension ; - vl_uindex x = vl_rand_uindex(rand, numData) ; - numRestartedCenters ++ ; - for (d = 0 ; d < self->dimension ; ++d) { - cpt[d] = data[x * self->dimension + d] ; - } - } - } - } - break ; - default: - VL_PRINT("bad distance set: %d\n",self->distance); - abort(); - } /* done compute centers */ - - totNumRestartedCenters += numRestartedCenters ; - if (self->verbosity && numRestartedCenters) { - VL_PRINTF("kmeans: ANN iter %d: restarted %d centers\n", iteration, - numRestartedCenters) ; - } - } - - if (permutations) { - vl_free(permutations) ; - } - if (numSeenSoFar) { - vl_free(numSeenSoFar) ; - } - - vl_free(distances) ; - vl_free(assignments) ; - vl_free(clusterMasses) ; - return energy ; -} - -/* ---------------------------------------------------------------- */ -/* Elkan refinement */ -/* ---------------------------------------------------------------- */ - -static double -VL_XCAT(_vl_kmeans_refine_centers_elkan_, SFX) -(VlKMeans * self, - TYPE const * data, - vl_size numData) -{ - vl_size d, iteration ; - vl_index x ; - vl_uint32 c, j ; - vl_bool allDone ; - TYPE * distances = vl_malloc (sizeof(TYPE) * numData) ; - vl_uint32 * assignments = vl_malloc (sizeof(vl_uint32) * numData) ; - vl_size * clusterMasses = vl_malloc (sizeof(vl_size) * numData) ; - VlRand * rand = vl_get_rand () ; - -#if (FLT == VL_TYPE_FLOAT) - VlFloatVectorComparisonFunction distFn = vl_get_vector_comparison_function_f(self->distance) ; -#else - VlDoubleVectorComparisonFunction distFn = vl_get_vector_comparison_function_d(self->distance) ; -#endif - - TYPE * nextCenterDistances = vl_malloc (sizeof(TYPE) * self->numCenters) ; - TYPE * pointToClosestCenterUB = vl_malloc (sizeof(TYPE) * numData) ; - vl_bool * pointToClosestCenterUBIsStrict = vl_malloc (sizeof(vl_bool) * numData) ; - TYPE * pointToCenterLB = vl_malloc (sizeof(TYPE) * numData * self->numCenters) ; - TYPE * newCenters = vl_malloc(sizeof(TYPE) * self->dimension * self->numCenters) ; - TYPE * centerToNewCenterDistances = vl_malloc (sizeof(TYPE) * self->numCenters) ; - - vl_uint32 * permutations = NULL ; - vl_size * numSeenSoFar = NULL ; - - double energy ; - - vl_size totDistanceComputationsToInit = 0 ; - vl_size totDistanceComputationsToRefreshUB = 0 ; - vl_size totDistanceComputationsToRefreshLB = 0 ; - vl_size totDistanceComputationsToRefreshCenterDistances = 0 ; - vl_size totDistanceComputationsToNewCenters = 0 ; - vl_size totDistanceComputationsToFinalize = 0 ; - vl_size totNumRestartedCenters = 0 ; - - if (self->distance == VlDistanceL1) { - permutations = vl_malloc(sizeof(vl_uint32) * numData * self->dimension) ; - numSeenSoFar = vl_malloc(sizeof(vl_size) * self->numCenters) ; - VL_XCAT(_vl_kmeans_sort_data_helper_, SFX)(self, permutations, data, numData) ; - } - - /* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ */ - /* Initialization */ - /* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ */ - - /* An iteration is: get_new_centers + reassign + get_energy. - This counts as iteration 0, where get_new_centers is assumed - to be performed before calling the train function by - the initialization function */ - - /* update distances between centers */ - totDistanceComputationsToInit += - VL_XCAT(_vl_kmeans_update_center_distances_, SFX)(self) ; - - /* assigmen points to the initial centers and initialize bounds */ - memset(pointToCenterLB, 0, sizeof(TYPE) * self->numCenters * numData) ; - for (x = 0 ; x < (signed)numData ; ++x) { - TYPE distance ; - - /* do the first center */ - assignments[x] = 0 ; - distance = distFn(self->dimension, - data + x * self->dimension, - (TYPE*)self->centers + 0) ; - pointToClosestCenterUB[x] = distance ; - pointToClosestCenterUBIsStrict[x] = VL_TRUE ; - pointToCenterLB[0 + x * self->numCenters] = distance ; - totDistanceComputationsToInit += 1 ; - - /* do other centers */ - for (c = 1 ; c < self->numCenters ; ++c) { - - /* Can skip if the center assigned so far is twice as close - as its distance to the center under consideration */ - - if (((self->distance == VlDistanceL1) ? 2.0 : 4.0) * - pointToClosestCenterUB[x] <= - ((TYPE*)self->centerDistances) - [c + assignments[x] * self->numCenters]) { - continue ; - } - - distance = distFn(self->dimension, - data + x * self->dimension, - (TYPE*)self->centers + c * self->dimension) ; - pointToCenterLB[c + x * self->numCenters] = distance ; - totDistanceComputationsToInit += 1 ; - if (distance < pointToClosestCenterUB[x]) { - pointToClosestCenterUB[x] = distance ; - assignments[x] = c ; - } - } - } - - /* compute UB on energy */ - energy = 0 ; - for (x = 0 ; x < (signed)numData ; ++x) { - energy += pointToClosestCenterUB[x] ; - } - - if (self->verbosity) { - VL_PRINTF("kmeans: Elkan iter 0: energy = %g, dist. calc. = %d\n", - energy, totDistanceComputationsToInit) ; - } - - /* #define SANITY*/ -#ifdef SANITY - { - int xx ; - int cc ; - TYPE tol = 1e-5 ; - VL_PRINTF("inconsistencies after initial assignments:\n"); - for (xx = 0 ; xx < numData ; ++xx) { - for (cc = 0 ; cc < self->numCenters ; ++cc) { - TYPE a = pointToCenterLB[cc + xx * self->numCenters] ; - TYPE b = distFn(self->dimension, - data + self->dimension * xx, - (TYPE*)self->centers + self->dimension * cc) ; - if (cc == assignments[xx]) { - TYPE z = pointToClosestCenterUB[xx] ; - if (z+tolb+tol) VL_PRINTF("LB %d %d = %f > %f\n", - cc, xx, a, b) ; - } - } - } -#endif - - /* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ */ - /* Iterations */ - /* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ */ - - for (iteration = 1 ; 1; ++iteration) { - - vl_size numDistanceComputationsToRefreshUB = 0 ; - vl_size numDistanceComputationsToRefreshLB = 0 ; - vl_size numDistanceComputationsToRefreshCenterDistances = 0 ; - vl_size numDistanceComputationsToNewCenters = 0 ; - vl_size numRestartedCenters = 0 ; - - /* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ */ - /* Compute new centers */ - /* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ */ - - memset(clusterMasses, 0, sizeof(vl_size) * numData) ; - for (x = 0 ; x < (signed)numData ; ++x) { - clusterMasses[assignments[x]] ++ ; - } - - switch (self->distance) { - case VlDistanceL2: - memset(newCenters, 0, sizeof(TYPE) * self->dimension * self->numCenters) ; - for (x = 0 ; x < (signed)numData ; ++x) { - TYPE * cpt = newCenters + assignments[x] * self->dimension ; - TYPE const * xpt = data + x * self->dimension ; - for (d = 0 ; d < self->dimension ; ++d) { - cpt[d] += xpt[d] ; - } - } - for (c = 0 ; c < self->numCenters ; ++c) { - TYPE * cpt = newCenters + c * self->dimension ; - if (clusterMasses[c] > 0) { - TYPE mass = clusterMasses[c] ; - for (d = 0 ; d < self->dimension ; ++d) { - cpt[d] /= mass ; - } - } else { - /* restart the center */ - vl_uindex x = vl_rand_uindex(rand, numData) ; - numRestartedCenters ++ ; - for (d = 0 ; d < self->dimension ; ++d) { - cpt[d] = data[x * self->dimension + d] ; - } - } - } - break ; - case VlDistanceL1: - for (d = 0 ; d < self->dimension ; ++d) { - vl_uint32 * perm = permutations + d * numData ; - memset(numSeenSoFar, 0, sizeof(vl_size) * self->numCenters) ; - for (x = 0; x < (signed)numData ; ++x) { - c = assignments[perm[x]] ; - if (2 * numSeenSoFar[c] < clusterMasses[c]) { - newCenters [d + c * self->dimension] = - data [d + perm[x] * self->dimension] ; - } - numSeenSoFar[c] ++ ; - } - } - /* restart the centers as required */ - for (c = 0 ; c < self->numCenters ; ++c) { - if (clusterMasses[c] == 0) { - TYPE * cpt = newCenters + c * self->dimension ; - vl_uindex x = vl_rand_uindex(rand, numData) ; - numRestartedCenters ++ ; - for (d = 0 ; d < self->dimension ; ++d) { - cpt[d] = data[x * self->dimension + d] ; - } - } - } - break ; - default: - abort(); - } /* done compute centers */ - - /* compute the distance from the old centers to the new centers */ - for (c = 0 ; c < self->numCenters ; ++c) { - TYPE distance = distFn(self->dimension, - newCenters + c * self->dimension, - (TYPE*)self->centers + c * self->dimension) ; - centerToNewCenterDistances[c] = distance ; - numDistanceComputationsToNewCenters += 1 ; - } - - /* make the new centers current */ - { - TYPE * tmp = self->centers ; - self->centers = newCenters ; - newCenters = tmp ; - } - - /* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ */ - /* Reassign points to a centers */ - /* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ */ - - /* - Update distances between centers. - */ - numDistanceComputationsToRefreshCenterDistances - += VL_XCAT(_vl_kmeans_update_center_distances_, SFX)(self) ; - - for (c = 0 ; c < self->numCenters ; ++c) { - nextCenterDistances[c] = (TYPE) VL_INFINITY_D ; - for (j = 0 ; j < self->numCenters ; ++j) { - if (j == c) continue ; - nextCenterDistances[c] = VL_MIN(nextCenterDistances[c], - ((TYPE*)self->centerDistances) - [j + c * self->numCenters]) ; - } - } - - /* - Update upper bounds on point-to-closest-center distances - based on the center variation. - */ - for (x = 0 ; x < (signed)numData ; ++x) { - TYPE a = pointToClosestCenterUB[x] ; - TYPE b = centerToNewCenterDistances[assignments[x]] ; - if (self->distance == VlDistanceL1) { - pointToClosestCenterUB[x] = a + b ; - } else { -#if (FLT == VL_TYPE_FLOAT) - TYPE sqrtab = sqrtf (a * b) ; -#else - TYPE sqrtab = sqrt (a * b) ; -#endif - pointToClosestCenterUB[x] = a + b + 2.0 * sqrtab ; - } - pointToClosestCenterUBIsStrict[x] = VL_FALSE ; - } - - /* - Update lower bounds on point-to-center distances - based on the center variation. - */ - -#if defined(_OPENMP) -#pragma omp parallel for default(shared) private(x,c) num_threads(vl_get_max_threads()) -#endif - for (x = 0 ; x < (signed)numData ; ++x) { - for (c = 0 ; c < self->numCenters ; ++c) { - TYPE a = pointToCenterLB[c + x * self->numCenters] ; - TYPE b = centerToNewCenterDistances[c] ; - if (a < b) { - pointToCenterLB[c + x * self->numCenters] = 0 ; - } else { - if (self->distance == VlDistanceL1) { - pointToCenterLB[c + x * self->numCenters] = a - b ; - } else { -#if (FLT == VL_TYPE_FLOAT) - TYPE sqrtab = sqrtf (a * b) ; -#else - TYPE sqrtab = sqrt (a * b) ; -#endif - pointToCenterLB[c + x * self->numCenters] = a + b - 2.0 * sqrtab ; - } - } - } - } - -#ifdef SANITY - { - int xx ; - int cc ; - TYPE tol = 1e-5 ; - VL_PRINTF("inconsistencies before assignments:\n"); - for (xx = 0 ; xx < numData ; ++xx) { - for (cc = 0 ; cc < self->numCenters ; ++cc) { - TYPE a = pointToCenterLB[cc + xx * self->numCenters] ; - TYPE b = distFn(self->dimension, - data + self->dimension * xx, - (TYPE*)self->centers + self->dimension * cc) ; - if (cc == assignments[xx]) { - TYPE z = pointToClosestCenterUB[xx] ; - if (z+tolb+tol) VL_PRINTF("LB %d %d = %f > %f (assign = %d)\n", - cc, xx, a, b, assignments[xx]) ; - } - } - } -#endif - - /* - Scan the data and do the reassignments. Use the bounds to - skip as many point-to-center distance calculations as possible. - */ - allDone = VL_TRUE ; - -#if defined(_OPENMP) -#pragma omp parallel for \ - default(none) \ - shared(self,numData, \ - pointToClosestCenterUB,pointToCenterLB, \ - nextCenterDistances,pointToClosestCenterUBIsStrict, \ - assignments,data,distFn,allDone) \ - private(c,x) \ - reduction(+:numDistanceComputationsToRefreshUB,numDistanceComputationsToRefreshLB) \ - num_threads(vl_get_max_threads()) -#endif - for (x = 0 ; x < (signed)numData ; ++ x) { - /* - A point x sticks with its current center assignmets[x] - the UB to d(x, c[assigmnets[x]]) is not larger than half - the distance of c[assigments[x]] to any other center c. - */ - if (((self->distance == VlDistanceL1) ? 2.0 : 4.0) * - pointToClosestCenterUB[x] <= nextCenterDistances[assignments[x]]) { - continue ; - } - - for (c = 0 ; c < self->numCenters ; ++c) { - vl_uint32 cx = assignments[x] ; - TYPE distance ; - - /* The point is not reassigned to a given center c - if either: - - 0 - c is already the assigned center - 1 - The UB of d(x, c[assignments[x]]) is smaller than half - the distance of c[assigments[x]] to c, OR - 2 - The UB of d(x, c[assignmets[x]]) is smaller than the - LB of the distance of x to c. - */ - if (cx == c) { - continue ; - } - if (((self->distance == VlDistanceL1) ? 2.0 : 4.0) * - pointToClosestCenterUB[x] <= ((TYPE*)self->centerDistances) - [c + cx * self->numCenters]) { - continue ; - } - if (pointToClosestCenterUB[x] <= pointToCenterLB - [c + x * self->numCenters]) { - continue ; - } - - /* If the UB is loose, try recomputing it and test again */ - if (! pointToClosestCenterUBIsStrict[x]) { - distance = distFn(self->dimension, - data + self->dimension * x, - (TYPE*)self->centers + self->dimension * cx) ; - pointToClosestCenterUB[x] = distance ; - pointToClosestCenterUBIsStrict[x] = VL_TRUE ; - pointToCenterLB[cx + x * self->numCenters] = distance ; - numDistanceComputationsToRefreshUB += 1 ; - - if (((self->distance == VlDistanceL1) ? 2.0 : 4.0) * - pointToClosestCenterUB[x] <= ((TYPE*)self->centerDistances) - [c + cx * self->numCenters]) { - continue ; - } - if (pointToClosestCenterUB[x] <= pointToCenterLB - [c + x * self->numCenters]) { - continue ; - } - } - - /* - Now the UB is strict (equal to d(x, assignments[x])), but - we still could not exclude that x should be reassigned to - c. We therefore compute the distance, update the LB, - and check if a reassigmnet must be made - */ - distance = distFn(self->dimension, - data + x * self->dimension, - (TYPE*)self->centers + c * self->dimension) ; - numDistanceComputationsToRefreshLB += 1 ; - pointToCenterLB[c + x * self->numCenters] = distance ; - - if (distance < pointToClosestCenterUB[x]) { - assignments[x] = c ; - pointToClosestCenterUB[x] = distance ; - allDone = VL_FALSE ; - /* the UB strict flag is already set here */ - } - - } /* assign center */ - } /* next data point */ - - - totDistanceComputationsToRefreshUB - += numDistanceComputationsToRefreshUB ; - - totDistanceComputationsToRefreshLB - += numDistanceComputationsToRefreshLB ; - - totDistanceComputationsToRefreshCenterDistances - += numDistanceComputationsToRefreshCenterDistances ; - - totDistanceComputationsToNewCenters - += numDistanceComputationsToNewCenters ; - - totNumRestartedCenters - += numRestartedCenters ; - -#ifdef SANITY - { - int xx ; - int cc ; - TYPE tol = 1e-5 ; - VL_PRINTF("inconsistencies after assignments:\n"); - for (xx = 0 ; xx < numData ; ++xx) { - for (cc = 0 ; cc < self->numCenters ; ++cc) { - TYPE a = pointToCenterLB[cc + xx * self->numCenters] ; - TYPE b = distFn(self->dimension, - data + self->dimension * xx, - (TYPE*)self->centers + self->dimension * cc) ; - if (cc == assignments[xx]) { - TYPE z = pointToClosestCenterUB[xx] ; - if (z+tolb+tol) VL_PRINTF("LB %d %d = %f > %f (assign = %d)\n", - cc, xx, a, b, assignments[xx]) ; - } - } - } -#endif - - /* compute UB on energy */ - energy = 0 ; - for (x = 0 ; x < (signed)numData ; ++x) { - energy += pointToClosestCenterUB[x] ; - } - - if (self->verbosity) { - vl_size numDistanceComputations = - numDistanceComputationsToRefreshUB + - numDistanceComputationsToRefreshLB + - numDistanceComputationsToRefreshCenterDistances + - numDistanceComputationsToNewCenters ; - VL_PRINTF("kmeans: Elkan iter %d: energy <= %g, dist. calc. = %d\n", - iteration, - energy, - numDistanceComputations) ; - if (numRestartedCenters) { - VL_PRINTF("kmeans: Elkan iter %d: restarted %d centers\n", - iteration, - energy, - numRestartedCenters) ; - } - if (self->verbosity > 1) { - VL_PRINTF("kmeans: Elkan iter %d: total dist. calc. per type: " - "UB: %.1f%% (%d), LB: %.1f%% (%d), " - "intra_center: %.1f%% (%d), " - "new_center: %.1f%% (%d)\n", - iteration, - 100.0 * numDistanceComputationsToRefreshUB / numDistanceComputations, - numDistanceComputationsToRefreshUB, - 100.0 *numDistanceComputationsToRefreshLB / numDistanceComputations, - numDistanceComputationsToRefreshLB, - 100.0 * numDistanceComputationsToRefreshCenterDistances / numDistanceComputations, - numDistanceComputationsToRefreshCenterDistances, - 100.0 * numDistanceComputationsToNewCenters / numDistanceComputations, - numDistanceComputationsToNewCenters) ; - } - } - - /* check termination conditions */ - if (iteration >= self->maxNumIterations) { - if (self->verbosity) { - VL_PRINTF("kmeans: Elkan terminating because maximum number of iterations reached\n") ; - } - break ; - } - if (allDone) { - if (self->verbosity) { - VL_PRINTF("kmeans: Elkan terminating because the algorithm fully converged\n") ; - } - break ; - } - - } /* next Elkan iteration */ - - /* compute true energy */ - energy = 0 ; - for (x = 0 ; x < (signed)numData ; ++ x) { - vl_uindex cx = assignments [x] ; - energy += distFn(self->dimension, - data + self->dimension * x, - (TYPE*)self->centers + self->dimension * cx) ; - totDistanceComputationsToFinalize += 1 ; - } - - { - vl_size totDistanceComputations = - totDistanceComputationsToInit + - totDistanceComputationsToRefreshUB + - totDistanceComputationsToRefreshLB + - totDistanceComputationsToRefreshCenterDistances + - totDistanceComputationsToNewCenters + - totDistanceComputationsToFinalize ; - - double saving = (double)totDistanceComputations - / (iteration * self->numCenters * numData) ; - - if (self->verbosity) { - VL_PRINTF("kmeans: Elkan: total dist. calc.: %d (%.2f %% of Lloyd)\n", - totDistanceComputations, saving * 100.0) ; - if (totNumRestartedCenters) { - VL_PRINTF("kmeans: Elkan: there have been %d restarts\n", - totNumRestartedCenters) ; - } - } - - if (self->verbosity > 1) { - VL_PRINTF("kmeans: Elkan: total dist. calc. per type: " - "init: %.1f%% (%d), UB: %.1f%% (%d), LB: %.1f%% (%d), " - "intra_center: %.1f%% (%d), " - "new_center: %.1f%% (%d), " - "finalize: %.1f%% (%d)\n", - 100.0 * totDistanceComputationsToInit / totDistanceComputations, - totDistanceComputationsToInit, - 100.0 * totDistanceComputationsToRefreshUB / totDistanceComputations, - totDistanceComputationsToRefreshUB, - 100.0 *totDistanceComputationsToRefreshLB / totDistanceComputations, - totDistanceComputationsToRefreshLB, - 100.0 * totDistanceComputationsToRefreshCenterDistances / totDistanceComputations, - totDistanceComputationsToRefreshCenterDistances, - 100.0 * totDistanceComputationsToNewCenters / totDistanceComputations, - totDistanceComputationsToNewCenters, - 100.0 * totDistanceComputationsToFinalize / totDistanceComputations, - totDistanceComputationsToFinalize) ; - } - } - - if (permutations) { - vl_free(permutations) ; - } - if (numSeenSoFar) { - vl_free(numSeenSoFar) ; - } - - vl_free(distances) ; - vl_free(assignments) ; - vl_free(clusterMasses) ; - - vl_free(nextCenterDistances) ; - vl_free(pointToClosestCenterUB) ; - vl_free(pointToClosestCenterUBIsStrict) ; - vl_free(pointToCenterLB) ; - vl_free(newCenters) ; - vl_free(centerToNewCenterDistances) ; - - return energy ; -} - -/* ---------------------------------------------------------------- */ -static double -VL_XCAT(_vl_kmeans_refine_centers_, SFX) -(VlKMeans * self, - TYPE const * data, - vl_size numData) -{ - switch (self->algorithm) { - case VlKMeansLloyd: - return - VL_XCAT(_vl_kmeans_refine_centers_lloyd_, SFX)(self, data, numData) ; - break ; - case VlKMeansElkan: - return - VL_XCAT(_vl_kmeans_refine_centers_elkan_, SFX)(self, data, numData) ; - break ; - case VlKMeansANN: - return - VL_XCAT(_vl_kmeans_refine_centers_ann_, SFX)(self, data, numData) ; - break ; - default: - abort() ; - } -} - -/* VL_KMEANS_INSTANTIATING */ -#else - -#ifndef __DOXYGEN__ -#define FLT VL_TYPE_FLOAT -#define TYPE float -#define SFX f -#define VL_KMEANS_INSTANTIATING -#include "kmeans.c" - -#define FLT VL_TYPE_DOUBLE -#define TYPE double -#define SFX d -#define VL_KMEANS_INSTANTIATING -#include "kmeans.c" -#endif - -/* VL_KMEANS_INSTANTIATING */ -#endif - -/* ================================================================ */ -#ifndef VL_KMEANS_INSTANTIATING - -/** ------------------------------------------------------------------ - ** @brief Set centers - ** @param self KMeans object. - ** @param centers centers to copy. - ** @param dimension data dimension. - ** @param numCenters number of centers. - **/ - -VL_EXPORT void -vl_kmeans_set_centers -(VlKMeans * self, - void const * centers, - vl_size dimension, - vl_size numCenters) -{ - vl_kmeans_reset (self) ; - - switch (self->dataType) { - case VL_TYPE_FLOAT : - _vl_kmeans_set_centers_f - (self, (float const *)centers, dimension, numCenters) ; - break ; - case VL_TYPE_DOUBLE : - _vl_kmeans_set_centers_d - (self, (double const *)centers, dimension, numCenters) ; - break ; - default: - abort() ; - } -} - -/** ------------------------------------------------------------------ - ** @brief init centers by randomly sampling data - ** @param self KMeans object. - ** @param data data to sample from. - ** @param dimension data dimension. - ** @param numData nmber of data points. - ** @param numCenters number of centers. - ** - ** The function inits the KMeans centers by randomly sampling - ** the data @a data. - **/ - -VL_EXPORT void -vl_kmeans_init_centers_with_rand_data -(VlKMeans * self, - void const * data, - vl_size dimension, - vl_size numData, - vl_size numCenters) -{ - vl_kmeans_reset (self) ; - - switch (self->dataType) { - case VL_TYPE_FLOAT : - _vl_kmeans_init_centers_with_rand_data_f - (self, (float const *)data, dimension, numData, numCenters) ; - break ; - case VL_TYPE_DOUBLE : - _vl_kmeans_init_centers_with_rand_data_d - (self, (double const *)data, dimension, numData, numCenters) ; - break ; - default: - abort() ; - } -} - -/** ------------------------------------------------------------------ - ** @brief Seed centers by the KMeans++ algorithm - ** @param self KMeans object. - ** @param data data to sample from. - ** @param dimension data dimension. - ** @param numData nmber of data points. - ** @param numCenters number of centers. - **/ - -VL_EXPORT void -vl_kmeans_init_centers_plus_plus -(VlKMeans * self, - void const * data, - vl_size dimension, - vl_size numData, - vl_size numCenters) -{ - vl_kmeans_reset (self) ; - - switch (self->dataType) { - case VL_TYPE_FLOAT : - _vl_kmeans_init_centers_plus_plus_f - (self, (float const *)data, dimension, numData, numCenters) ; - break ; - case VL_TYPE_DOUBLE : - _vl_kmeans_init_centers_plus_plus_d - (self, (double const *)data, dimension, numData, numCenters) ; - break ; - default: - abort() ; - } -} - -/** ------------------------------------------------------------------ - ** @brief Quantize data - ** @param self KMeans object. - ** @param assignments data to closest center assignments (output). - ** @param distances data to closest center distance (output). - ** @param data data to quantize. - ** @param numData number of data points to quantize. - **/ - -VL_EXPORT void -vl_kmeans_quantize -(VlKMeans * self, - vl_uint32 * assignments, - void * distances, - void const * data, - vl_size numData) -{ - switch (self->dataType) { - case VL_TYPE_FLOAT : - _vl_kmeans_quantize_f - (self, assignments, distances, (float const *)data, numData) ; - break ; - case VL_TYPE_DOUBLE : - _vl_kmeans_quantize_d - (self, assignments, distances, (double const *)data, numData) ; - break ; - default: - abort() ; - } -} - -/** ------------------------------------------------------------------ - ** @brief Quantize data using approximate nearest neighbours (ANN). - ** @param self KMeans object. - ** @param assignments data to centers assignments (output). - ** @param distances data to closes center distance (output) - ** @param data data to quantize. - ** @param numData number of data points. - ** @param update choose wether to update current assignments. - ** - ** The function uses an ANN procedure to compute the approximate - ** nearest neighbours of the input data point. - ** - ** Setting @a update to ::VL_TRUE will cause the algorithm - ** to *update existing assignments*. This means that each - ** element of @a assignments and @a distances is updated ony if the - ** ANN procedure can find a better assignment of the existing one. - **/ - -VL_EXPORT void -vl_kmeans_quantize_ann -(VlKMeans * self, - vl_uint32 * assignments, - void * distances, - void const * data, - vl_size numData, - vl_bool update) -{ - switch (self->dataType) { - case VL_TYPE_FLOAT : - _vl_kmeans_quantize_ann_f - (self, assignments, distances, (float const *)data, numData, update) ; - break ; - case VL_TYPE_DOUBLE : - _vl_kmeans_quantize_ann_d - (self, assignments, distances, (double const *)data, numData, update) ; - break ; - default: - abort() ; - } -} - -/** ------------------------------------------------------------------ - ** @brief Refine center locations. - ** @param self KMeans object. - ** @param data data to quantize. - ** @param numData number of data points. - ** @return K-means energy at the end of optimization. - ** - ** The function calls the underlying K-means quantization algorithm - ** (@ref VlKMeansAlgorithm) to quantize the specified data @a data. - ** The function assumes that the cluster centers have already - ** been assigned by using one of the seeding functions, or by - ** setting them. - **/ - -VL_EXPORT double -vl_kmeans_refine_centers -(VlKMeans * self, - void const * data, - vl_size numData) -{ - assert (self->centers) ; - - switch (self->dataType) { - case VL_TYPE_FLOAT : - return - _vl_kmeans_refine_centers_f - (self, (float const *)data, numData) ; - case VL_TYPE_DOUBLE : - return - _vl_kmeans_refine_centers_d - (self, (double const *)data, numData) ; - default: - abort() ; - } -} - - -/** ------------------------------------------------------------------ - ** @brief Cluster data. - ** @param self KMeans object. - ** @param data data to quantize. - ** @param dimension data dimension. - ** @param numData number of data points. - ** @param numCenters number of clusters. - ** @return K-means energy at the end of optimization. - ** - ** The function initializes the centers by using the initialization - ** algorithm set by ::vl_kmeans_set_initialization and refines them - ** by the quantization algorithm set by ::vl_kmeans_set_algorithm. - ** The process is repeated one or more times (see - ** ::vl_kmeans_set_num_repetitions) and the resutl with smaller - ** energy is retained. - **/ - -VL_EXPORT double -vl_kmeans_cluster (VlKMeans * self, - void const * data, - vl_size dimension, - vl_size numData, - vl_size numCenters) -{ - vl_uindex repetition ; - double bestEnergy = VL_INFINITY_D ; - void * bestCenters = NULL ; - - for (repetition = 0 ; repetition < self->numRepetitions ; ++ repetition) { - double energy ; - double timeRef ; - - if (self->verbosity) { - VL_PRINTF("kmeans: repetition %d of %d\n", repetition + 1, self->numRepetitions) ; - } - - timeRef = vl_get_cpu_time() ; - switch (self->initialization) { - case VlKMeansRandomSelection : - vl_kmeans_init_centers_with_rand_data (self, - data, dimension, numData, - numCenters) ; - break ; - case VlKMeansPlusPlus : - vl_kmeans_init_centers_plus_plus (self, - data, dimension, numData, - numCenters) ; - break ; - default: - abort() ; - } - - if (self->verbosity) { - VL_PRINTF("kmeans: K-means initialized in %.2f s\n", - vl_get_cpu_time() - timeRef) ; - } - - timeRef = vl_get_cpu_time () ; - energy = vl_kmeans_refine_centers (self, data, numData) ; - if (self->verbosity) { - VL_PRINTF("kmeans: K-means terminated in %.2f s with energy %g\n", - vl_get_cpu_time() - timeRef, energy) ; - } - - /* copy centers to output if current solution is optimal */ - /* check repetition == 0 as well in case energy = NaN, which */ - /* can happen if the data contain NaNs */ - if (energy < bestEnergy || repetition == 0) { - void * temp ; - bestEnergy = energy ; - - if (bestCenters == NULL) { - bestCenters = vl_malloc(vl_get_type_size(self->dataType) * - self->dimension * - self->numCenters) ; - } - - /* swap buffers */ - temp = bestCenters ; - bestCenters = self->centers ; - self->centers = temp ; - } /* better energy */ - } /* next repetition */ - - vl_free (self->centers) ; - self->centers = bestCenters ; - return bestEnergy ; -} - -/* VL_KMEANS_INSTANTIATING */ -#endif - -#undef SFX -#undef TYPE -#undef FLT -#undef VL_KMEANS_INSTANTIATING diff --git a/opensfm/src/third_party/vlfeat/vl/kmeans.h b/opensfm/src/third_party/vlfeat/vl/kmeans.h deleted file mode 100644 index a3cd17631..000000000 --- a/opensfm/src/third_party/vlfeat/vl/kmeans.h +++ /dev/null @@ -1,435 +0,0 @@ -/** @file kmeans.h - ** @brief K-means (@ref kmeans) - ** @author Andrea Vedaldi - ** @author David Novotny - **/ - -/* -Copyright (C) 2007-12 Andrea Vedaldi and Brian Fulkerson. -Copyright (C) 2013 Andrea Vedaldi and David Novotny. -All rights reserved. - -This file is part of the VLFeat library and is made available under -the terms of the BSD license (see the COPYING file). -*/ - -#ifndef VL_KMEANS_H -#define VL_KMEANS_H - -#include "generic.h" -#include "random.h" -#include "mathop.h" -#include "kdtree.h" - -/* ---------------------------------------------------------------- */ - -/** @brief K-means algorithms */ - -typedef enum _VlKMeansAlgorithm { - VlKMeansLloyd, /**< Lloyd algorithm */ - VlKMeansElkan, /**< Elkan algorithm */ - VlKMeansANN /**< Approximate nearest neighbors */ -} VlKMeansAlgorithm ; - -/** @brief K-means initialization algorithms */ - -typedef enum _VlKMeansInitialization { - VlKMeansRandomSelection, /**< Randomized selection */ - VlKMeansPlusPlus /**< Plus plus raondomized selection */ -} VlKMeansInitialization ; - -/** ------------------------------------------------------------------ - ** @brief K-means quantizer - **/ - -typedef struct _VlKMeans -{ - - vl_type dataType ; /**< Data type. */ - vl_size dimension ; /**< Data dimensionality. */ - vl_size numCenters ; /**< Number of centers. */ - vl_size numTrees ; /**< Number of trees in forest when using ANN-kmeans. */ - vl_size maxNumComparisons ; /**< Maximum number of comparisons when using ANN-kmeans. */ - - VlKMeansInitialization initialization ; /**< Initalization algorithm. */ - VlKMeansAlgorithm algorithm ; /**< Clustring algorithm. */ - VlVectorComparisonType distance ; /**< Distance. */ - vl_size maxNumIterations ; /**< Maximum number of refinement iterations. */ - double minEnergyVariation ; /**< Minimum energy variation. */ - vl_size numRepetitions ; /**< Number of clustering repetitions. */ - int verbosity ; /**< Verbosity level. */ - - void * centers ; /**< Centers */ - void * centerDistances ; /**< Centers inter-distances. */ - - double energy ; /**< Current solution energy. */ - VlFloatVectorComparisonFunction floatVectorComparisonFn ; - VlDoubleVectorComparisonFunction doubleVectorComparisonFn ; -} VlKMeans ; - -/** @name Create and destroy - ** @{ - **/ -VL_EXPORT VlKMeans * vl_kmeans_new (vl_type dataType, VlVectorComparisonType distance) ; -VL_EXPORT VlKMeans * vl_kmeans_new_copy (VlKMeans const * kmeans) ; -VL_EXPORT void vl_kmeans_delete (VlKMeans * self) ; -/** @} */ - -/** @name Basic data processing - ** @{ - **/ -VL_EXPORT void vl_kmeans_reset (VlKMeans * self) ; - -VL_EXPORT double vl_kmeans_cluster (VlKMeans * self, - void const * data, - vl_size dimension, - vl_size numData, - vl_size numCenters) ; - -VL_EXPORT void vl_kmeans_quantize (VlKMeans * self, - vl_uint32 * assignments, - void * distances, - void const * data, - vl_size numData) ; - -VL_EXPORT void vl_kmeans_quantize_ANN (VlKMeans * self, - vl_uint32 * assignments, - void * distances, - void const * data, - vl_size numData, - vl_size iteration ); -/** @} */ - -/** @name Advanced data processing - ** @{ - **/ -VL_EXPORT void vl_kmeans_set_centers (VlKMeans * self, - void const * centers, - vl_size dimension, - vl_size numCenters) ; - -VL_EXPORT void vl_kmeans_init_centers_with_rand_data - (VlKMeans * self, - void const * data, - vl_size dimensions, - vl_size numData, - vl_size numCenters) ; - -VL_EXPORT void vl_kmeans_init_centers_plus_plus - (VlKMeans * self, - void const * data, - vl_size dimensions, - vl_size numData, - vl_size numCenters) ; - -VL_EXPORT double vl_kmeans_refine_centers (VlKMeans * self, - void const * data, - vl_size numData) ; - -/** @} */ - -/** @name Retrieve data and parameters - ** @{ - **/ -VL_INLINE vl_type vl_kmeans_get_data_type (VlKMeans const * self) ; -VL_INLINE VlVectorComparisonType vl_kmeans_get_distance (VlKMeans const * self) ; - -VL_INLINE VlKMeansAlgorithm vl_kmeans_get_algorithm (VlKMeans const * self) ; -VL_INLINE VlKMeansInitialization vl_kmeans_get_initialization (VlKMeans const * self) ; -VL_INLINE vl_size vl_kmeans_get_num_repetitions (VlKMeans const * self) ; - -VL_INLINE vl_size vl_kmeans_get_dimension (VlKMeans const * self) ; -VL_INLINE vl_size vl_kmeans_get_num_centers (VlKMeans const * self) ; - -VL_INLINE int vl_kmeans_get_verbosity (VlKMeans const * self) ; -VL_INLINE vl_size vl_kmeans_get_max_num_iterations (VlKMeans const * self) ; -VL_INLINE double vl_kmeans_get_min_energy_variation (VlKMeans const * self) ; -VL_INLINE vl_size vl_kmeans_get_max_num_comparisons (VlKMeans const * self) ; -VL_INLINE vl_size vl_kmeans_get_num_trees (VlKMeans const * self) ; -VL_INLINE double vl_kmeans_get_energy (VlKMeans const * self) ; -VL_INLINE void const * vl_kmeans_get_centers (VlKMeans const * self) ; -/** @} */ - -/** @name Set parameters - ** @{ - **/ -VL_INLINE void vl_kmeans_set_algorithm (VlKMeans * self, VlKMeansAlgorithm algorithm) ; -VL_INLINE void vl_kmeans_set_initialization (VlKMeans * self, VlKMeansInitialization initialization) ; -VL_INLINE void vl_kmeans_set_num_repetitions (VlKMeans * self, vl_size numRepetitions) ; -VL_INLINE void vl_kmeans_set_max_num_iterations (VlKMeans * self, vl_size maxNumIterations) ; -VL_INLINE void vl_kmeans_set_min_energy_variation (VlKMeans * self, double minEnergyVariation) ; -VL_INLINE void vl_kmeans_set_verbosity (VlKMeans * self, int verbosity) ; -VL_INLINE void vl_kmeans_set_max_num_comparisons (VlKMeans * self, vl_size maxNumComparisons) ; -VL_INLINE void vl_kmeans_set_num_trees (VlKMeans * self, vl_size numTrees) ; -/** @} */ - -/** ------------------------------------------------------------------ - ** @brief Get data type - ** @param self KMeans object instance. - ** @return data type. - **/ - -VL_INLINE vl_type -vl_kmeans_get_data_type (VlKMeans const * self) -{ - return self->dataType ; -} - -/** @brief Get data dimension - ** @param self KMeans object instance. - ** @return data dimension. - **/ - -VL_INLINE vl_size -vl_kmeans_get_dimension (VlKMeans const * self) -{ - return self->dimension ; -} - -/** @brief Get data type - ** @param self KMeans object instance. - ** @return data type. - **/ - -VL_INLINE VlVectorComparisonType -vl_kmeans_get_distance (VlKMeans const * self) -{ - return self->distance ; -} - -/** @brief Get the number of centers (K) - ** @param self KMeans object instance. - ** @return number of centers. - **/ - -VL_INLINE vl_size -vl_kmeans_get_num_centers (VlKMeans const * self) -{ - return self->numCenters ; -} - -/** @brief Get the number energy of the current fit - ** @param self KMeans object instance. - ** @return energy. - **/ - -VL_INLINE double -vl_kmeans_get_energy (VlKMeans const * self) -{ - return self->energy ; -} - -/** ------------------------------------------------------------------ - ** @brief Get verbosity level - ** @param self KMeans object instance. - ** @return verbosity level. - **/ - -VL_INLINE int -vl_kmeans_get_verbosity (VlKMeans const * self) -{ - return self->verbosity ; -} - -/** @brief Set verbosity level - ** @param self KMeans object instance. - ** @param verbosity verbosity level. - **/ - -VL_INLINE void -vl_kmeans_set_verbosity (VlKMeans * self, int verbosity) -{ - self->verbosity = verbosity ; -} - -/** ------------------------------------------------------------------ - ** @brief Get centers - ** @param self KMeans object instance. - ** @return cluster centers. - **/ - -VL_INLINE void const * -vl_kmeans_get_centers (VlKMeans const * self) -{ - return self->centers ; -} - -/** ------------------------------------------------------------------ - ** @brief Get maximum number of iterations - ** @param self KMeans object instance. - ** @return maximum number of iterations. - **/ - -VL_INLINE vl_size -vl_kmeans_get_max_num_iterations (VlKMeans const * self) -{ - return self->maxNumIterations ; -} - -/** @brief Set maximum number of iterations - ** @param self KMeans filter. - ** @param maxNumIterations maximum number of iterations. - **/ - -VL_INLINE void -vl_kmeans_set_max_num_iterations (VlKMeans * self, vl_size maxNumIterations) -{ - self->maxNumIterations = maxNumIterations ; -} - -/** ------------------------------------------------------------------ - ** @brief Get maximum number of repetitions. - ** @param self KMeans object instance. - ** @return current number of repretitions for quantization. - **/ - -VL_INLINE vl_size -vl_kmeans_get_num_repetitions (VlKMeans const * self) -{ - return self->numRepetitions ; -} - -/** @brief Set maximum number of repetitions - ** @param self KMeans object instance. - ** @param numRepetitions maximum number of repetitions. - ** The number of repetitions cannot be smaller than 1. - **/ - -VL_INLINE void -vl_kmeans_set_num_repetitions (VlKMeans * self, - vl_size numRepetitions) -{ - assert (numRepetitions >= 1) ; - self->numRepetitions = numRepetitions ; -} - -/** ------------------------------------------------------------------ - ** @brief Get the minimum relative energy variation for convergence. - ** @param self KMeans object instance. - ** @return minimum energy variation. - **/ - -VL_INLINE double -vl_kmeans_get_min_energy_variation (VlKMeans const * self) -{ - return self->minEnergyVariation ; -} - -/** @brief Set the maximum relative energy variation for convergence. - ** @param self KMeans object instance. - ** @param minEnergyVariation maximum number of repetitions. - ** The variation cannot be negative. - ** - ** The relative energy variation is calculated after the $t$-th update - ** to the parameters as: - ** - ** \[ \epsilon_t = \frac{E_{t-1} - E_t}{E_0 - E_t} \] - ** - ** Note that this quantitiy is non-negative since $E_{t+1} \leq E_t$. - ** Hence, $\epsilon_t$ is the improvement to the energy made in the last - ** iteration compared to the total improvement so far. The algorithm - ** stops if this value is less or equal than @a minEnergyVariation. - ** - ** This test is applied only to the LLoyd and ANN algorithms. - **/ - -VL_INLINE void -vl_kmeans_set_min_energy_variation (VlKMeans * self, - double minEnergyVariation) -{ - assert (minEnergyVariation >= 0) ; - self->minEnergyVariation = minEnergyVariation ; -} - -/** ------------------------------------------------------------------ - ** @brief Get K-means algorithm - ** @param self KMeans object. - ** @return algorithm. - **/ - -VL_INLINE VlKMeansAlgorithm -vl_kmeans_get_algorithm (VlKMeans const * self) -{ - return self->algorithm ; -} - -/** @brief Set K-means algorithm - ** @param self KMeans object. - ** @param algorithm K-means algorithm. - **/ - -VL_INLINE void -vl_kmeans_set_algorithm (VlKMeans * self, VlKMeansAlgorithm algorithm) -{ - self->algorithm = algorithm ; -} - -/** ------------------------------------------------------------------ - ** @brief Get K-means initialization algorithm - ** @param self KMeans object. - ** @return algorithm. - **/ - -VL_INLINE VlKMeansInitialization -vl_kmeans_get_initialization (VlKMeans const * self) -{ - return self->initialization ; -} - -/** @brief Set K-means initialization algorithm - ** @param self KMeans object. - ** @param initialization initialization. - **/ - -VL_INLINE void -vl_kmeans_set_initialization (VlKMeans * self, - VlKMeansInitialization initialization) -{ - self->initialization = initialization ; -} - -/** ------------------------------------------------------------------ - ** @brief Get the maximum number of comparisons in the KD-forest ANN algorithm. - ** @param self KMeans object instance. - ** @return maximum number of comparisons. - **/ - -VL_INLINE vl_size -vl_kmeans_get_max_num_comparisons (VlKMeans const * self) -{ - return self->maxNumComparisons ; -} - -/** @brief Set maximum number of comparisons in ANN-KD-Tree. - ** @param self KMeans filter. - ** @param maxNumComparisons maximum number of comparisons. - **/ - -VL_INLINE void -vl_kmeans_set_max_num_comparisons (VlKMeans * self, - vl_size maxNumComparisons) -{ - self->maxNumComparisons = maxNumComparisons; -} - -/** ------------------------------------------------------------------ - ** @brief Set the number of trees in the KD-forest ANN algorithm - ** @param self KMeans object instance. - ** @param numTrees number of trees to use. - **/ - -VL_INLINE void -vl_kmeans_set_num_trees (VlKMeans * self, vl_size numTrees) -{ - self->numTrees = numTrees; -} - -VL_INLINE vl_size -vl_kmeans_get_num_trees (VlKMeans const * self) -{ - return self->numTrees; -} - - -/* VL_IKMEANS_H */ -#endif diff --git a/opensfm/src/third_party/vlfeat/vl/lbp.c b/opensfm/src/third_party/vlfeat/vl/lbp.c deleted file mode 100644 index 6cea7ccd9..000000000 --- a/opensfm/src/third_party/vlfeat/vl/lbp.c +++ /dev/null @@ -1,347 +0,0 @@ -/** @file lbp.c - ** @brief Local Binary Patterns (LBP) - Definition - ** @author Andrea Vedaldi - **/ - -/* -Copyright (C) 2013 Andrea Vedaldi. -Copyright (C) 2007-12 Andrea Vedaldi and Brian Fulkerson. -All rights reserved. - -This file is part of the VLFeat library and is made available under -the terms of the BSD license (see the COPYING file). -*/ - -/** - -@page lbp Local Binary Patterns (LBP) descriptor -@author Andrea Vedaldi - - -@ref lbp.h implements the Local Binary Pattern (LBP) feature -descriptor. The LBP descriptor @cite{ojala10multiresolution} is a -histogram of quantized LBPs pooled in a local image neighborhood. @ref -lbp-starting demonstrates how to use the C API to compute the LBP -descriptors of an image. For further details refer to: - -- @subpage lbp-fundamentals - LBP definition and parameters. - - -@section lbp-starting Getting started with LBP - - -To compute the LBP descriptor of an image, start by creating a ::VlLbp -object instance by specifying the type of LBP quantization. Given the -configure LBP object, then call ::vl_lbp_process to process a -grayscale image and obtain the corresponding LBP descriptors. This -function expects as input a buffer large enough to contain the -computed features. If the image has size @c width x @c height, there -are exactly @c floor(width/cellSize) x @c floor(height/cellSize) -cells, each of which has a histogram of LBPs of size @c dimension (as -returned by ::vl_lbp_get_dimension). Thus the required buffer has size -@c floor(width/cellSize) x @c floor(height/cellSize) x @c dimension. - -::VlLbp supports computing transposed LPBs as well. A transposed LBP -is the LBP obtained by transposing the input image (regarded as a -matrix). This functionality can be useful to compute the features when -the input image is stored in column major format (e.g. MATLAB) rather -than row major. -**/ - -/** - -@page lbp-fundamentals Local Binary Patterns fundamentals -@tableofcontents - - -A *Locally Binary Pattern* (LBP) is a local descriptor that captures -the appearance of an image in a small neighborhood around a pixel. An -LBP is a string of bits, with one bit for each of the pixels in the -neighborhood. Each bit is turned on or off depending on whether the -intensity of the corresponding pixel is greater than the intensity of -the central pixel. LBP are seldom used directly, however. Instead, the -binary string thus produced are further quantized (@ref -lbp-quantization) and pooled in local histograms (@ref -lbp-histograms). - -While many variants are possible, ::VlLbp implements only the case of -3 × 3 pixel neighborhoods (this setting was found to be optimal -in several applications). In particular, the LBP centered on pixel -$(x,y)$ is a string of eight bits. Each bit is equal to one if the -corresponding pixel is brighter than the central one. Pixels are -scanned starting from the one to the right in anti-clockwise order. -For example the first bit is one if, and only if, $I(x+1,y) > -I(x,y)$, and the second bit is one if, and only if, $I(x+1,y-1) > -I(x,y)$. - - -@section lbp-quantization Quantized LBP - - -For a 3 × 3 neighborhood, an LBP is a string of eight bits and -so there are 256 possible LBPs. These are usually too many for a -reliable statistics (histogram) to be computed. Therefore the 256 -patterns are further quantized into a smaller number of patterns -according to one of the following rules: - -- Uniform (::VlLbpUniform) There is one quantized pattern for - each LBP that has exactly a transitions from 0 to 1 and one from 1 - to 0 when scanned in anti-clockwise order, plus one quantized - pattern comprising the two uniform LBPs, and one quantized pattern - comprising all the other LBPs. This yields a total of 58 quantized - patterns. - - @image html lbp.png "LBP quantized patterns." - -The number of quantized LBPs, which depends on the quantization type, -can be obtained by ::vl_lbp_get_dimension. - - -@section lbp-histograms Histograms of LBPs - - -The quantized LBP patterns are further grouped into local -histograms. The image is divided into a number of cells of a -prescribed size (as specified by the parameter @c cellSize passed to -::vl_lbp_process as described in @ref lbp-starting). Then the -quantized LBPs are aggregated into histogram by using bilinear -interpolation along the two spatial dimensions (similar to HOG and -SIFT). -**/ - -#include "lbp.h" -#include "mathop.h" -#include "string.h" - -/* ---------------------------------------------------------------- */ -/* Initialization helpers */ -/* ---------------------------------------------------------------- */ - -/* - This function creates the LBP quantization table for the uniform LBP - patterns. The purpose of this lookup table is to map a 8-bit LBP - strings to one of 58 uniform pattern codes. - - Pixels in the 8-neighbourhoods are read in counterclockwise order - starting from the east direction, as follows: - - NW(5) N(6) NE(7) - W(4) E(0) -> b0 b1 b2 b3 b4 b5 b6 b7 - SW(3) S(2) SE(1) - - There are 256 such strings, indexing the lookup table. The table - contains the corresponding code, effectively quantizing the 256 - patterns into 58. There is one bin for constant patterns (all zeros - or ones), 8*7 for the uniform ones, and one for all other. - - A uniform pattern is a circular sequence of bit b0b1...b7 such that - there is exactly one switch from 0 to 1 and one from 1 to 0. These - uniform patterns are enumerated as follows. The slowest varying index - i (0...7) points to the first bit that is on and the slowest varying - index j (1...7) to the length of the run of bits equal to one, - resulting in the sequence: - - 0: 1000 0000 - 1: 1100 0000 - ... - 7: 1111 1110 - 8: 0100 0000 - 9: 0110 0000 - ... - 56: 1111 1101 - - The function also accounts for when the image is stored in transposed - format. The sampling function is unchanged, so that the first bit to - be read is not the one to the east, but the one to the south, and - overall the following sequence is read: - - NW(5) W(4) SW(3) - N(6) S(2) -> b2 b1 b0 b7 b6 b5 b4 b3 - NE(7) E(0) SE(1) - - In enumerating the uniform patterns, the index j is unchanged as it - encodes the runlenght. On the contrary, the index i changes to - account for the transposition and for the fact that the beginning and - ending of the run are swapped. With modular arithmetic, the i must be - transformed as - - ip = - i + 2 - (j - 1) - */ - -static void -_vl_lbp_init_uniform(VlLbp * self) -{ - int i, j ; - - /* overall number of quantized LBPs */ - self->dimension = 58 ; - - /* all but selected patterns map to bin 57 (the first bin has index 0) */ - for (i = 0 ; i < 256 ; ++i) { - self->mapping[i] = 57 ; - } - - /* the uniform (all zeros or ones) patterns map to bin 56 */ - self->mapping[0x00] = 56 ; - self->mapping[0xff] = 56 ; - - /* 56 uniform patterns */ - for (i = 0 ; i < 8 ; ++i) { - for (j = 1 ; j <= 7 ; ++j) { - int ip ; - int unsigned string ; - if (self->transposed) { - ip = (- i + 2 - (j - 1) + 16) % 8 ; - } else { - ip = i ; - } - - /* string starting with j ones */ - string = (1 << j) - 1 ; - string <<= ip ; - string = (string | (string >> 8)) & 0xff ; - - self->mapping[string] = i * 7 + (j-1) ; - } - } -} - -/* ---------------------------------------------------------------- */ - -/** @brief Create a new LBP object - ** @param type type of LBP features. - ** @param transposed if @c true, then transpose each LBP pattern. - ** @return new VlLbp object instance. - **/ - -VlLbp * -vl_lbp_new(VlLbpMappingType type, vl_bool transposed) -{ - VlLbp * self = vl_malloc(sizeof(VlLbp)) ; - if (self == NULL) { - vl_set_last_error(VL_ERR_ALLOC, NULL) ; - return NULL ; - } - self->transposed = transposed ; - switch (type) { - case VlLbpUniform: _vl_lbp_init_uniform(self) ; break ; - default: exit(1) ; - } - return self ; -} - -/** @brief Delete VlLbp object - ** @param self object to delete. - **/ - -void -vl_lbp_delete(VlLbp * self) { - vl_free(self) ; -} - -/** @brief Get the dimension of the LBP histograms - ** @return dimension of the LBP histograms. - ** The dimension depends on the type of quantization used. - ** @see ::vl_lbp_new(). - **/ - -VL_EXPORT vl_size vl_lbp_get_dimension(VlLbp * self) -{ - return self->dimension ; -} - -/* ---------------------------------------------------------------- */ - -/** @brief Extract LBP features - ** @param self LBP object. - ** @param features buffer to write the features to. - ** @param image image. - ** @param width image width. - ** @param height image height. - ** @param cellSize size of the LBP cells. - ** - ** @a features is a @c numColumns x @c numRows x @c dimension where - ** @c dimension is the dimension of a LBP feature obtained from ::vl_lbp_get_dimension, - ** @c numColumns is equal to @c floor(width / cellSize), and similarly - ** for @c numRows. - **/ - -VL_EXPORT void -vl_lbp_process (VlLbp * self, - float * features, - float * image, vl_size width, vl_size height, - vl_size cellSize) -{ - vl_size cwidth = width / cellSize; - vl_size cheight = height / cellSize ; - vl_size cstride = cwidth * cheight ; - vl_size cdimension = vl_lbp_get_dimension(self) ; - vl_index x,y,cx,cy,k,bin ; - -#define at(u,v) (*(image + width * (v) + (u))) -#define to(u,v,w) (*(features + cstride * (w) + cwidth * (v) + (u))) - - /* clear the output buffer */ - memset(features, 0, sizeof(float)*cdimension*cstride) ; - - /* accumulate pixel-level measurements into cells */ - for (y = 1 ; y < (signed)height - 1 ; ++y) { - float wy1 = (y + 0.5f) / (float)cellSize - 0.5f ; - int cy1 = (int) vl_floor_f(wy1) ; - int cy2 = cy1 + 1 ; - float wy2 = wy1 - (float)cy1 ; - wy1 = 1.0f - wy2 ; - if (cy1 >= (signed)cheight) continue ; - - for (x = 1 ; x < (signed)width - 1; ++x) { - float wx1 = (x + 0.5f) / (float)cellSize - 0.5f ; - int cx1 = (int) vl_floor_f(wx1) ; - int cx2 = cx1 + 1 ; - float wx2 = wx1 - (float)cx1 ; - wx1 = 1.0f - wx2 ; - if (cx1 >= (signed)cwidth) continue ; - - { - int unsigned bitString = 0 ; - float center = at(x,y) ; - if(at(x+1,y+0) > center) bitString |= 0x1 << 0; /* E */ - if(at(x+1,y+1) > center) bitString |= 0x1 << 1; /* SE */ - if(at(x+0,y+1) > center) bitString |= 0x1 << 2; /* S */ - if(at(x-1,y+1) > center) bitString |= 0x1 << 3; /* SW */ - if(at(x-1,y+0) > center) bitString |= 0x1 << 4; /* W */ - if(at(x-1,y-1) > center) bitString |= 0x1 << 5; /* NW */ - if(at(x+0,y-1) > center) bitString |= 0x1 << 6; /* N */ - if(at(x+1,y-1) > center) bitString |= 0x1 << 7; /* NE */ - bin = self->mapping[bitString] ; - } - - if ((cx1 >= 0) & (cy1 >=0)) { - to(cx1,cy1,bin) += wx1 * wy1; - } - if ((cx2 < (signed)cwidth) & (cy1 >=0)) { - to(cx2,cy1,bin) += wx2 * wy1 ; - } - if ((cx1 >= 0) & (cy2 < (signed)cheight)) { - to(cx1,cy2,bin) += wx1 * wy2 ; - } - if ((cx2 < (signed)cwidth) & (cy2 < (signed)cheight)) { - to(cx2,cy2,bin) += wx2 * wy2 ; - } - } /* x */ - } /* y */ - - /* normalize cells */ - for (cy = 0 ; cy < (signed)cheight ; ++cy) { - for (cx = 0 ; cx < (signed)cwidth ; ++ cx) { - float norm = 0 ; - for (k = 0 ; k < (signed)cdimension ; ++k) { - norm += features[k * cstride] ; - } - norm = sqrtf(norm) + 1e-10f; ; - for (k = 0 ; k < (signed)cdimension ; ++k) { - features[k * cstride] = sqrtf(features[k * cstride]) / norm ; - } - features += 1 ; - } - } /* next cell to normalize */ -} diff --git a/opensfm/src/third_party/vlfeat/vl/lbp.h b/opensfm/src/third_party/vlfeat/vl/lbp.h deleted file mode 100644 index d33715b5e..000000000 --- a/opensfm/src/third_party/vlfeat/vl/lbp.h +++ /dev/null @@ -1,44 +0,0 @@ -/** @file lbp.h - ** @brief Local Binary Patterns (LBP) descriptor (@ref lbp) - ** @author Andrea Vedaldi - **/ - -/* -Copyright (C) 2007-12 Andrea Vedaldi and Brian Fulkerson. -All rights reserved. - -This file is part of the VLFeat library and is made available under -the terms of the BSD license (see the COPYING file). -*/ - -#ifndef VL_LBP_H -#define VL_LBP_H - -#include "generic.h" - -/** @brief Type of quantization for the LBP descriptors - ** @see @ref lbp-quantization - **/ -typedef enum _VlLbpMappingType -{ - VlLbpUniform /**< Uniform local binary patterns. */ -} VlLbpMappingType ; - -/** @brief Local Binary Pattern extractor */ -typedef struct VlLbp_ -{ - vl_size dimension ; - vl_uint8 mapping [256] ; - vl_bool transposed ; -} VlLbp ; - -VL_EXPORT VlLbp * vl_lbp_new(VlLbpMappingType type, vl_bool transposed) ; -VL_EXPORT void vl_lbp_delete(VlLbp * self) ; -VL_EXPORT void vl_lbp_process(VlLbp * self, - float * features, - float * image, vl_size width, vl_size height, - vl_size cellSize) ; -VL_EXPORT vl_size vl_lbp_get_dimension(VlLbp * self) ; - -/* VL_LBP_H */ -#endif diff --git a/opensfm/src/third_party/vlfeat/vl/liop.c b/opensfm/src/third_party/vlfeat/vl/liop.c deleted file mode 100644 index ae788ec9d..000000000 --- a/opensfm/src/third_party/vlfeat/vl/liop.c +++ /dev/null @@ -1,641 +0,0 @@ -/** @file liop.c - ** @brief Local Intensity Order Pattern (LIOP) descriptor - Definition - ** @author Hana Sarbortova - ** @author Andrea Vedaldi - **/ - -/* -Copyright (C) 2013 Hana Sarbortova and Andrea Vedaldi. -All rights reserved. - -This file is part of the VLFeat library and is made available under -the terms of the BSD license (see the COPYING file). -*/ - -/** - -@page liop Local Intensity Order Pattern (LIOP) descriptor -@author Hana Sarbortova -@author Andrea Vedaldi - - -@ref liop.h implements *Local Intensity Order Pattern descriptor* -(LIOP) of @cite{wang11local}. LIOP is a local image descriptor, -similarly to the @ref sift "SIFT descriptor". - -@ref liop-starting demonstrates how to use the C API to compute the -LIOP descriptor of a patch. For further details refer to: - -- @subpage liop-fundamentals - LIOP definition and parameters. - - -@section liop-starting Getting started with LIOP - - -The following code fragment demonstrates how tow to use @ref liop.h in -a C program in order to compute the LIOP descriptor of an image patch. - -@code -#include - -// Create a new object instance (these numbers corresponds to parameter -// values proposed by authors of the paper, except for 41) -vl_size sideLength = 41 ; -VlLiopDesc * liop = vl_liopdesc_new_basic (sideLength); - -// allocate the descriptor array -vl_size dimension = vl_liopdesc_get_dimension(liop) ; -float * desc = vl_malloc(sizeof(float) * dimension) ; - -// compute descriptor from a patch (an array of length sideLegnth * -// sideLength) -vl_liopdesc_process(liop, desc, patch) ; - -// delete the object -vl_liopdesc_delete(liop) ; -@endcode - -The image patch must be of odd side length and in single -precision. There are several parameters affecting the LIOP -descriptor. An example is the @ref liop-weighing "threshold" used to -discard low-contrast oder pattern in the computation of the -statistics. This is changed by using ::vl_liopdesc_set_intensity_threshold. -**/ - -/** - -@page liop-fundamentals LIOP fundamentals -@tableofcontents - - -The *Local Invariant Order Pattern* (LIOP) descriptor -@cite{wang11local} is a local image descriptor based on the concept of -*local order pattern*. An order pattern is simply the order obtained -by sorting selected image samples by increasing intensity. Consider in -particular a pixel $\bx$ and $n$ neighbors -$\bx_1,\bx_2,\dots,\bx_n$. The local order pattern at $\bx$ is the -permutation $\sigma$ that sorts the neighbours by increasing intensity -$I(\bx_{\sigma(1)}) \leq I(\bx_{\sigma(2)}) \leq \dots \leq -I(\bx_{\sigma(2)})$. - -An advantage of order patterns is that they are invariant to monotonic -changes of the image intensity. However, an order pattern describes -only a small portion of a patch and is not very distinctive. LIOP -assembles local order patterns computed at all image locations to -obtain a descriptor that at the same time distinctive and invariant to -monotonic intensity changes as well as image rotations. - -In order to make order patterns rotation invariant, the neighborhood -of samples around $\bx$ is taken in a rotation-covariant manner. In -particular, the points $\bx_1,\dots,\bx_n$ are sampled anticlockwise -on a circle of radius $r$ around $\bx$, as shown in the following -figure: - -@image html liop.png "LIOP descriptor layout: square input patch (shaded area), circular measurement region (white area), local neighborhood of a point (blue)." - -Since the sample points do not necessarily have integer coordinates, -$I(\bx_i)$ is computed using bilinear interpolation. - - -@section liop-spatial-binning Intensity rank spatial binning - - -Once local order patterns are computed for all pixels $\bx$ in the -image, they can be pooled into a histogram to form an image -descriptor. Pooling discards spatial information resulting in a -warp-invariant statistics. In practice, there are two restriction on -which pixels can be used for this purpose: - -- A margin of $r$ pixels from the image boundary must be maintained so - that neighborhoods fall within the image boundaries. -- Rotation invariance requires the pooling regions to be rotation - co-variant. A way to do so is to make the shape of the pooling - region rotation invariant. - -For this reason, the histogram pooling region is restricted to the -circular region shown with a light color in the figure above. - -In order to increase distinctiveness of the descriptor, LIOP pools -multiple histograms from a number of regions $R_1,\dots,R_m$ (spatial -pooling). These regions are selected in an illumination-invariant and -rotation-covariant manner by looking at level sets: -\[ -R_t = \{\bx :\tau_{t} \leq I(\bx) < \tau_{t+1} \}. -\] -In order to be invariant to monotonic changes of the intensity, the -thresholds $\tau_t$ are selected so that all regions contain the same -number of pixels. This can be done efficiently by sorting pixels by -increasing intensity and then partitioning the resulting list into $m$ -equal parts (when $m$ does not divide the number of pixels exactly, -the remaining pixels are incorporated into the last partition). - - -@section liop-weighing Weighted pooling - - -In order to compute a histogram of order pattern occurrences, one -needs to map permutations to histogram bins. This is obtained by -sorting permutation in lexycogrpahical order. For example, for $n=4$ -neighbors one has the following $n!=24$ permutations: - -Permutation | Lexycographical rank ---------------|---------------------- -1 2 3 4 | 1 -1 2 4 3 | 2 -1 3 2 4 | 3 -1 3 4 2 | 4 -... | ... -4 3 1 2 | 23 -4 3 2 1 | 24 - -In the following, $q(\bx) \in [1, n!]$ will denote the index of the -local order pattern $\sigma$ centered at pixel $\bx$. - -The local order patterns $q(\bx)$ in a region $R_t$ are then pooled to -form a histogram of size $!n$. In this process, patterns are weighted -based on their stability. The latter is assumed to be proportional to -the number of pairs of pixels in the neighborhood that have a -sufficiently large intensity difference: - -@f[ -w(\bx) = \sum_{i=1}^n \sum_{j=1}^n [ |I(\bx_{i}) - I(\bx_{j})| > \Theta) ] -@f] - -where $[\cdot]$ is the indicator function. - -In VLFeat LIOP implementation, the threshold $\Theta$ is either set as -an absolute value, or as a faction of the difference between the -maximum and minimum intensity in the image (restricted to the pixels -in the light area in the figure above). - -Overall, LIOP consists of $m$ histograms of size $n!$ obtained as - -\[ - h_{qt} = \sum_{\bx : q(\bx) = q \ \wedge\ \bx \in R_t} w(\bx). -\] - - - -@section liop-normalization Normalization - - -After computing the weighted counts $h_{qt}$, the LIOP descriptor is -obtained by stacking the values $\{h_{qt}\}$ into a vector -$\mathbf{h}$ and then normalising it: - -\[ - \Phi = \frac{\mathbf{h}}{\|\mathbf{h}\|_2} -\] - -The dimensionality is therefore $m n!$, where $m$ is the @c -numSpatialBins number of spatial bins and $n$ is the @c numNeighbours -number of neighbours (see ::vl_liopdesc_new). By default, this -descriptor is stored in @c single format. It can be stored as a -sequence of bytes by premultiplying the values by the constant 255 and -then rounding: - -\[ - \operatorname{round}\left[ 255\, \times \Phi\right]. -\] - -*/ - -#include "liop.h" -#include "mathop.h" -#include "imopv.h" -#include - -#define DEFAULT_INTENSITY_THRESHOLD -(5.0/255) -#define DEFAULT_RADIUS 6.0 -#define DEFAULT_NUM_SPATIAL_BINS 6 -#define DEFAULT_NUM_NEIGHBOURS 4 - -/* ---------------------------------------------------------------- */ -/* Helper functions */ -/* ---------------------------------------------------------------- */ - -static -vl_int factorial(vl_int num) -{ - vl_int result = 1; - while(num > 1){ - result = num*result; - num--; - } - return result ; -} - -/** @internal @brief Compute permutation index. - ** @param permutation array containing all values from 0 to (size - 1) (input/output). - ** @param size size of the permutation array. - ** @return permutation index. - ** - ** Compute the position of @a permutation in the lexycographcial - ** sorting of permutations of the given @a size. - ** - ** For example, in the lexicographical ordering, permutations of four elements - ** are listed as [1 2 3 4], [1 2 4 3], [1 3 2 4], [1 3 4 2], [1 4 2 3], - ** [1 4 3 2], [2 1 3 4], ..., [4 3 2 1]. - ** - ** The index can be computed as follows. First pick the first digit - ** perm[1]. This is either 1,2,...,n. For each - ** choice of the first digits, there are (n-1)! other permutations, separated - ** therefore by (n-1)! elements in lexicographical order. - ** - ** Process then the second digit perm[2]. This can be though as finding - ** the lexycotraphical index of perm[2], ..., perm[n], a permutation of - ** n-1 elements. This can be explicitly obtained by taking out 1 from - ** all elements perm[i] > perm[1]. */ - -VL_INLINE vl_index get_permutation_index(vl_uindex *permutation, vl_size size){ - vl_index index = 0 ; - vl_index i ; - vl_index j ; - - for (i = 0 ; i < (signed)size ; ++i) { - index = index * ((signed)size - i) + permutation[i] ; - for (j = i + 1 ; j < (signed)size ; ++j) { - if (permutation[j] > permutation[i]) { permutation[j] -- ; } - } - } - return index ; -} - -/* instantiate two quick sort algorithms */ -VL_INLINE float patch_cmp (VlLiopDesc * liop, vl_index i, vl_index j) -{ - vl_index ii = liop->patchPermutation[i] ; - vl_index jj = liop->patchPermutation[j] ; - return liop->patchIntensities[ii] - liop->patchIntensities[jj] ; -} - -VL_INLINE void patch_swap (VlLiopDesc * liop, vl_index i, vl_index j) -{ - vl_index tmp = liop->patchPermutation[i] ; - liop->patchPermutation[i] = liop->patchPermutation[j] ; - liop->patchPermutation[j] = tmp ; -} - -#define VL_QSORT_prefix patch -#define VL_QSORT_array VlLiopDesc* -#define VL_QSORT_cmp patch_cmp -#define VL_QSORT_swap patch_swap -#include "qsort-def.h" - -VL_INLINE float neigh_cmp (VlLiopDesc * liop, vl_index i, vl_index j) -{ - vl_index ii = liop->neighPermutation[i] ; - vl_index jj = liop->neighPermutation[j] ; - return liop->neighIntensities[ii] - liop->neighIntensities[jj] ; -} - -VL_INLINE void neigh_swap (VlLiopDesc * liop, vl_index i, vl_index j) -{ - vl_index tmp = liop->neighPermutation[i] ; - liop->neighPermutation[i] = liop->neighPermutation[j] ; - liop->neighPermutation[j] = tmp ; -} - -#define VL_QSORT_prefix neigh -#define VL_QSORT_array VlLiopDesc* -#define VL_QSORT_cmp neigh_cmp -#define VL_QSORT_swap neigh_swap -#include "qsort-def.h" - -/* ---------------------------------------------------------------- */ -/* Construct and destroy */ -/* ---------------------------------------------------------------- */ - -/** @brief Create a new LIOP object instance. - ** @param numNeighbours number of neighbours. - ** @param numSpatialBins number of bins. - ** @param radius radius of the cirucal sample neighbourhoods. - ** @param sideLength width of the input image patch (the patch is square). - ** @return new object instance. - ** - ** The value of @a radius should be at least less than half the @a - ** sideLength of the patch. - **/ - -VlLiopDesc * -vl_liopdesc_new (vl_int numNeighbours, vl_int numSpatialBins, - float radius, vl_size sideLength) -{ - vl_index i, t ; - VlLiopDesc * self = vl_calloc(sizeof(VlLiopDesc), 1); - - assert(radius <= sideLength/2) ; - - self->numNeighbours = numNeighbours ; - self->numSpatialBins = numSpatialBins ; - self->neighRadius = radius ; - self->intensityThreshold = DEFAULT_INTENSITY_THRESHOLD ; - - self->dimension = factorial(numNeighbours) * numSpatialBins ; - - /* - Precompute a list of pixels within a circular patch inside - the square image. Leave a suitable marging for sampling around - these pixels. - */ - - self->patchSize = 0 ; - self->patchPixels = vl_malloc(sizeof(vl_uindex)*sideLength*sideLength) ; - self->patchSideLength = sideLength ; - - { - vl_index x, y ; - vl_index center = (sideLength - 1) / 2 ; - double t = center - radius + 0.6 ; - vl_index t2 = (vl_index) (t * t) ; - for (y = 0 ; y < (signed)sideLength ; ++y) { - for (x = 0 ; x < (signed)sideLength ; ++x) { - vl_index dx = x - center ; - vl_index dy = y - center ; - if (x == 0 && y == 0) continue ; - if (dx*dx + dy*dy <= t2) { - self->patchPixels[self->patchSize++] = x + y * sideLength ; - } - } - } - } - - self->patchIntensities = vl_malloc(sizeof(vl_uindex)*self->patchSize) ; - self->patchPermutation = vl_malloc(sizeof(vl_uindex)*self->patchSize) ; - - /* - Precompute the samples in the circular neighbourhood of each - measurement point. - */ - - self->neighPermutation = vl_malloc(sizeof(vl_uindex) * self->numNeighbours) ; - self->neighIntensities = vl_malloc(sizeof(float) * self->numNeighbours) ; - self->neighSamplesX = vl_calloc(sizeof(double), self->numNeighbours * self->patchSize) ; - self->neighSamplesY = vl_calloc(sizeof(double), self->numNeighbours * self->patchSize) ; - - for (i = 0 ; i < (signed)self->patchSize ; ++i) { - vl_index pixel ; - double x, y ; - double dangle = 2*VL_PI / (double)self->numNeighbours ; - double angle0 ; - vl_index center = (sideLength - 1) / 2 ; - - pixel = self->patchPixels[i] ; - x = (pixel % (signed)self->patchSideLength) - center ; - y = (pixel / (signed)self->patchSideLength) - center ; - - angle0 = atan2(y,x) ; - - for (t = 0 ; t < (signed)self->numNeighbours ; ++t) { - double x1 = x + radius * cos(angle0 + dangle * t) + center ; - double y1 = y + radius * sin(angle0 + dangle * t) + center ; - self->neighSamplesX[t + (signed)self->numNeighbours * i] = x1 ; - self->neighSamplesY[t + (signed)self->numNeighbours * i] = y1 ; - } - } - return self ; -} - -/** @brief Create a new object with default parameters - ** @param sideLength size of the patches to be processed. - ** @return new object. - ** - ** @see ::vl_liopdesc_new. */ - -VlLiopDesc * vl_liopdesc_new_basic (vl_size sideLength) -{ - return vl_liopdesc_new(DEFAULT_NUM_NEIGHBOURS, - DEFAULT_NUM_SPATIAL_BINS, - DEFAULT_RADIUS, - sideLength) ; -} - -/** @brief Delete object instance. - ** @param self object instance. */ - -void -vl_liopdesc_delete (VlLiopDesc * self) -{ - vl_free (self->patchPixels) ; - vl_free (self->patchIntensities) ; - vl_free (self->patchPermutation) ; - vl_free (self->neighPermutation) ; - vl_free (self->neighIntensities) ; - vl_free (self->neighSamplesX) ; - vl_free (self->neighSamplesY) ; - vl_free (self) ; -} - -/* ---------------------------------------------------------------- */ -/* Compute LIOP descriptor */ -/* ---------------------------------------------------------------- */ - -/** @brief Compute liop descriptor for a patch - ** @param self object instance - ** @param desc descriptor to be computed (output). - ** @param patch patch to process - ** - ** Use ::vl_liopdesc_get_dimension to get the size of the descriptor - ** @a desc. */ - -void -vl_liopdesc_process (VlLiopDesc * self, float * desc, float const * patch) -{ - vl_index i,t ; - vl_index offset,numPermutations ; - vl_index spatialBinArea, spatialBinEnd, spatialBinIndex ; - float threshold ; - - memset(desc, 0, sizeof(float) * self->dimension) ; - - /* - * Sort pixels in the patch by increasing intensity. - */ - - for (i = 0 ; i < (signed)self->patchSize ; ++i) { - vl_index pixel = self->patchPixels[i] ; - self->patchIntensities[i] = patch[pixel] ; - self->patchPermutation[i] = i ; - } - patch_sort(self, self->patchSize) ; - - /* - * Tune the threshold if needed. - */ - - if (self->intensityThreshold < 0) { - i = self->patchPermutation[0] ; - t = self->patchPermutation[self->patchSize-1] ; - threshold = - self->intensityThreshold - * (self->patchIntensities[t] - self->patchIntensities[i]); - } else { - threshold = self->intensityThreshold ; - } - - /* - * Process pixels in order of increasing intenisity, dividing them into - * spatial bins on the fly. - */ - - numPermutations = factorial(self->numNeighbours) ; - spatialBinArea = self->patchSize / self->numSpatialBins ; - spatialBinEnd = spatialBinArea ; - spatialBinIndex = 0 ; - offset = 0 ; - - for (i = 0 ; i < (signed)self->patchSize ; ++i) { - vl_index permIndex ; - double *sx, *sy ; - - /* advance to the next spatial bin if needed */ - if (i >= (signed)spatialBinEnd && spatialBinIndex < (signed)self->numSpatialBins - 1) { - spatialBinEnd += spatialBinArea ; - spatialBinIndex ++ ; - offset += numPermutations ; - } - - /* get intensities of neighbours of the current patch element and sort them */ - sx = self->neighSamplesX + self->numNeighbours * self->patchPermutation[i] ; - sy = self->neighSamplesY + self->numNeighbours * self->patchPermutation[i] ; - for (t = 0 ; t < self->numNeighbours ; ++t) { - double x = *sx++ ; - double y = *sy++ ; - - /* bilinear interpolation */ - vl_index ix = vl_floor_d(x) ; - vl_index iy = vl_floor_d(y) ; - - double wx = x - ix ; - double wy = y - iy ; - - double a = 0, b = 0, c = 0, d = 0 ; - - int L = (int) self->patchSideLength ; - - if (ix >= 0 && iy >= 0 ) { a = patch[ix + iy * L] ; } - if (ix < L-1 && iy >= 0 ) { b = patch[ix+1 + iy * L] ; } - if (ix >= 0 && iy < L-1) { c = patch[ix + (iy+1) * L] ; } - if (ix < L-1 && iy < L-1) { d = patch[ix+1 + (iy+1) * L] ; } - - self->neighPermutation[t] = t; - self->neighIntensities[t] = (1 - wy) * (a + (b - a) * wx) + wy * (c + (d - c) * wx) ; - } - neigh_sort (self, self->numNeighbours) ; - - /* get permutation index */ - permIndex = get_permutation_index(self->neighPermutation, self->numNeighbours); - - /* - * Compute weight according to difference in intensity values and - * accumulate. - */ - { - int k, t ; - float weight = 0 ; - for(k = 0; k < self->numNeighbours ; ++k) { - for(t = k + 1; t < self->numNeighbours; ++t){ - double a = self->neighIntensities[k] ; - double b = self->neighIntensities[t] ; - weight += (a > b + threshold || b > a + threshold) ; - } - } - desc[permIndex + offset] += weight ; - } - } - - /* normalization */ - { - float norm = 0; - for(i = 0; i < (signed)self->dimension; i++) { - norm += desc[i]*desc[i]; - } - norm = VL_MAX(sqrt(norm), 1e-12) ; - for(i = 0; i < (signed)self->dimension; i++){ - desc[i] /= norm ; - } - } -} - - -/* ---------------------------------------------------------------- */ -/* Getters and setters */ -/* ---------------------------------------------------------------- */ - -/** @brief Get the dimension of a LIOP descriptor. - ** @param self object. - ** @return dimension. */ - -vl_size -vl_liopdesc_get_dimension (VlLiopDesc const * self) -{ - return self->dimension ; -} - - -/** @brief Get the number of neighbours. - ** @param self object. - ** @return number of neighbours. - **/ - -vl_size -vl_liopdesc_get_num_neighbours (VlLiopDesc const * self) -{ - assert(self) ; - return self->numNeighbours ; -} - -/** @brief Get the intensity threshold - ** @param self object. - ** @return intensity threshold. - ** @see liop-weighing - **/ - -float -vl_liopdesc_get_intensity_threshold (VlLiopDesc const * self) -{ - assert(self) ; - return self->intensityThreshold ; -} - -/** @brief Set the intensity threshold - ** @param self object. - ** @param x intensity threshold. - ** - ** If non-negative, the threshold as is is used when comparing - ** intensities. If negative, the absolute value of the specified - ** number is multipled by the maximum intensity difference inside a - ** patch to obtain the threshold. - ** - ** @see liop-weighing - **/ - -void -vl_liopdesc_set_intensity_threshold (VlLiopDesc * self, float x) -{ - assert(self) ; - self->intensityThreshold = x ; -} - -/** @brief Get the neighbourhood radius. - ** @param self object. - ** @return neighbourhood radius. - **/ - -double -vl_liopdesc_get_neighbourhood_radius (VlLiopDesc const * self) -{ - assert(self) ; - return self->neighRadius ; -} - -/** @brief Get the number of spatial bins. - ** @param self object. - ** @return number of spatial bins. - **/ - -vl_size -vl_liopdesc_get_num_spatial_bins (VlLiopDesc const * self) -{ - assert(self) ; - return self->numSpatialBins ; -} diff --git a/opensfm/src/third_party/vlfeat/vl/liop.h b/opensfm/src/third_party/vlfeat/vl/liop.h deleted file mode 100644 index d96de915d..000000000 --- a/opensfm/src/third_party/vlfeat/vl/liop.h +++ /dev/null @@ -1,78 +0,0 @@ -/** @file liop.h - ** @brief Local Intensity Order Pattern (LIOP) descriptor (@ref liop) - ** @author Hana Sarbortova - ** @author Andrea Vedaldi - ** @see @ref liop - **/ - -/* -Copyright (C) 2013 Hana Sarbortova and Andrea Vedaldi. -All rights reserved. - -This file is part of the VLFeat library and is made available under -the terms of the BSD license (see the COPYING file). -*/ - -#ifndef VL_LIOP_H -#define VL_LIOP_H - -#include "generic.h" - -/** @brief LIOP descriptor extractor object */ -typedef struct _VlLiopDesc -{ - vl_int numNeighbours; /**< Number of neighbours. */ - vl_int numSpatialBins; /**< Number of bins. */ - float intensityThreshold; /**< Weight threshold. */ - vl_size dimension; /**< LIOP descriptor size. */ - - /* Pixels in the circular patch */ - vl_size patchSideLength ; - vl_size patchSize ; /* only circular neighbourhood */ - vl_uindex * patchPixels ; - float * patchIntensities ; - vl_uindex * patchPermutation ; - - /* Neighbourhoods of each pixel (samples in a circle) */ - float neighRadius; /**< Point to neighbour radius (distance). */ - - float * neighIntensities ; - vl_uindex * neighPermutation ; - double * neighSamplesX ; - double * neighSamplesY ; - -} VlLiopDesc ; - -/** @name Construct and destroy - ** @{ */ -VL_EXPORT -VlLiopDesc * vl_liopdesc_new (vl_int numNeighbours, - vl_int numSpatialBins, - float radius, - vl_size sideLength) ; - -VL_EXPORT -VlLiopDesc * vl_liopdesc_new_basic (vl_size sideLength) ; - -VL_EXPORT -void vl_liopdesc_delete (VlLiopDesc * self) ; -/** @} */ - -/** @name Get data and parameters - ** @{ */ -VL_EXPORT vl_size vl_liopdesc_get_dimension (VlLiopDesc const * self) ; -VL_EXPORT vl_size vl_liopdesc_get_num_neighbours (VlLiopDesc const * self) ; -VL_EXPORT float vl_liopdesc_get_intensity_threshold (VlLiopDesc const * self) ; -VL_EXPORT vl_size vl_liopdesc_get_num_spatial_bins (VlLiopDesc const * self) ; -VL_EXPORT double vl_liopdesc_get_neighbourhood_radius (VlLiopDesc const * self) ; -VL_EXPORT void vl_liopdesc_set_intensity_threshold (VlLiopDesc * self, float x) ; -/** @} */ - -/** @name Compute LIOP descriptor - ** @{ */ -VL_EXPORT -void vl_liopdesc_process (VlLiopDesc * liop, float * desc, float const * patch) ; -/** @} */ - -/* VL_LIOP_H */ -#endif diff --git a/opensfm/src/third_party/vlfeat/vl/mathop.c b/opensfm/src/third_party/vlfeat/vl/mathop.c deleted file mode 100644 index d2a292697..000000000 --- a/opensfm/src/third_party/vlfeat/vl/mathop.c +++ /dev/null @@ -1,1032 +0,0 @@ -/** @file mathop.c - ** @brief Math operations - Definition - ** @author Andrea Vedaldi, David Novotny - **/ - -/* -Copyright (C) 2014 Andrea Vedaldi. -Copyright (C) 2007-12 Andrea Vedaldi and Brian Fulkerson. -All rights reserved. - -This file is part of the VLFeat library and is made available under -the terms of the BSD license (see the COPYING file). -*/ - -/** - -@page mathop Mathematical operations -@author Andrea Vedaldi -@author Brian Fulkerson -@tableofcontents - - -VLFeat include several low-level routines to speedup common -mathematical operations used throughout the library. Most are -collected in the @ref mathop.h module. - - -@section mathop-usage-vector-comparison Comparing vectors - - -@ref mathop.h includes a number of functions to quickly compute -distances or similarity of pairs of vector. Applications include -clustering and evaluation of SVM-like classifiers. - -Use ::vl_get_vector_comparison_function_f or -::vl_get_vector_comparison_function_d obtain an approprite function -to comprare vectors of floats or doubles, respectively. Such -functions are usually optimized (for instance, on X86 platforms they -use the SSE vector extension) and are several times faster than a -naive implementation. ::vl_eval_vector_comparison_on_all_pairs_f and -::vl_eval_vector_comparison_on_all_pairs_d can be used to evaluate -the comparison function on all pairs of one or two sequences of -vectors. - -Let @f$ \mathbf{x} = (x_1,\dots,x_d) @f$ and @f$ \mathbf{y} = -(y_1,\dots,y_d) @f$ be two vectors. The following comparison -functions are supported: - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
@f$ l^1 @f$::VlDistanceL1@f$ \sum_{i=1}^d |x_i - y_i| @f$l1 distance (squared intersection metric)
@f$ l^2 @f$::VlDistanceL2@f$\sum_{i=1}^d (x_i - y_i)^2@f$Squared Euclidean disance
@f$ \chi^2 @f$::VlDistanceChi2@f$\sum_{i=1}^d \frac{(x_i - y_i)^2}{x_i + y_i}@f$Squared chi-square distance
-::VlDistanceHellinger@f$\sum_{i=1}^d (\sqrt{x_i} - \sqrt{y_i})^2@f$Squared Hellinger's distance
-::VlDistanceJS@f$ -\sum_{i=1}^d -\left( - x_i \log\frac{2x_i}{x_i+y_i} -+ y_i \log\frac{2y_i}{x_i+y_i} -\right) -@f$ -Squared Jensen-Shannon distance
@f$ l^1 @f$::VlKernelL1@f$ \sum_{i=1}^d \min\{ x_i, y_i \} @f$intersection kernel
@f$ l^2 @f$::VlKernelL2@f$\sum_{i=1}^d x_iy_i @f$linear kernel
@f$ \chi^2 @f$::VlKernelChi2@f$\sum_{i=1}^d 2 \frac{x_iy_i}{x_i + y_i}@f$chi-square kernel
-::VlKernelHellinger@f$\sum_{i=1}^d 2 \sqrt{x_i y_i}@f$Hellinger's kernel (Bhattacharya coefficient)
-::VlKernelJS@f$ -\sum_{i=1}^d -\left( - \frac{x_i}{2} \log_2\frac{x_i+y_i}{x_i} -+ \frac{y_i}{2} \log_2\frac{x_i+y_i}{y_i} -\right) -@f$ -Jensen-Shannon kernel
- -@remark The definitions have been choosen so that corresponding kernels and -distances are related by the equation: -@f[ - d^2(\mathbf{x},\mathbf{y}) - = - k(\mathbf{x},\mathbf{x}) - +k(\mathbf{y},\mathbf{y}) - -k(\mathbf{x},\mathbf{y}) - -k(\mathbf{y},\mathbf{x}) -@f] -This means that each of these distances can be interpreted as a -squared distance or metric in the corresponding reproducing kernel -Hilbert space. Notice in particular that the @f$ l^1 @f$ or Manhattan -distance is also a squared distance in this sense. - - -@section mathop-integer-ops Fast basic functions operations - - -In certain algorithm it is useful to quickly compute integer -approximation of certain mathematical operations. Presently, VLFeat -includes and implementations of: - -- Fast single precision atan2: ::vl_fast_sqrt_f. -- Fast inverse square root: ::vl_fast_resqrt_f, ::vl_fast_resqrt_d. -- Fast square root: ::vl_fast_sqrt_f, ::vl_fast_sqrt_d. -- Fast integer square root: ::vl_fast_sqrt_ui16, ::vl_fast_sqrt_ui32, - ::vl_fast_sqrt_ui64 (see also @subpage mathop-sqrti). -**/ - -/** @fn vl_get_vector_comparison_function_f(VlVectorComparisonType) - ** - ** @brief Get vector comparison function from comparison type - ** @param type vector comparison type. - ** @return comparison function. - **/ - -/** @fn vl_get_vector_comparison_function_d(VlVectorComparisonType) - ** @brief Get vector comparison function from comparison type - ** @sa vl_get_vector_comparison_function_f - **/ - -/** @fn vl_eval_vector_comparison_on_all_pairs_f(float*,vl_size, - ** float const*,vl_size,float const*,vl_size,VlFloatVectorComparisonFunction) - ** - ** @brief Evaluate vector comparison function on all vector pairs - ** @param result comparison matrix (output). - ** @param dimension number of vector components (rows of @a X and @a Y). - ** @param X data matrix X. - ** @param Y data matrix Y. - ** @param numDataX number of vectors in @a X (columns of @a X) - ** @param numDataY number of vectros in @a Y (columns of @a Y) - ** @param function vector comparison function. - ** - ** The function evaluates @a function on all pairs of columns - ** from matrices @a X and @a Y, filling a @a numDataX by @a numDataY - ** matrix. - ** - ** If @a Y is a null pointer the function compares all columns from - ** @a X with themselves. - **/ - -/** @fn vl_eval_vector_comparison_on_all_pairs_d(double*,vl_size, - ** double const*,vl_size,double const*,vl_size,VlDoubleVectorComparisonFunction) - ** @brief Evaluate vector comparison function on all vector pairs - ** @sa vl_eval_vector_comparison_on_all_pairs_f - **/ - -/** -@page mathop-sqrti Fast integer square root algorithm -@tableofcontents - -This section describes the fast integer square root algorithm used by -vl_fast_sqrt_ui8, ::vl_fast_sqrt_ui16, ::vl_fast_sqrt_ui32, -::vl_fast_sqrt_ui64. - -Given a non-negative integer $x \in \mathbb{Z}_+$, the goal of this -algorithm is to quickly compute the integer approximation of the -square root of an integer number: - -\[ -y = \max_{\bar y\in\mathbb{Z}} \bar y, \qquad \text{such that}\ \bar y^2 \leq x. -\] - -Consider determining the k-th bit of $y$. To this end, decompose $y$ -in three parts: - -\[ -y = y_{k+1} + q 2^k + r, -\qquad \text{where}\ y_{k+1} \geq 2^{k+1}, r < 2^k, -\] - -and $q\in\{0,1\}$ is the bit to be determined. Here $y_{k+1}$ is a part -of the result $y$ that has already been determined, while the bit $q$ -and the remainder $r$ are still unknown. Recall that the goal is to -find the largest $y^2$ such that $y^2 \leq x$. Expanding $y^2$ this -condition becomes - -\[ -q (2^{2k} + 2 y_{k+1} 2^k) + r(r + 2q 2^k + 2 y_{k+1}) \leq x - y_{k+1}^2. -\] - -We can now determine if $q=1$ or $q=0$ based on the value of the -residual $x - y_{k+1}^2$. Specifically, $q=1$ requires that: - -\[ -\boxed{ -2^{2k} + 2a2^k \leq x - y_{k+1}^2. -} -\] - -On the other hand, if this equation is satisfied, then setting $r=0$ -shows that there exists at least one $y$ such that $q=1$ and $y^2 \leq -x$. In particular, greedily choosing $q=1$ in $x=y_{k+1} + 2^k q + r$ is -optimal because $2^k > r$. This yields the algorithm: - -1. Note that if $x$ is stored in $n$ bits and $n$ is even, then the - integer square root $y$ does not require more than $m = n / 2$ bit - to be stored. Thus the first bit to be determined is $k \leftarrow - m - 1 = n/2 - 1$ and $y_{n/2}=0$. -2. The algorithm stores and updates $y_k/2^{k}$ and $x - y_{k}^2$ for - convenience. -3. During iteration $k$, $y_k$ is determined. On entering the - iteration, the first step is to compute $y_{k+1}/2^k = 2 - y_{k+1}/2^{k+1}$. -4. Then the bound $t = (2^{2k} + 2 y_{k+1})2^k = 2^{2k}(1 + 2 - y_{k+1}/2^k)$. -5. If $t \geq x - y_{k+1}$, the $k$-th bit of $y_k$ is set to - one. This means applying the update $\hat y_{k}/2^k \leftarrow - y_{k+1}/2^k + 1$. This also requires computing $x - y_{k}^2 - \leftarrow x - y_{k+1}^2 - t$. -6. Decrement $k \leftarrow k -1$ and, if $k\geq 0$, continue from 3. - -**/ - -/* ---------------------------------------------------------------- */ -#ifndef VL_MATHOP_INSTANTIATING - -#include "mathop.h" -#include "mathop_sse2.h" - #include "mathop_avx.h" -#include - -#undef FLT -#define FLT VL_TYPE_FLOAT -#define VL_MATHOP_INSTANTIATING -#include "mathop.c" - -#undef FLT -#define FLT VL_TYPE_DOUBLE -#define VL_MATHOP_INSTANTIATING -#include "mathop.c" -#endif - -/* ---------------------------------------------------------------- */ -#ifdef VL_MATHOP_INSTANTIATING -#include "float.h" - -#undef COMPARISONFUNCTION_TYPE -#undef COMPARISONFUNCTION3_TYPE -#if (FLT == VL_TYPE_FLOAT) -# define COMPARISONFUNCTION_TYPE VlFloatVectorComparisonFunction -# define COMPARISONFUNCTION3_TYPE VlFloatVector3ComparisonFunction -#else -# define COMPARISONFUNCTION_TYPE VlDoubleVectorComparisonFunction -# define COMPARISONFUNCTION3_TYPE VlDoubleVector3ComparisonFunction -#endif - -/* ---------------------------------------------------------------- */ - -VL_EXPORT T -VL_XCAT(_vl_distance_l2_, SFX) -(vl_size dimension, T const * X, T const * Y) -{ - T const * X_end = X + dimension ; - T acc = 0.0 ; - while (X < X_end) { - T d = *X++ - *Y++ ; - acc += d * d ; - } - return acc ; -} - -VL_EXPORT T -VL_XCAT(_vl_distance_l1_, SFX) -(vl_size dimension, T const * X, T const * Y) -{ - T const * X_end = X + dimension ; - T acc = 0.0 ; - while (X < X_end) { - T d = *X++ - *Y++ ; - acc += VL_MAX(d, -d) ; - } - return acc ; -} - -VL_EXPORT T -VL_XCAT(_vl_distance_chi2_, SFX) -(vl_size dimension, T const * X, T const * Y) -{ - T const * X_end = X + dimension ; - T acc = 0.0 ; - while (X < X_end) { - T a = *X++ ; - T b = *Y++ ; - T delta = a - b ; - T denom = (a + b) ; - T numer = delta * delta ; - if (denom) { - T ratio = numer / denom ; - acc += ratio ; - } - } - return acc ; -} - -VL_EXPORT T -VL_XCAT(_vl_distance_hellinger_, SFX) -(vl_size dimension, T const * X, T const * Y) -{ - T const * X_end = X + dimension ; - T acc = 0.0 ; - while (X < X_end) { - T a = *X++ ; - T b = *Y++ ; -#if (FLT == VL_TYPE_FLOAT) - acc += a + b - 2.0 * sqrtf (a*b) ; -#else - acc += a + b - 2.0 * sqrt (a*b) ; -#endif - } - return acc ; -} - -VL_EXPORT T -VL_XCAT(_vl_distance_js_, SFX) -(vl_size dimension, T const * X, T const * Y) -{ - T const * X_end = X + dimension ; - T acc = 0.0 ; - while (X < X_end) { - T x = *X++ ; - T y = *Y++ ; - if (x) acc += x - x * VL_XCAT(vl_log2_,SFX)(1 + y/x) ; - if (y) acc += y - y * VL_XCAT(vl_log2_,SFX)(1 + x/y) ; - } - return acc ; -} - -VL_EXPORT T -VL_XCAT(_vl_kernel_l2_, SFX) -(vl_size dimension, T const * X, T const * Y) -{ - T const * X_end = X + dimension ; - T acc = 0.0 ; - while (X < X_end) { - T a = *X++ ; - T b = *Y++ ; - acc += a * b ; - } - return acc ; -} - -VL_EXPORT T -VL_XCAT(_vl_kernel_l1_, SFX) -(vl_size dimension, T const * X, T const * Y) -{ - T const * X_end = X + dimension ; - T acc = 0.0 ; - while (X < X_end) { - T a = *X++ ; - T b = *Y++ ; - T a_ = VL_XCAT(vl_abs_, SFX) (a) ; - T b_ = VL_XCAT(vl_abs_, SFX) (b) ; - acc += a_ + b_ - VL_XCAT(vl_abs_, SFX) (a - b) ; - } - return acc / ((T)2) ; -} - -VL_EXPORT T -VL_XCAT(_vl_kernel_chi2_, SFX) -(vl_size dimension, T const * X, T const * Y) -{ - T const * X_end = X + dimension ; - T acc = 0.0 ; - while (X < X_end) { - T a = *X++ ; - T b = *Y++ ; - T denom = (a + b) ; - if (denom) { - T numer = 2 * a * b ; - T ratio = numer / denom ; - acc += ratio ; - } - } - return acc ; -} - -VL_EXPORT T -VL_XCAT(_vl_kernel_hellinger_, SFX) -(vl_size dimension, T const * X, T const * Y) -{ - T const * X_end = X + dimension ; - T acc = 0.0 ; - while (X < X_end) { - T a = *X++ ; - T b = *Y++ ; -#if (FLT == VL_TYPE_FLOAT) - acc += sqrtf (a*b) ; -#else - acc += sqrt (a*b) ; -#endif - } - return acc ; -} - -VL_EXPORT T -VL_XCAT(_vl_kernel_js_, SFX) -(vl_size dimension, T const * X, T const * Y) -{ - T const * X_end = X + dimension ; - T acc = 0.0 ; - while (X < X_end) { - T x = *X++ ; - T y = *Y++ ; - if (x) acc += x * VL_XCAT(vl_log2_,SFX)(1 + y/x) ; - if (y) acc += y * VL_XCAT(vl_log2_,SFX)(1 + x/y) ; - } - return (T)0.5 * acc ; -} - -VL_EXPORT T -VL_XCAT(_vl_distance_mahalanobis_sq_, SFX) -(vl_size dimension, T const * X, T const * MU, T const * S) -{ - T const * X_end = X + dimension ; - T acc = 0.0 ; - while (X < X_end) { - T d = *X++ - *MU++ ; - acc += d * d * (*S++) ; - } - return acc ; -} - -/* ---------------------------------------------------------------- */ - -VL_EXPORT COMPARISONFUNCTION_TYPE -VL_XCAT(vl_get_vector_comparison_function_, SFX)(VlVectorComparisonType type) -{ - COMPARISONFUNCTION_TYPE function = 0 ; - switch (type) { - case VlDistanceL2 : function = VL_XCAT(_vl_distance_l2_, SFX) ; break ; - case VlDistanceL1 : function = VL_XCAT(_vl_distance_l1_, SFX) ; break ; - case VlDistanceChi2 : function = VL_XCAT(_vl_distance_chi2_, SFX) ; break ; - case VlDistanceHellinger : function = VL_XCAT(_vl_distance_hellinger_, SFX) ; break ; - case VlDistanceJS : function = VL_XCAT(_vl_distance_js_, SFX) ; break ; - case VlKernelL2 : function = VL_XCAT(_vl_kernel_l2_, SFX) ; break ; - case VlKernelL1 : function = VL_XCAT(_vl_kernel_l1_, SFX) ; break ; - case VlKernelChi2 : function = VL_XCAT(_vl_kernel_chi2_, SFX) ; break ; - case VlKernelHellinger : function = VL_XCAT(_vl_kernel_hellinger_, SFX) ; break ; - case VlKernelJS : function = VL_XCAT(_vl_kernel_js_, SFX) ; break ; - default: abort() ; - } - -#ifndef VL_DISABLE_SSE2 - /* if a SSE2 implementation is available, use it */ - if (vl_cpu_has_sse2() && vl_get_simd_enabled()) { - switch (type) { - case VlDistanceL2 : function = VL_XCAT(_vl_distance_l2_sse2_, SFX) ; break ; - case VlDistanceL1 : function = VL_XCAT(_vl_distance_l1_sse2_, SFX) ; break ; - case VlDistanceChi2 : function = VL_XCAT(_vl_distance_chi2_sse2_, SFX) ; break ; - case VlKernelL2 : function = VL_XCAT(_vl_kernel_l2_sse2_, SFX) ; break ; - case VlKernelL1 : function = VL_XCAT(_vl_kernel_l1_sse2_, SFX) ; break ; - case VlKernelChi2 : function = VL_XCAT(_vl_kernel_chi2_sse2_, SFX) ; break ; - default: break ; - } - } -#endif - -#ifndef VL_DISABLE_AVX - /* if an AVX implementation is available, use it */ - if (vl_cpu_has_avx() && vl_get_simd_enabled()) { - switch (type) { - case VlDistanceL2 : function = VL_XCAT(_vl_distance_l2_avx_, SFX) ; break ; - default: break ; - } - } -#endif - - return function ; -} - -/* ---------------------------------------------------------------- */ - -VL_EXPORT COMPARISONFUNCTION3_TYPE -VL_XCAT(vl_get_vector_3_comparison_function_, SFX)(VlVectorComparisonType type) -{ - COMPARISONFUNCTION3_TYPE function = 0 ; - switch (type) { - case VlDistanceMahalanobis : function = VL_XCAT(_vl_distance_mahalanobis_sq_, SFX) ; break ; - default: abort() ; - } - -#ifndef VL_DISABLE_SSE2 - /* if a SSE2 implementation is available, use it */ - if (vl_cpu_has_sse2() && vl_get_simd_enabled()) { - switch (type) { - case VlDistanceMahalanobis : function = VL_XCAT(_vl_distance_mahalanobis_sq_sse2_, SFX) ; break ; - default: break ; - } - } -#endif - -#ifndef VL_DISABLE_AVX - /* if an AVX implementation is available, use it */ - if (vl_cpu_has_avx() && vl_get_simd_enabled()) { - switch (type) { - case VlDistanceMahalanobis : function = VL_XCAT(_vl_distance_mahalanobis_sq_avx_, SFX) ; break ; - default: break ; - } - } -#endif - - return function ; -} - -/* ---------------------------------------------------------------- */ - -VL_EXPORT void -VL_XCAT(vl_eval_vector_comparison_on_all_pairs_, SFX) -(T * result, vl_size dimension, - T const * X, vl_size numDataX, - T const * Y, vl_size numDataY, - COMPARISONFUNCTION_TYPE function) -{ - vl_uindex xi ; - vl_uindex yi ; - - if (dimension == 0) return ; - if (numDataX == 0) return ; - assert (X) ; - - if (Y) { - if (numDataY == 0) return ; - for (yi = 0 ; yi < numDataY ; ++ yi) { - for (xi = 0 ; xi < numDataX ; ++ xi) { - *result++ = (*function)(dimension, X, Y) ; - X += dimension ; - } - X -= dimension * numDataX ; - Y += dimension ; - } - } else { - T * resultTransp = result ; - Y = X ; - for (yi = 0 ; yi < numDataX ; ++ yi) { - for (xi = 0 ; xi <= yi ; ++ xi) { - T z = (*function)(dimension, X, Y) ; - X += dimension ; - *result = z ; - *resultTransp = z ; - result += 1 ; - resultTransp += numDataX ; - } - X -= dimension * (yi + 1) ; - Y += dimension ; - result += numDataX - (yi + 1) ; - resultTransp += 1 - (yi + 1) * numDataX ; - } - } -} - -/* VL_MATHOP_INSTANTIATING */ -#endif - - -/* ---------------------------------------------------------------- */ -/* Numerical analysis */ -/* ---------------------------------------------------------------- */ - -#ifndef VL_MATHOP_INSTANTIATING - -/** @brief SVD of a 2x2 real matrix - ** @param S 2x2 real diagonal matrix of the singular values (out). - ** @param U first 2x2 real orthonormal matrix (out). - ** @param V second 2x2 real orthonormal matrix (out). - ** @param M 2x2 matrix. - ** - ** The function comptues the SVD decomposition of the 2x2 - ** real matrix @f$ M @f$: - ** @f[ - ** M = U \operatorname S V^\top - ** @f] - ** where @f$ U @f$ and @f$ V @f$ are real orthonormal matrices - ** and @f$ S @f$ is the diagonal matrix of the singular values - ** in decreasing order. - ** - ** @par Algorithm - ** - ** The fist step is to find rotation matrices @f$ U_1 @f$ and - ** @f$ V_1 @f$ such taht - ** @f[ - ** M = U_1 R V_1^\top, \quad - ** U_1 = \begin{barray} c_{u1} & - s_{u1} \\ s_{u1} & c_{u1} \end{barray}, \quad - ** V_1 = \begin{barray} c_{v1} & - s_{v1} \\ s_{v1} & c_{v1} \end{barray}, \quad - ** R = \begin{barray} f & g \\ 0 & h \end{barray}. - ** @f] - ** Gives a 2x2 triangular matrix. The second step is to call - ** ::vl_lapack_dlasv2 on the matrix @f$ R @f$ obtaining - ** @f[ - ** M = U_1 (U_2 S V_2^\top) V_2. - ** @f] - **/ - -void -vl_svd2 (double* S, double *U, double *V, double const *M) -{ - double m11 = M[0] ; - double m21 = M[1] ; - double m12 = M[2] ; - double m22 = M[3] ; - double cu1 = m11 ; - double su1 = m21 ; - double norm = sqrt(cu1*cu1 + su1*su1) ; - double cu2, su2, cv2, sv2 ; - double f, g, h ; - double smin, smax ; - cu1 /= norm ; - su1 /= norm ; - - f = cu1 * m11 + su1 * m21 ; - g = cu1 * m12 + su1 * m22 ; - h = - su1 * m12 + cu1 * m22 ; - - vl_lapack_dlasv2 (&smin, &smax, - &sv2, &cv2, - &su2, &cu2, - f, g, h) ; - - assert(S) ; - S[0] = smax ; - S[1] = 0 ; - S[2] = 0 ; - S[3] = smin ; - - if (U) { - U[0] = cu2*cu1 - su2*su1 ; - U[1] = su2*cu1 + cu2*su1 ; - U[2] = - cu2*su1 - su2*cu1 ; - U[3] = - su2*su1 + cu2*cu1 ; - } - if (V) { - V[0] = cv2 ; - V[1] = sv2 ; - V[2] = - sv2 ; - V[3] = cv2 ; - } -} - -/** @brief SVD of a 2x2 upper triangular matrix (LAPACK @c dlasv2 equivalent) - ** @param smin smallest (in modulus) singular value (out). - ** @param smax largest (in modulus) singuarl value (out). - ** @param sv second component of the right singular vector of @c smax (out). - ** @param cv first component of the right singular vector of @c smax (out). - ** @param su second component of the left singular vector of @c smax (out). - ** @param cu first component of the left singular vector of @c smax (out). - ** @param f first entry of the upper triangular matrix. - ** @param g second entry of the upper triangular matrix. - ** @param h third entry of the upper triangular matrix. - ** - ** @f[ - ** \begin{bmatrix} f & g \\ 0 & h \end{bmatrix} - ** = - ** \begin{bmatrix} cv & - sv \\ sv & cv \end{bmatrix} - ** \begon{bmatrix} smax & 0 \\ 0 & smin \end{bmatrix} - ** \begin{bmatrix} cv & - sv \\ sv & cv \end{bmatrix} - ** @f] - ** - ** Z.Bai and J.Demmel, - ** "Computing the Generalized Singular Value Decomposition", - ** SIAM J. Sci. Comput., Vol. 14, No. 6, pp. 1464-1486, November 1993 - **/ - -#define isign(i) ((i)<0 ? (-1) : (+1)) /* integer sign function */ -#define sign(x) ((x)<0.0 ? (-1) : (+1)) /* double sign function */ - -void -vl_lapack_dlasv2 (double *smin, - double *smax, - double *sv, - double *cv, - double *su, - double *cu, - double f, - double g, - double h) -{ - double svt, cvt, sut, cut; /* temporary sv, cv, su, and cu */ - double ft = f, gt = g, ht = h; /* temporary f, g, h */ - double fa = fabs(f), ga = fabs(g), ha = fabs(h); /* |f|, |g|, and |h| */ - int pmax = 1 ; /* pointer to max abs entry */ - int swap = 0 ; /* is swapped */ - int glarge = 0 ; /* is g very large */ - int tsign ; /* tmp sign */ - double fmh ; /* |f| -|h| */ - double d ; /* (|f| -|h|)/|f| */ - double dd ; /* d*d */ - double q ; /* g/f */ - double qq ; /* q*q */ - double s ; /* (|f| + |h|)/|f| */ - double ss ; /* s*s */ - double spq ; /* sqrt(ss + qq) */ - double dpq ; /* sqrt(dd + qq) */ - double a ; /* (spq + dpq)/2 */ - double tmp ; /* temporaries */ - double tt; - - /* make fa >= ha */ - if (fa < ha) { - pmax = 3 ; - tmp =ft ; ft = ht ; ht = tmp ; /* swap ft and ht */ - tmp =fa ; fa = ha ; ha = tmp ; /* swap fa and ha */ - swap = 1 ; - } - - if (ga == 0.0) { /* diagonal */ - *smin = ha ; - *smax = fa ; - /* identity matrix */ - cut = 1.0 ; sut = 0.0 ; - cvt = 1.0 ; svt = 0.0 ; - } - else { /* not diagonal */ - if (ga > fa) { /* g is the largest entry */ - pmax = 2 ; - if ((fa / ga) < VL_EPSILON_D) { /* g is very large */ - glarge = 1 ; - *smax = ga ; /* 1 ulp */ - if (ha > 1.0) { - *smin = fa / (ga / ha) ; /* 2 ulps */ - } else { - *smin = (fa / ga) * ha ; /* 2 ulps */ - } - cut = 1.0 ; sut = ht / gt ; - cvt = 1.0 ; svt = ft / gt ; - } - } - - if (glarge == 0) { /* normal case */ - fmh = fa - ha ; /* 1ulp */ - if (fmh == fa) { /* cope with infinite f or h */ - d = 1.0 ; - } else { - d = fmh / fa ; /* note 0<=d<=1.0, 2 ulps */ - } - q = gt / ft ; /* note |q|<1/EPS, 1 ulp */ - s = 2.0 - d ; /* note s>=1.0, 3 ulps */ - dd = d*d ; - qq = q*q ; - ss = s*s ; - spq = sqrt(ss + qq) ; /* note 1<=spq<=1+1/EPS, 5 ulps */ - if (d == 0.0) { - dpq = fabs(q) ; /* 0 ulp */ - } else { - dpq = sqrt(dd + qq) ; /* note 0<=dpq<=1+1/EPS, 3.5 ulps */ - } - a = 0.5 * (spq + dpq) ; /* note 1<=a<=1 + |q|, 6 ulps */ - *smin = ha / a; /* 7 ulps */ - *smax = fa * a; /* 7 ulps */ - if (qq==0.0) { /* qq underflow */ - if (d==0.0) { - tmp = sign(ft)*2*sign(gt); /* 0ulp */ - } - else { - tmp = gt/(sign(ft)*fmh) + q/s; /* 6 ulps */ - } - } else { - tmp = (q/(spq + s) + q/(dpq + d))*(1.0 + a); /* 17 ulps */ - } - /* if qq */ - tt = sqrt(tmp*tmp + 4.0) ; /* 18.5 ulps */ - cvt = 2.0 / tt ; /* 19.5 ulps */ - svt = tmp / tt ; /* 36.5 ulps */ - cut = (cvt + svt*q) / a ; /* 46.5 ulps */ - sut = (ht / ft) * svt / a ; /* 45.5 ulps */ - } /* if g not large */ - } /* if ga */ - if (swap == 1) { - *cu = svt ; *su = cvt ; - *cv = sut ; *sv = cut ; - } else { - *cu = cut ; *su = sut ; - *cv = cvt ; *sv = svt ; - } - /* correct the signs of smax and smin */ - if (pmax==1) { tsign = sign(*cv) * sign(*cu) * sign(f) ; } - if (pmax==2) { tsign = sign(*sv) * sign(*cu) * sign(g) ; } - if (pmax==3) { tsign = sign(*sv) * sign(*su) * sign(h) ; } - *smax = isign(tsign) * (*smax); - *smin = isign(tsign * sign(f) * sign(h)) * (*smin) ; -} - - -/** @brief Solve a 3x3 linear system - ** @param x result. - ** @param A system matrix. - ** @param b coefficients. - ** - ** The function computes a solution to @f$ Ax =b @f$ for a 3x3 - ** matrix. - **/ - -VL_EXPORT int -vl_solve_linear_system_3 (double * x, double const * A, double const *b) -{ - int err ; - double M[3*4] ; - M[0] = A[0] ; - M[1] = A[1] ; - M[2] = A[2] ; - M[3] = A[3] ; - M[4] = A[4] ; - M[5] = A[5] ; - M[6] = A[6] ; - M[7] = A[7] ; - M[8] = A[8] ; - M[9] = b[0] ; - M[10] = b[1] ; - M[11] = b[2] ; - err = vl_gaussian_elimination(M,3,4) ; - x[0] = M[9] ; - x[1] = M[10] ; - x[2] = M[11] ; - return err ; -} - -/** @brief Solve a 2x2 linear system - ** @param x result. - ** @param A system matrix. - ** @param b coefficients. - ** - ** The function computes a solution to @f$ Ax =b @f$ for a 2x2 - ** matrix. - **/ - -VL_EXPORT int -vl_solve_linear_system_2 (double * x, double const * A, double const *b) -{ - int err ; - double M[2*3] ; - M[0] = A[0] ; - M[1] = A[1] ; - M[2] = A[2] ; - M[3] = A[3] ; - M[4] = b[0]; - M[5] = b[1] ; - err = vl_gaussian_elimination(M,2,3) ; - x[0] = M[4] ; - x[1] = M[5] ; - return err ; -} - -/** @brief Gaussian elimination - ** @param M matrix. - ** @param numRows number of rows of @c M. - ** @param numColumns number of columns of @c M. - ** - ** The function runs Gaussian elimination with pivoting - ** on the matrix @a M in place. - ** @c numRows must be not larger than @c numColumns. - ** - ** Let @f$ M = [A, b] @f$ to obtain the solution to the linear - ** system @f$ Ax=b @f$ (as the last column of @c M after - ** elimination). - ** - ** Let @f$ M = [A, I] @f$ to compute the inverse of @c A in - ** a similar manner. - **/ - -VL_EXPORT vl_bool -vl_gaussian_elimination (double * A, vl_size numRows, vl_size numColumns) -{ - vl_index i, j, ii, jj ; - assert(A) ; - assert(numRows <= numColumns) ; - -#define Aat(i,j) A[(i) + (j)*numRows] - - /* Gauss elimination */ - for(j = 0 ; j < (signed)numRows ; ++j) { - double maxa = 0 ; - double maxabsa = 0 ; - vl_index maxi = -1 ; - double tmp ; - -#if 0 - { - vl_index iii, jjj ; - for (iii = 0 ; iii < 2 ; ++iii) { - for (jjj = 0 ; jjj < 3 ; ++jjj) { - VL_PRINTF("%5.2g ", Aat(iii,jjj)) ; - - } - VL_PRINTF("\n") ; - } - VL_PRINTF("\n") ; - } -#endif - - /* look for the maximally stable pivot */ - for (i = j ; i < (signed)numRows ; ++i) { - double a = Aat(i,j) ; - double absa = vl_abs_d (a) ; - if (absa > maxabsa) { - maxa = a ; - maxabsa = absa ; - maxi = i ; - } - } - i = maxi ; - - /* if singular give up */ - if (maxabsa < 1e-10) return VL_ERR_OVERFLOW ; - - /* swap j-th row with i-th row and normalize j-th row */ - for(jj = j ; jj < (signed)numColumns ; ++jj) { - tmp = Aat(i,jj) ; Aat(i,jj) = Aat(j,jj) ; Aat(j,jj) = tmp ; - Aat(j,jj) /= maxa ; - } - -#if 0 - { - vl_index iii, jjj ; - VL_PRINTF("after swap %d %d\n", j, i); - for (iii = 0 ; iii < 2 ; ++iii) { - for (jjj = 0 ; jjj < 3 ; ++jjj) { - VL_PRINTF("%5.2g ", Aat(iii,jjj)) ; - - } - VL_PRINTF("\n") ; - } - VL_PRINTF("\n") ; - } -#endif - - /* elimination */ - for (ii = j+1 ; ii < (signed)numRows ; ++ii) { - double x = Aat(ii,j) ; - for (jj = j ; jj < (signed)numColumns ; ++jj) { - Aat(ii,jj) -= x * Aat(j,jj) ; - } - } - -#if 0 - { - VL_PRINTF("after elimination\n"); - - vl_index iii, jjj ; - for (iii = 0 ; iii < 2 ; ++iii) { - for (jjj = 0 ; jjj < 3 ; ++jjj) { - VL_PRINTF("%5.2g ", Aat(iii,jjj)) ; - - } - VL_PRINTF("\n") ; - } - VL_PRINTF("\n") ; - } -#endif - - } - - /* backward substitution */ - for (i = numRows - 1 ; i > 0 ; --i) { - /* substitute in all rows above */ - for (ii = i - 1 ; ii >= 0 ; --ii) { - double x = Aat(ii,i) ; - /* j = numRows */ - for (j = numRows ; j < (signed)numColumns ; ++j) { - Aat(ii,j) -= x * Aat(i,j) ; - } - } - } - -#if 0 - { - VL_PRINTF("after substitution\n"); - - vl_index iii, jjj ; - for (iii = 0 ; iii < 2 ; ++iii) { - for (jjj = 0 ; jjj < 3 ; ++jjj) { - VL_PRINTF("%5.2g ", Aat(iii,jjj)) ; - - } - VL_PRINTF("\n") ; - } - VL_PRINTF("\n") ; - } -#endif - - - return VL_ERR_OK ; -} - -/* VL_MATHOP_INSTANTIATING */ -#endif - -#undef VL_MATHOP_INSTANTIATING diff --git a/opensfm/src/third_party/vlfeat/vl/mathop.h b/opensfm/src/third_party/vlfeat/vl/mathop.h deleted file mode 100644 index 6a1df8058..000000000 --- a/opensfm/src/third_party/vlfeat/vl/mathop.h +++ /dev/null @@ -1,719 +0,0 @@ -/** @file mathop.h - ** @brief Math operations (@ref mathop) - ** @author Andrea Vedaldi, David Novotny - **/ - -/* -Copyright (C) 2007-12 Andrea Vedaldi and Brian Fulkerson. -All rights reserved. - -This file is part of the VLFeat library and is made available under -the terms of the BSD license (see the COPYING file). -*/ - -#ifndef VL_MATHOP_H -#define VL_MATHOP_H - -#include "generic.h" -#include -#include - -/** @brief Euler constant*/ -#define VL_E 2.718281828459045 - -/** @brief Logarithm of 2 (math constant)*/ -#define VL_LOG_OF_2 0.693147180559945 - -/** @brief Pi (math constant) */ -#define VL_PI 3.141592653589793 - -/** @brief IEEE single precision epsilon (math constant) - ** - ** 1.0F + VL_EPSILON_F is the smallest representable - ** single precision number greater than @c 1.0F. Numerically, - ** ::VL_EPSILON_F is equal to @f$ 2^{-23} @f$. - ** - **/ -#define VL_EPSILON_F 1.19209290E-07F - -/** @brief IEEE double precision epsilon (math constant) - ** - ** 1.0 + VL_EPSILON_D is the smallest representable - ** double precision number greater than @c 1.0. Numerically, - ** ::VL_EPSILON_D is equal to @f$ 2^{-52} @f$. - **/ -#define VL_EPSILON_D 2.220446049250313e-16 - -/* - For the code below: An ANSI C compiler takes the two expressions, - LONG_VAR and CHAR_VAR, and implicitly casts them to the type of the - first member of the union. Refer to K&R Second Edition Page 148, - last paragraph. -*/ - -/** @internal @brief IEEE single precision quiet NaN constant */ -static union { vl_uint32 raw ; float value ; } - const vl_nan_f = - { 0x7FC00000UL } ; - -/** @internal @brief IEEE single precision infinity constant */ -static union { vl_uint32 raw ; float value ; } - const vl_infinity_f = - { 0x7F800000UL } ; - -/** @internal @brief IEEE double precision quiet NaN constant */ -static union { vl_uint64 raw ; double value ; } - const vl_nan_d = -#ifdef VL_COMPILER_MSC - { 0x7FF8000000000000ui64 } ; -#else - { 0x7FF8000000000000ULL } ; -#endif - -/** @internal @brief IEEE double precision infinity constant */ -static union { vl_uint64 raw ; double value ; } - const vl_infinity_d = -#ifdef VL_COMPILER_MSC - { 0x7FF0000000000000ui64 } ; -#else - { 0x7FF0000000000000ULL } ; -#endif - -/** @brief IEEE single precision NaN (not signaling) */ -#define VL_NAN_F (vl_nan_f.value) - -/** @brief IEEE single precision positive infinity (not signaling) */ -#define VL_INFINITY_F (vl_infinity_f.value) - -/** @brief IEEE double precision NaN (not signaling) */ -#define VL_NAN_D (vl_nan_d.value) - -/** @brief IEEE double precision positive infinity (not signaling) */ -#define VL_INFINITY_D (vl_infinity_d.value) - -/* ---------------------------------------------------------------- */ - -/** @brief Fast mod(x, 2 * VL_PI) - ** - ** @param x input value. - ** @return mod(x, 2 * VL_PI) - ** - ** The function is optimized for small absolute values of @a x. - ** - ** The result is guaranteed to be not smaller than 0. However, due to - ** finite numerical precision and rounding errors, the result can be - ** equal to 2 * VL_PI (for instance, if @c x is a very small negative - ** number). - **/ - -VL_INLINE float -vl_mod_2pi_f (float x) -{ - while (x > (float)(2 * VL_PI)) x -= (float) (2 * VL_PI) ; - while (x < 0.0F) x += (float) (2 * VL_PI); - return x ; -} - -/** @brief Fast mod(x, 2 * VL_PI) - ** @see vl_mod_2pi_f - **/ - -VL_INLINE double -vl_mod_2pi_d (double x) -{ - while (x > 2.0 * VL_PI) x -= 2 * VL_PI ; - while (x < 0.0) x += 2 * VL_PI ; - return x ; -} - -/** @brief Floor and convert to integer - ** @param x argument. - ** @return Similar to @c (int) floor(x) - **/ - -VL_INLINE long int -vl_floor_f (float x) -{ - long int xi = (long int) x ; - if (x >= 0 || (float) xi == x) return xi ; - else return xi - 1 ; -} - -/** @brief Floor and convert to integer - ** @see vl_floor_f - **/ - -VL_INLINE long int -vl_floor_d (double x) -{ - long int xi = (long int) x ; - if (x >= 0 || (double) xi == x) return xi ; - else return xi - 1 ; -} - -/** @brief Ceil and convert to integer - ** @param x argument. - ** @return @c lceilf(x) - **/ - -VL_INLINE long int -vl_ceil_f (float x) -{ -#ifdef VL_COMPILER_GNUC - return (long int) __builtin_ceilf(x) ; -#else - return (long int) ceilf(x) ; -#endif -} - -/** @brief Ceil and convert to integer - ** @see vl_ceil_f - **/ - -VL_INLINE long int -vl_ceil_d (double x) -{ -#ifdef VL_COMPILER_GNUC - return __builtin_ceil(x) ; -#else - return (long int) ceil(x) ; -#endif -} - -/** @brief Round - ** @param x argument. - ** @return @c lroundf(x) - ** This function is either the same or similar to C99 @c lroundf(). - **/ - -VL_INLINE long int -vl_round_f (float x) -{ -#ifdef VL_COMPILER_GNUC - return __builtin_lroundf(x) ; -#elif VL_COMPILER_MSC - if (x >= 0.0F) { - return vl_floor_f(x + 0.5F) ; - } else { - return vl_ceil_f(x - 0.5F) ; - } -#else - return lroundf(x) ; -#endif -} - -/** @brief Round - ** @param x argument. - ** @return @c lround(x) - ** This function is either the same or similar to C99 @c lround(). - **/ - -VL_INLINE long int -vl_round_d (double x) -{ -#ifdef VL_COMPILER_GNUC - return __builtin_lround(x) ; -#elif VL_COMPILER_MSC - if (x >= 0.0) { - return vl_floor_d(x + 0.5) ; - } else { - return vl_ceil_d(x - 0.5) ; - } -#else - return lround(x) ; -#endif -} - -/** @brief Fast @c abs(x) - ** @param x argument. - ** @return @c abs(x) - **/ - -VL_INLINE float -vl_abs_f (float x) -{ -#ifdef VL_COMPILER_GNUC - return __builtin_fabsf (x) ; -#else - return fabsf(x) ; -#endif -} - -/** @brief Fast @c abs(x) - ** @sa vl_abs_f - **/ - -VL_INLINE double -vl_abs_d (double x) -{ -#ifdef VL_COMPILER_GNUC - return __builtin_fabs (x) ; -#else - return fabs(x) ; -#endif -} - -/** @brief Base-2 logaritghm - ** @param x argument. - ** @return @c log(x). - **/ - -VL_INLINE double -vl_log2_d (double x) -{ -#ifdef VL_COMPILER_GNUC - return __builtin_log2(x) ; -#elif VL_COMPILER_MSC - return log(x) / 0.693147180559945 ; -#else - return log2(x) ; -#endif -} - -/** @copydoc vl_log2_d */ -VL_INLINE float -vl_log2_f (float x) -{ -#ifdef VL_COMPILER_GNUC - return __builtin_log2f (x) ; -#elif VL_COMPILER_MSC - return logf(x) / 0.6931472F ; -#else - return log2(x) ; -#endif -} - -/** @brief Square root. - ** @param x argument. - ** @return @c sqrt(x). - **/ - -VL_INLINE double -vl_sqrt_d (double x) -{ -#ifdef VL_COMPILER_GNUC - return __builtin_sqrt(x) ; -#else - return sqrt(x) ; -#endif -} - -/** @copydoc vl_sqrt_d */ -VL_INLINE float -vl_sqrt_f (float x) -{ -#ifdef VL_COMPILER_GNUC - return __builtin_sqrtf(x) ; -#else - return sqrtf(x) ; -#endif -} - - -/** @brief Check whether a floating point value is NaN - ** @param x argument. - ** @return true if @a x is NaN. - **/ -VL_INLINE vl_bool -vl_is_nan_f (float x) -{ -#ifdef VL_COMPILER_GNUC - return __builtin_isnan (x) ; -#elif VL_COMPILER_MSC - return _isnan(x) ; -#else - return isnan(x) ; -#endif -} - -/** @copydoc vl_is_nan_f */ -VL_INLINE vl_bool -vl_is_nan_d (double x) -{ -#ifdef VL_COMPILER_GNUC - return __builtin_isnan (x) ; -#elif VL_COMPILER_MSC - return _isnan(x) ; -#else - return isnan(x) ; -#endif -} - -/** @brief Check whether a floating point value is infinity - ** @param x argument. - ** @return true if @a x is infinity. - **/ -VL_INLINE vl_bool -vl_is_inf_f (float x) -{ -#ifdef VL_COMPILER_GNUC - return __builtin_isinf (x) ; -#elif VL_COMPILER_MSC - return ! _finite(x) ; -#else - return isinf(x) ; -#endif -} - -/** @copydoc vl_is_inf_f */ -VL_INLINE vl_bool -vl_is_inf_d (double x) -{ -#ifdef VL_COMPILER_GNUC - return __builtin_isinf (x) ; -#elif VL_COMPILER_MSC - return ! _finite(x) ; -#else - return isinf(x) ; -#endif -} - -/** ------------------------------------------------------------------ - ** @brief Fast @c atan2 approximation - ** @param y argument. - ** @param x argument. - ** - ** The function computes a relatively rough but fast approximation of - ** @c atan2(y,x). - ** - ** @par Algorithm - ** - ** The algorithm approximates the function @f$ f(r)=atan((1-r)/(1+r)) - ** @f$, @f$ r \in [-1,1] @f$ with a third order polynomial @f$ - ** f(r)=c_0 + c_1 r + c_2 r^2 + c_3 r^3 @f$. To fit the polynomial - ** we impose the constraints - ** - ** @f{eqnarray*} - ** f(+1) &=& c_0 + c_1 + c_2 + c_3 = atan(0) = 0,\\ - ** f(-1) &=& c_0 - c_1 + c_2 - c_3 = atan(\infty) = \pi/2,\\ - ** f(0) &=& c_0 = atan(1) = \pi/4. - ** @f} - ** - ** The last degree of freedom is fixed by minimizing the @f$ - ** l^{\infty} @f$ error, which yields - ** - ** @f[ - ** c_0=\pi/4, \quad - ** c_1=-0.9675, \quad - ** c_2=0, \quad - ** c_3=0.1821, - ** @f] - ** - ** with maximum error of 0.0061 radians at 0.35 degrees. - ** - ** @return Approximation of @c atan2(y,x). - **/ - -VL_INLINE float -vl_fast_atan2_f (float y, float x) -{ - float angle, r ; - float const c3 = 0.1821F ; - float const c1 = 0.9675F ; - float abs_y = vl_abs_f (y) + VL_EPSILON_F ; - - if (x >= 0) { - r = (x - abs_y) / (x + abs_y) ; - angle = (float) (VL_PI / 4) ; - } else { - r = (x + abs_y) / (abs_y - x) ; - angle = (float) (3 * VL_PI / 4) ; - } - angle += (c3*r*r - c1) * r ; - return (y < 0) ? - angle : angle ; -} - -/** @brief Fast @c atan2 approximation - ** @sa vl_fast_atan2_f - **/ - -VL_INLINE double -vl_fast_atan2_d (double y, double x) -{ - double angle, r ; - double const c3 = 0.1821 ; - double const c1 = 0.9675 ; - double abs_y = vl_abs_d (y) + VL_EPSILON_D ; - - if (x >= 0) { - r = (x - abs_y) / (x + abs_y) ; - angle = VL_PI / 4 ; - } else { - r = (x + abs_y) / (abs_y - x) ; - angle = 3 * VL_PI / 4 ; - } - angle += (c3*r*r - c1) * r ; - return (y < 0) ? - angle : angle ; -} - -/** ------------------------------------------------------------------ - ** @brief Fast @c resqrt approximation - ** @param x argument. - ** @return approximation of @c resqrt(x). - ** - ** The function quickly computes an approximation of @f$ x^{-1/2} - ** @f$. - ** - ** @par Algorithm - ** - ** The goal is to compute @f$ y = x^{-1/2} @f$, which we do by - ** finding the solution of @f$ 0 = f(y) = y^{-2} - x @f$ by two Newton - ** steps. Each Newton iteration is given by - ** - ** @f[ - ** y \leftarrow - ** y - \frac{f(y)}{\frac{df(y)}{dy}} = - ** y + \frac{1}{2} (y-xy^3) = - ** \frac{y}{2} \left( 3 - xy^2 \right) - ** @f] - ** - ** which yields a simple polynomial update rule. - ** - ** The clever bit (attributed to either J. Carmack or G. Tarolli) is - ** the way an initial guess @f$ y \approx x^{-1/2} @f$ is chosen. - ** - ** @see Inverse Sqare Root. - ** - **/ - -VL_INLINE float -vl_fast_resqrt_f (float x) -{ - /* 32-bit version */ - union { - float x ; - vl_int32 i ; - } u ; - - float xhalf = (float) 0.5 * x ; - - /* convert floating point value in RAW integer */ - u.x = x ; - - /* gives initial guess y0 */ - u.i = 0x5f3759df - (u.i >> 1); - /*u.i = 0xdf59375f - (u.i>>1);*/ - - /* two Newton steps */ - u.x = u.x * ( (float) 1.5 - xhalf*u.x*u.x) ; - u.x = u.x * ( (float) 1.5 - xhalf*u.x*u.x) ; - return u.x ; -} - -/** @brief Fast @c resqrt approximation - ** @sa vl_fast_resqrt_d - **/ - -VL_INLINE double -vl_fast_resqrt_d (double x) -{ - /* 64-bit version */ - union { - double x ; - vl_int64 i ; - } u ; - - double xhalf = (double) 0.5 * x ; - - /* convert floating point value in RAW integer */ - u.x = x ; - - /* gives initial guess y0 */ -#ifdef VL_COMPILER_MSC - u.i = 0x5fe6ec85e7de30dai64 - (u.i >> 1) ; -#else - u.i = 0x5fe6ec85e7de30daLL - (u.i >> 1) ; -#endif - - /* two Newton steps */ - u.x = u.x * ( (double) 1.5 - xhalf*u.x*u.x) ; - u.x = u.x * ( (double) 1.5 - xhalf*u.x*u.x) ; - return u.x ; -} - -/** ------------------------------------------------------------------ - ** @brief Fast @c sqrt approximation - ** @param x argument. - ** @return approximation of @c sqrt(x). - ** - ** The function uses ::vl_fast_resqrt_f - ** (or ::vl_fast_resqrt_d) to compute x * - ** vl_fast_resqrt_f(x). - **/ - -VL_INLINE float -vl_fast_sqrt_f (float x) -{ - return (x < 1e-8) ? 0 : x * vl_fast_resqrt_f (x) ; -} - -/** @brief Fast @c sqrt approximation - ** @copydoc vl_fast_sqrt_f - **/ - -VL_INLINE double -vl_fast_sqrt_d (float x) -{ - return (x < 1e-8) ? 0 : x * vl_fast_resqrt_d (x) ; -} - -/** @brief Fast integer @c sqrt approximation - ** @param x non-negative integer. - ** @return largest integer $y$ such that $y^2 \leq x$. - ** @sa @ref mathop-sqrti "Algorithm" - **/ -VL_INLINE vl_uint64 vl_fast_sqrt_ui64 (vl_uint64 x) ; - -/** @brief Fast @c sqrt approximation - ** @copydoc vl_fast_sqrt_ui64 */ -VL_INLINE vl_uint32 vl_fast_sqrt_ui32 (vl_uint32 x) ; - -/** @brief Fast @c sqrt approximation - ** @copydoc vl_fast_sqrt_ui64 */ -VL_INLINE vl_uint16 vl_fast_sqrt_ui16 (vl_uint16 x) ; - -/** @brief Fast @c sqrt approximation - ** @copydoc vl_fast_sqrt_ui64 */ -VL_INLINE vl_uint8 vl_fast_sqrt_ui8 (vl_uint8 x) ; - -#define VL_FAST_SQRT_UI(T,SFX) \ -VL_INLINE T \ -vl_fast_sqrt_ ## SFX (T x) \ -{ \ - T y = 0 ; \ - T tmp = 0 ; \ - int twice_k ; \ - for (twice_k = 8 * sizeof(T) - 2 ; \ - twice_k >= 0 ; twice_k -= 2) { \ - y <<= 1 ; /* y = 2 * y */ \ - tmp = (2*y + 1) << twice_k ; \ - if (x >= tmp) { \ - x -= tmp ; \ - y += 1 ; \ - } \ - } \ - return y ; \ -} - -VL_FAST_SQRT_UI(vl_uint64,ui64) -VL_FAST_SQRT_UI(vl_uint32,ui32) -VL_FAST_SQRT_UI(vl_uint16,ui16) -VL_FAST_SQRT_UI(vl_uint8,ui8) - -/* ---------------------------------------------------------------- */ -/* Vector distances and similarities */ -/* ---------------------------------------------------------------- */ - -/** @typedef VlFloatVectorComparisonFunction - ** @brief Pointer to a function to compare vectors of floats - **/ -typedef float (*VlFloatVectorComparisonFunction)(vl_size dimension, float const * X, float const * Y) ; - -/** @typedef VlDoubleVectorComparisonFunction - ** @brief Pointer to a function to compare vectors of doubles - **/ -typedef double (*VlDoubleVectorComparisonFunction)(vl_size dimension, double const * X, double const * Y) ; - -/** @typedef VlFloatVector3ComparisonFunction - ** @brief Pointer to a function to compare 3 vectors of doubles - **/ -typedef float (*VlFloatVector3ComparisonFunction)(vl_size dimension, float const * X, float const * Y, float const * Z) ; - -/** @typedef VlDoubleVector3ComparisonFunction - ** @brief Pointer to a function to compare 3 vectors of doubles - **/ -typedef double (*VlDoubleVector3ComparisonFunction)(vl_size dimension, double const * X, double const * Y, double const * Z) ; - -/** @brief Vector comparison types */ -enum _VlVectorComparisonType { - VlDistanceL1, /**< l1 distance (squared intersection metric) */ - VlDistanceL2, /**< squared l2 distance */ - VlDistanceChi2, /**< squared Chi2 distance */ - VlDistanceHellinger, /**< squared Hellinger's distance */ - VlDistanceJS, /**< squared Jensen-Shannon distance */ - VlDistanceMahalanobis, /**< squared mahalanobis distance */ - VlKernelL1, /**< intersection kernel */ - VlKernelL2, /**< l2 kernel */ - VlKernelChi2, /**< Chi2 kernel */ - VlKernelHellinger, /**< Hellinger's kernel */ - VlKernelJS /**< Jensen-Shannon kernel */ -} ; - -/** @brief Vector comparison types */ -typedef enum _VlVectorComparisonType VlVectorComparisonType ; - -/** @brief Get the symbolic name of a vector comparison type - ** @param type vector comparison type. - ** @return data symbolic name. - **/ - -VL_INLINE char const * -vl_get_vector_comparison_type_name (int type) -{ - switch (type) { - case VlDistanceL1 : return "l1" ; - case VlDistanceL2 : return "l2" ; - case VlDistanceChi2 : return "chi2" ; - case VlDistanceMahalanobis : return "mahalanobis" ; - case VlKernelL1 : return "kl1" ; - case VlKernelL2 : return "kl2" ; - case VlKernelChi2 : return "kchi2" ; - default: return NULL ; - } -} - -VL_EXPORT VlFloatVectorComparisonFunction -vl_get_vector_comparison_function_f (VlVectorComparisonType type) ; - -VL_EXPORT VlDoubleVectorComparisonFunction -vl_get_vector_comparison_function_d (VlVectorComparisonType type) ; - -VL_EXPORT VlFloatVector3ComparisonFunction -vl_get_vector_3_comparison_function_f (VlVectorComparisonType type) ; - -VL_EXPORT VlDoubleVector3ComparisonFunction -vl_get_vector_3_comparison_function_d (VlVectorComparisonType type) ; - - -VL_EXPORT void -vl_eval_vector_comparison_on_all_pairs_f (float * result, vl_size dimension, - float const * X, vl_size numDataX, - float const * Y, vl_size numDataY, - VlFloatVectorComparisonFunction function) ; - -VL_EXPORT void -vl_eval_vector_comparison_on_all_pairs_d (double * result, vl_size dimension, - double const * X, vl_size numDataX, - double const * Y, vl_size numDataY, - VlDoubleVectorComparisonFunction function) ; - -/* ---------------------------------------------------------------- */ -/* Numerical analysis */ -/* ---------------------------------------------------------------- */ - -VL_EXPORT void -vl_svd2 (double* S, double *U, double *V, double const *M) ; - -VL_EXPORT void -vl_lapack_dlasv2 (double *smin, - double *smax, - double *sv, - double *cv, - double *su, - double *cu, - double f, - double g, - double h) ; - - -VL_EXPORT int -vl_solve_linear_system_3 (double * x, double const * A, double const *b) ; - -VL_EXPORT int -vl_solve_linear_system_2 (double * x, double const * A, double const *b) ; - -VL_EXPORT int -vl_gaussian_elimination (double * A, vl_size numRows, vl_size numColumns) ; - -/* VL_MATHOP_H */ -#endif diff --git a/opensfm/src/third_party/vlfeat/vl/mathop_avx.c b/opensfm/src/third_party/vlfeat/vl/mathop_avx.c deleted file mode 100644 index 03dba22d8..000000000 --- a/opensfm/src/third_party/vlfeat/vl/mathop_avx.c +++ /dev/null @@ -1,275 +0,0 @@ -/** @file mathop_avx.c - ** @brief mathop for AVX - Definition - ** @author Andrea Vedaldi, David Novotny - **/ - -/* -Copyright (C) 2007-12 Andrea Vedaldi and Brian Fulkerson. -All rights reserved. - -This file is part of the VLFeat library and is made available under -the terms of the BSD license (see the COPYING file). -*/ - -/* ---------------------------------------------------------------- */ -#if ! defined(VL_MATHOP_AVX_INSTANTIATING) - -#include "mathop_avx.h" - -#undef FLT -#define FLT VL_TYPE_DOUBLE -#define VL_MATHOP_AVX_INSTANTIATING -#include "mathop_avx.c" - -#undef FLT -#define FLT VL_TYPE_FLOAT -#define VL_MATHOP_AVX_INSTANTIATING -#include "mathop_avx.c" - -/* ---------------------------------------------------------------- */ -/* VL_MATHOP_AVX_INSTANTIATING */ -#else -#ifndef VL_DISABLE_AVX - -#ifndef __AVX__ -#error Compiling AVX functions but AVX does not seem to be supported by the compiler. -#endif - -#include -#include "generic.h" -#include "mathop.h" -#include "float.h" - -VL_INLINE T -VL_XCAT(_vl_vhsum_avx_, SFX)(VTYPEavx x) -{ - T acc ; -#if (VSIZEavx == 8) - { - //VTYPEavx hsum = _mm256_hadd_ps(x, x); - //hsum = _mm256_add_ps(hsum, _mm256_permute2f128_ps(hsum, hsum, 0x1)); - //_mm_store_ss(&acc, _mm_hadd_ps( _mm256_castps256_ps128(hsum), _mm256_castps256_ps128(hsum) ) ); - VTYPEavx hsum = VHADD2avx(x, x); - hsum = VADDavx(hsum, VPERMavx(hsum, hsum, 0x1)); - VST1(&acc, VHADDavx( VCSTavx(hsum), VCSTavx(hsum) ) ); - } -#else - { - //VTYPEavx hsum = _mm256_add_pd(x, _mm256_permute2f128_pd(x, x, 0x1)); - VTYPEavx hsum = VADDavx(x, VPERMavx(x, x, 0x1)); - - //_mm_store_sd(&acc, _mm_hadd_pd( _mm256_castpd256_pd128(hsum), _mm256_castpd256_pd128(hsum) ) ); - VST1(&acc, VHADDavx( VCSTavx(hsum), VCSTavx(hsum) ) ); - } -#endif - return acc ; -} - -VL_EXPORT T -VL_XCAT(_vl_distance_l2_avx_, SFX) -(vl_size dimension, T const * X, T const * Y) -{ - - T const * X_end = X + dimension ; - T const * X_vec_end = X_end - VSIZEavx + 1 ; - T acc ; - VTYPEavx vacc = VSTZavx() ; - vl_bool dataAligned = VALIGNEDavx(X) & VALIGNEDavx(Y) ; - - if (dataAligned) { - while (X < X_vec_end) { - VTYPEavx a = *(VTYPEavx*)X ; - VTYPEavx b = *(VTYPEavx*)Y ; - VTYPEavx delta = VSUBavx(a, b) ; - VTYPEavx delta2 = VMULavx(delta, delta) ; - vacc = VADDavx(vacc, delta2) ; - X += VSIZEavx ; - Y += VSIZEavx ; - } - } else { - while (X < X_vec_end) { - VTYPEavx a = VLDUavx(X) ; - VTYPEavx b = VLDUavx(Y) ; - VTYPEavx delta = VSUBavx(a, b) ; - VTYPEavx delta2 = VMULavx(delta, delta) ; - vacc = VADDavx(vacc, delta2) ; - X += VSIZEavx ; - Y += VSIZEavx ; - } - } - - acc = VL_XCAT(_vl_vhsum_avx_, SFX)(vacc) ; - - while (X < X_end) { - T a = *X++ ; - T b = *Y++ ; - T delta = a - b ; - acc += delta * delta ; - } - - return acc ; -} - -VL_EXPORT T -VL_XCAT(_vl_distance_mahalanobis_sq_avx_, SFX) -(vl_size dimension, T const * X, T const * MU, T const * S) -{ - T const * X_end = X + dimension ; - T const * X_vec_end = X_end - VSIZEavx + 1 ; - T acc ; - VTYPEavx vacc = VSTZavx() ; - vl_bool dataAligned = VALIGNEDavx(X) & VALIGNEDavx(MU) & VALIGNEDavx(S); - - if (dataAligned) { - while (X < X_vec_end) { - VTYPEavx a = *(VTYPEavx*)X ; - VTYPEavx b = *(VTYPEavx*)MU ; - VTYPEavx c = *(VTYPEavx*)S ; - - VTYPEavx delta = VSUBavx(a, b) ; - VTYPEavx delta2 = VMULavx(delta, delta) ; - VTYPEavx delta2div = VMULavx(delta2,c); - - vacc = VADDavx(vacc, delta2div) ; - - X += VSIZEavx ; - MU += VSIZEavx ; - S += VSIZEavx ; - } - } else { - while (X < X_vec_end) { - - VTYPEavx a = VLDUavx(X) ; - VTYPEavx b = VLDUavx(MU) ; - VTYPEavx c = VLDUavx(S) ; - - VTYPEavx delta = VSUBavx(a, b) ; - VTYPEavx delta2 = VMULavx(delta, delta) ; - VTYPEavx delta2div = VMULavx(delta2,c); - - vacc = VADDavx(vacc, delta2div) ; - - X += VSIZEavx ; - MU += VSIZEavx ; - S += VSIZEavx ; - } - } - - acc = VL_XCAT(_vl_vhsum_avx_, SFX)(vacc) ; - - while (X < X_end) { - T a = *X++ ; - T b = *MU++ ; - T c = *S++ ; - T delta = a - b ; - acc += (delta * delta) * c; - } - - return acc ; -} - -VL_EXPORT void -VL_XCAT(_vl_weighted_mean_avx_, SFX) -(vl_size dimension, T * MU, T const * X, T const W) -{ - T const * X_end = X + dimension ; - T const * X_vec_end = X_end - VSIZEavx + 1 ; - - vl_bool dataAligned = VALIGNEDavx(X) & VALIGNEDavx(MU); - VTYPEavx w = VLD1avx (&W) ; - - if (dataAligned) { - while (X < X_vec_end) { - VTYPEavx a = *(VTYPEavx*)X ; - VTYPEavx mu = *(VTYPEavx*)MU ; - - VTYPEavx aw = VMULavx(a, w) ; - VTYPEavx meanStore = VADDavx(aw, mu); - - *(VTYPEavx *)MU = meanStore; - - X += VSIZEavx ; - MU += VSIZEavx ; - } - } else { - while (X < X_vec_end) { - VTYPEavx a = VLDUavx(X) ; - VTYPEavx mu = VLDUavx(MU) ; - - VTYPEavx aw = VMULavx(a, w) ; - VTYPEavx meanStore = VADDavx(aw, mu); - - VST2Uavx(MU,meanStore); - - X += VSIZEavx ; - MU += VSIZEavx ; - } - } - - while (X < X_end) { - T a = *X++ ; - *MU += a * W ; - MU++; - } -} - -VL_EXPORT void -VL_XCAT(_vl_weighted_sigma_avx_, SFX) -(vl_size dimension, T * S, T const * X, T const * Y, T const W) -{ - T const * X_end = X + dimension ; - T const * X_vec_end = X_end - VSIZEavx + 1 ; - - vl_bool dataAligned = VALIGNEDavx(X) & VALIGNEDavx(Y) & VALIGNEDavx(S); - - VTYPEavx w = VLD1avx (&W) ; - - if (dataAligned) { - while (X < X_vec_end) { - VTYPEavx a = *(VTYPEavx*)X ; - VTYPEavx b = *(VTYPEavx*)Y ; - VTYPEavx s = *(VTYPEavx*)S ; - - VTYPEavx delta = VSUBavx(a, b) ; - VTYPEavx delta2 = VMULavx(delta, delta) ; - VTYPEavx delta2w = VMULavx(delta2, w) ; - VTYPEavx sigmaStore = VADDavx(s,delta2w); - - *(VTYPEavx *)S = sigmaStore; - - X += VSIZEavx ; - Y += VSIZEavx ; - S += VSIZEavx ; - } - } else { - while (X < X_vec_end) { - VTYPEavx a = VLDUavx(X) ; - VTYPEavx b = VLDUavx(Y) ; - VTYPEavx s = VLDUavx(S) ; - - VTYPEavx delta = VSUBavx(a, b) ; - VTYPEavx delta2 = VMULavx(delta, delta) ; - VTYPEavx delta2w = VMULavx(delta2, w) ; - VTYPEavx sigmaStore = VADDavx(s,delta2w); - - VST2Uavx(S,sigmaStore); - - X += VSIZEavx ; - Y += VSIZEavx ; - S += VSIZEavx ; - } - } - - while (X < X_end) { - T a = *X++ ; - T b = *Y++ ; - T delta = a - b ; - *S += ((delta * delta)*W) ; - S++; - } -} - -/* VL_DISABLE_AVX */ -#endif -#undef VL_MATHOP_AVX_INSTANTIATING -#endif diff --git a/opensfm/src/third_party/vlfeat/vl/mathop_avx.h b/opensfm/src/third_party/vlfeat/vl/mathop_avx.h deleted file mode 100644 index 2acebf0fd..000000000 --- a/opensfm/src/third_party/vlfeat/vl/mathop_avx.h +++ /dev/null @@ -1,61 +0,0 @@ -/** @file mathop_avx.h - ** @brief mathop for avx - ** @author Andrea Vedaldi - **/ - -/* -Copyright (C) 2007-12 Andrea Vedaldi and Brian Fulkerson. -All rights reserved. - -This file is part of the VLFeat library and is made available under -the terms of the BSD license (see the COPYING file). -*/ - -/* ---------------------------------------------------------------- */ -#ifndef VL_MATHOP_AVX_H_INSTANTIATING - -#ifndef VL_MATHOP_AVX_H -#define VL_MATHOP_AVX_H - -#undef FLT -#define FLT VL_TYPE_DOUBLE -#define VL_MATHOP_AVX_H_INSTANTIATING -#include "mathop_avx.h" - -#undef FLT -#define FLT VL_TYPE_FLOAT -#define VL_MATHOP_AVX_H_INSTANTIATING -#include "mathop_avx.h" - -/* VL_MATHOP_AVX_H */ -#endif - -/* ---------------------------------------------------------------- */ -/* VL_MATHOP_AVX_H_INSTANTIATING */ -#else - -#ifndef VL_DISABLE_AVX -#include "generic.h" -#include "float.h" - -VL_EXPORT T -VL_XCAT(_vl_distance_mahalanobis_sq_avx_, SFX) -(vl_size dimension, T const * X, T const * MU, T const * S); - -VL_EXPORT T -VL_XCAT(_vl_distance_l2_avx_, SFX) -(vl_size dimension, T const * X, T const * Y); - -VL_EXPORT void -VL_XCAT(_vl_weighted_sigma_avx_, SFX) -(vl_size dimension, T * S, T const * X, T const * Y, T const W); - -VL_EXPORT void -VL_XCAT(_vl_weighted_mean_avx_, SFX) -(vl_size dimension, T * MU, T const * X, T const W); - -/* ! VL_DISABLE_AVX */ -#endif - -#undef VL_MATHOP_AVX_H_INSTANTIATING -#endif diff --git a/opensfm/src/third_party/vlfeat/vl/mathop_sse2.c b/opensfm/src/third_party/vlfeat/vl/mathop_sse2.c deleted file mode 100644 index dd98a5bea..000000000 --- a/opensfm/src/third_party/vlfeat/vl/mathop_sse2.c +++ /dev/null @@ -1,564 +0,0 @@ -/** @file mathop_sse2.c - ** @brief mathop for SSE2 - Definition - ** @author Andrea Vedaldi, David Novotny - **/ - -/* -Copyright (C) 2007-12 Andrea Vedaldi and Brian Fulkerson. -All rights reserved. - -This file is part of the VLFeat library and is made available under -the terms of the BSD license (see the COPYING file). -*/ - -/* ---------------------------------------------------------------- */ -#ifndef VL_MATHOP_SSE2_INSTANTIATING - -#include "mathop_sse2.h" - -#undef FLT -#define FLT VL_TYPE_DOUBLE -#define VL_MATHOP_SSE2_INSTANTIATING -#include "mathop_sse2.c" - -#undef FLT -#define FLT VL_TYPE_FLOAT -#define VL_MATHOP_SSE2_INSTANTIATING -#include "mathop_sse2.c" - -/* ---------------------------------------------------------------- */ -/* VL_MATHOP_SSE2_INSTANTIATING */ -#else -#ifndef VL_DISABLE_SSE2 - -#ifndef __SSE2__ -#error Compiling SSE2 functions but SSE2 does not to be supported by the compiler. -#endif - -#include -#include "mathop.h" -#include "generic.h" -#include "float.h" - -VL_INLINE T -VL_XCAT(_vl_vhsum_sse2_, SFX)(VTYPE x) -{ - T acc ; -#if (VSIZE == 4) - { - VTYPE sum ; - VTYPE shuffle ; - /* shuffle = [1 0 3 2] */ - /* sum = [3+1 2+0 1+3 0+2] */ - /* shuffle = [2+0 3+1 0+2 1+3] */ - /* vacc = [3+1+2+0 3+1+2+0 1+3+0+2 0+2+1+3] */ - shuffle = VSHU (x, x, _MM_SHUFFLE(1, 0, 3, 2)) ; - sum = VADD (x, shuffle) ; - shuffle = VSHU (sum, sum, _MM_SHUFFLE(2, 3, 0, 1)) ; - x = VADD (sum, shuffle) ; - } -#else - { - VTYPE shuffle ; - /* acc = [1 0 ] */ - /* shuffle = [0 1 ] */ - /* sum = [1+0 0+1] */ - shuffle = VSHU (x, x, _MM_SHUFFLE2(0, 1)) ; - x = VADD (x, shuffle) ; - } -#endif - VST1(&acc, x); - return acc ; -} - - - -VL_EXPORT T -VL_XCAT(_vl_dot_sse2_, SFX) -(vl_size dimension, T const * X, T const * Y) -{ - T const * X_end = X + dimension ; - T const * X_vec_end = X_end - VSIZE + 1 ; - T acc ; - VTYPE vacc = VSTZ() ; - vl_bool dataAligned = VALIGNED(X) & VALIGNED(Y) ; - - if (dataAligned) { - while (X < X_vec_end) { - VTYPE a = *(VTYPE*)X ; - VTYPE b = *(VTYPE*)Y ; - VTYPE d = VMUL(a, b) ; - vacc = VADD(vacc, d) ; - X += VSIZE ; - Y += VSIZE ; - } - } else { - while (X < X_vec_end) { - VTYPE a = VLDU(X) ; - VTYPE b = VLDU(Y) ; - VTYPE d = VMUL(a, b) ; - vacc = VADD(vacc, d) ; - X += VSIZE ; - Y += VSIZE ; - } - } - - acc = VL_XCAT(_vl_vhsum_sse2_, SFX)(vacc) ; - - while (X < X_end) { - T a = *X++ ; - T b = *Y++ ; - acc += a * b ; - } - - return acc ; -} - -VL_EXPORT T -VL_XCAT(_vl_distance_l2_sse2_, SFX) -(vl_size dimension, T const * X, T const * Y) -{ - T const * X_end = X + dimension ; - T const * X_vec_end = X_end - VSIZE + 1 ; - T acc ; - VTYPE vacc = VSTZ() ; - vl_bool dataAligned = VALIGNED(X) & VALIGNED(Y) ; - - if (dataAligned) { - while (X < X_vec_end) { - VTYPE a = *(VTYPE*)X ; - VTYPE b = *(VTYPE*)Y ; - VTYPE delta = VSUB(a, b) ; - VTYPE delta2 = VMUL(delta, delta) ; - vacc = VADD(vacc, delta2) ; - X += VSIZE ; - Y += VSIZE ; - } - } else { - while (X < X_vec_end) { - VTYPE a = VLDU(X) ; - VTYPE b = VLDU(Y) ; - VTYPE delta = VSUB(a, b) ; - VTYPE delta2 = VMUL(delta, delta) ; - vacc = VADD(vacc, delta2) ; - X += VSIZE ; - Y += VSIZE ; - } - } - - acc = VL_XCAT(_vl_vhsum_sse2_, SFX)(vacc) ; - - while (X < X_end) { - T a = *X++ ; - T b = *Y++ ; - T delta = a - b ; - acc += delta * delta ; - } - - return acc ; -} - -VL_EXPORT T -VL_XCAT(_vl_distance_mahalanobis_sq_sse2_, SFX) -(vl_size dimension, T const * X, T const * MU, T const * S) -{ - T const * X_end = X + dimension ; - T const * X_vec_end = X_end - VSIZE + 1 ; - T acc ; - VTYPE vacc = VSTZ() ; - vl_bool dataAligned = VALIGNED(X) & VALIGNED(MU) & VALIGNED(S); - - if (dataAligned) { - while (X < X_vec_end) { - VTYPE a = *(VTYPE*)X ; - VTYPE b = *(VTYPE*)MU ; - VTYPE c = *(VTYPE*)S ; - - VTYPE delta = VSUB(a, b) ; - VTYPE delta2 = VMUL(delta, delta) ; - VTYPE delta2div = VMUL(delta2,c); - - vacc = VADD(vacc, delta2div) ; - - X += VSIZE ; - MU += VSIZE ; - S += VSIZE ; - } - } else { - while (X < X_vec_end) { - - VTYPE a = VLDU(X) ; - VTYPE b = VLDU(MU) ; - VTYPE c = VLDU(S) ; - - VTYPE delta = VSUB(a, b) ; - VTYPE delta2 = VMUL(delta, delta) ; - VTYPE delta2div = VMUL(delta2,c); - - vacc = VADD(vacc, delta2div) ; - - X += VSIZE ; - MU += VSIZE ; - S += VSIZE ; - } - } - - acc = VL_XCAT(_vl_vhsum_sse2_, SFX)(vacc) ; - - while (X < X_end) { - T a = *X++ ; - T b = *MU++ ; - T c = *S++ ; - T delta = a - b ; - acc += (delta * delta) * c; - } - - return acc ; -} - - - -VL_EXPORT T -VL_XCAT(_vl_distance_l1_sse2_, SFX) -(vl_size dimension, T const * X, T const * Y) -{ - T const * X_end = X + dimension ; - T const * X_vec_end = X + dimension - VSIZE ; - T acc ; - VTYPE vacc = VSTZ() ; - VTYPE vminus = VL_XCAT(_mm_set1_p, VSFX) ((T) -0.0) ; /* sign bit */ - vl_bool dataAligned = VALIGNED(X) & VALIGNED(Y) ; - - if (dataAligned) { - while (X < X_vec_end) { - VTYPE a = *(VTYPE*)X ; - VTYPE b = *(VTYPE*)Y ; - VTYPE delta = VSUB(a, b) ; - vacc = VADD(vacc, VANDN(vminus, delta)) ; - X += VSIZE ; - Y += VSIZE ; - } - } else { - while (X < X_vec_end) { - VTYPE a = VLDU(X) ; - VTYPE b = VLDU(Y) ; - VTYPE delta = VSUB(a, b) ; - vacc = VADD(vacc, VANDN(vminus, delta)) ; - X += VSIZE ; - Y += VSIZE ; - } - } - - acc = VL_XCAT(_vl_vhsum_sse2_, SFX)(vacc) ; - - while (X < X_end) { - T a = *X++ ; - T b = *Y++ ; - T delta = a - b ; - acc += VL_MAX(delta, - delta) ; - } - - return acc ; -} - -VL_EXPORT T -VL_XCAT(_vl_distance_chi2_sse2_, SFX) -(vl_size dimension, T const * X, T const * Y) -{ - T const * X_end = X + dimension ; - T const * X_vec_end = X + dimension - VSIZE ; - T acc ; - VTYPE vacc = VSTZ() ; - vl_bool dataAligned = VALIGNED(X) & VALIGNED(Y) ; - - if (dataAligned) { - while (X < X_vec_end) { - VTYPE a = *(VTYPE*)X ; - VTYPE b = *(VTYPE*)Y ; - VTYPE delta = VSUB(a, b) ; - VTYPE denom = VADD(a, b) ; - VTYPE numer = VMUL(delta, delta) ; - VTYPE ratio = VDIV(numer, denom) ; - ratio = VAND(ratio, VNEQ(denom, VSTZ())) ; - vacc = VADD(vacc, ratio) ; - X += VSIZE ; - Y += VSIZE ; - } - } else { - while (X < X_vec_end) { - VTYPE a = VLDU(X) ; - VTYPE b = VLDU(Y) ; - VTYPE delta = VSUB(a, b) ; - VTYPE denom = VADD(a, b) ; - VTYPE numer = VMUL(delta, delta) ; - VTYPE ratio = VDIV(numer, denom) ; - ratio = VAND(ratio, VNEQ(denom, VSTZ())) ; - vacc = VADD(vacc, ratio) ; - X += VSIZE ; - Y += VSIZE ; - } - } - - acc = VL_XCAT(_vl_vhsum_sse2_, SFX)(vacc) ; - - while (X < X_end) { - T a = *X++ ; - T b = *Y++ ; - T delta = a - b ; - T denom = a + b ; - T numer = delta * delta ; - if (denom) { - T ratio = numer / denom ; - acc += ratio ; - } - } - return acc ; -} - - -VL_EXPORT T -VL_XCAT(_vl_kernel_l2_sse2_, SFX) -(vl_size dimension, T const * X, T const * Y) -{ - T const * X_end = X + dimension ; - T const * X_vec_end = X_end - VSIZE + 1 ; - T acc ; - VTYPE vacc = VSTZ() ; - vl_bool dataAligned = VALIGNED(X) & VALIGNED(Y) ; - - if (dataAligned) { - while (X < X_vec_end) { - VTYPE a = *(VTYPE*)X ; - VTYPE b = *(VTYPE*)Y ; - vacc = VADD(vacc, VMUL(a,b)) ; - X += VSIZE ; - Y += VSIZE ; - } - } else { - while (X < X_vec_end) { - VTYPE a = VLDU(X) ; - VTYPE b = VLDU(Y) ; - vacc = VADD(vacc, VMUL(a,b)) ; - X += VSIZE ; - Y += VSIZE ; - } - } - - acc = VL_XCAT(_vl_vhsum_sse2_, SFX)(vacc) ; - - while (X < X_end) { - T a = *X++ ; - T b = *Y++ ; - acc += a * b ; - } - return acc ; -} - -VL_EXPORT T -VL_XCAT(_vl_kernel_l1_sse2_, SFX) -(vl_size dimension, T const * X, T const * Y) -{ - T const * X_end = X + dimension ; - T const * X_vec_end = X_end - VSIZE + 1 ; - T acc ; - VTYPE vacc = VSTZ() ; - VTYPE vminus = VL_XCAT(_mm_set1_p, VSFX) ((T) -0.0) ; - vl_bool dataAligned = VALIGNED(X) & VALIGNED(Y) ; - - if (dataAligned) { - while (X < X_vec_end) { - VTYPE a = *(VTYPE*)X ; - VTYPE b = *(VTYPE*)Y ; - VTYPE a_ = VANDN(vminus, a) ; - VTYPE b_ = VANDN(vminus, b) ; - VTYPE sum = VADD(a_,b_) ; - VTYPE diff = VSUB(a, b) ; - VTYPE diff_ = VANDN(vminus, diff) ; - vacc = VADD(vacc, VSUB(sum, diff_)) ; - X += VSIZE ; - Y += VSIZE ; - } - } else { - while (X < X_vec_end) { - VTYPE a = VLDU(X) ; - VTYPE b = VLDU(Y) ; - VTYPE a_ = VANDN(vminus, a) ; - VTYPE b_ = VANDN(vminus, b) ; - VTYPE sum = VADD(a_,b_) ; - VTYPE diff = VSUB(a, b) ; - VTYPE diff_ = VANDN(vminus, diff) ; - vacc = VADD(vacc, VSUB(sum, diff_)) ; - X += VSIZE ; - Y += VSIZE ; - } - } - - acc = VL_XCAT(_vl_vhsum_sse2_, SFX)(vacc) ; - - while (X < X_end) { - T a = *X++ ; - T b = *Y++ ; - T a_ = VL_XCAT(vl_abs_, SFX) (a) ; - T b_ = VL_XCAT(vl_abs_, SFX) (b) ; - acc += a_ + b_ - VL_XCAT(vl_abs_, SFX) (a - b) ; - } - - return acc / ((T)2) ; -} - -VL_EXPORT T -VL_XCAT(_vl_kernel_chi2_sse2_, SFX) -(vl_size dimension, T const * X, T const * Y) -{ - T const * X_end = X + dimension ; - T const * X_vec_end = X + dimension - VSIZE ; - T acc ; - VTYPE vacc = VSTZ() ; - vl_bool dataAligned = VALIGNED(X) & VALIGNED(Y) ; - - if (dataAligned) { - while (X < X_vec_end) { - VTYPE a = *(VTYPE*)X ; - VTYPE b = *(VTYPE*)Y ; - VTYPE denom = VADD(a, b) ; - VTYPE numer = VMUL(a,b) ; - VTYPE ratio = VDIV(numer, denom) ; - ratio = VAND(ratio, VNEQ(denom, VSTZ())) ; - vacc = VADD(vacc, ratio) ; - X += VSIZE ; - Y += VSIZE ; - } - } else { - while (X < X_vec_end) { - VTYPE a = VLDU(X) ; - VTYPE b = VLDU(Y) ; - VTYPE denom = VADD(a, b) ; - VTYPE numer = VMUL(a,b) ; - VTYPE ratio = VDIV(numer, denom) ; - ratio = VAND(ratio, VNEQ(denom, VSTZ())) ; - vacc = VADD(vacc, ratio) ; - X += VSIZE ; - Y += VSIZE ; - } - } - - acc = VL_XCAT(_vl_vhsum_sse2_, SFX)(vacc) ; - - while (X < X_end) { - T a = *X++ ; - T b = *Y++ ; - T denom = a + b ; - if (denom) { - T ratio = a * b / denom ; - acc += ratio ; - } - } - return ((T)2) * acc ; -} -// -VL_EXPORT void -VL_XCAT(_vl_weighted_sigma_sse2_, SFX) -(vl_size dimension, T * S, T const * X, T const * Y, T const W) -{ - T const * X_end = X + dimension ; - T const * X_vec_end = X_end - VSIZE + 1 ; - - vl_bool dataAligned = VALIGNED(X) & VALIGNED(Y) & VALIGNED(S); - - VTYPE w = VLD1 (&W) ; - - if (dataAligned) { - while (X < X_vec_end) { - VTYPE a = *(VTYPE*)X ; - VTYPE b = *(VTYPE*)Y ; - VTYPE s = *(VTYPE*)S ; - - VTYPE delta = VSUB(a, b) ; - VTYPE delta2 = VMUL(delta, delta) ; - VTYPE delta2w = VMUL(delta2, w) ; - VTYPE sigmaStore = VADD(s,delta2w); - - *(VTYPE *)S = sigmaStore; - - X += VSIZE ; - Y += VSIZE ; - S += VSIZE ; - } - } else { - while (X < X_vec_end) { - VTYPE a = VLDU(X) ; - VTYPE b = VLDU(Y) ; - VTYPE s = VLDU(S) ; - - VTYPE delta = VSUB(a, b) ; - VTYPE delta2 = VMUL(delta, delta) ; - VTYPE delta2w = VMUL(delta2, w) ; - VTYPE sigmaStore = VADD(s,delta2w); - - VST2U(S,sigmaStore); - - X += VSIZE ; - Y += VSIZE ; - S += VSIZE ; - } - } - - - while (X < X_end) { - T a = *X++ ; - T b = *Y++ ; - T delta = a - b ; - *S += ((delta * delta)*W) ; - S++; - } -} - -VL_EXPORT void -VL_XCAT(_vl_weighted_mean_sse2_, SFX) -(vl_size dimension, T * MU, T const * X, T const W) -{ - T const * X_end = X + dimension ; - T const * X_vec_end = X_end - VSIZE + 1 ; - - vl_bool dataAligned = VALIGNED(X) & VALIGNED(MU); - VTYPE w = VLD1 (&W) ; - - if (dataAligned) { - while (X < X_vec_end) { - VTYPE a = *(VTYPE*)X ; - VTYPE mu = *(VTYPE*)MU ; - - VTYPE aw = VMUL(a, w) ; - VTYPE meanStore = VADD(aw, mu); - - *(VTYPE *)MU = meanStore; - - X += VSIZE ; - MU += VSIZE ; - } - } else { - while (X < X_vec_end) { - VTYPE a = VLDU(X) ; - VTYPE mu = VLDU(MU) ; - - VTYPE aw = VMUL(a, w) ; - VTYPE meanStore = VADD(aw, mu); - - VST2U(MU,meanStore); - - X += VSIZE ; - MU += VSIZE ; - } - } - - while (X < X_end) { - T a = *X++ ; - *MU += a * W ; - MU++; - } -} - -/* VL_DISABLE_SSE2 */ -#endif -#undef VL_MATHOP_SSE2_INSTANTIATING -#endif diff --git a/opensfm/src/third_party/vlfeat/vl/mathop_sse2.h b/opensfm/src/third_party/vlfeat/vl/mathop_sse2.h deleted file mode 100644 index 553cea12f..000000000 --- a/opensfm/src/third_party/vlfeat/vl/mathop_sse2.h +++ /dev/null @@ -1,85 +0,0 @@ -/** @file mathop_sse2.h - ** @brief mathop for sse2 - ** @author Andrea Vedaldi - **/ - -/* -Copyright (C) 2007-12 Andrea Vedaldi and Brian Fulkerson. -All rights reserved. - -This file is part of the VLFeat library and is made available under -the terms of the BSD license (see the COPYING file). -*/ - -/* ---------------------------------------------------------------- */ -#ifndef VL_MATHOP_SSE2_H_INSTANTIATING - -#ifndef VL_MATHOP_SSE2_H -#define VL_MATHOP_SSE2_H - -#undef FLT -#define FLT VL_TYPE_DOUBLE -#define VL_MATHOP_SSE2_H_INSTANTIATING -#include "mathop_sse2.h" - -#undef FLT -#define FLT VL_TYPE_FLOAT -#define VL_MATHOP_SSE2_H_INSTANTIATING -#include "mathop_sse2.h" - -/* VL_MATHOP_SSE2_H */ -#endif - -/* ---------------------------------------------------------------- */ -/* VL_MATHOP_SSE2_H_INSTANTIATING */ -#else - -#ifndef VL_DISABLE_SSE2 - -#include "generic.h" -#include "float.h" - -VL_EXPORT T -VL_XCAT(_vl_dot_sse2_, SFX) -(vl_size dimension, T const * X, T const * Y) ; - -VL_EXPORT T -VL_XCAT(_vl_distance_l2_sse2_, SFX) -(vl_size dimension, T const * X, T const * Y) ; - -VL_EXPORT T -VL_XCAT(_vl_distance_l1_sse2_, SFX) -(vl_size dimension, T const * X, T const * Y) ; - -VL_EXPORT T -VL_XCAT(_vl_distance_chi2_sse2_, SFX) -(vl_size dimension, T const * X, T const * Y) ; - -VL_EXPORT T -VL_XCAT(_vl_kernel_l2_sse2_, SFX) -(vl_size dimension, T const * X, T const * Y) ; - -VL_EXPORT T -VL_XCAT(_vl_kernel_l1_sse2_, SFX) -(vl_size dimension, T const * X, T const * Y) ; - -VL_EXPORT T -VL_XCAT(_vl_kernel_chi2_sse2_, SFX) -(vl_size dimension, T const * X, T const * Y) ; - -VL_EXPORT T -VL_XCAT(_vl_distance_mahalanobis_sq_sse2_, SFX) -(vl_size dimension, T const * X, T const * MU, T const * S); - -VL_EXPORT void -VL_XCAT(_vl_weighted_sigma_sse2_, SFX) -(vl_size dimension, T * S, T const * X, T const * Y, T const W); - -VL_EXPORT void -VL_XCAT(_vl_weighted_mean_sse2_, SFX) -(vl_size dimension, T * MU, T const * X, T const W); - -/* ! VL_DISABLE_SSE2 */ -#endif -#undef VL_MATHOP_SSE2_INSTANTIATING -#endif diff --git a/opensfm/src/third_party/vlfeat/vl/mser.c b/opensfm/src/third_party/vlfeat/vl/mser.c deleted file mode 100644 index e6e879e50..000000000 --- a/opensfm/src/third_party/vlfeat/vl/mser.c +++ /dev/null @@ -1,1001 +0,0 @@ -/** @file mser.c - ** @brief MSER - Definition - ** @author Andrea Vedaldi - **/ - -/* -Copyright (C) 2007-13 Andrea Vedaldi and Brian Fulkerson. -All rights reserved. - -This file is part of the VLFeat library and is made available under -the terms of the BSD license (see the COPYING file). -*/ - -/** - -@page mser Maximally Stable Extremal Regions (MSER) -@author Andrea Vedaldi -@tableofcontents - - -@ref mser.h implements the *Maximally Stable Extremal Regions* (MSER) -local feature detector of @cite{matas03robust}. This detector extracts -as features the the connected components of the level sets of the -input intensity image. Among all such regions, the ones that are -locally maximally stable are selected. MSERs are affine co-variant, as -well as largely co-variant to generic diffeomorphic transformations. - -See @ref mser-starting for an introduction on how to use the detector -from the C API. For further details refer to: - -- @subpage mser-fundamentals - MSER definition and parameters. - - -@section mser-starting Getting started with the MSER detector - - -Running the MSER filter usually involves the following steps: - -- Initialize the MSER filter by ::vl_mser_new(). The - filter can be reused for images of the same size. -- Compute the MSERs by ::vl_mser_process(). -- Optionally fit ellipsoids to the MSERs by ::vl_mser_ell_fit(). -- Retrieve the results by ::vl_mser_get_regions() (and optionally ::vl_mser_get_ell()). -- Optionally retrieve filter statistics by ::vl_mser_get_stats(). -- Delete the MSER filter by ::vl_mser_delete(). - - -@page mser-fundamentals MSER fundamentals -@tableofcontents - - -The *extermal regions* of an image are the connected components of the -level sets $S_l = \{ x : I(x) \leq l \}, l \in \real$ of the image -$I(x)$. Consider a discretization of the intensity levels $l$ -consisting of $M$ samples $\mathcal{L}=\{0,\dots,M-1\}$. The extremal -regions $R_l \subset S_l$ of the level sets $S_l, l \in \mathcal{L}$ -can be arranged in a tree, where a region $R_l$ is a children of a -region $R_{l+1}$ if $R_l \subset R_{l+1}$. The following figures shows -a 1D example where the regions are denoted by dark thick lines: - -@image html mser-tree.png "Connected components of the image level sets arranged in a tree." - -Note that, depending on the image, regions at different levels can be -identical as sets: - -@image html mser-er-step.png "Connected components when the image contains step changes." - -A *stable extremal region* is an extremal region that does not change -much as the index $l$ is varied. Here we use a criterion which is -similar but not identical to the original paper. This definition is -somewhat simpler both to understand and code. - -Let $B(R_l)=(R_l,R_{l+1},\dots,R_{l+\Delta})$ be the branch of the -tree $R_l \subset R_{l+1} \subset \dots \subset R_{l + \Delta}$ -rooted at $R_l$. We associate to the branch the (in)stability score - -@f[ - v(R_l) = \frac{|R_{l+\Delta} - R_l|}{|R_l|}. -@f] - -This score is a relative measure of how much $R_l$ changes as the -index is increased from $l$ to $l+\Delta$, as illustrated in the -following figure. - -@image html mser-er.png "Stability is measured by looking at how much a region changes with the intensity level." - -The score is low if the regions along the branch have similar area -(and thus similar shape). We aim to select maximally stable -branches; then a maximally stable region is just a representative -region selected from a maximally stable branch (for simplicity we -select $R_l$, but one could choose for example -$R_{l+\Delta/2}$). - -Roughly speaking, a branch is maximally stable if it is a local -minimum of the (in)stability score. More accurately, we start by -assuming that all branches are maximally stable. Then we consider -each branch $B(R_{l})$ and its parent branch -$B(R_{l+1}):R_{l+1}\supset R_l$ (notice that, due to the -discrete nature of the calculations, they might be geometrically -identical) and we mark as unstable the less stable one, i.e.: - - - if $v(R_l)v(R_{l+1})$, mark $R_{l}$ as unstable; - - otherwise, do nothing. - -This criterion selects among nearby regions the ones that are more -stable. We optionally refine the selection by running (starting -from the bigger and going to the smaller regions) the following -tests: - -- $a_- \leq |R_{l}|/|R_{\infty}| \leq a_+$: exclude MSERs too - small or too big ($|R_{\infty}|$ is the area of the image). - -- $v(R_{l}) < v_+$: exclude MSERs too unstable. - -- For any MSER $R_l$, find the parent MSER $R_{l'}$ and check - if - $|R_{l'} - R_l|/|R_l'| < d_+$: remove duplicated MSERs. - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
parameteralt. namestandard valueset by
$\Delta$@c delta5::vl_mser_set_delta()
$a_+$@c max_area0.75::vl_mser_set_max_area()
$a_-$@c min_area3.0/$|R_\infty|$::vl_mser_set_min_area()
$v_+$@c max_var0.25::vl_mser_set_max_variation()
$d_+$@c min_diversity0.2::vl_mser_set_min_diversity()
- - -@section mser-vol Volumetric images - - -The code supports images of arbitrary dimension. For instance, it -is possible to find the MSER regions of volumetric images or time -sequences. See ::vl_mser_new() for further details - - -@section mser-ell Ellipsoids - - -Usually extremal regions are returned as a set of ellipsoids -fitted to the actual regions (which have arbitrary shape). The fit -is done by calculating the mean and variance of the pixels -composing the region: -@f[ -\mu_l = \frac{1}{|R_l|}\sum_{x\in R_l}x, -\qquad -\Sigma_l = \frac{1}{|R_l|}\sum_{x\in R_l} (x-\mu_l)^\top(x-\mu_l) -@f] -Ellipsoids are fitted by ::vl_mser_ell_fit(). Notice that for a -n dimensional image, the mean has n components -and the variance has n(n+1)/2 independent components. The -total number of components is obtained by ::vl_mser_get_ell_dof() -and the total number of fitted ellipsoids by -::vl_mser_get_ell_num(). A matrix with an ellipsoid per column is -returned by ::vl_mser_get_ell(). The column is the stacking of the -mean and of the independent components of the variance, in the -order (1,1),(1,2),..,(1,n), (2,2),(2,3).... In the -calculations, the pixel coordinate $x=(x_1,...,x_n)$ use the -standard index order and ranges. - - -@section mser-algo Algorithm - - -The algorithm is quite efficient. While some details may be -tricky, the overall idea is easy to grasp. - -- Pixels are sorted by increasing intensity. -- Pixels are added to a forest by increasing intensity. The forest has the - following properties: - - All the descendent of a certain pixels are subset of an extremal region. - - All the extremal regions are the descendants of some pixels. -- Extremal regions are extracted from the region tree and the extremal regions tree is - calculated. -- Stable regions are marked. -- Duplicates and other bad regions are removed. - -@remark The extremal region tree which is calculated is a subset -of the actual extremal region tree. In particular, it does not -contain redundant entries extremal regions that coincide as -sets. So, for example, in the calculated extremal region tree, the -parent $R_q$ of an extremal region $R_{l}$ may or may -not correspond to $R_{l+1}$, depending whether -$q\leq l+1$ or not. These subtleties are important when -calculating the stability tests. - -**/ - -#include "mser.h" -#include -#include -#include - -/** ------------------------------------------------------------------- - ** @brief Advance N-dimensional subscript - ** - ** The function increments by one the subscript @a subs indexing an - ** array the @a ndims dimensions @a dims. - ** - ** @param ndims number of dimensions. - ** @param dims dimensions. - ** @param subs subscript to advance. - **/ - -VL_INLINE void -adv(int ndims, int const *dims, int *subs) -{ - int d = 0 ; - while(d < ndims) { - if( ++subs[d] < dims[d] ) return ; - subs[d++] = 0 ; - } -} - -/** ------------------------------------------------------------------- - ** @brief Climb the region forest to reach aa root - ** - ** The function climbs the regions forest @a r starting from the node - ** @a idx to the corresponding root. - ** - ** To speed-up the operation, the function uses the - ** VlMserReg::shortcut field to quickly jump to the root. After the - ** root is reached, all the used shortcut are updated. - ** - ** @param r regions' forest. - ** @param idx stating node. - ** @return index of the reached root. - **/ - -VL_INLINE vl_uint -climb (VlMserReg* r, vl_uint idx) -{ - - vl_uint prev_idx = idx ; - vl_uint next_idx ; - vl_uint root_idx ; - - /* move towards root to find it */ - while (1) { - - /* next jump to the root */ - next_idx = r [idx] .shortcut ; - - /* recycle shortcut to remember how we came here */ - r [idx] .shortcut = prev_idx ; - - /* stop if the root is found */ - if( next_idx == idx ) break ; - - /* next guy */ - prev_idx = idx ; - idx = next_idx ; - } - - root_idx = idx ; - - /* move backward to update shortcuts */ - while (1) { - - /* get previously visited one */ - prev_idx = r [idx] .shortcut ; - - /* update shortcut to point to the new root */ - r [idx] .shortcut = root_idx ; - - /* stop if the first visited node is reached */ - if( prev_idx == idx ) break ; - - /* next guy */ - idx = prev_idx ; - } - - return root_idx ; -} - -/** ------------------------------------------------------------------- - ** @brief Create a new MSER filter - ** - ** Initializes a new MSER filter for images of the specified - ** dimensions. Images are @a ndims -dimensional arrays of dimensions - ** @a dims. - ** - ** @param ndims number of dimensions. - ** @param dims dimensions. - **/ -VL_EXPORT -VlMserFilt* -vl_mser_new (int ndims, int const* dims) -{ - VlMserFilt* f ; - int *strides, k ; - - f = vl_calloc (sizeof(VlMserFilt), 1) ; - - f-> ndims = ndims ; - f-> dims = vl_malloc (sizeof(int) * ndims) ; - f-> subs = vl_malloc (sizeof(int) * ndims) ; - f-> dsubs = vl_malloc (sizeof(int) * ndims) ; - f-> strides = vl_malloc (sizeof(int) * ndims) ; - - /* shortcuts */ - strides = f-> strides ; - - /* copy dims to f->dims */ - for(k = 0 ; k < ndims ; ++k) { - f-> dims [k] = dims [k] ; - } - - /* compute strides to move into the N-dimensional image array */ - strides [0] = 1 ; - for(k = 1 ; k < ndims ; ++k) { - strides [k] = strides [k-1] * dims [k-1] ; - } - - /* total number of pixels */ - f-> nel = strides [ndims-1] * dims [ndims-1] ; - - /* dof of ellipsoids */ - f-> dof = ndims * (ndims + 1) / 2 + ndims ; - - /* more buffers */ - f-> perm = vl_malloc (sizeof(vl_uint) * f-> nel) ; - f-> joins = vl_malloc (sizeof(vl_uint) * f-> nel) ; - f-> r = vl_malloc (sizeof(VlMserReg) * f-> nel) ; - - f-> er = 0 ; - f-> rer = 0 ; - f-> mer = 0 ; - f-> rmer = 0 ; - f-> ell = 0 ; - f-> rell = 0 ; - - /* other parameters */ - f-> delta = 5 ; - f-> max_area = 0.75 ; - f-> min_area = 3.0 / f-> nel ; - f-> max_variation = 0.25 ; - f-> min_diversity = 0.2 ; - - return f ; -} - -/** ------------------------------------------------------------------- - ** @brief Delete MSER filter - ** - ** The function releases the MSER filter @a f and all its resources. - ** - ** @param f MSER filter to be deleted. - **/ -VL_EXPORT -void -vl_mser_delete (VlMserFilt* f) -{ - if(f) { - if(f-> acc ) vl_free( f-> acc ) ; - if(f-> ell ) vl_free( f-> ell ) ; - - if(f-> er ) vl_free( f-> er ) ; - if(f-> r ) vl_free( f-> r ) ; - if(f-> joins ) vl_free( f-> joins ) ; - if(f-> perm ) vl_free( f-> perm ) ; - - if(f-> strides) vl_free( f-> strides) ; - if(f-> dsubs ) vl_free( f-> dsubs ) ; - if(f-> subs ) vl_free( f-> subs ) ; - if(f-> dims ) vl_free( f-> dims ) ; - - if(f-> mer ) vl_free( f-> mer ) ; - vl_free (f) ; - } -} - - -/** ------------------------------------------------------------------- - ** @brief Process image - ** - ** The functions calculates the Maximally Stable Extremal Regions - ** (MSERs) of image @a im using the MSER filter @a f. - ** - ** The filter @a f must have been initialized to be compatible with - ** the dimensions of @a im. - ** - ** @param f MSER filter. - ** @param im image data. - **/ -VL_EXPORT -void -vl_mser_process (VlMserFilt* f, vl_mser_pix const* im) -{ - /* shortcuts */ - vl_uint nel = f-> nel ; - vl_uint *perm = f-> perm ; - vl_uint *joins = f-> joins ; - int ndims = f-> ndims ; - int *dims = f-> dims ; - int *subs = f-> subs ; - int *dsubs = f-> dsubs ; - int *strides = f-> strides ; - VlMserReg *r = f-> r ; - VlMserExtrReg *er = f-> er ; - vl_uint *mer = f-> mer ; - int delta = f-> delta ; - - int njoins = 0 ; - int ner = 0 ; - int nmer = 0 ; - int nbig = 0 ; - int nsmall = 0 ; - int nbad = 0 ; - int ndup = 0 ; - - int i, j, k ; - - /* delete any previosuly computed ellipsoid */ - f-> nell = 0 ; - - /* ----------------------------------------------------------------- - * Sort pixels by intensity - * -------------------------------------------------------------- */ - - { - vl_uint buckets [ VL_MSER_PIX_MAXVAL ] ; - - /* clear buckets */ - memset (buckets, 0, sizeof(vl_uint) * VL_MSER_PIX_MAXVAL ) ; - - /* compute bucket size (how many pixels for each intensity - value) */ - for(i = 0 ; i < (int) nel ; ++i) { - vl_mser_pix v = im [i] ; - ++ buckets [v] ; - } - - /* cumulatively add bucket sizes */ - for(i = 1 ; i < VL_MSER_PIX_MAXVAL ; ++i) { - buckets [i] += buckets [i-1] ; - } - - /* empty buckets computing pixel ordering */ - for(i = nel ; i >= 1 ; ) { - vl_mser_pix v = im [ --i ] ; - vl_uint j = -- buckets [v] ; - perm [j] = i ; - } - } - - /* initialize the forest with all void nodes */ - for(i = 0 ; i < (int) nel ; ++i) { - r [i] .parent = VL_MSER_VOID_NODE ; - } - - /* ----------------------------------------------------------------- - * Compute regions and count extremal regions - * -------------------------------------------------------------- */ - /* - In the following: - - idx : index of the current pixel - val : intensity of the current pixel - r_idx : index of the root of the current pixel - n_idx : index of the neighbors of the current pixel - nr_idx : index of the root of the neighbor of the current pixel - - */ - - /* process each pixel by increasing intensity */ - for(i = 0 ; i < (int) nel ; ++i) { - - /* pop next node xi */ - vl_uint idx = perm [i] ; - vl_mser_pix val = im [idx] ; - vl_uint r_idx ; - - /* add the pixel to the forest as a root for now */ - r [idx] .parent = idx ; - r [idx] .shortcut = idx ; - r [idx] .area = 1 ; - r [idx] .height = 1 ; - - r_idx = idx ; - - /* convert the index IDX into the subscript SUBS; also initialize - DSUBS to (-1,-1,...,-1) */ - { - vl_uint temp = idx ; - for(k = ndims - 1 ; k >= 0 ; --k) { - dsubs [k] = -1 ; - subs [k] = temp / strides [k] ; - temp = temp % strides [k] ; - } - } - - /* examine the neighbors of the current pixel */ - while (1) { - vl_uint n_idx = 0 ; - vl_bool good = 1 ; - - /* - Compute the neighbor subscript as NSUBS+SUB, the - corresponding neighbor index NINDEX and check that the - neighbor is within the image domain. - */ - for(k = 0 ; k < ndims && good ; ++k) { - int temp = dsubs [k] + subs [k] ; - good &= (0 <= temp) && (temp < dims [k]) ; - n_idx += temp * strides [k] ; - } - - /* - The neighbor should be processed if the following conditions - are met: - - 1. The neighbor is within image boundaries. - - 2. The neighbor is indeed different from the current node - (the opposite happens when DSUB=(0,0,...,0)). - - 3. The neighbor is already in the forest, meaning that it has - already been processed. - */ - if (good && - n_idx != idx && - r [n_idx] .parent != VL_MSER_VOID_NODE ) { - - vl_mser_pix nr_val = 0 ; - vl_uint nr_idx = 0 ; - int hgt = r [ r_idx] .height ; - int n_hgt = r [nr_idx] .height ; - - /* - Now we join the two subtrees rooted at - - R_IDX = ROOT( IDX) - NR_IDX = ROOT(N_IDX). - - Note that R_IDX = ROOT(IDX) might change as we process more - neighbors, so we need keep updating it. - */ - - r_idx = climb(r, idx) ; - nr_idx = climb(r, n_idx) ; - - /* - At this point we have three possibilities: - - (A) ROOT(IDX) == ROOT(NR_IDX). In this case the two trees - have already been joined and we do not do anything. - - (B) I(ROOT(IDX)) == I(ROOT(NR_IDX)). In this case the pixel - IDX is extending an extremal region with the same - intensity value. Since ROOT(NR_IDX) will NOT be an - extremal region of the full image, ROOT(IDX) can be - safely added as children of ROOT(NR_IDX) if this - reduces the height according to the union rank - heuristic. - - (C) I(ROOT(IDX)) > I(ROOT(NR_IDX)). In this case the pixel - IDX is starting a new extremal region. Thus ROOT(NR_IDX) - WILL be an extremal region of the final image and the - only possibility is to add ROOT(NR_IDX) as children of - ROOT(IDX), which becomes parent. - */ - - if( r_idx != nr_idx ) { /* skip if (A) */ - - nr_val = im [nr_idx] ; - - if( nr_val == val && hgt < n_hgt ) { - - /* ROOT(IDX) becomes the child */ - r [r_idx] .parent = nr_idx ; - r [r_idx] .shortcut = nr_idx ; - r [nr_idx] .area += r [r_idx] .area ; - r [nr_idx] .height = VL_MAX(n_hgt, hgt+1) ; - - joins [njoins++] = r_idx ; - - } else { - - /* cases ROOT(IDX) becomes the parent */ - r [nr_idx] .parent = r_idx ; - r [nr_idx] .shortcut = r_idx ; - r [r_idx] .area += r [nr_idx] .area ; - r [r_idx] .height = VL_MAX(hgt, n_hgt + 1) ; - - joins [njoins++] = nr_idx ; - - /* count if extremal */ - if (nr_val != val) ++ ner ; - - } /* check b vs c */ - } /* check a vs b or c */ - } /* neighbor done */ - - /* move to next neighbor */ - k = 0 ; - while(++ dsubs [k] > 1) { - dsubs [k++] = -1 ; - if(k == ndims) goto done_all_neighbors ; - } - } /* next neighbor */ - done_all_neighbors : ; - } /* next pixel */ - - /* the last root is extremal too */ - ++ ner ; - - /* save back */ - f-> njoins = njoins ; - - f-> stats. num_extremal = ner ; - - /* ----------------------------------------------------------------- - * Extract extremal regions - * -------------------------------------------------------------- */ - - /* - Extremal regions are extracted and stored into the array ER. The - structure R is also updated so that .SHORTCUT indexes the - corresponding extremal region if any (otherwise it is set to - VOID). - */ - - /* make room */ - if (f-> rer < ner) { - if (er) vl_free (er) ; - f->er = er = vl_malloc (sizeof(VlMserExtrReg) * ner) ; - f->rer = ner ; - } ; - - /* save back */ - f-> nmer = ner ; - - /* count again */ - ner = 0 ; - - /* scan all regions Xi */ - for(i = 0 ; i < (int) nel ; ++i) { - - /* pop next node xi */ - vl_uint idx = perm [i] ; - - vl_mser_pix val = im [idx] ; - vl_uint p_idx = r [idx] .parent ; - vl_mser_pix p_val = im [p_idx] ; - - /* is extremal ? */ - vl_bool is_extr = (p_val > val) || idx == p_idx ; - - if( is_extr ) { - - /* if so, add it */ - er [ner] .index = idx ; - er [ner] .parent = ner ; - er [ner] .value = im [idx] ; - er [ner] .area = r [idx] .area ; - - /* link this region to this extremal region */ - r [idx] .shortcut = ner ; - - /* increase count */ - ++ ner ; - } else { - /* link this region to void */ - r [idx] .shortcut = VL_MSER_VOID_NODE ; - } - } - - /* ----------------------------------------------------------------- - * Link extremal regions in a tree - * -------------------------------------------------------------- */ - - for(i = 0 ; i < ner ; ++i) { - - vl_uint idx = er [i] .index ; - - do { - idx = r[idx] .parent ; - } while (r[idx] .shortcut == VL_MSER_VOID_NODE) ; - - er[i] .parent = r[idx] .shortcut ; - er[i] .shortcut = i ; - } - - /* ----------------------------------------------------------------- - * Compute variability of +DELTA branches - * -------------------------------------------------------------- */ - /* For each extremal region Xi of value VAL we look for the biggest - * parent that has value not greater than VAL+DELTA. This is dubbed - * `top parent'. */ - - for(i = 0 ; i < ner ; ++i) { - - /* Xj is the current region the region and Xj are the parents */ - int top_val = er [i] .value + delta ; - int top = er [i] .shortcut ; - - /* examine all parents */ - while (1) { - int next = er [top] .parent ; - int next_val = er [next] .value ; - - /* Break if: - * - there is no node above the top or - * - the next node is above the top value. - */ - if (next == top || next_val > top_val) break ; - - /* so next could be the top */ - top = next ; - } - - /* calculate branch variation */ - { - int area = er [i ] .area ; - int area_top = er [top] .area ; - er [i] .variation = (float) (area_top - area) / area ; - er [i] .max_stable = 1 ; - } - - /* Optimization: since extremal regions are processed by - * increasing intensity, all next extremal regions being processed - * have value at least equal to the one of Xi. If any of them has - * parent the parent of Xi (this comprises the parent itself), we - * can safely skip most intermediate node along the branch and - * skip directly to the top to start our search. */ - { - int parent = er [i] .parent ; - int curr = er [parent] .shortcut ; - er [parent] .shortcut = VL_MAX (top, curr) ; - } - } - - /* ----------------------------------------------------------------- - * Select maximally stable branches - * -------------------------------------------------------------- */ - - nmer = ner ; - for(i = 0 ; i < ner ; ++i) { - vl_uint parent = er [i ] .parent ; - vl_mser_pix val = er [i ] .value ; - float var = er [i ] .variation ; - vl_mser_pix p_val = er [parent] .value ; - float p_var = er [parent] .variation ; - vl_uint loser ; - - /* - Notice that R_parent = R_{l+1} only if p_val = val + 1. If not, - this and the parent region coincide and there is nothing to do. - */ - if(p_val > val + 1) continue ; - - /* decide which one to keep and put that in loser */ - if(var < p_var) loser = parent ; else loser = i ; - - /* make loser NON maximally stable */ - if(er [loser] .max_stable) { - -- nmer ; - er [loser] .max_stable = 0 ; - } - } - - f-> stats. num_unstable = ner - nmer ; - - /* ----------------------------------------------------------------- - * Further filtering - * -------------------------------------------------------------- */ - /* It is critical for correct duplicate detection to remove regions - * from the bottom (smallest one first). */ - { - float max_area = (float) f-> max_area * nel ; - float min_area = (float) f-> min_area * nel ; - float max_var = (float) f-> max_variation ; - float min_div = (float) f-> min_diversity ; - - /* scan all extremal regions (intensity value order) */ - for(i = ner-1 ; i >= 0L ; --i) { - - /* process only maximally stable extremal regions */ - if (! er [i] .max_stable) continue ; - - if (er [i] .variation >= max_var ) { ++ nbad ; goto remove ; } - if (er [i] .area > max_area) { ++ nbig ; goto remove ; } - if (er [i] .area < min_area) { ++ nsmall ; goto remove ; } - - /* - * Remove duplicates - */ - if (min_div < 1.0) { - vl_uint parent = er [i] .parent ; - int area, p_area ; - float div ; - - /* check all but the root mser */ - if((int) parent != i) { - - /* search for the maximally stable parent region */ - while(! er [parent] .max_stable) { - vl_uint next = er [parent] .parent ; - if(next == parent) break ; - parent = next ; - } - - /* Compare with the parent region; if the current and parent - * regions are too similar, keep only the parent. */ - area = er [i] .area ; - p_area = er [parent] .area ; - div = (float) (p_area - area) / (float) p_area ; - - if (div < min_div) { ++ ndup ; goto remove ; } - } /* remove dups end */ - - } - continue ; - remove : - er [i] .max_stable = 0 ; - -- nmer ; - } /* check next region */ - - f-> stats .num_abs_unstable = nbad ; - f-> stats .num_too_big = nbig ; - f-> stats .num_too_small = nsmall ; - f-> stats .num_duplicates = ndup ; - } - /* ----------------------------------------------------------------- - * Save the result - * -------------------------------------------------------------- */ - - /* make room */ - if (f-> rmer < nmer) { - if (mer) vl_free (mer) ; - f->mer = mer = vl_malloc( sizeof(vl_uint) * nmer) ; - f->rmer = nmer ; - } - - /* save back */ - f-> nmer = nmer ; - - j = 0 ; - for (i = 0 ; i < ner ; ++i) { - if (er [i] .max_stable) mer [j++] = er [i] .index ; - } -} - -/** ------------------------------------------------------------------- - ** @brief Fit ellipsoids - ** - ** @param f MSER filter. - ** - ** @sa @ref mser-ell - **/ - -VL_EXPORT -void -vl_mser_ell_fit (VlMserFilt* f) -{ - /* shortcuts */ - int nel = f-> nel ; - int dof = f-> dof ; - int *dims = f-> dims ; - int ndims = f-> ndims ; - int *subs = f-> subs ; - int njoins = f-> njoins ; - vl_uint *joins = f-> joins ; - VlMserReg *r = f-> r ; - vl_uint *mer = f-> mer ; - int nmer = f-> nmer ; - vl_mser_acc *acc = f-> acc ; - vl_mser_acc *ell = f-> ell ; - - int d, index, i, j ; - - /* already fit ? */ - if (f->nell == f->nmer) return ; - - /* make room */ - if (f->rell < f->nmer) { - if (f->ell) vl_free (f->ell) ; - f->ell = vl_malloc (sizeof(float) * f->nmer * f->dof) ; - f->rell = f-> nmer ; - } - - if (f->acc == 0) { - f->acc = vl_malloc (sizeof(float) * f->nel) ; - } - - acc = f-> acc ; - ell = f-> ell ; - - /* ----------------------------------------------------------------- - * Integrate moments - * -------------------------------------------------------------- */ - - /* for each dof */ - for(d = 0 ; d < f->dof ; ++d) { - - /* start from the upper-left pixel (0,0,...,0) */ - memset (subs, 0, sizeof(int) * ndims) ; - - /* step 1: fill acc pretending that each region has only one pixel */ - if(d < ndims) { - /* 1-order ................................................... */ - - for(index = 0 ; index < nel ; ++ index) { - acc [index] = subs [d] ; - adv(ndims, dims, subs) ; - } - } - else { - /* 2-order ................................................... */ - - /* map the dof d to a second order moment E[x_i x_j] */ - i = d - ndims ; - j = 0 ; - while(i > j) { - i -= j + 1 ; - j ++ ; - } - /* initialize acc with x_i * x_j */ - for(index = 0 ; index < nel ; ++ index){ - acc [index] = subs [i] * subs [j] ; - adv(ndims, dims, subs) ; - } - } - - /* step 2: integrate */ - for(i = 0 ; i < njoins ; ++i) { - vl_uint index = joins [i] ; - vl_uint parent = r [index] .parent ; - acc [parent] += acc [index] ; - } - - /* step 3: save back to ellpises */ - for(i = 0 ; i < nmer ; ++i) { - vl_uint idx = mer [i] ; - ell [d + dof*i] = acc [idx] ; - } - - } /* next dof */ - - /* ----------------------------------------------------------------- - * Compute central moments - * -------------------------------------------------------------- */ - - for(index = 0 ; index < nmer ; ++index) { - float *pt = ell + index * dof ; - vl_uint idx = mer [index] ; - float area = r [idx] .area ; - - for(d = 0 ; d < dof ; ++d) { - - pt [d] /= area ; - - if(d >= ndims) { - /* remove squared mean from moment to get variance */ - i = d - ndims ; - j = 0 ; - while(i > j) { - i -= j + 1 ; - j ++ ; - } - pt [d] -= pt [i] * pt [j] ; - } - - } - } - - /* save back */ - f-> nell = nmer ; -} diff --git a/opensfm/src/third_party/vlfeat/vl/mser.h b/opensfm/src/third_party/vlfeat/vl/mser.h deleted file mode 100644 index bd63cedb1..000000000 --- a/opensfm/src/third_party/vlfeat/vl/mser.h +++ /dev/null @@ -1,424 +0,0 @@ -/** @file mser.h - ** @brief MSER (@ref mser) - ** @author Andrea Vedaldi - **/ - -/* -Copyright (C) 2007-12 Andrea Vedaldi and Brian Fulkerson. -All rights reserved. - -This file is part of the VLFeat library and is made available under -the terms of the BSD license (see the COPYING file). -*/ - -#ifndef VL_MSER -#define VL_MSER - -#include "generic.h" - -/** @brief MSER image data type - ** - ** This is the data type of the image pixels. It has to be an - ** integer. - **/ -typedef vl_uint8 vl_mser_pix ; - -/** @brief Maximum value - ** - ** Maximum value of the integer type ::vl_mser_pix. - **/ -#define VL_MSER_PIX_MAXVAL 256 - -/** @brief MSER Filter - ** - ** The MSER filter computes the Maximally Stable Extremal Regions of - ** an image. - ** - ** @sa @ref mser - **/ -typedef struct _VlMserFilt VlMserFilt ; - -/** @brief MSER filter statistics */ -typedef struct _VlMserStats VlMserStats ; - -/** @brief MSER filter statistics definition */ -struct _VlMserStats -{ - int num_extremal ; /**< number of extremal regions */ - int num_unstable ; /**< number of unstable extremal regions */ - int num_abs_unstable ; /**< number of regions that failed the absolute stability test */ - int num_too_big ; /**< number of regions that failed the maximum size test */ - int num_too_small ; /**< number of regions that failed the minimum size test */ - int num_duplicates ; /**< number of regions that failed the duplicate test */ -} ; - -/** @name Construction and Destruction - ** @{ - **/ -VL_EXPORT VlMserFilt* vl_mser_new (int ndims, int const* dims) ; -VL_EXPORT void vl_mser_delete (VlMserFilt *f) ; -/** @} */ - -/** @name Processing - ** @{ - **/ -VL_EXPORT void vl_mser_process (VlMserFilt *f, - vl_mser_pix const *im) ; -VL_EXPORT void vl_mser_ell_fit (VlMserFilt *f) ; -/** @} */ - -/** @name Retrieving data - ** @{ - **/ -VL_INLINE vl_uint vl_mser_get_regions_num (VlMserFilt const *f) ; -VL_INLINE vl_uint const* vl_mser_get_regions (VlMserFilt const *f) ; -VL_INLINE float const* vl_mser_get_ell (VlMserFilt const *f) ; -VL_INLINE vl_uint vl_mser_get_ell_num (VlMserFilt const *f) ; -VL_INLINE vl_uint vl_mser_get_ell_dof (VlMserFilt const *f) ; -VL_INLINE VlMserStats const* vl_mser_get_stats (VlMserFilt const *f) ; -/** @} */ - -/** @name Retrieving parameters - ** @{ - **/ -VL_INLINE vl_mser_pix vl_mser_get_delta (VlMserFilt const *f) ; -VL_INLINE double vl_mser_get_min_area (VlMserFilt const *f) ; -VL_INLINE double vl_mser_get_max_area (VlMserFilt const *f) ; -VL_INLINE double vl_mser_get_max_variation (VlMserFilt const *f) ; -VL_INLINE double vl_mser_get_min_diversity (VlMserFilt const *f) ; -/** @} */ - -/** @name Setting parameters - ** @{ - **/ -VL_INLINE void vl_mser_set_delta (VlMserFilt *f, vl_mser_pix x) ; -VL_INLINE void vl_mser_set_min_area (VlMserFilt *f, double x) ; -VL_INLINE void vl_mser_set_max_area (VlMserFilt *f, double x) ; -VL_INLINE void vl_mser_set_max_variation (VlMserFilt *f, double x) ; -VL_INLINE void vl_mser_set_min_diversity (VlMserFilt *f, double x) ; -/** @} */ - -/* ==================================================================== - * INLINE DEFINITIONS - * ================================================================== */ - -/** @internal - ** @brief MSER accumulator data type - ** - ** This is a large integer type. It should be large enough to contain - ** a number equal to the area (volume) of the image by the image - ** width by the image height (for instance, if the image is a square - ** of side 256, the maximum value is 256 x 256 x 256). - **/ -typedef float vl_mser_acc ; - -/** @internal @brief Basic region flag: null region */ -#ifdef VL_COMPILER_MSC -#define VL_MSER_VOID_NODE ((1ui64<<32) - 1) -#else -#define VL_MSER_VOID_NODE ((1ULL<<32) - 1) -#endif - -/* ----------------------------------------------------------------- */ -/** @internal - ** @brief MSER: basic region (declaration) - ** - ** Extremal regions and maximally stable extremal regions are - ** instances of image regions. - ** - ** There is an image region for each pixel of the image. Each region - ** is represented by an instance of this structure. Regions are - ** stored into an array in pixel order. - ** - ** Regions are arranged into a forest. VlMserReg::parent points to - ** the parent node, or to the node itself if the node is a root. - ** VlMserReg::parent is the index of the node in the node array - ** (which therefore is also the index of the corresponding - ** pixel). VlMserReg::height is the distance of the fartest leaf. If - ** the node itself is a leaf, then VlMserReg::height is zero. - ** - ** VlMserReg::area is the area of the image region corresponding to - ** this node. - ** - ** VlMserReg::region is the extremal region identifier. Not all - ** regions are extremal regions however; if the region is NOT - ** extremal, this field is set to .... - **/ -struct _VlMserReg -{ - vl_uint parent ; /**< points to the parent region. */ - vl_uint shortcut ; /**< points to a region closer to a root. */ - vl_uint height ; /**< region height in the forest. */ - vl_uint area ; /**< area of the region. */ -} ; - -/** @internal @brief MSER: basic region */ -typedef struct _VlMserReg VlMserReg ; - -/* ----------------------------------------------------------------- */ -/** @internal - ** @brief MSER: extremal region (declaration) - ** - ** Extremal regions (ER) are extracted from the region forest. Each - ** region is represented by an instance of this structure. The - ** structures are stored into an array, in arbitrary order. - ** - ** ER are arranged into a tree. @a parent points to the parent ER, or - ** to itself if the ER is the root. - ** - ** An instance of the structure represents the extremal region of the - ** level set of intensity VlMserExtrReg::value and containing the - ** pixel VlMserExtReg::index. - ** - ** VlMserExtrReg::area is the area of the extremal region and - ** VlMserExtrReg::area_top is the area of the extremal region - ** containing this region in the level set of intensity - ** VlMserExtrReg::area + @c delta. - ** - ** VlMserExtrReg::variation is the relative area variation @c - ** (area_top-area)/area. - ** - ** VlMserExtrReg::max_stable is a flag signaling whether this extremal - ** region is also maximally stable. - **/ -struct _VlMserExtrReg -{ - int parent ; /**< index of the parent region */ - int index ; /**< index of pivot pixel */ - vl_mser_pix value ; /**< value of pivot pixel */ - vl_uint shortcut ; /**< shortcut used when building a tree */ - vl_uint area ; /**< area of the region */ - float variation ; /**< rel. area variation */ - vl_uint max_stable ; /**< max stable number (=0 if not maxstable) */ -} ; - -/** @internal - ** @brief MSER: extremal region */ -typedef struct _VlMserExtrReg VlMserExtrReg ; - -/* ----------------------------------------------------------------- */ -/** @internal - ** @brief MSER filter - ** @see @ref mser - **/ -struct _VlMserFilt -{ - - /** @name Image data and meta data @internal */ - /*@{*/ - int ndims ; /**< number of dimensions */ - int *dims ; /**< dimensions */ - int nel ; /**< number of image elements (pixels) */ - int *subs ; /**< N-dimensional subscript */ - int *dsubs ; /**< another subscript */ - int *strides ; /**< strides to move in image data */ - /*@}*/ - - vl_uint *perm ; /**< pixel ordering */ - vl_uint *joins ; /**< sequence of join ops */ - int njoins ; /**< number of join ops */ - - /** @name Regions */ - /*@{*/ - VlMserReg *r ; /**< basic regions */ - VlMserExtrReg *er ; /**< extremal tree */ - vl_uint *mer ; /**< maximally stable extremal regions */ - int ner ; /**< number of extremal regions */ - int nmer ; /**< number of maximally stable extr. reg. */ - int rer ; /**< size of er buffer */ - int rmer ; /**< size of mer buffer */ - /*@}*/ - - /** @name Ellipsoids fitting */ - /*@{*/ - float *acc ; /**< moment accumulator. */ - float *ell ; /**< ellipsoids list. */ - int rell ; /**< size of ell buffer */ - int nell ; /**< number of ellipsoids extracted */ - int dof ; /**< number of dof of ellipsoids. */ - - /*@}*/ - - /** @name Configuration */ - /*@{*/ - vl_bool verbose ; /**< be verbose */ - int delta ; /**< delta filter parameter */ - double max_area ; /**< badness test parameter */ - double min_area ; /**< badness test parameter */ - double max_variation ; /**< badness test parameter */ - double min_diversity ; /**< minimum diversity */ - /*@}*/ - - VlMserStats stats ; /** run statistic */ -} ; - -/* ----------------------------------------------------------------- */ -/** @brief Get delta - ** @param f MSER filter. - ** @return value of @c delta. - **/ -VL_INLINE vl_mser_pix -vl_mser_get_delta (VlMserFilt const *f) -{ - return f-> delta ; -} - -/** @brief Set delta - ** @param f MSER filter. - ** @param x value of @c delta. - **/ -VL_INLINE void -vl_mser_set_delta (VlMserFilt *f, vl_mser_pix x) -{ - f-> delta = x ; -} - -/* ----------------------------------------------------------------- */ -/** @brief Get minimum diversity - ** @param f MSER filter. - ** @return value of @c minimum diversity. - **/ -VL_INLINE double -vl_mser_get_min_diversity (VlMserFilt const *f) -{ - return f-> min_diversity ; -} - -/** @brief Set minimum diversity - ** @param f MSER filter. - ** @param x value of @c minimum diversity. - **/ -VL_INLINE void -vl_mser_set_min_diversity (VlMserFilt *f, double x) -{ - f-> min_diversity = x ; -} - -/* ----------------------------------------------------------------- */ -/** @brief Get statistics - ** @param f MSER filter. - ** @return statistics. - **/ -VL_INLINE VlMserStats const* -vl_mser_get_stats (VlMserFilt const *f) -{ - return & f-> stats ; -} - -/* ----------------------------------------------------------------- */ -/** @brief Get maximum region area - ** @param f MSER filter. - ** @return maximum region area. - **/ -VL_INLINE double -vl_mser_get_max_area (VlMserFilt const *f) -{ - return f-> max_area ; -} - -/** @brief Set maximum region area - ** @param f MSER filter. - ** @param x maximum region area. - **/ -VL_INLINE void -vl_mser_set_max_area (VlMserFilt *f, double x) -{ - f-> max_area = x ; -} - -/* ----------------------------------------------------------------- */ -/** @brief Get minimum region area - ** @param f MSER filter. - ** @return minimum region area. - **/ -VL_INLINE double -vl_mser_get_min_area (VlMserFilt const *f) -{ - return f-> min_area ; -} - -/** @brief Set minimum region area - ** @param f MSER filter. - ** @param x minimum region area. - **/ -VL_INLINE void -vl_mser_set_min_area (VlMserFilt *f, double x) -{ - f-> min_area = x ; -} - -/* ----------------------------------------------------------------- */ -/** @brief Get maximum region variation - ** @param f MSER filter. - ** @return maximum region variation. - **/ -VL_INLINE double -vl_mser_get_max_variation (VlMserFilt const *f) -{ - return f-> max_variation ; -} - -/** @brief Set maximum region variation - ** @param f MSER filter. - ** @param x maximum region variation. - **/ -VL_INLINE void -vl_mser_set_max_variation (VlMserFilt *f, double x) -{ - f-> max_variation = x ; -} - -/* ----------------------------------------------------------------- */ -/** @brief Get maximally stable extremal regions - ** @param f MSER filter. - ** @return array of MSER pivots. - **/ -VL_INLINE vl_uint const * -vl_mser_get_regions (VlMserFilt const* f) -{ - return f-> mer ; -} - -/** @brief Get number of maximally stable extremal regions - ** @param f MSER filter. - ** @return number of MSERs. - **/ -VL_INLINE vl_uint -vl_mser_get_regions_num (VlMserFilt const* f) -{ - return f-> nmer ; -} - -/* ----------------------------------------------------------------- */ -/** @brief Get ellipsoids - ** @param f MSER filter. - ** @return ellipsoids. - **/ -VL_INLINE float const * -vl_mser_get_ell (VlMserFilt const* f) -{ - return f-> ell ; -} - -/** @brief Get number of degrees of freedom of ellipsoids - ** @param f MSER filter. - ** @return number of degrees of freedom. - **/ -VL_INLINE vl_uint -vl_mser_get_ell_dof (VlMserFilt const* f) -{ - return f-> dof ; -} - -/** @brief Get number of ellipsoids - ** @param f MSER filter. - ** @return number of ellipsoids - **/ -VL_INLINE vl_uint -vl_mser_get_ell_num (VlMserFilt const* f) -{ - return f-> nell ; -} - -/* VL_MSER */ -#endif diff --git a/opensfm/src/third_party/vlfeat/vl/pgm.c b/opensfm/src/third_party/vlfeat/vl/pgm.c deleted file mode 100644 index 81a3e3daf..000000000 --- a/opensfm/src/third_party/vlfeat/vl/pgm.c +++ /dev/null @@ -1,542 +0,0 @@ -/** @file pgm.c - ** @brief Portable graymap format (PGM) parser - Definition - ** @author Andrea Vedaldi - **/ - -/* -Copyright (C) 2007-12 Andrea Vedaldi and Brian Fulkerson. -Copyright (C) 2013 Andrea Vedaldi. -All rights reserved. - -This file is part of the VLFeat library and is made available under -the terms of the BSD license (see the COPYING file). -*/ - -/** @file pgm.h - -This module implements basic input and ouptut of images in PGM -format. - -Extracting an image encoded in PGM format from an imput -file stream involves the following steps: - -- use ::vl_pgm_extract_head to extract the image meta data - (size and bit depth); -- allocate a buffer to store the image data; -- use ::vl_pgm_extract_data to extract the image data to the allocated - buffer. - -Writing an image in PGM format to an ouptut file stream -can be done by using ::vl_pgm_insert. - -To quickly read/write a PGM image from/to a given file, use -::vl_pgm_read_new() and ::vl_pgm_write(). To to the same from a -buffer in floating point format use ::vl_pgm_read_new_f() and -::vl_pgm_write_f(). - -**/ - -#include "pgm.h" - -#include -#include -#include - -/** ------------------------------------------------------------------ - ** @internal @brief Remove all characters to the next new-line. - ** @param f file to strip. - ** @return number of characters removed. - **/ - -static int -remove_line(FILE* f) -{ - int count = 0 ; - int c ; - - while (1) { - c = fgetc(f) ; - ++ count ; - - switch(c) { - case '\n' : - goto quit_remove_line ; - - case EOF : - -- count ; - goto quit_remove_line ; - } - } - quit_remove_line : - return count ; -} - -/** ------------------------------------------------------------------ - ** @internal @brief Remove white-spaces and comments. - ** @param f file to strip. - ** @return number of characters removed. - **/ - -static int -remove_blanks(FILE* f) -{ - int count = 0 ; - int c ; - - while (1) { - c = fgetc(f) ; - - switch(c) { - - case '\t' : case '\n' : - case '\r' : case ' ' : - ++ count ; - break ; - - case '#' : - count += 1 + remove_line(f) ; - break ; - - case EOF : - goto quit_remove_blanks ; - - default: - ungetc(c, f) ; - goto quit_remove_blanks ; - } - } - quit_remove_blanks: - return count ; -} - -/** ------------------------------------------------------------------ - ** @brief Get PGM image number of pixels. - ** @param im PGM image descriptor. - ** @return number of pixels of the image. - ** - ** The functions returns the number of pixels of the PGM image @a im. - ** - ** To calculate the image data size in bytes, this value must be - ** multiplied by the number of byte per pixels (see - ** ::vl_pgm_get_bpp()). - **/ - -VL_EXPORT vl_size -vl_pgm_get_npixels (VlPgmImage const *im) -{ - return im->width * im->height ; -} - -/** ------------------------------------------------------------------ - ** @brief Get PGM image bytes per pixel. - ** @param im PGM image descriptor. - ** @return number of bytes per pixel. - ** - ** The function returns the number of bytes for each pixel of the - ** PGM image @a im. - **/ - -VL_EXPORT vl_size -vl_pgm_get_bpp (VlPgmImage const *im) -{ - return (im->max_value >= 256) + 1 ; -} - -/** ------------------------------------------------------------------ - ** @brief Extract PGM header from stream. - ** @param f input file. - ** @param im image structure to fill. - ** @return error code. - ** - ** The function extracts from the file @a f the meta-data section of - ** an image encoded in PGM format. The function fills the structure - ** ::VlPgmImage accordingly. - ** - ** The error may be either ::VL_ERR_PGM_INV_HEAD or ::VL_ERR_PGM_INV_META - ** depending whether the error occurred in decoding the header or - ** meta section of the PGM file. - **/ - -VL_EXPORT int -vl_pgm_extract_head (FILE* f, VlPgmImage *im) -{ - char magic [2] ; - int c ; - int is_raw ; - int width ; - int height ; - int max_value ; - size_t sz ; - vl_bool good ; - - /* ----------------------------------------------------------------- - * check magic number - * -------------------------------------------------------------- */ - sz = fread(magic, 1, 2, f) ; - - if (sz < 2) { - return vl_set_last_error(VL_ERR_PGM_INV_HEAD, "Invalid PGM header") ; - } - - good = magic [0] == 'P' ; - - switch (magic [1]) { - case '2' : /* ASCII format */ - is_raw = 0 ; - break ; - - case '5' : /* RAW format */ - is_raw = 1 ; - break ; - - default : - good = 0 ; - break ; - } - - if( ! good ) { - return vl_set_last_error(VL_ERR_PGM_INV_HEAD, "Invalid PGM header") ; - } - - /* ----------------------------------------------------------------- - * parse width, height, max_value - * -------------------------------------------------------------- */ - good = 1 ; - - c = remove_blanks(f) ; - good &= c > 0 ; - - c = fscanf(f, "%d", &width) ; - good &= c == 1 ; - - c = remove_blanks(f) ; - good &= c > 0 ; - - c = fscanf(f, "%d", &height) ; - good &= c == 1 ; - - c = remove_blanks(f) ; - good &= c > 0 ; - - c = fscanf(f, "%d", &max_value) ; - good &= c == 1 ; - - /* must end with a single blank */ - c = fgetc(f) ; - good &= - c == '\n' || - c == '\t' || - c == ' ' || - c == '\r' ; - - if(! good) { - return vl_set_last_error(VL_ERR_PGM_INV_META, "Invalid PGM meta information"); - } - - if(! max_value >= 65536) { - return vl_set_last_error(VL_ERR_PGM_INV_META, "Invalid PGM meta information"); - } - - /* exit */ - im-> width = width ; - im-> height = height ; - im-> max_value = max_value ; - im-> is_raw = is_raw ; - return 0 ; -} - -/** ------------------------------------------------------------------ - ** @brief Extract PGM data from stream. - ** @param f input file. - ** @param im PGM image descriptor. - ** @param data data buffer to fill. - ** @return error code. - ** - ** The function extracts from the file @a f the data section of an - ** image encoded in PGM format. The function fills the buffer @a data - ** according. The buffer @a data should be ::vl_pgm_get_npixels() by - ** ::vl_pgm_get_bpp() bytes large. - **/ - -VL_EXPORT -int -vl_pgm_extract_data (FILE* f, VlPgmImage const *im, void *data) -{ - vl_size bpp = vl_pgm_get_bpp(im) ; - vl_size data_size = vl_pgm_get_npixels(im) ; - vl_bool good = 1 ; - size_t c ; - - /* ----------------------------------------------------------------- - * read data - * -------------------------------------------------------------- */ - - /* - In RAW mode we read directly an array of bytes or shorts. In - the latter case, however, we must take care of the - endianess. PGM files are sorted in big-endian format. If our - architecture is little endian, we must do a conversion. - */ - if (im->is_raw) { - - c = fread( data, - bpp, - data_size, - f ) ; - good = (c == data_size) ; - - /* adjust endianess */ -#if defined(VL_ARCH_LITTLE_ENDIAN) - if (bpp == 2) { - vl_uindex i ; - vl_uint8 *pt = (vl_uint8*) data ; - for(i = 0 ; i < 2 * data_size ; i += 2) { - vl_uint8 tmp = pt [i] ; - pt [i] = pt [i+1] ; - pt [i+1] = tmp ; - } - } -#endif - } - /* - In ASCII mode we read a sequence of decimal numbers separated - by whitespaces. - */ - else { - vl_uindex i ; - int unsigned v ; - for(good = 1, i = 0 ; - i < data_size && good ; - ++i) { - c = fscanf(f, " %ud", &v) ; - if (bpp == 1) { - * ((vl_uint8* ) data + i) = (vl_uint8) v ; - } else { - * ((vl_uint16*) data + i) = (vl_uint16) v ; - } - good &= c == 1 ; - } - } - - if(! good ) { - return vl_set_last_error(VL_ERR_PGM_INV_DATA, "Invalid PGM data") ; - } - return 0 ; -} - -/** ------------------------------------------------------------------ - ** @brief Insert a PGM image into a stream. - ** @param f output file. - ** @param im PGM image meta-data. - ** @param data image data. - ** @return error code. - **/ - -VL_EXPORT -int -vl_pgm_insert(FILE* f, VlPgmImage const *im, void const *data) -{ - vl_size bpp = vl_pgm_get_bpp (im) ; - vl_size data_size = vl_pgm_get_npixels (im) ; - size_t c ; - - /* write preamble */ - fprintf(f, - "P5\n%d\n%d\n%d\n", - (signed)im->width, - (signed)im->height, - (signed)im->max_value) ; - - /* take care of endianness */ -#if defined(VL_ARCH_LITTLE_ENDIAN) - if (bpp == 2) { - vl_uindex i ; - vl_uint8* temp = vl_malloc (2 * data_size) ; - memcpy(temp, data, 2 * data_size) ; - for(i = 0 ; i < 2 * data_size ; i += 2) { - vl_uint8 tmp = temp [i] ; - temp [i] = temp [i+1] ; - temp [i+1] = tmp ; - } - c = fwrite(temp, 2, data_size, f) ; - vl_free (temp) ; - } - else { -#endif - c = fwrite(data, bpp, data_size, f) ; -#if defined(VL_ARCH_LITTLE_ENDIAN) - } -#endif - - if(c != data_size) { - return vl_set_last_error(VL_ERR_PGM_IO, "Error writing PGM data") ; - } - return 0 ; -} - -/** ------------------------------------------------------------------ - ** @brief Read a PGM file. - ** @param name file name. - ** @param im a pointer to the PGM image structure to fill. - ** @param data a pointer to the pointer to the allocated buffer. - ** @return error code. - ** - ** The function reads a PGM image from file @a name and initializes - ** the structure @a im and the buffer @a data accordingly. - ** - ** The ownership of the buffer @a data is transfered to the caller. - ** @a data should be freed by means of ::vl_free(). - ** - ** @bug Only PGM files with 1 BPP are supported. - **/ - -VL_EXPORT -int vl_pgm_read_new (char const *name, VlPgmImage *im, vl_uint8** data) -{ - int err = 0 ; - FILE *f = fopen (name, "rb") ; - - if (! f) { - return vl_set_last_error(VL_ERR_PGM_IO, "Error opening PGM file `%s' for reading", name) ; - } - - err = vl_pgm_extract_head(f, im) ; - if (err) { - fclose (f) ; - return err ; - } - - if (vl_pgm_get_bpp(im) > 1) { - return vl_set_last_error(VL_ERR_BAD_ARG, "PGM with BPP > 1 not supported") ; - } - - *data = vl_malloc (vl_pgm_get_npixels(im) * sizeof(vl_uint8)) ; - err = vl_pgm_extract_data(f, im, *data) ; - - if (err) { - vl_free (data) ; - fclose (f) ; - } - - fclose (f) ; - return err ; -} - -/** ------------------------------------------------------------------ - ** @brief Read floats from a PGM file. - ** @param name file name. - ** @param im a pointer to the PGM image structure to fill. - ** @param data a pointer to the pointer to the allocated buffer. - ** @return error code. - ** - ** The function reads a PGM image from file @a name and initializes - ** the structure @a im and the buffer @a data accordingly. The buffer - ** @a data is an array of floats in the range [0, 1]. - ** - ** The ownership of the buffer @a data is transfered to the caller. - ** @a data should be freed by means of ::vl_free(). - ** - ** @bug Only PGM files with 1 BPP are supported. - **/ - -VL_EXPORT -int vl_pgm_read_new_f (char const *name, VlPgmImage *im, float** data) -{ - int err = 0 ; - size_t npixels ; - vl_uint8 *idata ; - - err = vl_pgm_read_new (name, im, &idata) ; - if (err) { - return err ; - } - - npixels = vl_pgm_get_npixels(im) ; - *data = vl_malloc (sizeof(float) * npixels) ; - { - size_t k ; - float scale = 1.0f / (float)im->max_value ; - for (k = 0 ; k < npixels ; ++ k) (*data)[k] = scale * idata[k] ; - } - - vl_free (idata) ; - return 0 ; -} - -/** ------------------------------------------------------------------ - ** @brief Write bytes to a PGM file. - ** @param name file name. - ** @param data data to write. - ** @param width width of the image. - ** @param height height of the image. - ** @return error code. - ** - ** The function dumps the image @a data to the PGM file of the specified - ** name. This is an helper function simplifying the usage of - ** vl_pgm_insert(). - **/ - -VL_EXPORT -int vl_pgm_write (char const *name, vl_uint8 const* data, int width, int height) -{ - int err = 0 ; - VlPgmImage pgm ; - FILE *f = fopen (name, "wb") ; - - if (! f) { - return vl_set_last_error(VL_ERR_PGM_IO, - "Error opening PGM file '%s' for writing", name) ; - } - - pgm.width = width ; - pgm.height = height ; - pgm.is_raw = 1 ; - pgm.max_value = 255 ; - - err = vl_pgm_insert (f, &pgm, data) ; - fclose (f) ; - - return err ; -} - -/** ------------------------------------------------------------------- - ** @brief Write floats to PGM file - ** @param name file name. - ** @param data data to write. - ** @param width width of the image. - ** @param height height of the image. - ** @return error code. - ** - ** The function dumps the image @a data to the PGM file of the - ** specified name. The data is re-scaled to fit in the range 0-255. - ** This is an helper function simplifying the usage of - ** vl_pgm_insert(). - **/ - -VL_EXPORT -int vl_pgm_write_f (char const *name, float const* data, int width, int height) -{ - int err = 0 ; - int k ; - float min = + VL_INFINITY_F ; - float max = - VL_INFINITY_F ; - float scale ; - - vl_uint8 * buffer = vl_malloc (sizeof(float) * width * height) ; - - for (k = 0 ; k < width * height ; ++k) { - min = VL_MIN(min, data [k]) ; - max = VL_MAX(max, data [k]) ; - } - - scale = 255 / (max - min + VL_EPSILON_F) ; - - for (k = 0 ; k < width * height ; ++k) { - buffer [k] = (vl_uint8) ((data [k] - min) * scale) ; - } - - err = vl_pgm_write (name, buffer, width, height) ; - - vl_free (buffer) ; - return err ; -} diff --git a/opensfm/src/third_party/vlfeat/vl/pgm.h b/opensfm/src/third_party/vlfeat/vl/pgm.h deleted file mode 100644 index 80b0ef0f1..000000000 --- a/opensfm/src/third_party/vlfeat/vl/pgm.h +++ /dev/null @@ -1,73 +0,0 @@ -/** @file pgm.h - ** @brief Portable graymap format (PGM) parser - ** @author Andrea Vedaldi - **/ - -/* -Copyright (C) 2007-12 Andrea Vedaldi and Brian Fulkerson. -All rights reserved. - -This file is part of the VLFeat library and is made available under -the terms of the BSD license (see the COPYING file). -*/ - -#ifndef VL_PGM_H -#define VL_PGM_H - -#include "generic.h" -#include "mathop.h" -#include - -/** @name PGM parser error codes - ** @{ */ -#define VL_ERR_PGM_INV_HEAD 101 /**< Invalid PGM header section. */ -#define VL_ERR_PGM_INV_META 102 /**< Invalid PGM meta section. */ -#define VL_ERR_PGM_INV_DATA 103 /**< Invalid PGM data section.*/ -#define VL_ERR_PGM_IO 104 /**< Generic I/O error. */ -/** @} */ - -/** @brief PGM image meta data - ** - ** A PGM image is a 2-D array of pixels of width #width and height - ** #height. Each pixel is an integer one or two bytes wide, depending - ** whether #max_value is smaller than 256. - **/ - -typedef struct _VlPgmImage -{ - vl_size width ; /**< image width. */ - vl_size height ; /**< image height. */ - vl_size max_value ; /**< pixel maximum value (<= 2^16-1). */ - vl_bool is_raw ; /**< is RAW format? */ -} VlPgmImage ; - -/** @name Core operations - ** @{ */ -VL_EXPORT int vl_pgm_extract_head (FILE *f, VlPgmImage *im) ; -VL_EXPORT int vl_pgm_extract_data (FILE *f, VlPgmImage const *im, void *data) ; -VL_EXPORT int vl_pgm_insert (FILE *f, - VlPgmImage const *im, - void const*data ) ; -VL_EXPORT vl_size vl_pgm_get_npixels (VlPgmImage const *im) ; -VL_EXPORT vl_size vl_pgm_get_bpp (VlPgmImage const *im) ; -/** @} */ - -/** @name Helper functions - ** @{ */ -VL_EXPORT int vl_pgm_write (char const *name, - vl_uint8 const *data, - int width, int height) ; -VL_EXPORT int vl_pgm_write_f (char const *name, - float const *data, - int width, int height) ; -VL_EXPORT int vl_pgm_read_new (char const *name, - VlPgmImage *im, - vl_uint8 **data) ; -VL_EXPORT int vl_pgm_read_new_f (char const *name, - VlPgmImage *im, - float **data) ; - -/** @} */ - -/* VL_PGM_H */ -#endif diff --git a/opensfm/src/third_party/vlfeat/vl/qsort-def.h b/opensfm/src/third_party/vlfeat/vl/qsort-def.h deleted file mode 100644 index 63b61c837..000000000 --- a/opensfm/src/third_party/vlfeat/vl/qsort-def.h +++ /dev/null @@ -1,200 +0,0 @@ -/** @file qsort-def.h - ** @brief QSort preprocessor metaprogram - ** @author Andrea Vedaldi - **/ - -/* -Copyright (C) 2007-12 Andrea Vedaldi and Brian Fulkerson. -All rights reserved. - -This file is part of the VLFeat library and is made available under -the terms of the BSD license (see the COPYING file). -*/ - -/** @file qsort-def.h - -@section qsort-def-overview Overview - -@ref qsort-def.h is a metaprogram to define specialized instances -of the quick-sort algorithm. - -@section qsort-def-usage Usage - -@ref qsort-def.h is used to define a specialization of the -::VL_QSORT_sort function that operates -on a given type of array. For instance the code - -@code -#define VL_QSORT_type float -#define VL_QSORT_prefix my_qsort -#include -@endcode - -defines a function @c my_qsort_sort that operates on an array of floats. - -@todo large array compatibility. -**/ - -#include "host.h" -#include - -#ifndef VL_QSORT_prefix -#error "VL_QSORT_prefix must be defined" -#endif - -#ifndef VL_QSORT_array -#ifndef VL_QSORT_type -#error "VL_QSORT_type must be defined if VL_QSORT_array is not" -#endif -#define VL_QSORT_array VL_QSORT_type* -#define VL_QSORT_array_const VL_QSORT_type const* -#endif - -#ifdef __DOXYGEN__ -#define VL_QSORT_prefix QSortPrefix /**< Prefix of the qsort functions */ -#define VL_QSORT_type QSortType /**< Data type of the qsort elements */ -#define VL_QSORT_array QSortType* /**< Data type of the qsort container */ -#endif - -/* ---------------------------------------------------------------- */ - -#if ! defined(VL_QSORT_cmp) || defined(__DOXYGEN__) -#define VL_QSORT_cmp VL_XCAT(VL_QSORT_prefix, _cmp) - -/** @brief Compare two array elements - ** @param array qsort array. - ** @param indexA index of the first element @c A to compare. - ** @param indexB index of the second element @c B to comapre. - ** @return a negative number if @c AB. - **/ - -VL_INLINE VL_QSORT_type -VL_QSORT_cmp -(VL_QSORT_array_const array, - vl_uindex indexA, - vl_uindex indexB) -{ - return array[indexA] - array[indexB] ; -} - -/* VL_QSORT_cmp */ -#endif - -/* ---------------------------------------------------------------- */ - -#if ! defined(VL_QSORT_swap) || defined(__DOXYGEN__) -#define VL_QSORT_swap VL_XCAT(VL_QSORT_prefix, _swap) - -/** @brief Swap two array elements - ** @param array qsort array. - ** @param indexA index of the first element to swap. - ** @param indexB index of the second element to swap. - ** - ** The function swaps the two elements @a a and @ b. The function - ** uses a temporary element of type ::VL_QSORT_type - ** and the copy operator @c =. - **/ - -VL_INLINE void -VL_QSORT_swap -(VL_QSORT_array array, - vl_uindex indexA, - vl_uindex indexB) -{ - VL_QSORT_type t = array [indexA] ; - array [indexA] = array [indexB] ; - array [indexB] = t ; -} - -/* VL_QSORT_swap */ -#endif - -/* ---------------------------------------------------------------- */ -#if ! defined(VL_QSORT_sort_recursive) || defined(__DOXYGEN__) -#define VL_QSORT_sort_recursive VL_XCAT(VL_QSORT_prefix, _sort_recursive) - -/** @brief Sort portion of an array using quicksort - ** @param array (in/out) pointer to the array. - ** @param begin first element of the array portion. - ** @param end last element of the array portion. - ** - ** The function sorts the array using quick-sort. Note that - ** @c begin must be not larger than @c end. - **/ - -VL_INLINE void -VL_QSORT_sort_recursive -(VL_QSORT_array array, vl_uindex begin, vl_uindex end) -{ - vl_uindex pivot = (end + begin) / 2 ; - vl_uindex lowPart, i ; - - assert (begin <= end) ; - - /* swap pivot with last */ - VL_QSORT_swap (array, pivot, end) ; - pivot = end ; - - /* - Now scan from left to right, moving all element smaller - or equal than the pivot to the low part - array[0], array[1], ..., array[lowPart - 1]. - */ - lowPart = begin ; - for (i = begin; i < end ; ++i) { /* one less */ - if (VL_QSORT_cmp (array, i, pivot) <= 0) { - /* array[i] must be moved into the low part */ - VL_QSORT_swap (array, lowPart, i) ; - lowPart ++ ; - } - } - - /* the pivot should also go into the low part */ - VL_QSORT_swap (array, lowPart, pivot) ; - pivot = lowPart ; - - /* do recursion */ - if (pivot > begin) { - /* note that pivot-1 stays non-negative */ - VL_QSORT_sort_recursive (array, begin, pivot - 1) ; - } - if (pivot < end) { - VL_QSORT_sort_recursive (array, pivot + 1, end) ; - } -} - -/* VL_QSORT_sort_recursive */ -#endif - -/* ---------------------------------------------------------------- */ - -#if ! defined(VL_QSORT_sort) || defined(__DOXYGEN__) -#define VL_QSORT_sort VL_XCAT(VL_QSORT_prefix, _sort) - -/** @brief Sort array using quicksort - ** @param array (in/out) pointer to the array. - ** @param size size of the array. - ** - ** The function sorts the array using quick-sort. - **/ - -VL_INLINE void -VL_QSORT_sort -(VL_QSORT_array array, vl_size size) -{ - assert (size >= 1) ; - VL_QSORT_sort_recursive (array, 0, size - 1) ; -} - -/* VL_QSORT_qsort */ -#endif - -#undef VL_QSORT_prefix -#undef VL_QSORT_swap -#undef VL_QSORT_sort -#undef VL_QSORT_sort_recursive -#undef VL_QSORT_type -#undef VL_QSORT_array -#undef VL_QSORT_cmp - diff --git a/opensfm/src/third_party/vlfeat/vl/quickshift.c b/opensfm/src/third_party/vlfeat/vl/quickshift.c deleted file mode 100644 index 802dbf25c..000000000 --- a/opensfm/src/third_party/vlfeat/vl/quickshift.c +++ /dev/null @@ -1,465 +0,0 @@ -/** @file quickshift.c - ** @brief Quick shift - Definition - ** @author Brian Fulkerson - ** @author Andrea Vedaldi - **/ - -/* -Copyright (C) 2007-12 Andrea Vedaldi and Brian Fulkerson. -All rights reserved. - -This file is part of the VLFeat library and is made available under -the terms of the BSD license (see the COPYING file). -*/ - -/** - -@page quickshift Quick shift image segmentation -@author Brian Fulkerson -@author Andrea Vedaldi - - -@ref quickshift.h implements an image segmentation algorithm based on -the quick shift clustering algorithm @cite{vedaldi08quick}. - -- @ref quickshift-intro -- @ref quickshift-usage -- @ref quickshift-tech - - -@section quickshift-intro Overview - - -Quick shift @cite{vedaldi08quick} is a fast mode seeking algorithm, -similar to mean shift. The algorithm segments an RGB image (or any -image with more than one channel) by identifying clusters of pixels in -the joint spatial and color dimensions. Segments are local -(superpixels) and can be used as a basis for further processing. - -Given an image, the algorithm calculates a forest of pixels whose -branches are labeled with a distance value -(::vl_quickshift_get_parents, ::vl_quickshift_get_dists). This -specifies a hierarchical segmentation of the image, with segments -corresponding to subtrees. Useful superpixels can be identified by -cutting the branches whose distance label is above a given threshold -(the threshold can be either fixed by hand, or determined by cross -validation). - -Parameter influencing the algorithm are: - -- Kernel size. The pixel density and its modes are estimated by -using a Parzen window estimator with a Gaussian kernel of the -specified size (::vl_quickshift_set_kernel_size). The larger the size, -the larger the neighborhoods of pixels considered. -- Maximum distance. This (::vl_quickshift_set_max_dist) is the -maximum distance between two pixels that the algorithm considers when -building the forest. In principle, it can be infinity (so that a tree -is returned), but in practice it is much faster to consider only -relatively small distances (the maximum distance can be set to a small -multiple of the kernel size). - - -@section quickshift-usage Usage - - -- Create a new quick shift object (::vl_quickshift_new). The object - can be reused for multiple images of the same size. -- Configure quick shift by setting the kernel size - (::vl_quickshift_set_kernel_size) and the maximum gap - (::vl_quickshift_set_max_dist). The latter is in principle not - necessary, but useful to speedup processing. -- Process an image (::vl_quickshift_process). -- Retrieve the parents (::vl_quickshift_get_parents) and the distances - (::vl_quickshift_get_dists). These can be used to segment - the image in superpixels. -- Delete the quick shift object (::vl_quickshift_delete). - - -@section quickshift-tech Technical details - - -For each pixel (x,y), quick shift regards @f$ (x,y,I(x,y)) -@f$ as a sample from a d + 2 dimensional vector space. It -then calculates the Parzen density estimate (with a Gaussian kernel of -standard deviation @f$ \sigma @f$) - -@f[ -E(x,y) = P(x,y,I(x,y)) = \sum_{x'y'} -\frac{1}{(2\pi\sigma)^{d+2}} -\exp -\left( --\frac{1}{2\sigma^2} -\left[ -\begin{array}{c} -x - x' \\ -y - y' \\ -I(x,y) - I(x',y') \\ -\end{array} -\right] -\right) -@f] - -Then quick shift construct a tree connecting each image pixel to its -nearest neighbor which has greater density value. Formally, write @f$ -(x',y') >_P (x,y) @f$ if, and only if, - -@f[ - P(x',y',I(x',y')) > P(x,y,I(x,y))}. -@f] - -Each pixel (x, y) is connected to the closest higher density -pixel parent(x, y) that achieves the minimum distance in - -@f[ - \mathrm{dist}(x,y) = - \mathrm{min}_{(x',y') > P(x,y)} -\left( -(x - x')^2 + -(y - y')^2 + -\| I(x,y) - I(x',y') \|_2^2 -\right). -@f] - -**/ - -#include "quickshift.h" -#include "mathop.h" -#include -#include -#include - -/** ----------------------------------------------------------------- - ** @internal - ** @brief Computes the accumulated channel L2 distance between - ** i,j + the distance between i,j - ** - ** @param I input image buffer - ** @param N1 size of the first dimension of the image - ** @param N2 size of the second dimension of the image - ** @param K number of channels - ** @param i1 first dimension index of the first pixel to compare - ** @param i2 second dimension of the first pixel - ** @param j1 index of the second pixel to compare - ** @param j2 second dimension of the second pixel - ** - ** Takes the L2 distance between the values in I at pixel i and j, - ** accumulating along K channels and adding in the distance - ** between i,j in the image. - ** - ** @return the distance as described above - **/ - -VL_INLINE -vl_qs_type -vl_quickshift_distance(vl_qs_type const * I, - int N1, int N2, int K, - int i1, int i2, - int j1, int j2) -{ - vl_qs_type dist = 0 ; - int d1 = j1 - i1 ; - int d2 = j2 - i2 ; - int k ; - dist += d1*d1 + d2*d2 ; - /* For k = 0...K-1, d+= L2 distance between I(i1,i2,k) and - * I(j1,j2,k) */ - for (k = 0 ; k < K ; ++k) { - vl_qs_type d = - I [i1 + N1 * i2 + (N1*N2) * k] - - I [j1 + N1 * j2 + (N1*N2) * k] ; - dist += d*d ; - } - return dist ; -} - -/** ----------------------------------------------------------------- - ** @internal - ** @brief Computes the accumulated channel inner product between i,j + the - ** distance between i,j - ** - ** @param I input image buffer - ** @param N1 size of the first dimension of the image - ** @param N2 size of the second dimension of the image - ** @param K number of channels - ** @param i1 first dimension index of the first pixel to compare - ** @param i2 second dimension of the first pixel - ** @param j1 index of the second pixel to compare - ** @param j2 second dimension of the second pixel - ** - ** Takes the channel-wise inner product between the values in I at - ** pixel i and j, accumulating along K channels and adding in the - ** inner product between i,j in the image. - ** - ** @return the inner product as described above - **/ - -VL_INLINE -vl_qs_type -vl_quickshift_inner(vl_qs_type const * I, - int N1, int N2, int K, - int i1, int i2, - int j1, int j2) -{ - vl_qs_type ker = 0 ; - int k ; - ker += i1*j1 + i2*j2 ; - for (k = 0 ; k < K ; ++k) { - ker += - I [i1 + N1 * i2 + (N1*N2) * k] * - I [j1 + N1 * j2 + (N1*N2) * k] ; - } - return ker ; -} - -/** ----------------------------------------------------------------- - ** @brief Create a quick shift object - ** @param image the image. - ** @param height the height (number of rows) of the image. - ** @param width the width (number of columns) of the image. - ** @param channels the number of channels of the image. - ** @return new quick shift object. - ** - ** The @c image is an array of ::vl_qs_type values with three - ** dimensions (respectively @c widht, @c height, and @c - ** channels). Typically, a color (e.g, RGB) image has three - ** channels. The linear index of a pixel is computed with: - ** @c channels * @c width* @c height + @c row + @c height * @c col. - **/ - -VL_EXPORT -VlQS * -vl_quickshift_new(vl_qs_type const * image, int height, int width, - int channels) -{ - VlQS * q = vl_malloc(sizeof(VlQS)); - - q->image = (vl_qs_type *)image; - q->height = height; - q->width = width; - q->channels = channels; - - q->medoid = VL_FALSE; - q->tau = VL_MAX(height,width)/50; - q->sigma = VL_MAX(2, q->tau/3); - - q->dists = vl_calloc(height*width, sizeof(vl_qs_type)); - q->parents = vl_calloc(height*width, sizeof(int)); - q->density = vl_calloc(height*width, sizeof(vl_qs_type)) ; - - return q; -} - -/** ----------------------------------------------------------------- - ** @brief Create a quick shift objet - ** @param q quick shift object. - **/ - -VL_EXPORT -void vl_quickshift_process(VlQS * q) -{ - vl_qs_type const *I = q->image; - int *parents = q->parents; - vl_qs_type *E = q->density; - vl_qs_type *dists = q->dists; - vl_qs_type *M = 0, *n = 0 ; - vl_qs_type sigma = q->sigma ; - vl_qs_type tau = q->tau; - vl_qs_type tau2 = tau*tau; - - int K = q->channels, d; - int N1 = q->height, N2 = q->width; - int i1,i2, j1,j2, R, tR; - - d = 2 + K ; /* Total dimensions include spatial component (x,y) */ - - if (q->medoid) { /* n and M are only used in mediod shift */ - M = (vl_qs_type *) vl_calloc(N1*N2*d, sizeof(vl_qs_type)) ; - n = (vl_qs_type *) vl_calloc(N1*N2, sizeof(vl_qs_type)) ; - } - - R = (int) ceil (3 * sigma) ; - tR = (int) ceil (tau) ; - - /* ----------------------------------------------------------------- - * n - * -------------------------------------------------------------- */ - - /* If we are doing medoid shift, initialize n to the inner product of the - * image with itself - */ - if (n) { - for (i2 = 0 ; i2 < N2 ; ++ i2) { - for (i1 = 0 ; i1 < N1 ; ++ i1) { - n [i1 + N1 * i2] = vl_quickshift_inner(I,N1,N2,K, - i1,i2, - i1,i2) ; - } - } - } - - /* ----------------------------------------------------------------- - * E = - [oN'*F]', M - * -------------------------------------------------------------- */ - - /* - D_ij = d(x_i,x_j) - E_ij = exp(- .5 * D_ij / sigma^2) ; - F_ij = - E_ij - E_i = sum_j E_ij - M_di = sum_j X_j F_ij - - E is the parzen window estimate of the density - 0 = dissimilar to everything, windowsize = identical - */ - - for (i2 = 0 ; i2 < N2 ; ++ i2) { - for (i1 = 0 ; i1 < N1 ; ++ i1) { - - int j1min = VL_MAX(i1 - R, 0 ) ; - int j1max = VL_MIN(i1 + R, N1-1) ; - int j2min = VL_MAX(i2 - R, 0 ) ; - int j2max = VL_MIN(i2 + R, N2-1) ; - - /* For each pixel in the window compute the distance between it and the - * source pixel */ - for (j2 = j2min ; j2 <= j2max ; ++ j2) { - for (j1 = j1min ; j1 <= j1max ; ++ j1) { - vl_qs_type Dij = vl_quickshift_distance(I,N1,N2,K, i1,i2, j1,j2) ; - /* Make distance a similarity */ - vl_qs_type Fij = - exp(- Dij / (2*sigma*sigma)) ; - - /* E is E_i above */ - E [i1 + N1 * i2] -= Fij ; - - if (M) { - /* Accumulate votes for the median */ - int k ; - M [i1 + N1*i2 + (N1*N2) * 0] += j1 * Fij ; - M [i1 + N1*i2 + (N1*N2) * 1] += j2 * Fij ; - for (k = 0 ; k < K ; ++k) { - M [i1 + N1*i2 + (N1*N2) * (k+2)] += - I [j1 + N1*j2 + (N1*N2) * k] * Fij ; - } - } - - } /* j1 */ - } /* j2 */ - - } /* i1 */ - } /* i2 */ - - /* ----------------------------------------------------------------- - * Find best neighbors - * -------------------------------------------------------------- */ - - if (q->medoid) { - - /* - Qij = - nj Ei - 2 sum_k Gjk Mik - n is I.^2 - */ - - /* medoid shift */ - for (i2 = 0 ; i2 < N2 ; ++i2) { - for (i1 = 0 ; i1 < N1 ; ++i1) { - - vl_qs_type sc_best = 0 ; - /* j1/j2 best are the best indicies for each i */ - vl_qs_type j1_best = i1 ; - vl_qs_type j2_best = i2 ; - - int j1min = VL_MAX(i1 - R, 0 ) ; - int j1max = VL_MIN(i1 + R, N1-1) ; - int j2min = VL_MAX(i2 - R, 0 ) ; - int j2max = VL_MIN(i2 + R, N2-1) ; - - for (j2 = j2min ; j2 <= j2max ; ++ j2) { - for (j1 = j1min ; j1 <= j1max ; ++ j1) { - - vl_qs_type Qij = - n [j1 + j2 * N1] * E [i1 + i2 * N1] ; - int k ; - - Qij -= 2 * j1 * M [i1 + i2 * N1 + (N1*N2) * 0] ; - Qij -= 2 * j2 * M [i1 + i2 * N1 + (N1*N2) * 1] ; - for (k = 0 ; k < K ; ++k) { - Qij -= 2 * - I [j1 + j2 * N1 + (N1*N2) * k] * - M [i1 + i2 * N1 + (N1*N2) * (k + 2)] ; - } - - if (Qij > sc_best) { - sc_best = Qij ; - j1_best = j1 ; - j2_best = j2 ; - } - } - } - - /* parents_i is the linear index of j which is the best pair - * dists_i is the score of the best match - */ - parents [i1 + N1 * i2] = j1_best + N1 * j2_best ; - dists[i1 + N1 * i2] = sc_best ; - } - } - - } else { - - /* Quickshift assigns each i to the closest j which has an increase in the - * density (E). If there is no j s.t. Ej > Ei, then dists_i == inf (a root - * node in one of the trees of merges). - */ - for (i2 = 0 ; i2 < N2 ; ++i2) { - for (i1 = 0 ; i1 < N1 ; ++i1) { - - vl_qs_type E0 = E [i1 + N1 * i2] ; - vl_qs_type d_best = VL_QS_INF ; - vl_qs_type j1_best = i1 ; - vl_qs_type j2_best = i2 ; - - int j1min = VL_MAX(i1 - tR, 0 ) ; - int j1max = VL_MIN(i1 + tR, N1-1) ; - int j2min = VL_MAX(i2 - tR, 0 ) ; - int j2max = VL_MIN(i2 + tR, N2-1) ; - - for (j2 = j2min ; j2 <= j2max ; ++ j2) { - for (j1 = j1min ; j1 <= j1max ; ++ j1) { - if (E [j1 + N1 * j2] > E0) { - vl_qs_type Dij = vl_quickshift_distance(I,N1,N2,K, i1,i2, j1,j2) ; - if (Dij <= tau2 && Dij < d_best) { - d_best = Dij ; - j1_best = j1 ; - j2_best = j2 ; - } - } - } - } - - /* parents is the index of the best pair */ - /* dists_i is the minimal distance, inf implies no Ej > Ei within - * distance tau from the point */ - parents [i1 + N1 * i2] = j1_best + N1 * j2_best ; - dists[i1 + N1 * i2] = sqrt(d_best) ; - } - } - } - - if (M) vl_free(M) ; - if (n) vl_free(n) ; -} - -/** ----------------------------------------------------------------- - ** @brief Delete quick shift object - ** @param q quick shift object. - **/ - -void vl_quickshift_delete(VlQS * q) -{ - if (q) { - if (q->parents) vl_free(q->parents); - if (q->dists) vl_free(q->dists); - if (q->density) vl_free(q->density); - - vl_free(q); - } -} diff --git a/opensfm/src/third_party/vlfeat/vl/quickshift.h b/opensfm/src/third_party/vlfeat/vl/quickshift.h deleted file mode 100644 index d7bec8bf6..000000000 --- a/opensfm/src/third_party/vlfeat/vl/quickshift.h +++ /dev/null @@ -1,211 +0,0 @@ -/** @file quickshift.h - ** @brief Quick shift (@ref quickshift) - ** @author Andrea Vedaldi - ** @author Brian Fulkerson - **/ - -/* -Copyright (C) 2007-12 Andrea Vedaldi and Brian Fulkerson. -All rights reserved. - -This file is part of the VLFeat library and is made available under -the terms of the BSD license (see the COPYING file). -*/ - -#ifndef VL_QUICKSHIFT_H -#define VL_QUICKSHIFT_H - -#include "generic.h" -#include "mathop.h" - -/** @brief quick shift datatype */ -typedef double vl_qs_type ; - -/** @brief quick shift infinity constant */ -#define VL_QS_INF VL_INFINITY_D /* Change to _F for float math */ - -/** ------------------------------------------------------------------ - ** @brief quick shift results - ** - ** This implements quick shift mode seeking. - **/ - -typedef struct _VlQS -{ - vl_qs_type *image ; /**< height x width x channels feature image */ - int height; /**< height of the image */ - int width; /**< width of the image */ - int channels; /**< number of channels in the image */ - - vl_bool medoid; - vl_qs_type sigma; - vl_qs_type tau; - - int *parents ; - vl_qs_type *dists ; - vl_qs_type *density ; -} VlQS ; - -/** @name Create and destroy - ** @{ - **/ -VL_EXPORT -VlQS* vl_quickshift_new (vl_qs_type const * im, int height, int width, - int channels); - -VL_EXPORT -void vl_quickshift_delete (VlQS *q) ; -/** @} */ - -/** @name Process data - ** @{ - **/ - -VL_EXPORT -void vl_quickshift_process (VlQS *q) ; - -/** @} */ - -/** @name Retrieve data and parameters - ** @{ - **/ -VL_INLINE vl_qs_type vl_quickshift_get_max_dist (VlQS const *q) ; -VL_INLINE vl_qs_type vl_quickshift_get_kernel_size (VlQS const *q) ; -VL_INLINE vl_bool vl_quickshift_get_medoid (VlQS const *q) ; - -VL_INLINE int * vl_quickshift_get_parents (VlQS const *q) ; -VL_INLINE vl_qs_type * vl_quickshift_get_dists (VlQS const *q) ; -VL_INLINE vl_qs_type * vl_quickshift_get_density (VlQS const *q) ; -/** @} */ - -/** @name Set parameters - ** @{ - **/ -VL_INLINE void vl_quickshift_set_max_dist (VlQS *f, vl_qs_type tau) ; -VL_INLINE void vl_quickshift_set_kernel_size (VlQS *f, vl_qs_type sigma) ; -VL_INLINE void vl_quickshift_set_medoid (VlQS *f, vl_bool medoid) ; -/** @} */ - -/* ------------------------------------------------------------------- - * Inline functions implementation - * ---------------------------------------------------------------- */ - -/** ------------------------------------------------------------------ - ** @brief Get tau. - ** @param q quick shift object. - ** @return the maximum distance in the feature space between nodes in the - ** quick shift tree. - **/ - -VL_INLINE vl_qs_type -vl_quickshift_get_max_dist (VlQS const *q) -{ - return q->tau ; -} - -/** ------------------------------------------------------------------ - ** @brief Get sigma. - ** @param q quick shift object. - ** @return the standard deviation of the kernel used in the Parzen density - ** estimate. - **/ - -VL_INLINE vl_qs_type -vl_quickshift_get_kernel_size (VlQS const *q) -{ - return q->sigma ; -} - -/** ------------------------------------------------------------------ - ** @brief Get medoid. - ** @param q quick Shift object. - ** @return @c true if medoid shift is used instead of quick shift. - **/ - -VL_INLINE vl_bool -vl_quickshift_get_medoid (VlQS const *q) -{ - return q->medoid ; -} - -/** ------------------------------------------------------------------ - ** @brief Get parents. - ** @param q quick shift object. - ** @return a @c height x @c width matrix where each element contains the - ** linear index of its parent node. The node is a root if its - ** value is its own linear index. - **/ - -VL_INLINE int * -vl_quickshift_get_parents (VlQS const *q) -{ - return q->parents ; -} - -/** ------------------------------------------------------------------ - ** @brief Get dists. - ** @param q quick shift object. - ** @return for each pixel, the distance in feature space to the pixel - ** that is its parent in the quick shift tree. The distance is - ** set to 'inf' if the pixel is a root node. - **/ - -VL_INLINE vl_qs_type * -vl_quickshift_get_dists (VlQS const *q) -{ - return q->dists ; -} - -/** ------------------------------------------------------------------ - ** @brief Get density. - ** @param q quick shift object. - ** @return the estimate of the density at each pixel. - **/ - -VL_INLINE vl_qs_type * -vl_quickshift_get_density (VlQS const *q) -{ - return q->density ; -} - -/** ------------------------------------------------------------------ - ** @brief Set sigma - ** @param q quick shift object. - ** @param sigma standard deviation of the kernel used in the Parzen density - ** estimate. - **/ - -VL_INLINE void -vl_quickshift_set_kernel_size (VlQS *q, vl_qs_type sigma) -{ - q -> sigma = sigma ; -} - -/** ------------------------------------------------------------------ - ** @brief Set max distance - ** @param q quick shift object. - ** @param tau the maximum distance in the feature space between nodes in the - ** quick shift tree. - **/ - -VL_INLINE void -vl_quickshift_set_max_dist (VlQS *q, vl_qs_type tau) -{ - q -> tau = tau ; -} - -/** ------------------------------------------------------------------ - ** @brief Set medoid - ** @param q quick shift object. - ** @param medoid @c true to use kernelized medoid shift, @c false (default) uses - ** quick shift. - **/ - -VL_INLINE void -vl_quickshift_set_medoid (VlQS *q, vl_bool medoid) -{ - q -> medoid = medoid ; -} - - -#endif diff --git a/opensfm/src/third_party/vlfeat/vl/random.c b/opensfm/src/third_party/vlfeat/vl/random.c deleted file mode 100644 index 107ee1fb7..000000000 --- a/opensfm/src/third_party/vlfeat/vl/random.c +++ /dev/null @@ -1,266 +0,0 @@ -/** @file random.c - ** @brief Random number generator - Definition - ** @author Andrea Vedaldi - **/ - -/* -Copyright (C) 2007-12 Andrea Vedaldi and Brian Fulkerson. -Copyright (C) 2013 Andrea Vedaldi. -All rights reserved. - -This file is part of the VLFeat library and is made available under -the terms of the BSD license (see the COPYING file). -*/ - -/** - -@page random Random number generator -@author Andrea Vedaldi -@tableofcontents - - -The module @ref random.h implements random number generation in -VLFeat. The generator is based on the popular Mersenne Twister -algorithm @cite{matsumoto98mersenne} (which is the same as MATLAB -random generator from MATLAB version 7.4 onwards). - - -@section random-starting Getting started - - -In VLFeat, a random number generator is implemented by an object of -type ::VlRand. The simplest way to obtain such an object is to get the -default random generator by - -@code -VlRand * rand = vl_get_rand() ; -vl_int32 signedRandomInteger = vl_rand_int31(rand) ; -@code - -Note that there is one such generator per thread (see -::vl_get_rand). If more control is desired, a new ::VlRand object can -be easily created. The object is lightweight, designed to be -allocated on the stack: - -@code -VlRand rand ; -vl_rand_init (&rand) ; -@endcode - -The generator can be seeded by ::vl_rand_seed and ::vl_rand_seed_by_array. -For instance: - -@code -vl_rand_seed (&rand, clock()) ; -@endcode - -The generator can be used to obtain random quantities of -various types: - -- ::vl_rand_int31, ::vl_rand_uint32 for 32-bit random integers; -- ::vl_rand_real1 for a double in [0,1]; -- ::vl_rand_real2 for a double in [0,1); -- ::vl_rand_real3 for a double in (0,1); -- ::vl_rand_res53 for a double in [0,1) with high resolution. - -There is no need to explicitly destroy a ::VlRand instance. - -**/ - -#include "random.h" - -/* -A C-program for MT19937, with initialization improved 2002/1/26. -Coded by Takuji Nishimura and Makoto Matsumoto. - -Before using, initialize the state by using init_genrand(seed) -or init_by_array(init_key, keySize). - -Copyright (C) 1997 - 2002, Makoto Matsumoto and Takuji Nishimura, -All rights reserved. - -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. - -3. The names of its contributors 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 COPYRIGHT OWNER 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. - - -Any feedback is very welcome. -http://www.math.sci.hiroshima-u.ac.jp/~m-mat/MT/emt.html -email: m-mat @ math.sci.hiroshima-u.ac.jp (remove space) -*/ - -#include -#include - -/* Period parameters */ -#define N 624 -#define M 397 -#define MATRIX_A VL_UINT32_C(0x9908b0df) /* constant vector a */ -#define UPPER_MASK VL_UINT32_C(0x80000000) /* most asignificant w-r bits */ -#define LOWER_MASK VL_UINT32_C(0x7fffffff) /* least significant r bits */ - -/* initializes mt[N] with a seed */ - -/** @brief Initialise random number generator - ** @param self number generator. - **/ - -void -vl_rand_init (VlRand * self) -{ - memset (self->mt, 0, sizeof(self->mt[0]) * N) ; - self->mti = N + 1 ; -} - -/** @brief Seed the state of the random number generator - ** @param self random number generator. - ** @param s seed. - **/ - -void -vl_rand_seed (VlRand * self, vl_uint32 s) -{ -#define mti self->mti -#define mt self->mt - mt[0]= s & VL_UINT32_C(0xffffffff); - for (mti=1; mti> 30)) + mti); - /* See Knuth TAOCP Vol2. 3rd Ed. P.106 for multiplier. */ - /* In the previous versions, MSBs of the seed affect */ - /* only MSBs of the array mt[]. */ - /* 2002/01/09 modified by Makoto Matsumoto */ - mt[mti] &= VL_UINT32_C(0xffffffff); - /* for >32 bit machines */ - } -#undef mti -#undef mt -} - -/** @brief Seed the state of the random number generator by an array - ** @param self random number generator. - ** @param key array of numbers. - ** @param keySize length of the array. - **/ - -void -vl_rand_seed_by_array (VlRand * self, vl_uint32 const key [], vl_size keySize) -{ -#define mti self->mti -#define mt self->mt - int i, j, k; - vl_rand_seed (self, VL_UINT32_C(19650218)); - i=1; j=0; - k = (N > keySize ? N : (int)keySize); - for (; k; k--) { - mt[i] = (mt[i] ^ ((mt[i-1] ^ (mt[i-1] >> 30)) * VL_UINT32_C(1664525))) - + key[j] + j; /* non linear */ - mt[i] &= VL_UINT32_C(0xffffffff); /* for WORDSIZE > 32 machines */ - i++; j++; - if (i>=N) { mt[0] = mt[N-1]; i=1; } - if (j>=(signed)keySize) j=0; - } - for (k=N-1; k; k--) { - mt[i] = (mt[i] ^ ((mt[i-1] ^ (mt[i-1] >> 30)) * VL_UINT32_C(1566083941))) - - i; /* non linear */ - mt[i] &= VL_UINT32_C(0xffffffff) ; /* for WORDSIZE > 32 machines */ - i++; - if (i>=N) { mt[0] = mt[N-1]; i=1; } - } - - mt[0] = VL_UINT32_C(0x80000000); /* MSB is 1; assuring non-zero initial array */ -#undef mti -#undef mt -} - -/** @brief Randomly permute and array of indexes. - ** @param self random number generator. - ** @param array array of indexes. - ** @param size number of element in the array. - ** - ** The function uses *Algorithm P*, also known as *Knuth shuffle*. - **/ - -void -vl_rand_permute_indexes (VlRand *self, vl_index *array, vl_size size) -{ - vl_index i, j, tmp; - for (i = size - 1 ; i > 0; i--) { - /* Pick a random index j in the range 0, i + 1 and swap it with i */ - j = (vl_int) vl_rand_uindex (self, i + 1) ; - tmp = array[i] ; array[i] = array[j] ; array[j] = tmp ; - } -} - - -/** @brief Generate a random UINT32 - ** @param self random number generator. - ** @return a random number in [0, 0xffffffff]. - **/ - -vl_uint32 -vl_rand_uint32 (VlRand * self) -{ - vl_uint32 y; - static vl_uint32 mag01[2]={VL_UINT32_C(0x0), MATRIX_A}; - /* mag01[x] = x * MATRIX_A for x=0,1 */ - -#define mti self->mti -#define mt self->mt - - if (mti >= N) { /* generate N words at one time */ - int kk; - - if (mti == N+1) /* if init_genrand() has not been called, */ - vl_rand_seed (self, VL_UINT32_C(5489)); /* a default initial seed is used */ - - for (kk=0;kk> 1) ^ mag01[y & VL_UINT32_C(0x1)]; - } - for (;kk> 1) ^ mag01[y & VL_UINT32_C(0x1)]; - } - y = (mt[N-1]&UPPER_MASK)|(mt[0]&LOWER_MASK); - mt[N-1] = mt[M-1] ^ (y >> 1) ^ mag01[y & VL_UINT32_C(0x1)]; - - mti = 0; - } - - y = mt[mti++]; - - /* Tempering */ - y ^= (y >> 11); - y ^= (y << 7) & VL_UINT32_C(0x9d2c5680); - y ^= (y << 15) & VL_UINT32_C(0xefc60000); - y ^= (y >> 18); - - return (vl_uint32)y; - -#undef mti -#undef mt -} diff --git a/opensfm/src/third_party/vlfeat/vl/random.h b/opensfm/src/third_party/vlfeat/vl/random.h deleted file mode 100644 index f464fc47b..000000000 --- a/opensfm/src/third_party/vlfeat/vl/random.h +++ /dev/null @@ -1,162 +0,0 @@ -/** @file random.h - ** @brief Random number generator (@ref random) - ** @author Andrea Vedaldi - ** @see @ref random - **/ - -/* -Copyright (C) 2007-12 Andrea Vedaldi and Brian Fulkerson. -All rights reserved. - -This file is part of the VLFeat library and is made available under -the terms of the BSD license (see the COPYING file). -*/ - -#ifndef VL_RANDOM_H -#define VL_RANDOM_H - -#include "host.h" - -/** @brief Random numbber generator state */ -typedef struct _VlRand { - vl_uint32 mt [624] ; - vl_uint32 mti ; -} VlRand ; - -/** @name Setting and reading the state - ** - ** @{ */ -VL_EXPORT void vl_rand_init (VlRand * self) ; -VL_EXPORT void vl_rand_seed (VlRand * self, vl_uint32 s) ; -VL_EXPORT void vl_rand_seed_by_array (VlRand * self, - vl_uint32 const key [], - vl_size keySize) ; -/** @} */ - -/** @name Generate random numbers - ** - ** @{ */ -VL_INLINE vl_uint64 vl_rand_uint64 (VlRand * self) ; -VL_INLINE vl_int64 vl_rand_int63 (VlRand * self) ; -VL_EXPORT vl_uint32 vl_rand_uint32 (VlRand * self) ; -VL_INLINE vl_int32 vl_rand_int31 (VlRand * self) ; -VL_INLINE double vl_rand_real1 (VlRand * self) ; -VL_INLINE double vl_rand_real2 (VlRand * self) ; -VL_INLINE double vl_rand_real3 (VlRand * self) ; -VL_INLINE double vl_rand_res53 (VlRand * self) ; -VL_INLINE vl_uindex vl_rand_uindex (VlRand * self, vl_uindex range) ; -/** @} */ - -VL_EXPORT void vl_rand_permute_indexes (VlRand * self, vl_index* array, vl_size size) ; - -/* ---------------------------------------------------------------- */ - -/** @brief Generate a random index in a given range - ** @param self random number generator. - ** @param range range. - ** @return an index sampled uniformly at random in the interval [0, @c range - 1] - ** - ** @remark Currently, this function uses a simple algorithm that - ** may yield slightly biased samples if @c range is not a power of - ** two. - **/ - -VL_INLINE vl_uindex -vl_rand_uindex (VlRand * self, vl_uindex range) -{ - if (range <= 0xffffffff) { - /* 32-bit version */ - return (vl_rand_uint32 (self) % (vl_uint32)range) ; - } else { - /* 64-bit version */ - return (vl_rand_uint64 (self) % range) ; - } -} - -/** @brief Generate a random UINT64 - ** @param self random number generator. - ** @return a random number in [0, 0xffffffffffffffff]. - **/ - -VL_INLINE vl_uint64 -vl_rand_uint64 (VlRand * self) -{ - vl_uint64 a = vl_rand_uint32 (self) ; - vl_uint64 b = vl_rand_uint32 (self) ; - return (a << 32) | b ; -} - -/** @brief Generate a random INT63 - ** @param self random number generator. - ** @return a random number in [0, 0x7fffffffffffffff]. - **/ - -VL_INLINE vl_int64 -vl_rand_int63 (VlRand * self) -{ - return (vl_int64)(vl_rand_uint64 (self) >> 1) ; -} - -/** @brief Generate a random INT31 - ** @param self random number generator. - ** @return a random number in [0, 0x7fffffff]. - **/ - -VL_INLINE vl_int32 -vl_rand_int31 (VlRand * self) -{ - return (vl_int32)(vl_rand_uint32 (self) >> 1) ; -} - -/** @brief Generate a random number in [0,1] - ** @param self random number generator. - ** @return a random number. - **/ - -VL_INLINE double -vl_rand_real1 (VlRand * self) -{ - return vl_rand_uint32(self)*(1.0/4294967295.0); - /* divided by 2^32-1 */ -} - -/** @brief Generate a random number in [0,1) - ** @param self random number generator. - ** @return a random number. - **/ - -VL_INLINE double -vl_rand_real2 (VlRand * self) -{ - return vl_rand_uint32(self)*(1.0/4294967296.0); - /* divided by 2^32 */ -} - -/** @brief Generate a random number in (0,1) - ** @param self random number generator. - ** @return a random number. - **/ - -VL_INLINE double -vl_rand_real3 (VlRand * self) -{ - return (((double)vl_rand_uint32(self)) + 0.5)*(1.0/4294967296.0); - /* divided by 2^32 */ -} - -/** @brief Generate a random number in [0,1) with 53-bit resolution - ** @param self random number generator. - ** @return a random number. - **/ - -VL_INLINE double -vl_rand_res53 (VlRand * self) -{ - vl_uint32 - a = vl_rand_uint32(self) >> 5, - b = vl_rand_uint32(self) >> 6 ; - return (a * 67108864.0 + b) * (1.0 / 9007199254740992.0) ; -} - -/* VL_RANDOM_H */ -#endif diff --git a/opensfm/src/third_party/vlfeat/vl/rodrigues.c b/opensfm/src/third_party/vlfeat/vl/rodrigues.c deleted file mode 100644 index 14958c9df..000000000 --- a/opensfm/src/third_party/vlfeat/vl/rodrigues.c +++ /dev/null @@ -1,329 +0,0 @@ -/** @file rodrigues.c - ** @brief Rodrigues formulas - Definition - ** @author Andrea Vedaldi - **/ - -/* -Copyright (C) 2007-13 Andrea Vedaldi and Brian Fulkerson. -All rights reserved. - -This file is part of the VLFeat library and is made available under -the terms of the BSD license (see the COPYING file). -*/ - -#include "generic.h" -#include "mathop.h" -#include "rodrigues.h" - -#include - -/** @brief Rodrigues' formula - ** @param R_pt 3x3 matrix - array of 9 double (in) . - ** @param dR_pt 9x3 matrix - array of 27 double (in). - ** @param om_pt 3 vector - array of 3 dobule (out). - **/ - -void -vl_rodrigues(double* R_pt, double* dR_pt, const double* om_pt) -{ - /* - Let - - th = |om|, r=w/th, - sth=sin(th), cth=cos(th), - ^om = hat(om) - - Then the rodrigues formula is an expansion of the exponential - function: - - rodrigues(om) = exp ^om = I + ^r sth + ^r^2 (1 - cth). - - The derivative can be computed by elementary means and - results: - - d(vec rodrigues(om)) sth d ^r 1 - cth d (^r)^2 - -------------------- = ---- ----- + ------- -------- + - d om^T th d r^T th d r^T - - sth 1 - cth - + vec^r (cth - -----) + vec^r^2 (sth - 2-------)r^T - th th - */ - -#define OM(i) om_pt[(i)] -#define R(i,j) R_pt[(i)+3*(j)] -#define DR(i,j) dR_pt[(i)+9*(j)] -#undef small - - const double small = 1e-6 ; - - double th = sqrt( OM(0)*OM(0) + - OM(1)*OM(1) + - OM(2)*OM(2) ) ; - - if( th < small ) { - R(0,0) = 1.0 ; R(0,1) = 0.0 ; R(0,2) = 0.0 ; - R(1,0) = 0.0 ; R(1,1) = 1.0 ; R(1,2) = 0.0 ; - R(2,0) = 0.0 ; R(2,1) = 0.0 ; R(2,2) = 1.0 ; - - if(dR_pt) { - DR(0,0) = 0 ; DR(0,1) = 0 ; DR(0,2) = 0 ; - DR(1,0) = 0 ; DR(1,1) = 0 ; DR(1,2) = 1 ; - DR(2,0) = 0 ; DR(2,1) = -1 ; DR(2,2) = 0 ; - - DR(3,0) = 0 ; DR(3,1) = 0 ; DR(3,2) = -1 ; - DR(4,0) = 0 ; DR(4,1) = 0 ; DR(4,2) = 0 ; - DR(5,0) = 1 ; DR(5,1) = 0 ; DR(5,2) = 0 ; - - DR(6,0) = 0 ; DR(6,1) = 1 ; DR(6,2) = 0 ; - DR(7,0) = -1 ; DR(7,1) = 0 ; DR(7,2) = 0 ; - DR(8,0) = 0 ; DR(8,1) = 0 ; DR(8,2) = 0 ; - } - return ; - } - - { - double x = OM(0) / th ; - double y = OM(1) / th ; - double z = OM(2) / th ; - - double xx = x*x ; - double xy = x*y ; - double xz = x*z ; - double yy = y*y ; - double yz = y*z ; - double zz = z*z ; - - const double yx = xy ; - const double zx = xz ; - const double zy = yz ; - - double sth = sin(th) ; - double cth = cos(th) ; - double mcth = 1.0 - cth ; - - R(0,0) = 1 - mcth * (yy+zz) ; - R(1,0) = sth*z + mcth * xy ; - R(2,0) = - sth*y + mcth * xz ; - - R(0,1) = - sth*z + mcth * yx ; - R(1,1) = 1 - mcth * (zz+xx) ; - R(2,1) = sth*x + mcth * yz ; - - R(0,2) = sth*y + mcth * xz ; - R(1,2) = - sth*x + mcth * yz ; - R(2,2) = 1 - mcth * (xx+yy) ; - - if(dR_pt) { - double a = sth / th ; - double b = mcth / th ; - double c = cth - a ; - double d = sth - 2*b ; - - DR(0,0) = - d * (yy+zz) * x ; - DR(1,0) = b*y + c * zx + d * xy * x ; - DR(2,0) = b*z - c * yx + d * xz * x ; - - DR(3,0) = b*y - c * zx + d * xy * x ; - DR(4,0) = -2*b*x - d * (zz+xx) * x ; - DR(5,0) = a + c * xx + d * yz * x ; - - DR(6,0) = b*z + c * yx + d * zx * x ; - DR(7,0) = -a - c * xx + d * zy * x ; - DR(8,0) = -2*b*x - d * (yy+xx) * x ; - - DR(0,1) = -2*b*y - d * (yy+zz) * y ; - DR(1,1) = b*x + c * zy + d * xy * y ; - DR(2,1) = -a - c * yy + d * xz * y ; - - DR(3,1) = b*x - c * zy + d * xy * y ; - DR(4,1) = - d * (zz+xx) * y ; - DR(5,1) = b*z + c * xy + d * yz * y ; - - DR(6,1) = a + c * yy + d * zx * y ; - DR(7,1) = b*z - c * xy + d * zy * y ; - DR(8,1) = -2*b*y - d * (yy+xx) * y ; - - DR(0,2) = -2*b*z - d * (yy+zz) * z ; - DR(1,2) = a + c * zz + d * xy * z ; - DR(2,2) = b*x - c * yz + d * xz * z ; - - DR(3,2) = -a - c * zz + d * xy * z ; - DR(4,2) = -2*b*z - d * (zz+xx) * z ; - DR(5,2) = b*y + c * xz + d * yz * z ; - - DR(6,2) = b*x + c * yz + d * zx * z ; - DR(7,2) = b*y - c * xz + d * zy * z ; - DR(8,2) = - d * (yy+xx) * z ; - } - } - -#undef OM -#undef R -#undef DR - -} - -/** @brief Inverse Rodrigues formula - ** @param om_pt 3 vector - array of 3 dobule (out). - ** @param dom_pt 3x9 matrix - array of 3x9 dobule (out). - ** @param R_pt 3x3 matrix - array of 9 double (in). - ** - ** This function computes the Rodrigues formula of the argument @a - ** om_pt. The result is stored int the matrix @a R_pt. If @a dR_pt is - ** non null, then the derivative of the Rodrigues formula is computed - ** and stored into the matrix @a dR_pt. - **/ - -VL_EXPORT -void vl_irodrigues(double* om_pt, double* dom_pt, const double* R_pt) -{ - /* - tr R - 1 1 [ R32 - R23 ] - th = cos^{-1} --------, r = ------ [ R13 - R31 ], w = th r. - 2 2 sth [ R12 - R21 ] - - sth = sin(th) - - dw th*cth-sth dw th [di3 dj2 - di2 dj3] - ---- = ---------- r, ---- = ----- [di1 dj3 - di3 dj1]. - dRii 2 sth^2 dRij 2 sth [di1 dj2 - di2 dj1] - - trace(A) < -1 only for small num. errors. - */ - -#define OM(i) om_pt[(i)] -#define DOM(i,j) dom_pt[(i)+3*(j)] -#define R(i,j) R_pt[(i)+3*(j)] -#define W(i,j) W_pt[(i)+3*(j)] - - const double small = 1e-6 ; - - double th = acos - (0.5*(VL_MAX(R(0,0)+R(1,1)+R(2,2),-1.0) - 1.0)) ; - - double sth = sin(th) ; - double cth = cos(th) ; - - if(fabs(sth) < small && cth < 0) { - /* - we have this singularity when the rotation is about pi (or -pi) - we use the fact that in this case - - hat( sqrt(1-cth) * r )^2 = W = (0.5*(R+R') - eye(3)) - - which gives - - (1-cth) rx^2 = 0.5 * (W(1,1)-W(2,2)-W(3,3)) - (1-cth) ry^2 = 0.5 * (W(2,2)-W(3,3)-W(1,1)) - (1-cth) rz^2 = 0.5 * (W(3,3)-W(1,1)-W(2,2)) - */ - - double W_pt [9], x, y, z ; - W_pt[0] = 0.5*( R(0,0) + R(0,0) ) - 1.0 ; - W_pt[1] = 0.5*( R(1,0) + R(0,1) ) ; - W_pt[2] = 0.5*( R(2,0) + R(0,2) ); - - W_pt[3] = 0.5*( R(0,1) + R(1,0) ); - W_pt[4] = 0.5*( R(1,1) + R(1,1) ) - 1.0; - W_pt[5] = 0.5*( R(2,1) + R(1,2) ); - - W_pt[6] = 0.5*( R(0,2) + R(2,0) ) ; - W_pt[7] = 0.5*( R(1,2) + R(2,1) ) ; - W_pt[8] = 0.5*( R(2,2) + R(2,2) ) - 1.0 ; - - /* these are only absolute values */ - x = sqrt( 0.5 * (W(0,0)-W(1,1)-W(2,2)) ) ; - y = sqrt( 0.5 * (W(1,1)-W(2,2)-W(0,0)) ) ; - z = sqrt( 0.5 * (W(2,2)-W(0,0)-W(1,1)) ) ; - - /* set the biggest component to + and use the element of the - ** matrix W to determine the sign of the other components - ** then the solution is either (x,y,z) or its opposite */ - if( x >= y && x >= z ) { - y = (W(1,0) >=0) ? y : -y ; - z = (W(2,0) >=0) ? z : -z ; - } else if( y >= x && y >= z ) { - z = (W(2,1) >=0) ? z : -z ; - x = (W(1,0) >=0) ? x : -x ; - } else { - x = (W(2,0) >=0) ? x : -x ; - y = (W(2,1) >=0) ? y : -y ; - } - - /* we are left to chose between (x,y,z) and (-x,-y,-z) - ** unfortunately we cannot (as the rotation is too close to pi) and - ** we just keep what we have. */ - { - double scale = th / sqrt( 1 - cth ) ; - OM(0) = scale * x ; - OM(1) = scale * y ; - OM(2) = scale * z ; - - if( dom_pt ) { - int k ; - for(k=0; k<3*9; ++k) - dom_pt [k] = VL_NAN_D ; - } - return ; - } - - } else { - double a = (fabs(sth) < small) ? 1 : th/sin(th) ; - double b ; - OM(0) = 0.5*a*(R(2,1) - R(1,2)) ; - OM(1) = 0.5*a*(R(0,2) - R(2,0)) ; - OM(2) = 0.5*a*(R(1,0) - R(0,1)) ; - - if( dom_pt ) { - if( fabs(sth) < small ) { - a = 0.5 ; - b = 0 ; - } else { - a = th/(2*sth) ; - b = (th*cth - sth)/(2*sth*sth)/th ; - } - - DOM(0,0) = b*OM(0) ; - DOM(1,0) = b*OM(1) ; - DOM(2,0) = b*OM(2) ; - - DOM(0,1) = 0 ; - DOM(1,1) = 0 ; - DOM(2,1) = a ; - - DOM(0,2) = 0 ; - DOM(1,2) = -a ; - DOM(2,2) = 0 ; - - DOM(0,3) = 0 ; - DOM(1,3) = 0 ; - DOM(2,3) = -a ; - - DOM(0,4) = b*OM(0) ; - DOM(1,4) = b*OM(1) ; - DOM(2,4) = b*OM(2) ; - - DOM(0,5) = a ; - DOM(1,5) = 0 ; - DOM(2,5) = 0 ; - - DOM(0,6) = 0 ; - DOM(1,6) = a ; - DOM(2,6) = 0 ; - - DOM(0,7) = -a ; - DOM(1,7) = 0 ; - DOM(2,7) = 0 ; - - DOM(0,8) = b*OM(0) ; - DOM(1,8) = b*OM(1) ; - DOM(2,8) = b*OM(2) ; - } - } - -#undef OM -#undef DOM -#undef R -#undef W -} diff --git a/opensfm/src/third_party/vlfeat/vl/rodrigues.h b/opensfm/src/third_party/vlfeat/vl/rodrigues.h deleted file mode 100644 index d752725ba..000000000 --- a/opensfm/src/third_party/vlfeat/vl/rodrigues.h +++ /dev/null @@ -1,33 +0,0 @@ -/** @file rodrigues.h - ** @brief Rodrigues formulas - ** @author Andrea Vedaldi - **/ - -/* -Copyright (C) 2007-13 Andrea Vedaldi and Brian Fulkerson. -All rights reserved. - -This file is part of the VLFeat library and is made available under -the terms of the BSD license (see the COPYING file). -*/ - -/** @file rodrigues.h - -@section rodrigues Rodrigues formulas - -- Use ::vl_rodrigues to compute the Rodrigues formula and its derivative. -- Use ::vl_irodrigues to compute the inverse Rodrigues formula and - its derivative. - -**/ - -#ifndef VL_RODRIGUES -#define VL_RODRIGUES - -#include "generic.h" - -VL_EXPORT void vl_rodrigues (double* R_pt, double* dR_pt, const double* om_pt) ; -VL_EXPORT void vl_irodrigues (double* om_pt, double* dom_pt, const double* R_pt) ; - -/* VL_RODRIGUES */ -#endif diff --git a/opensfm/src/third_party/vlfeat/vl/scalespace.c b/opensfm/src/third_party/vlfeat/vl/scalespace.c deleted file mode 100644 index 962f28526..000000000 --- a/opensfm/src/third_party/vlfeat/vl/scalespace.c +++ /dev/null @@ -1,821 +0,0 @@ -/** @file scalespace.c - ** @brief Scale Space - Definition - ** @author Karel Lenc - ** @author Andrea Vedaldi - ** @author Michal Perdoch - **/ - -/* -Copyright (C) 2007-12 Andrea Vedaldi and Brian Fulkerson. -All rights reserved. - -This file is part of the VLFeat library and is made available under -the terms of the BSD license (see the COPYING file). -*/ - -/** - -@page scalespace Gaussian Scale Space (GSS) -@author Karel Lenc -@author Andrea Vedaldi -@author Michal Perdoch -@tableofcontents - - -@ref scalespace.h implements a Gaussian scale space, a data structure -representing an image at multiple resolutions -@cite{witkin83scale-space} @cite{koenderink84the-structure} -@cite{lindeberg94scale-space}. Scale spaces have many use, including -the detection of co-variant local features -@cite{lindeberg98principles} such as SIFT, Hessian-Affine, -Harris-Affine, Harris-Laplace, etc. @ref scalespace-starting -demonstreates how to use the C API to compute the scalespace of an -image. For further details refer to: - -- @subpage scalespace-fundamentals - - -@section scalespace-starting Getting started - - -Given an input image `image`, the following example uses the -::VlScaleSpace object to compute its Gaussian scale space and return -the image `level` at scale `(o,s)`, where `o` is the octave and `s` is -the octave subdivision or sublevel: - -@code -float* level ; -VlScaleSpace ss = vl_scalespace_new(imageWidth, imageHeight) ; -vl_scalespace_put_image(ss, image) ; -level = vl_scalespace_get_level(ss, o, s) ; -@endcode - -The image `level` is obtained by convolving `image` by a Gaussian -filter of isotropic standard deviation given by - -@code -double sigma = vl_scalespace_get_sigma(ss, o, s) ; -@endcode - -The resolution of `level` is in general different from the resolution -of `image` and is determined by the octave `o`. It can be obtained as -follows: - -@code -VlScaleSpaceOctaveGeometry ogeom = vl_scalespace_get_octave_geometry(ss, o) ; -ogeom.width // width of level (in number of pixels) -ogeom.height // height of level (in number of pixels) -ogeom.step // spatial sampling step -@endcode - -The parameter `ogeom.step` is the sampling step relatively to the -sampling of the input image `image`. The ranges of valid octaves and -scale sublevels can be obtained as - -@code -VlScaleSpaceGeometry geom = vl_scalespace_get_geometry(ss) ; -geom.firstOctave // Index of the fisrt octave -geom.lastOctave // Index of the last octave -geom.octaveResolution ; // Number of octave subdivisions -geom.octaveFirstSubdivision // Index of the first octave subdivision -geom.octaveLastSubdivision // Index of the last octave subdivision -@endcode - -So for example `o` minimum value is `geom.firstOctave` and maximum -value is `geom.lastOctave`. The subdivision index `s` naturally spans -the range 0 to `geom.octaveResolution-1`. However, the scale space -object is flexible in that it allows different ranges of subdivisions -to be computed and `s` varies in the range -`geom.octaveFirstSubdivision` to `geom.octaveLastSubdivision`. See -@ref scalespace-fundamentals for further details. - -The geometry of the scale space can be customized upon creation, as -follows: - -@code -VlScaleSpaceGeometry geom = vl_scalespace_get_default_geometry(imageWidth, imageHeight) ; -geom.firstOctave = -1 ; -geom.octaveFirstSubdivision = -1 ; -geom.octaveLastSubdivision = geom.octaveResolution ; -VlScaleSpacae ss = vl_scalespace_new_with_geometry (geom) ; -@endcode - - -@page scalespace-fundamentals Gaussian scale space fundamentals -@tableofcontents - - -This page discusses the notion of *Gaussian scale space* and the -relative data structure. For the C API see @ref scalespace.h and @ref -scalespace-starting. - -A *scale space* is representation of an image at multiple resolution -levels. An image is a function $\ell(x,y)$ of two coordinates $x$, -$y$; the scale space $\ell(x,y,\sigma)$ adds a third coordinate -$\sigma$ indexing the *scale*. Here the focus is the Gaussian scale -space, where the image $\ell(x,y,\sigma)$ is obtained by smoothing -$\ell(x,y)$ by a Gaussian kernel of isotropic standard deviation -$\sigma$. - - -@section scalespace-definition Scale space definition - - -Formally, the *Gaussian scale space* of an image $\ell(x,y)$ is -defined as - -\[ - \ell(x,y,\sigma) = - [g_{\sigma} * \ell](x,y,\sigma) -\] - -where $g_\sigma$ denotes a 2D Gaussian kernel of isotropic standard -deviation $\sigma$: - -\[ - g_{\sigma}(x,y) = \frac{1}{2\pi\sigma^2} - \exp\left( - - \frac{x^2 + y^2}{2\sigma^2} - \right). -\] - -An important detail is that the algorithm computing the scale space -assumes that the input image $\ell(x,y)$ is pre-smoothed, roughly -capturing the effect of the finite pixel size in a CCD. This is -modelled by assuming that the input is not $\ell(x,y)$, but -$\ell(x,y,\sigma_n)$, where $\sigma_n$ is a *nominal smoothing*, -usually taken to be 0.5 (half a pixel standard deviation). This also -means that $\sigma = \sigma_n = 0.5$ is the *finest scale* that can -actually be computed. - -The scale space structure stores samples of the function -$\ell(x,y,\sigma)$. The density of the sampling of the spatial -coordinates $x$ and $y$ is adjusted as a function of the scale -$\sigma$, corresponding to the intuition that images at a coarse -resolution can be sampled more coarsely without loss of -information. Thus, the scale space has the structure of a *pyramid*: a -collection of digital images sampled at progressively coarser spatial -resolution and hence of progressively smaller size (in pixels). - -The following figure illustrates the scale space pyramid structure: - -@image html scalespace-basic.png "A scalespace structure with 2 octaves and S=3 subdivisions per octave" - -The pyramid is organised in a number of *octaves*, indexed by a -parameter `o`. Each octave is further subdivided into *sublevels*, -indexed by a parameter `s`. These are related to the scale $\sigma$ by -the equation - -\[ - \sigma(s,o) = \sigma_o 2^{\displaystyle o + \frac{s}{\mathtt{octaveResolution}}} -\] - -where `octaveResolution` is the resolution of the octave subsampling -$\sigma_0$ is the *base smoothing*. - -At each octave the spatial resolution is doubled, in the sense that -samples are take with a step of -\[ -\mathtt{step} = 2^o. -\] -Hence, denoting as `level[i,j]` the corresponding samples, one has -$\ell(x,y,\sigma) = \mathtt{level}[i,j]$, where -\[ - (x,y) = (i,j) \times \mathtt{step}, -\quad -\sigma = \sigma(o,s), - \quad - 0 \leq i < \mathtt{lwidth}, -\quad - 0 \leq j < \mathtt{lheight}, -\] -where -\[ - \mathtt{lwidth} = \lfloor \frac{\mathtt{width}}{2^\mathtt{o}}\rfloor, \quad - \mathtt{lheight} = \lfloor \frac{\mathtt{height}}{2^\mathtt{o}}\rfloor. -\] - - -@section scalespace-geometry Scale space geometry - - -In addition to the parameters discussed above, the geometry of the -data stored in a scale space structure depends on the range of -allowable octaves `o` and scale sublevels `s`. - -While `o` may range in any reasonable value given the size of the -input image `image`, usually its minimum value is either 0 or -1. The -latter corresponds to doubling the resolution of the image in the -first octave of the scale space and it is often used in feature -extraction. While there is no information added to the image by -upsampling in this manner, fine scale filters, including derivative -filters, are much easier to compute by upsalmpling first. The maximum -practical value is dictated by the image resolution, as it should be -$2^o\leq\min\{\mathtt{width},\mathtt{height}\}$. VLFeat has the -flexibility of specifying the range of `o` using the `firstOctave` and -`lastOctave` parameters of the ::VlScaleSpaceGeometry structure. - -The sublevel `s` varies naturally in the range -$\{0,\dots,\mathtt{octaveResolution}-1\}$. However, it is often -convenient to store a few extra levels per octave (e.g. to compute the -local maxima of a function in scale or the Difference of Gaussian -cornerness measure). Thus VLFeat scale space structure allows this -parameter to vary in an arbitrary range, specified by the parameters -`octaveFirstSubdivision` and `octaveLastSubdivision` of -::VlScaleSpaceGeometry. - -Overall the possible values of the indexes `o` and `s` are: - -\[ -\mathtt{firstOctave} \leq o \leq \mathtt{lastOctave}, -\qquad -\mathtt{octaveFirstSubdivision} \leq s \leq \mathtt{octaveLastSubdivision}. -\] - -Note that, depending on these ranges, there could be *redundant pairs* -of indexes `o` and `s` that represent the *same* pyramid level at more -than one sampling resolution. In practice, the ability to generate -such redundant information is very useful in algorithms using -scalespaces, as coding multiscale operations using a fixed sampling -resolution is far easier. For example, the DoG feature detector -computes the scalespace with three redundant levels per octave, as -follows: - -@image html scalespace.png "A scalespace containing redundant representation of certain scale levels." - - -@section scalespace-algorithm Algorithm and limitations - - -Given $\ell(x,y,\sigma_n)$, any of a vast number digitial filtering -techniques can be used to compute the scale levels. Presently, VLFeat -uses a basic FIR implementation of the Gaussian filters. - -The FIR implementation is obtained by sampling the Gaussian function -and re-normalizing it to have unit norm. This simple construction does -not account properly for sampling effect, which may be a problem for -very small Gausisan kernels. As a rule of thumb, such filters work -sufficiently well for, say, standard deviation $\sigma$ at least 1.6 -times the sampling step. A work around to apply this basic FIR -implementation to very small Gaussian filters is to upsample the image -first. - -The limitations on the FIR filters have relatively important for the -pyramid construction, as the latter is obtained by *incremental -smoothing*: each successive level is obtained from the previous one by -adding the needed amount of smoothing. In this manner, the size of the -FIR filters remains small, which makes them efficient; at the same -time, for what discussed, excessively small filters are not -represented properly. - -*/ - -#include "scalespace.h" -#include "mathop.h" - -#include -#include -#include -#include -#include - -/** @file scalespace.h - ** @struct VlScaleSpace - ** @brief Scale space class - ** - ** This is an opaque class used to compute the scale space of an - ** image. - **/ - -struct _VlScaleSpace -{ - VlScaleSpaceGeometry geom ; /**< Geometry of the scale space */ - float **octaves ; /**< Data */ -} ; - -/* ---------------------------------------------------------------- */ -/** @brief Get the default geometry for a given image size. - ** @param width image width. - ** @param height image height. - ** @return the default scale space geometry. - ** - ** Both @a width and @a height must be at least one pixel wide. - **/ - -VlScaleSpaceGeometry -vl_scalespace_get_default_geometry (vl_size width, vl_size height) -{ - VlScaleSpaceGeometry geom ; - assert(width >= 1) ; - assert(height >= 1) ; - geom.width = width ; - geom.height = height ; - geom.firstOctave = 0 ; - geom.lastOctave = VL_MAX(floor(vl_log2_d(VL_MIN(width, height))) - 3, 0) ; - geom.octaveResolution= 3 ; - geom.octaveFirstSubdivision = 0 ; - geom.octaveLastSubdivision = geom.octaveResolution - 1 ; - geom.baseScale = 1.6 * pow(2.0, 1.0 / geom.octaveResolution) ; - geom.nominalScale = 0.5 ; - return geom ; -} - -#define is_valid_geometry(geom) (\ -geom.firstOctave <= geom.lastOctave && \ -geom.octaveResolution >= 1 && \ -geom.octaveFirstSubdivision <= geom.octaveLastSubdivision && \ -geom.baseScale >= 0.0 && \ -geom.nominalScale >= 0.0) - -/** @brief Check scale space geometries for equality - ** @param a first geometry. - ** @param b second geometry. - ** @return true if equal. - **/ - -vl_bool -vl_scalespacegeometry_is_equal (VlScaleSpaceGeometry a, - VlScaleSpaceGeometry b) -{ - return - a.width == b.width && - a.height == b.height && - a.firstOctave == b.firstOctave && - a.lastOctave == b.lastOctave && - a.octaveResolution == b.octaveResolution && - a.octaveFirstSubdivision == b.octaveLastSubdivision && - a.baseScale == b.baseScale && - a.nominalScale == b.nominalScale ; -} - -/** @brief Get the geometry of the scale space. - ** @param self object. - ** @return the scale space geometry. - **/ - -VlScaleSpaceGeometry -vl_scalespace_get_geometry (VlScaleSpace const * self) -{ - return self->geom ; -} - -/** @brief Get the geometry of an octave of the scalespace. - ** @param self object. - ** @param o octave index. - ** @return the geometry of octave @a o. - **/ - -VlScaleSpaceOctaveGeometry -vl_scalespace_get_octave_geometry (VlScaleSpace const * self, vl_index o) -{ - VlScaleSpaceOctaveGeometry ogeom ; - ogeom.width = VL_SHIFT_LEFT(self->geom.width, -o) ; - ogeom.height = VL_SHIFT_LEFT(self->geom.height, -o) ; - ogeom.step = pow(2.0, o) ; - return ogeom ; -} - -/** @brief Get the data of a scale space level - ** @param self object. - ** @param o octave index. - ** @param s level index. - ** @return pointer to the data for octave @a o, level @a s. - ** - ** The octave index @a o must be in the range @c firstOctave - ** to @c lastOctave and the scale index @a s must be in the - ** range @c octaveFirstSubdivision to @c octaveLastSubdivision. - **/ - -float * -vl_scalespace_get_level (VlScaleSpace *self, vl_index o, vl_index s) -{ - VlScaleSpaceOctaveGeometry ogeom = vl_scalespace_get_octave_geometry(self,o) ; - float * octave ; - assert(self) ; - assert(o >= self->geom.firstOctave) ; - assert(o <= self->geom.lastOctave) ; - assert(s >= self->geom.octaveFirstSubdivision) ; - assert(s <= self->geom.octaveLastSubdivision) ; - - octave = self->octaves[o - self->geom.firstOctave] ; - return octave + ogeom.width * ogeom.height * (s - self->geom.octaveFirstSubdivision) ; -} - -/** @brief Get the data of a scale space level (const) - ** @param self object. - ** @param o octave index. - ** @param s level index. - ** @return pointer to the data for octave @a o, level @a s. - ** - ** This function is the same as ::vl_scalespace_get_level but reutrns - ** a @c const pointer to the data. - **/ - -float const * -vl_scalespace_get_level_const (VlScaleSpace const * self, vl_index o, vl_index s) -{ - return vl_scalespace_get_level((VlScaleSpace*)self, o, s) ; -} - -/** ------------------------------------------------------------------ - ** @brief Get the scale of a given octave and sublevel - ** @param self object. - ** @param o octave index. - ** @param s sublevel index. - ** - ** The function returns the scale $\sigma(o,s)$ as a function of the - ** octave index @a o and sublevel @a s. - **/ - -double -vl_scalespace_get_level_sigma (VlScaleSpace const *self, vl_index o, vl_index s) -{ - return self->geom.baseScale * pow(2.0, o + (double) s / self->geom.octaveResolution) ; -} - -/** ------------------------------------------------------------------ - ** @internal @brief Upsample the rows and take the transpose - ** @param destination output image. - ** @param source input image. - ** @param width input image width. - ** @param height input image height. - ** - ** The output image has dimensions @a height by 2 @a width (so the - ** destination buffer must be at least as big as two times the - ** input buffer). - ** - ** Upsampling is performed by linear interpolation. - **/ - -static void -copy_and_upsample -(float *destination, - float const *source, vl_size width, vl_size height) -{ - vl_index x, y, ox, oy ; - float v00, v10, v01, v11 ; - - assert(destination) ; - assert(source) ; - - for(y = 0 ; y < (signed)height ; ++y) { - oy = (y < ((signed)height - 1)) * width ; - v10 = source[0] ; - v11 = source[oy] ; - for(x = 0 ; x < (signed)width ; ++x) { - ox = x < ((signed)width - 1) ; - v00 = v10 ; - v01 = v11 ; - v10 = source[ox] ; - v11 = source[ox + oy] ; - destination[0] = v00 ; - destination[1] = 0.5f * (v00 + v10) ; - destination[2*width] = 0.5f * (v00 + v01) ; - destination[2*width+1] = 0.25f * (v00 + v01 + v10 + v11) ; - destination += 2 ; - source ++; - } - destination += 2*width ; - } -} - -/** ------------------------------------------------------------------ - ** @internal @brief Downsample - ** @param destination output imgae buffer. - ** @param source input image buffer. - ** @param width input image width. - ** @param height input image height. - ** @param numOctaves octaves (non negative). - ** - ** The function downsamples the image @a d times, reducing it to @c - ** 1/2^d of its original size. The parameters @a width and @a height - ** are the size of the input image. The destination image @a dst is - ** assumed to be floor(width/2^d) pixels wide and - ** floor(height/2^d) pixels high. - **/ - -static void -copy_and_downsample -(float *destination, - float const *source, - vl_size width, vl_size height, vl_size numOctaves) -{ - vl_index x, y ; - vl_size step = 1 << numOctaves ; /* step = 2^numOctaves */ - - assert(destination) ; - assert(source) ; - - if (numOctaves == 0) { - memcpy(destination, source, sizeof(float) * width * height) ; - } else { - for(y = 0 ; y < (signed)height ; y += step) { - float const *p = source + y * width ; - for(x = 0 ; x < (signed)width - ((signed)step - 1) ; x += step) { - *destination++ = *p ; - p += step ; - } - } - } -} - -/* ---------------------------------------------------------------- */ -/** @brief Create a new scale space object - ** @param width image width. - ** @param height image height. - ** @return new scale space object. - ** - ** This function is the same as ::vl_scalespace_new_with_geometry() - ** but it uses ::vl_scalespace_get_default_geometry to initialise - ** the geometry of the scale space from the image size. - ** - ** @sa ::vl_scalespace_new_with_geometry(), ::vl_scalespace_delete(). - **/ - -VlScaleSpace * -vl_scalespace_new (vl_size width, vl_size height) -{ - VlScaleSpaceGeometry geom ; - geom = vl_scalespace_get_default_geometry(width, height) ; - return vl_scalespace_new_with_geometry(geom) ; -} - -/** ------------------------------------------------------------------ - ** @brief Create a new scale space with the specified geometry - ** @param geom scale space geomerty. - ** @return new scale space object. - ** - ** If the geometry is not valid (see ::VlScaleSpaceGeometry), the - ** result is unpredictable. - ** - ** The function returns `NULL` if it was not possible to allocate the - ** object because of an out-of-memory condition. - ** - ** @sa ::VlScaleSpaceGeometry, ::vl_scalespace_delete(). - **/ - -VlScaleSpace * -vl_scalespace_new_with_geometry (VlScaleSpaceGeometry geom) -{ - - vl_index o ; - vl_size numSublevels = geom.octaveLastSubdivision - geom.octaveFirstSubdivision + 1 ; - vl_size numOctaves = geom.lastOctave - geom.firstOctave + 1 ; - VlScaleSpace *self ; - - assert(is_valid_geometry(geom)) ; - numOctaves = geom.lastOctave - geom.firstOctave + 1 ; - numSublevels = geom.octaveLastSubdivision - geom.octaveFirstSubdivision + 1 ; - - self = vl_calloc(1, sizeof(VlScaleSpace)) ; - if (self == NULL) goto err_alloc_self ; - self->geom = geom ; - self->octaves = vl_calloc(numOctaves, sizeof(float*)) ; - if (self->octaves == NULL) goto err_alloc_octave_list ; - for (o = self->geom.firstOctave ; o <= self->geom.lastOctave ; ++o) { - VlScaleSpaceOctaveGeometry ogeom = vl_scalespace_get_octave_geometry(self,o) ; - vl_size octaveSize = ogeom.width * ogeom.height * numSublevels ; - self->octaves[o - self->geom.firstOctave] = vl_malloc(octaveSize * sizeof(float)) ; - if (self->octaves[o - self->geom.firstOctave] == NULL) goto err_alloc_octaves; - } - return self ; - -err_alloc_octaves: - for (o = self->geom.firstOctave ; o <= self->geom.lastOctave ; ++o) { - if (self->octaves[o - self->geom.firstOctave]) { - vl_free(self->octaves[o - self->geom.firstOctave]) ; - } - } -err_alloc_octave_list: - vl_free(self) ; -err_alloc_self: - return NULL ; -} - -/* ---------------------------------------------------------------- */ -/** @brief Create a new copy of the object - ** @param self object to copy from. - ** - ** The function returns `NULL` if the copy cannot be made due to an - ** out-of-memory condition. - **/ - -VlScaleSpace * -vl_scalespace_new_copy (VlScaleSpace* self) -{ - vl_index o ; - VlScaleSpace * copy = vl_scalespace_new_shallow_copy(self) ; - if (copy == NULL) return NULL ; - - for (o = self->geom.firstOctave ; o <= self->geom.lastOctave ; ++o) { - VlScaleSpaceOctaveGeometry ogeom = vl_scalespace_get_octave_geometry(self,o) ; - vl_size numSubevels = self->geom.octaveLastSubdivision - self->geom.octaveFirstSubdivision + 1; - memcpy(copy->octaves[o - self->geom.firstOctave], - self->octaves[o - self->geom.firstOctave], - ogeom.width * ogeom.height * numSubevels * sizeof(float)) ; - } - return copy ; -} - -/* ---------------------------------------------------------------- */ -/** @brief Create a new shallow copy of the object - ** @param self object to copy from. - ** - ** The function works like ::vl_scalespace_new_copy() but only allocates - ** the scale space, without actually copying the data. - **/ - -VlScaleSpace * -vl_scalespace_new_shallow_copy (VlScaleSpace* self) -{ - return vl_scalespace_new_with_geometry (self->geom) ; -} - -/* ---------------------------------------------------------------- */ -/** @brief Delete object - ** @param self object to delete. - ** @sa ::vl_scalespace_new() - **/ - -void -vl_scalespace_delete (VlScaleSpace * self) -{ - if (self) { - if (self->octaves) { - vl_index o ; - for (o = self->geom.firstOctave ; o <= self->geom.lastOctave ; ++o) { - if (self->octaves[o - self->geom.firstOctave]) { - vl_free(self->octaves[o - self->geom.firstOctave]) ; - } - } - vl_free(self->octaves) ; - } - vl_free(self) ; - } -} - -/* ---------------------------------------------------------------- */ - -/** @internal @brief Fill octave starting from the first level - ** @param self object instance. - ** @param o octave to process. - ** - ** The function takes the first sublevel of octave @a o (the one at - ** sublevel `octaveFirstLevel` and iteratively - ** smoothes it to obtain the other octave levels. - **/ - -void -_vl_scalespace_fill_octave (VlScaleSpace *self, vl_index o) -{ - vl_index s ; - VlScaleSpaceOctaveGeometry ogeom = vl_scalespace_get_octave_geometry(self, o) ; - - for(s = self->geom.octaveFirstSubdivision + 1 ; - s <= self->geom.octaveLastSubdivision ; ++s) { - double sigma = vl_scalespace_get_level_sigma(self, o, s) ; - double previousSigma = vl_scalespace_get_level_sigma(self, o, s - 1) ; - double deltaSigma = sqrtf(sigma*sigma - previousSigma*previousSigma) ; - - float* level = vl_scalespace_get_level (self, o, s) ; - float* previous = vl_scalespace_get_level (self, o, s-1) ; - vl_imsmooth_f (level, ogeom.width, - previous, ogeom.width, ogeom.height, ogeom.width, - deltaSigma / ogeom.step, deltaSigma / ogeom.step) ; - } -} - -/** ------------------------------------------------------------------ - ** @internal @brief Initialize the first level of an octave from an image - ** @param self ::VlScaleSpace object instance. - ** @param image image data. - ** @param o octave to start. - ** - ** The function initializes the first level of octave @a o from - ** image @a image. The dimensions of the image are the ones set - ** during the creation of the ::VlScaleSpace object instance. - **/ - -static void -_vl_scalespace_start_octave_from_image (VlScaleSpace *self, - float const *image, - vl_index o) -{ - float *level ; - double sigma, imageSigma ; - vl_index op ; - - assert(self) ; - assert(image) ; - assert(o >= self->geom.firstOctave) ; - assert(o <= self->geom.lastOctave) ; - - /* - * Copy the image to self->geom.octaveFirstSubdivision of octave o, upscaling or - * downscaling as needed. - */ - - level = vl_scalespace_get_level(self, VL_MAX(0, o), self->geom.octaveFirstSubdivision) ; - copy_and_downsample(level, image, self->geom.width, self->geom.height, VL_MAX(0, o)) ; - - for (op = -1 ; op >= o ; --op) { - VlScaleSpaceOctaveGeometry ogeom = vl_scalespace_get_octave_geometry(self, op + 1) ; - float *succLevel = vl_scalespace_get_level(self, op + 1, self->geom.octaveFirstSubdivision) ; - level = vl_scalespace_get_level(self, op, self->geom.octaveFirstSubdivision) ; - copy_and_upsample(level, succLevel, ogeom.width, ogeom.height) ; - } - - /* - * Adjust the smoothing of the first level just initialised, accounting - * for the fact that the input image is assumed to be a nominal scale - * level. - */ - - sigma = vl_scalespace_get_level_sigma(self, o, self->geom.octaveFirstSubdivision) ; - imageSigma = self->geom.nominalScale ; - - if (sigma > imageSigma) { - VlScaleSpaceOctaveGeometry ogeom = vl_scalespace_get_octave_geometry(self, o) ; - double deltaSigma = sqrt (sigma*sigma - imageSigma*imageSigma) ; - level = vl_scalespace_get_level (self, o, self->geom.octaveFirstSubdivision) ; - vl_imsmooth_f (level, ogeom.width, - level, ogeom.width, ogeom.height, ogeom.width, - deltaSigma / ogeom.step, deltaSigma / ogeom.step) ; - } -} - -/** @internal @brief Initialize the first level of an octave from the previous octave - ** @param self object. - ** @param o octave to initialize. - ** - ** The function initializes the first level of octave @a o from the - ** content of octave o - 1. - **/ - -static void -_vl_scalespace_start_octave_from_previous_octave (VlScaleSpace *self, vl_index o) -{ - double sigma, prevSigma ; - float *level, *prevLevel ; - vl_index prevLevelIndex ; - VlScaleSpaceOctaveGeometry ogeom ; - - assert(self) ; - assert(o > self->geom.firstOctave) ; /* must not be the first octave */ - assert(o <= self->geom.lastOctave) ; - - /* - * From the previous octave pick the level which is closer to - * self->geom.octaveFirstSubdivision in this octave. - * The is self->geom.octaveFirstSubdivision + self->numLevels since there are - * self->geom.octaveResolution levels in an octave, provided that - * this value does not exceed self->geom.octaveLastSubdivision. - */ - - prevLevelIndex = VL_MIN(self->geom.octaveFirstSubdivision - + (signed)self->geom.octaveResolution, - self->geom.octaveLastSubdivision) ; - prevLevel = vl_scalespace_get_level (self, o - 1, prevLevelIndex) ; - level = vl_scalespace_get_level (self, o, self->geom.octaveFirstSubdivision) ; - ogeom = vl_scalespace_get_octave_geometry(self, o - 1) ; - - copy_and_downsample (level, prevLevel, ogeom.width, ogeom.height, 1) ; - - /* - * Add remaining smoothing, if any. - */ - - sigma = vl_scalespace_get_level_sigma(self, o, self->geom.octaveFirstSubdivision) ; - prevSigma = vl_scalespace_get_level_sigma(self, o - 1, prevLevelIndex) ; - - if (sigma > prevSigma) { - VlScaleSpaceOctaveGeometry ogeom = vl_scalespace_get_octave_geometry(self, o) ; - double deltaSigma = sqrt (sigma*sigma - prevSigma*prevSigma) ; - level = vl_scalespace_get_level (self, o, self->geom.octaveFirstSubdivision) ; - - /* todo: this may fail due to an out-of-memory condition */ - vl_imsmooth_f (level, ogeom.width, - level, ogeom.width, ogeom.height, ogeom.width, - deltaSigma / ogeom.step, deltaSigma / ogeom.step) ; - } -} - -/** @brief Initialise Scale space with new image - ** @param self ::VlScaleSpace object instance. - ** @param image image to process. - ** - ** Compute the data of all the defined octaves and scales of the scale - ** space @a self. - **/ - -void -vl_scalespace_put_image (VlScaleSpace *self, float const *image) -{ - vl_index o ; - _vl_scalespace_start_octave_from_image(self, image, self->geom.firstOctave) ; - _vl_scalespace_fill_octave(self, self->geom.firstOctave) ; - for (o = self->geom.firstOctave + 1 ; o <= self->geom.lastOctave ; ++o) { - _vl_scalespace_start_octave_from_previous_octave(self, o) ; - _vl_scalespace_fill_octave(self, o) ; - } -} diff --git a/opensfm/src/third_party/vlfeat/vl/scalespace.h b/opensfm/src/third_party/vlfeat/vl/scalespace.h deleted file mode 100644 index 3f7af38d8..000000000 --- a/opensfm/src/third_party/vlfeat/vl/scalespace.h +++ /dev/null @@ -1,99 +0,0 @@ -/** @file scalespace.h - ** @brief Scale Space (@ref scalespace) - ** @author Andrea Vedaldi - ** @author Karel Lenc - ** @author Michal Perdoch - **/ - -/* -Copyright (C) 2007-12 Andrea Vedaldi and Brian Fulkerson. -All rights reserved. - -This file is part of the VLFeat library and is made available under -the terms of the BSD license (see the COPYING file). -*/ - -#ifndef VL_SCALESPACE_H -#define VL_SCALESPACE_H - -#include "generic.h" -#include "imopv.h" -#include "mathop.h" - -/* ---------------------------------------------------------------- */ -/* VlScaleSpaceGeometry */ -/* ---------------------------------------------------------------- */ - -/** @brief Geometry of a scale space - ** - ** There are a few restrictions on the valid geometrties. - */ -typedef struct _VlScaleSpaceGeometry -{ - vl_size width ; /**< Image width */ - vl_size height ; /**< Image height */ - vl_index firstOctave ; /**< Index of the fisrt octave */ - vl_index lastOctave ; /**< Index of the last octave */ - vl_size octaveResolution ; /**< Number of octave subdivisions */ - vl_index octaveFirstSubdivision ; /**< Index of the first octave subdivision */ - vl_index octaveLastSubdivision ; /**< Index of the last octave subdivision */ - double baseScale ; /**< Base smoothing (smoothing of octave 0, level 0) */ - double nominalScale ; /**< Nominal smoothing of the original image */ -} VlScaleSpaceGeometry ; - -VL_EXPORT -vl_bool vl_scalespacegeometry_is_equal (VlScaleSpaceGeometry a, - VlScaleSpaceGeometry b) ; - -/* ---------------------------------------------------------------- */ -/* VlScaleSpaceOctaveGeometry */ -/* ---------------------------------------------------------------- */ - -/** @brief Geometry of one octave of a scale space */ -typedef struct _VlScaleSpaceOctaveGeometry -{ - vl_size width ; /**< Width (number of pixels) */ - vl_size height ; /**< Height (number of pixels) */ - double step ; /**< Sampling step (size of a pixel) */ -} VlScaleSpaceOctaveGeometry ; - -/* ---------------------------------------------------------------- */ -/* VlScaleSpace */ -/* ---------------------------------------------------------------- */ - -typedef struct _VlScaleSpace VlScaleSpace ; - -/** @name Create and destroy - ** @{ - **/ -VL_EXPORT VlScaleSpaceGeometry vl_scalespace_get_default_geometry(vl_size width, vl_size height) ; -VL_EXPORT VlScaleSpace * vl_scalespace_new (vl_size width, vl_size height) ; -VL_EXPORT VlScaleSpace * vl_scalespace_new_with_geometry (VlScaleSpaceGeometry geom) ; -VL_EXPORT VlScaleSpace * vl_scalespace_new_copy (VlScaleSpace* src); -VL_EXPORT VlScaleSpace * vl_scalespace_new_shallow_copy (VlScaleSpace* src); -VL_EXPORT void vl_scalespace_delete (VlScaleSpace *self) ; -/** @} */ - -/** @name Process data - ** @{ - **/ -VL_EXPORT void -vl_scalespace_put_image (VlScaleSpace *self, float const* image); -/** @} */ - -/** @name Retrieve data and parameters - ** @{ - **/ -VL_EXPORT VlScaleSpaceGeometry vl_scalespace_get_geometry (VlScaleSpace const * self) ; -VL_EXPORT VlScaleSpaceOctaveGeometry vl_scalespace_get_octave_geometry (VlScaleSpace const * self, vl_index o) ; -VL_EXPORT float * -vl_scalespace_get_level (VlScaleSpace * self, vl_index o, vl_index s) ; -VL_EXPORT float const * -vl_scalespace_get_level_const (VlScaleSpace const * self, vl_index o, vl_index s) ; -VL_EXPORT double -vl_scalespace_get_level_sigma (VlScaleSpace const *self, vl_index o, vl_index s) ; -/** @} */ - -/* VL_SCALESPACE_H */ -#endif - diff --git a/opensfm/src/third_party/vlfeat/vl/shuffle-def.h b/opensfm/src/third_party/vlfeat/vl/shuffle-def.h deleted file mode 100644 index 4b74ea6bd..000000000 --- a/opensfm/src/third_party/vlfeat/vl/shuffle-def.h +++ /dev/null @@ -1,101 +0,0 @@ -/** @file shuffle-def.h - ** @brief Shuffle preprocessor metaprogram - ** @author Andrea Vedaldi - **/ - -/* -Copyright (C) 2007-12 Andrea Vedaldi and Brian Fulkerson. -All rights reserved. - -This file is part of the VLFeat library and is made available under -the terms of the BSD license (see the COPYING file). -*/ - -/** @file shuffle-def.h - - @todo large array compatibility. - **/ - -#include "host.h" -#include "random.h" -#include - -#ifndef VL_SHUFFLE_prefix -#error "VL_SHUFFLE_prefix must be defined" -#endif - -#ifndef VL_SHUFFLE_array -#ifndef VL_SHUFFLE_type -#error "VL_SHUFFLE_type must be defined if VL_SHUFFLE_array is not" -#endif -#define VL_SHUFFLE_array VL_SHUFFLE_type* -#endif - -#ifdef __DOXYGEN__ -#define VL_SHUFFLE_prefix ShufflePrefix /**< Prefix of the shuffle functions */ -#define VL_SHUFFLE_type ShuffleType /**< Data type of the shuffle elements */ -#define VL_SHUFFLE_array ShuffleType* /**< Data type of the shuffle container */ -#endif - -/* ---------------------------------------------------------------- */ - -#if ! defined(VL_SHUFFLE_swap) || defined(__DOXYGEN__) -#define VL_SHUFFLE_swap VL_XCAT(VL_SHUFFLE_prefix, _swap) - -/** @brief Swap two array elements - ** @param array shuffle array. - ** @param indexA index of the first element to swap. - ** @param indexB index of the second element to swap. - ** - ** The function swaps the two elements @a a and @ b. The function - ** uses a temporary element of type ::VL_SHUFFLE_type - ** and the copy operator @c =. - **/ - -VL_INLINE void -VL_SHUFFLE_swap -(VL_SHUFFLE_array array, - vl_uindex indexA, - vl_uindex indexB) -{ - VL_SHUFFLE_type t = array [indexA] ; - array [indexA] = array [indexB] ; - array [indexB] = t ; -} - -/* VL_SHUFFLE_swap */ -#endif - -/* ---------------------------------------------------------------- */ - -#if ! defined(VL_SHUFFLE_shuffle) || defined(__DOXYGEN__) -#define VL_SHUFFLE_shuffle VL_XCAT(VL_SHUFFLE_prefix, _shuffle) - -/** @brief Shuffle - ** @param array (in/out) pointer to the array. - ** @param size size of the array. - ** @param rand random number generator to use. - ** - ** The function randomly permutes the array. - **/ - -VL_INLINE void -VL_SHUFFLE_shuffle -(VL_SHUFFLE_array array, vl_size size, VlRand * rand) -{ - vl_uindex n = size ; - while (n > 1) { - vl_uindex k = vl_rand_uindex (rand, n) ; - n -- ; - VL_SHUFFLE_swap (array, n, k) ; - } -} - -/* VL_SHUFFLE_shuffle */ -#endif - -#undef VL_SHUFFLE_prefix -#undef VL_SHUFFLE_swap -#undef VL_SHUFFLE_shuffle -#undef VL_SHUFFLE_type -#undef VL_SHUFFLE_array diff --git a/opensfm/src/third_party/vlfeat/vl/sift.c b/opensfm/src/third_party/vlfeat/vl/sift.c deleted file mode 100644 index 03963fe6f..000000000 --- a/opensfm/src/third_party/vlfeat/vl/sift.c +++ /dev/null @@ -1,2197 +0,0 @@ -/** @file sift.c - ** @brief SIFT - Definition - ** @author Andrea Vedaldi - **/ - -/* -Copyright (C) 2007-12 Andrea Vedaldi and Brian Fulkerson. -All rights reserved. - -This file is part of the VLFeat library and is made available under -the terms of the BSD license (see the COPYING file). -*/ - -/** - -@page sift Scale Invariant Feature Transform (SIFT) -@author Andrea Vedaldi -@par "Credits:" May people have contributed with suggestions and bug -reports. Although the following list is certainly incomplete, we would -like to thank: Wei Dong, Loic, Giuseppe, Liu, Erwin, P. Ivanov, and -Q. S. Luo. -@tableofcontents - - -@ref sift.h implements a @ref sift-usage "SIFT filter object", a -reusable object to extract SIFT features @cite{lowe99object} from one -or multiple images. - -This is the original VLFeat implementation of SIFT, designed to be -compatible with Lowe's original SIFT. See @ref covdet for a different -version of SIFT integrated in the more general covariant feature -detector engine. - - -@section sift-intro Overview - - -A SIFT feature is a selected image region (also called keypoint) with -an associated descriptor. Keypoints are extracted by the @ref -sift-intro-detector "SIFT detector" and their descriptors are -computed by the @ref sift-intro-descriptor "SIFT descriptor". It is -also common to use independently the SIFT detector (i.e. computing the -keypoints without descriptors) or the SIFT descriptor (i.e. computing -descriptors of custom keypoints). - - -@subsection sift-intro-detector SIFT detector - - -A SIFT keypoint is a circular image region with an -orientation. It is described by a geometric frame of four -parameters: the keypoint center coordinates @e x and @e y, its @e -scale (the radius of the region), and its @e orientation (an angle -expressed in radians). The SIFT detector uses as keypoints image -structures which resemble “blobs”. By searching for blobs -at multiple scales and positions, the SIFT detector is invariant (or, -more accurately, covariant) to translation, rotations, and re scaling -of the image. - -The keypoint orientation is also determined from the local image -appearance and is covariant to image rotations. Depending on the -symmetry of the keypoint appearance, determining the orientation can -be ambiguous. In this case, the SIFT detectors returns a list of up to -four possible orientations, constructing up to four frames (differing -only by their orientation) for each detected image blob. - -@image html sift-frame.png "SIFT keypoints are circular image regions with an orientation." - -There are several parameters that influence the detection of SIFT -keypoints. First, searching keypoints at multiple scales is obtained -by constructing a so-called “Gaussian scale space”. The -scale space is just a collection of images obtained by progressively -smoothing the input image, which is analogous to gradually reducing -the image resolution. Conventionally, the smoothing level is called -scale of the image. The construction of the scale space is -influenced by the following parameters, set when creating the SIFT -filter object by ::vl_sift_new(): - -- Number of octaves. Increasing the scale by an octave means - doubling the size of the smoothing kernel, whose effect is roughly - equivalent to halving the image resolution. By default, the scale - space spans as many octaves as possible (i.e. roughly - log2(min(width,height)), which has the effect of searching - keypoints of all possible sizes. -- First octave index. By convention, the octave of index 0 - starts with the image full resolution. Specifying an index greater - than 0 starts the scale space at a lower resolution (e.g. 1 halves - the resolution). Similarly, specifying a negative index starts the - scale space at an higher resolution image, and can be useful to - extract very small features (since this is obtained by interpolating - the input image, it does not make much sense to go past -1). -- Number of levels per octave. Each octave is sampled at this - given number of intermediate scales (by default 3). Increasing this - number might in principle return more refined keypoints, but in - practice can make their selection unstable due to noise (see [1]). - -Keypoints are further refined by eliminating those that are likely to -be unstable, either because they are selected nearby an image edge, -rather than an image blob, or are found on image structures with low -contrast. Filtering is controlled by the follow: - -- Peak threshold. This is the minimum amount of contrast to - accept a keypoint. It is set by configuring the SIFT filter object - by ::vl_sift_set_peak_thresh(). -- Edge threshold. This is the edge rejection threshold. It is - set by configuring the SIFT filter object by - ::vl_sift_set_edge_thresh(). - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
Summary of the parameters influencing the SIFT detector.
ParameterSee alsoControlled byComment
number of octaves @ref sift-intro-detector ::vl_sift_new
first octave index @ref sift-intro-detector ::vl_sift_newset to -1 to extract very small features
number of scale levels per octave @ref sift-intro-detector ::vl_sift_newcan affect the number of extracted keypoints
edge threshold @ref sift-intro-detector ::vl_sift_set_edge_threshdecrease to eliminate more keypoints
peak threshold @ref sift-intro-detector ::vl_sift_set_peak_threshincrease to eliminate more keypoints
- - -@subsection sift-intro-descriptor SIFT Descriptor - - -@sa @ref sift-tech-descriptor "Descriptor technical details" - -A SIFT descriptor is a 3-D spatial histogram of the image gradients in -characterizing the appearance of a keypoint. The gradient at each -pixel is regarded as a sample of a three-dimensional elementary -feature vector, formed by the pixel location and the gradient -orientation. Samples are weighed by the gradient norm and accumulated -in a 3-D histogram @em h, which (up to normalization and clamping) -forms the SIFT descriptor of the region. An additional Gaussian -weighting function is applied to give less importance to gradients -farther away from the keypoint center. Orientations are quantized into -eight bins and the spatial coordinates into four each, as follows: - -@image html sift-descr-easy.png "The SIFT descriptor is a spatial histogram of the image gradient." - -SIFT descriptors are computed by either calling -::vl_sift_calc_keypoint_descriptor or -::vl_sift_calc_raw_descriptor. They accept as input a keypoint -frame, which specifies the descriptor center, its size, and its -orientation on the image plane. The following parameters influence the -descriptor calculation: - -- magnification factor. The descriptor size is determined by -multiplying the keypoint scale by this factor. It is set by -::vl_sift_set_magnif. -- Gaussian window size. The descriptor support is determined by -a Gaussian window, which discounts gradient contributions farther away -from the descriptor center. The standard deviation of this window is -set by ::vl_sift_set_window_size and expressed in unit of bins. - -VLFeat SIFT descriptor uses the following convention. The @em y axis -points downwards and angles are measured clockwise (to be consistent -with the standard image convention). The 3-D histogram (consisting of -@f$ 8 \times 4 \times 4 = 128 @f$ bins) is stacked as a single -128-dimensional vector, where the fastest varying dimension is the -orientation and the slowest the @em y spatial coordinate. This is -illustrated by the following figure. - -@image html sift-conv-vlfeat.png "VLFeat conventions" - -@note Keypoints (frames) D. Lowe's SIFT implementation convention is -slightly different: The @em y axis points upwards and the angles are -measured counter-clockwise. - -@image html sift-conv.png "D. Lowes' SIFT implementation conventions" - - - - - - - - - - - - - - - - - - - - - -
Summary of the parameters influencing the SIFT descriptor.
ParameterSee alsoControlled byComment
magnification factor @ref sift-intro-descriptor ::vl_sift_set_magnifincrease this value to enlarge the image region described
Gaussian window size @ref sift-intro-descriptor ::vl_sift_set_window_sizesmaller values let the center of the descriptor count more
- - - -@section sift-intro-extensions Extensions - - -Eliminating low-contrast descriptors. Near-uniform patches do -not yield stable keypoints or descriptors. ::vl_sift_set_norm_thresh() -can be used to set a threshold on the average norm of the local -gradient to zero-out descriptors that correspond to very low contrast -regions. By default, the threshold is equal to zero, which means that -no descriptor is zeroed. Normally this option is useful only with -custom keypoints, as detected keypoints are implicitly selected at -high contrast image regions. - - -@section sift-usage Using the SIFT filter object - - -The code provided in this module can be used in different ways. You -can instantiate and use a SIFT filter to extract both SIFT -keypoints and descriptors from one or multiple images. Alternatively, -you can use one of the low level functions to run only a part of the -SIFT algorithm (for instance, to compute the SIFT descriptors of -custom keypoints). - -To use a SIFT filter object: - -- Initialize a SIFT filter object with ::vl_sift_new(). The filter can - be reused for multiple images of the same size (e.g. for an entire - video sequence). -- For each octave in the scale space: - - Compute the next octave of the DOG scale space using either - ::vl_sift_process_first_octave() or ::vl_sift_process_next_octave() - (stop processing if ::VL_ERR_EOF is returned). - - Run the SIFT detector with ::vl_sift_detect() to get the keypoints. - - For each keypoint: - - Use ::vl_sift_calc_keypoint_orientations() to get the keypoint orientation(s). - - For each orientation: - - Use ::vl_sift_calc_keypoint_descriptor() to get the keypoint descriptor. -- Delete the SIFT filter by ::vl_sift_delete(). - -To compute SIFT descriptors of custom keypoints, use -::vl_sift_calc_raw_descriptor(). - - -@section sift-tech Technical details - - - -@subsection sift-tech-ss Scale space - - -In order to search for image blobs at multiple scale, the SIFT -detector construct a scale space, defined as follows. Let -@f$I_0(\mathbf{x})@f$ denote an idealized infinite resolution -image. Consider the Gaussian kernel - -@f[ - g_{\sigma}(\mathbf{x}) - = - \frac{1}{2\pi\sigma^2} - \exp - \left( - -\frac{1}{2} - \frac{\mathbf{x}^\top\mathbf{x}}{\sigma^2} - \right) -@f] - -The Gaussian scale space is the collection of smoothed images - -@f[ - I_\sigma = g_\sigma * I, \quad \sigma \geq 0. -@f] - -The image at infinite resolution @f$ I_0 @f$ is useful conceptually, -but is not available to us; instead, the input image @f$ I_{\sigma_n} -@f$ is assumed to be pre-smoothed at a nominal level @f$ \sigma_n = -0.5 @f$ to account for the finite resolution of the pixels. Thus in -practice the scale space is computed by - -@f[ -I_\sigma = g_{\sqrt{\sigma^2 - \sigma_n^2}} * I_{\sigma_n}, -\quad \sigma \geq \sigma_n. -@f] - -Scales are sampled at logarithmic steps given by - -@f[ -\sigma = \sigma_0 2^{o+s/S}, -\quad s = 0,\dots,S-1, -\quad o = o_{\min}, \dots, o_{\min}+O-1, -@f] - -where @f$ \sigma_0 = 1.6 @f$ is the base scale, @f$ o_{\min} -@f$ is the first octave index, @em O the number of -octaves and @em S the number of scales per octave. - -Blobs are detected as local extrema of the Difference of -Gaussians (DoG) scale space, obtained by subtracting successive -scales of the Gaussian scale space: - -@f[ -\mathrm{DoG}_{\sigma(o,s)} = I_{\sigma(o,s+1)} - I_{\sigma(o,s)} -@f] - -At each next octave, the resolution of the images is halved to save -computations. The images composing the Gaussian and DoG scale space -can then be arranged as in the following figure: - -@image html sift-ss.png "GSS and DoG scale space structures." - -The black vertical segments represent images of the Gaussian Scale -Space (GSS), arranged by increasing scale @f$\sigma@f$. Notice that -the scale level index @e s varies in a slightly redundant set - -@f[ -s = -1, \dots, S+2 -@f] - -This simplifies glueing together different octaves and extracting DoG -maxima (required by the SIFT detector). - - -@subsection sift-tech-detector Detector - - -The SIFT frames (keypoints) are extracted based on local extrema -(peaks) of the DoG scale space. Numerically, local extrema are -elements whose @f$ 3 \times 3 \times 3 @f$ neighbors (in space and -scale) have all smaller (or larger) value. Once extracted, local -extrema are quadratically interpolated (this is very important -especially at the lower resolution scales in order to have accurate -keypoint localization at the full resolution). Finally, they are -filtered to eliminate low-contrast responses or responses close to -edges and the orientation(s) are assigned, as explained next. - - -@subsubsection sift-tech-detector-peak Eliminating low contrast responses - - -Peaks which are too short may have been generated by noise and are -discarded. This is done by comparing the absolute value of the DoG -scale space at the peak with the peak threshold @f$t_p@f$ and -discarding the peak its value is below the threshold. - - -@subsubsection sift-tech-detector-edge Eliminating edge responses - - -Peaks which are too flat are often generated by edges and do not yield -stable features. These peaks are detected and removed as follows. -Given a peak @f$x,y,\sigma@f$, the algorithm evaluates the @em x,@em y -Hessian of of the DoG scale space at the scale @f$\sigma@f$. Then the -following score (similar to the Harris function) is computed: - -@f[ -\frac{(\mathrm{tr}\,D(x,y,\sigma))^2}{\det D(x,y,\sigma)}, -\quad -D = -\left[ -\begin{array}{cc} -\frac{\partial^2 \mathrm{DoG}}{\partial x^2} & -\frac{\partial^2 \mathrm{DoG}}{\partial x\partial y} \\ -\frac{\partial^2 \mathrm{DoG}}{\partial x\partial y} & -\frac{\partial^2 \mathrm{DoG}}{\partial y^2} -\end{array} -\right]. - @f] - -This score has a minimum (equal to 4) when both eigenvalues of the -Jacobian are equal (curved peak) and increases as one of the -eigenvalues grows and the other stays small. Peaks are retained if the -score is below the quantity @f$(t_e+1)(t_e+1)/t_e@f$, where @f$t_e@f$ -is the edge threshold. Notice that this quantity has a minimum -equal to 4 when @f$t_e=1@f$ and grows thereafter. Therefore the range -of the edge threshold is @f$[1,\infty)@f$. - - -@subsection sift-tech-detector-orientation Orientation assignment - - -A peak in the DoG scale space fixes 2 parameters of the keypoint: the -position and scale. It remains to choose an orientation. In order to -do this, SIFT computes an histogram of the gradient orientations in a -Gaussian window with a standard deviation which is 1.5 times bigger -than the scale @f$\sigma@f$ of the keypoint. - -@image html sift-orient.png - -This histogram is then smoothed and the maximum is selected. In -addition to the biggest mode, up to other three modes whose amplitude -is within the 80% of the biggest mode are retained and returned as -additional orientations. - - -@subsection sift-tech-descriptor Descriptor - - -A SIFT descriptor of a local region (keypoint) is a 3-D spatial -histogram of the image gradients. The gradient at each pixel is -regarded as a sample of a three-dimensional elementary feature vector, -formed by the pixel location and the gradient orientation. Samples are -weighed by the gradient norm and accumulated in a 3-D histogram @em h, -which (up to normalization and clamping) forms the SIFT descriptor of -the region. An additional Gaussian weighting function is applied to -give less importance to gradients farther away from the keypoint -center. - - - - -@subsubsection sift-tech-descriptor-can Construction in the canonical frame - - -Denote the gradient vector field computed at the scale @f$ \sigma @f$ by -@f[ - J(x,y) = \nabla I_\sigma(x,y) - = - \left[\begin{array}{cc} - \frac{\partial I_\sigma}{\partial x} & - \frac{\partial I_\sigma}{\partial y} & - \end{array}\right] -@f] - -The descriptor is a 3-D spatial histogram capturing the distribution -of @f$ J(x,y) @f$. It is convenient to describe its construction in -the canonical frame. In this frame, the image and descriptor -axes coincide and each spatial bin has side 1. The histogram has @f$ -N_\theta \times N_x \times N_y @f$ bins (usually @f$ 8 \times 4 \times -4 @f$), as in the following figure: - -@image html sift-can.png Canonical SIFT descriptor and spatial binning functions - -Bins are indexed by a triplet of indexes t, i, j and their -centers are given by - -@f{eqnarray*} - \theta_t &=& \frac{2\pi}{N_\theta} t, \quad t = 0,\dots,N_{\theta}-1, \\ - x_i &=& i - \frac{N_x -1}{2}, \quad i = 0,\dots,N_x-1, \\ - y_j &=& j - \frac{N_x -1}{2}, \quad j = 0,\dots,N_y-1. \\ -@f} - -The histogram is computed by using trilinear interpolation, i.e. by -weighing contributions by the binning functions - -@f{eqnarray*} - \displaystyle - w(z) &=& \mathrm{max}(0, 1 - |z|), - \\ - \displaystyle - w_\mathrm{ang}(z) &=& \sum_{k=-\infty}^{+\infty} - w\left( - \frac{N_\theta}{2\pi} z + N_\theta k - \right). -@f} - -The gradient vector field is transformed in a three-dimensional -density map of weighed contributions - -@f[ - f(\theta, x, y) = |J(x,y)| \delta(\theta - \angle J(x,y)) -@f] - -The historam is localized in the keypoint support by a Gaussian window -of standard deviation @f$ \sigma_{\mathrm{win}} @f$. The histogram is -then given by - -@f{eqnarray*} - h(t,i,j) &=& \int - g_{\sigma_\mathrm{win}}(x,y) - w_\mathrm{ang}(\theta - \theta_t) w(x-x_i) w(y-y_j) - f(\theta,x,y) - d\theta\,dx\,dy -\\ -&=& \int - g_{\sigma_\mathrm{win}}(x,y) - w_\mathrm{ang}(\angle J(x,y) - \theta_t) w(x-x_i) w(y-y_j) - |J(x,y)|\,dx\,dy -@f} - -In post processing, the histogram is @f$ l^2 @f$ normalized, then -clamped at 0.2, and @f$ l^2 @f$ normalized again. - - -@subsubsection sift-tech-descriptor-image Calculation in the image frame - - -Invariance to similarity transformation is attained by attaching -descriptors to SIFT keypoints (or other similarity-covariant frames). -Then projecting the image in the canonical descriptor frames has the -effect of undoing the image deformation. - -In practice, however, it is convenient to compute the descriptor -directly in the image frame. To do this, denote with a hat quantities -relative to the canonical frame and without a hat quantities relative -to the image frame (so for instance @f$ \hat x @f$ is the @e -x-coordinate in the canonical frame and @f$ x @f$ the x-coordinate in -the image frame). Assume that canonical and image frame are -related by an affinity: - -@f[ - \mathbf{x} = A \hat{\mathbf{x}} + T, - \qquad - \mathbf{x} = - \begin{bmatrix}{c} - x \\ - y - \end{bmatrix}, - \quad - \mathbf{x} = - \begin{bmatrix}{c} - \hat x \\ - \hat y - \end{bmatrix}. -@f] - -@image html sift-image-frame.png - -Then all quantities can be computed in the image frame directly. For instance, -the image at infinite resolution in the two frames are related by - -@f[ - \hat I_0(\hat{\mathbf{x}}) = I_0(\mathbf{x}), - \qquad - \mathbf{x} = A \hat{\mathbf{x}} + T. -@f] - -The canonized image at scale @f$ \hat \sigma @f$ is in relation with the scaled image - -@f[ - \hat I_{\hat{\sigma}}(\hat{\mathbf{x}}) = I_{A\hat{\sigma}}(\mathbf{x}), - \qquad \mathbf{x} = A \hat{\mathbf{x}} + T -@f] - -where, by generalizing the previous definitions, we have - -@f[ - I_{A\hat \sigma}(\mathbf{x}) = (g_{A\hat\sigma} * I_0)(\mathbf{x}), -\quad - g_{A\hat\sigma}(\mathbf{x}) - = - \frac{1}{2\pi|A|\hat \sigma^2} - \exp - \left( - -\frac{1}{2} - \frac{\mathbf{x}^\top A^{-\top}A^{-1}\mathbf{x}}{\hat \sigma^2} - \right) -@f] - -Deriving shows that the gradient fields are in relation - -@f[ - \hat J(\hat{\mathbf{x}}) = J(\mathbf{x}) A, - \quad J(\mathbf{x}) = (\nabla I_{A\hat\sigma})(\mathbf{x}), - \qquad \mathbf{x} = A \hat{\mathbf{x}} + T. -@f] - -Therefore we can compute the descriptor either in the image or canonical frame as: - -@f{eqnarray*} - h(t,i,j) - &=& - \int - g_{\hat \sigma_\mathrm{win}}(\hat{\mathbf{x}})\, - w_\mathrm{ang}(\angle \hat J(\hat{\mathbf{x}}) - \theta_t)\, - w_{ij}(\hat{\mathbf{x}})\, - |\hat J(\hat{\mathbf{x}})|\, - d\hat{\mathbf{x}} - \\ - &=& \int - g_{A \hat \sigma_\mathrm{win}}(\mathbf{x} - T)\, - w_\mathrm{ang}(\angle J(\mathbf{x})A - \theta_t)\, - w_{ij}(A^{-1}(\mathbf{x} - T))\, - |J(\mathbf{x})A|\, - d\mathbf{x}. -@f} - -where we defined the product of the two spatial binning functions - -@f[ - w_{ij}(\hat{\mathbf{x}}) = w(\hat x - \hat x_i) w(\hat y - \hat y_j) -@f] - - -In the actual implementation, this integral is computed by visiting a -rectangular area of the image that fully contains the keypoint grid -(along with half a bin border to fully include the bin windowing -function). Since the descriptor can be rotated, this area is a -rectangle of sides @f$m/2\sqrt{2} (N_x+1,N_y+1)@f$ (see also the -illustration). - - -@subsubsection sift-tech-descriptor-std Standard SIFT descriptor - - -For a SIFT-detected keypoint of center @f$ T @f$, scale @f$ \sigma @f$ -and orientation @f$ \theta @f$, the affine transformation @f$ (A,T) -@f$ reduces to the similarity transformation - -@f[ - \mathbf{x} = m \sigma R(\theta) \hat{\mathbf{x}} + T -@f] - -where @f$ R(\theta) @f$ is a counter-clockwise rotation of @f$ \theta -@f$ radians, @f$ m \mathcal{\sigma} @f$ is the size of a descriptor -bin in pixels, and @e m is the descriptor magnification factor -which expresses how much larger a descriptor bin is compared to -the scale of the keypoint @f$ \sigma @f$ -(the default value is @e m = 3). Moreover, the -standard SIFT descriptor computes the image gradient at the scale of -the keypoints, which in the canonical frame is equivalent to a -smoothing of @f$ \hat \sigma = 1/m @f$. Finally, the default -Gaussian window size is set to have standard deviation - @f$ \hat \sigma_\mathrm{win} = 2 @f$. This yields the formula - -@f{eqnarray*} - h(t,i,j) - &=& - m \sigma \int - g_{\sigma_\mathrm{win}}(\mathbf{x} - T)\, - w_\mathrm{ang}(\angle J(\mathbf{x}) - \theta - \theta_t)\, - w_{ij}\left(\frac{R(\theta)^\top \mathbf{x} - T}{m\sigma}\right)\, - |J(\mathbf{x})|\, - d\mathbf{x}, -\\ -\sigma_{\mathrm{win}} &=& m\sigma\hat \sigma_{\mathrm{win}}, -\\ - J(\mathbf{x}) - &=& \nabla (g_{m \sigma \hat \sigma} * I)(\mathbf{x}) - = \nabla (g_{\sigma} * I)(\mathbf{x}) - = \nabla I_{\sigma} (\mathbf{x}). -@f} - - - -**/ - -#include "sift.h" -#include "imopv.h" -#include "mathop.h" - -#include -#include -#include -#include -#include - -/** @internal @brief Use bilinear interpolation to compute orientations */ -#define VL_SIFT_BILINEAR_ORIENTATIONS 1 - -#define EXPN_SZ 256 /**< ::fast_expn table size @internal */ -#define EXPN_MAX 25.0 /**< ::fast_expn table max @internal */ -double expn_tab [EXPN_SZ+1] ; /**< ::fast_expn table @internal */ - -#define NBO 8 -#define NBP 4 - -#define log2(x) (log(x)/VL_LOG_OF_2) - -/** ------------------------------------------------------------------ - ** @internal - ** @brief Fast @f$exp(-x)@f$ approximation - ** - ** @param x argument. - ** - ** The argument must be in the range [0, ::EXPN_MAX] . - ** - ** @return approximation of @f$exp(-x)@f$. - **/ - -VL_INLINE double -fast_expn (double x) -{ - double a,b,r ; - int i ; - /*assert(0 <= x && x <= EXPN_MAX) ;*/ - - if (x > EXPN_MAX) return 0.0 ; - - x *= EXPN_SZ / EXPN_MAX ; - i = (int)vl_floor_d (x) ; - r = x - i ; - a = expn_tab [i ] ; - b = expn_tab [i + 1] ; - return a + r * (b - a) ; -} - -/** ------------------------------------------------------------------ - ** @internal - ** @brief Initialize tables for ::fast_expn - **/ - -VL_INLINE void -fast_expn_init () -{ - int k ; - for(k = 0 ; k < EXPN_SZ + 1 ; ++ k) { - expn_tab [k] = exp (- (double) k * (EXPN_MAX / EXPN_SZ)) ; - } -} - -/** ------------------------------------------------------------------ - ** @internal - ** @brief Copy image, upsample rows and take transpose - ** - ** @param dst output image buffer. - ** @param src input image buffer. - ** @param width input image width. - ** @param height input image height. - ** - ** The output image has dimensions @a height by 2 @a width (so the - ** destination buffer must be at least as big as two times the - ** input buffer). - ** - ** Upsampling is performed by linear interpolation. - **/ - -static void -copy_and_upsample_rows -(vl_sift_pix *dst, - vl_sift_pix const *src, int width, int height) -{ - int x, y ; - vl_sift_pix a, b ; - - for(y = 0 ; y < height ; ++y) { - b = a = *src++ ; - for(x = 0 ; x < width - 1 ; ++x) { - b = *src++ ; - *dst = a ; dst += height ; - *dst = 0.5 * (a + b) ; dst += height ; - a = b ; - } - *dst = b ; dst += height ; - *dst = b ; dst += height ; - dst += 1 - width * 2 * height ; - } -} - -/** ------------------------------------------------------------------ - ** @internal - ** @brief Smooth an image - ** @param self SIFT filter. - ** @param outputImage output imgae buffer. - ** @param tempImage temporary image buffer. - ** @param inputImage input image buffer. - ** @param width input image width. - ** @param height input image height. - ** @param sigma smoothing. - **/ - -static void -_vl_sift_smooth (VlSiftFilt * self, - vl_sift_pix * outputImage, - vl_sift_pix * tempImage, - vl_sift_pix const * inputImage, - vl_size width, - vl_size height, - double sigma) -{ - /* prepare Gaussian filter */ - if (self->gaussFilterSigma != sigma) { - vl_uindex j ; - vl_sift_pix acc = 0 ; - if (self->gaussFilter) vl_free (self->gaussFilter) ; - self->gaussFilterWidth = VL_MAX(ceil(4.0 * sigma), 1) ; - self->gaussFilterSigma = sigma ; - self->gaussFilter = vl_malloc (sizeof(vl_sift_pix) * (2 * self->gaussFilterWidth + 1)) ; - - for (j = 0 ; j < 2 * self->gaussFilterWidth + 1 ; ++j) { - vl_sift_pix d = ((vl_sift_pix)((signed)j - (signed)self->gaussFilterWidth)) / ((vl_sift_pix)sigma) ; - self->gaussFilter[j] = (vl_sift_pix) exp (- 0.5 * (d*d)) ; - acc += self->gaussFilter[j] ; - } - for (j = 0 ; j < 2 * self->gaussFilterWidth + 1 ; ++j) { - self->gaussFilter[j] /= acc ; - } - } - - if (self->gaussFilterWidth == 0) { - memcpy (outputImage, inputImage, sizeof(vl_sift_pix) * width * height) ; - return ; - } - - vl_imconvcol_vf (tempImage, height, - inputImage, width, height, width, - self->gaussFilter, - - self->gaussFilterWidth, self->gaussFilterWidth, - 1, VL_PAD_BY_CONTINUITY | VL_TRANSPOSE) ; - - vl_imconvcol_vf (outputImage, width, - tempImage, height, width, height, - self->gaussFilter, - - self->gaussFilterWidth, self->gaussFilterWidth, - 1, VL_PAD_BY_CONTINUITY | VL_TRANSPOSE) ; -} - -/** ------------------------------------------------------------------ - ** @internal - ** @brief Copy and downsample an image - ** - ** @param dst output imgae buffer. - ** @param src input image buffer. - ** @param width input image width. - ** @param height input image height. - ** @param d octaves (non negative). - ** - ** The function downsamples the image @a d times, reducing it to @c - ** 1/2^d of its original size. The parameters @a width and @a height - ** are the size of the input image. The destination image @a dst is - ** assumed to be floor(width/2^d) pixels wide and - ** floor(height/2^d) pixels high. - **/ - -static void -copy_and_downsample -(vl_sift_pix *dst, - vl_sift_pix const *src, - int width, int height, int d) -{ - int x, y ; - - d = 1 << d ; /* d = 2^d */ - for(y = 0 ; y < height ; y+=d) { - vl_sift_pix const * srcrowp = src + y * width ; - for(x = 0 ; x < width - (d-1) ; x+=d) { - *dst++ = *srcrowp ; - srcrowp += d ; - } - } -} - -/** ------------------------------------------------------------------ - ** @brief Create a new SIFT filter - ** - ** @param width image width. - ** @param height image height. - ** @param noctaves number of octaves. - ** @param nlevels number of levels per octave. - ** @param o_min first octave index. - ** - ** The function allocates and returns a new SIFT filter for the - ** specified image and scale space geometry. - ** - ** Setting @a O to a negative value sets the number of octaves to the - ** maximum possible value depending on the size of the image. - ** - ** @return the new SIFT filter. - ** @sa ::vl_sift_delete(). - **/ - -VL_EXPORT -VlSiftFilt * -vl_sift_new (int width, int height, - int noctaves, int nlevels, - int o_min) -{ - VlSiftFilt *f = vl_malloc (sizeof(VlSiftFilt)) ; - - int w = VL_SHIFT_LEFT (width, -o_min) ; - int h = VL_SHIFT_LEFT (height, -o_min) ; - int nel = w * h ; - - /* negative value O => calculate max. value */ - if (noctaves < 0) { - noctaves = VL_MAX (floor (log2 (VL_MIN(width, height))) - o_min - 3, 1) ; - } - - f-> width = width ; - f-> height = height ; - f-> O = noctaves ; - f-> S = nlevels ; - f-> o_min = o_min ; - f-> s_min = -1 ; - f-> s_max = nlevels + 1 ; - f-> o_cur = o_min ; - - f-> temp = vl_malloc (sizeof(vl_sift_pix) * nel ) ; - f-> octave = vl_malloc (sizeof(vl_sift_pix) * nel - * (f->s_max - f->s_min + 1) ) ; - f-> dog = vl_malloc (sizeof(vl_sift_pix) * nel - * (f->s_max - f->s_min ) ) ; - f-> grad = vl_malloc (sizeof(vl_sift_pix) * nel * 2 - * (f->s_max - f->s_min ) ) ; - - f-> sigman = 0.5 ; - f-> sigmak = pow (2.0, 1.0 / nlevels) ; - f-> sigma0 = 1.6 * f->sigmak ; - f-> dsigma0 = f->sigma0 * sqrt (1.0 - 1.0 / (f->sigmak*f->sigmak)) ; - - f-> gaussFilter = NULL ; - f-> gaussFilterSigma = 0 ; - f-> gaussFilterWidth = 0 ; - - f-> octave_width = 0 ; - f-> octave_height = 0 ; - - f-> keys = 0 ; - f-> nkeys = 0 ; - f-> keys_res = 0 ; - - f-> peak_thresh = 0.0 ; - f-> edge_thresh = 10.0 ; - f-> norm_thresh = 0.0 ; - f-> magnif = 3.0 ; - f-> windowSize = NBP / 2 ; - - f-> grad_o = o_min - 1 ; - - /* initialize fast_expn stuff */ - fast_expn_init () ; - - return f ; -} - -/** ------------------------------------------------------------------- - ** @brief Delete SIFT filter - ** - ** @param f SIFT filter to delete. - ** - ** The function frees the resources allocated by ::vl_sift_new(). - **/ - -VL_EXPORT -void -vl_sift_delete (VlSiftFilt* f) -{ - if (f) { - if (f->keys) vl_free (f->keys) ; - if (f->grad) vl_free (f->grad) ; - if (f->dog) vl_free (f->dog) ; - if (f->octave) vl_free (f->octave) ; - if (f->temp) vl_free (f->temp) ; - if (f->gaussFilter) vl_free (f->gaussFilter) ; - vl_free (f) ; - } -} - -/** ------------------------------------------------------------------ - ** @brief Start processing a new image - ** - ** @param f SIFT filter. - ** @param im image data. - ** - ** The function starts processing a new image by computing its - ** Gaussian scale space at the lower octave. It also empties the - ** internal keypoint buffer. - ** - ** @return error code. The function returns ::VL_ERR_EOF if there are - ** no more octaves to process. - ** - ** @sa ::vl_sift_process_next_octave(). - **/ - -VL_EXPORT -int -vl_sift_process_first_octave (VlSiftFilt *f, vl_sift_pix const *im) -{ - int o, s, h, w ; - double sa, sb ; - vl_sift_pix *octave ; - - /* shortcuts */ - vl_sift_pix *temp = f-> temp ; - int width = f-> width ; - int height = f-> height ; - int o_min = f-> o_min ; - int s_min = f-> s_min ; - int s_max = f-> s_max ; - double sigma0 = f-> sigma0 ; - double sigmak = f-> sigmak ; - double sigman = f-> sigman ; - double dsigma0 = f-> dsigma0 ; - - /* restart from the first */ - f->o_cur = o_min ; - f->nkeys = 0 ; - w = f-> octave_width = VL_SHIFT_LEFT(f->width, - f->o_cur) ; - h = f-> octave_height = VL_SHIFT_LEFT(f->height, - f->o_cur) ; - - /* is there at least one octave? */ - if (f->O == 0) - return VL_ERR_EOF ; - - /* ------------------------------------------------------------------ - * Compute the first sublevel of the first octave - * --------------------------------------------------------------- */ - - /* - * If the first octave has negative index, we upscale the image; if - * the first octave has positive index, we downscale the image; if - * the first octave has index zero, we just copy the image. - */ - - octave = vl_sift_get_octave (f, s_min) ; - - if (o_min < 0) { - /* double once */ - copy_and_upsample_rows (temp, im, width, height) ; - copy_and_upsample_rows (octave, temp, height, 2 * width ) ; - - /* double more */ - for(o = -1 ; o > o_min ; --o) { - copy_and_upsample_rows (temp, octave, - width << -o, height << -o ) ; - copy_and_upsample_rows (octave, temp, - width << -o, 2 * (height << -o)) ; - } - } - else if (o_min > 0) { - /* downsample */ - copy_and_downsample (octave, im, width, height, o_min) ; - } - else { - /* direct copy */ - memcpy(octave, im, sizeof(vl_sift_pix) * width * height) ; - } - - /* - * Here we adjust the smoothing of the first level of the octave. - * The input image is assumed to have nominal smoothing equal to - * f->simgan. - */ - - sa = sigma0 * pow (sigmak, s_min) ; - sb = sigman * pow (2.0, - o_min) ; - - if (sa > sb) { - double sd = sqrt (sa*sa - sb*sb) ; - _vl_sift_smooth (f, octave, temp, octave, w, h, sd) ; - } - - /* ----------------------------------------------------------------- - * Compute the first octave - * -------------------------------------------------------------- */ - - for(s = s_min + 1 ; s <= s_max ; ++s) { - double sd = dsigma0 * pow (sigmak, s) ; - _vl_sift_smooth (f, vl_sift_get_octave(f, s), temp, - vl_sift_get_octave(f, s - 1), w, h, sd) ; - } - - return VL_ERR_OK ; -} - -/** ------------------------------------------------------------------ - ** @brief Process next octave - ** - ** @param f SIFT filter. - ** - ** The function computes the next octave of the Gaussian scale space. - ** Notice that this clears the record of any feature detected in the - ** previous octave. - ** - ** @return error code. The function returns the error - ** ::VL_ERR_EOF when there are no more octaves to process. - ** - ** @sa ::vl_sift_process_first_octave(). - **/ - -VL_EXPORT -int -vl_sift_process_next_octave (VlSiftFilt *f) -{ - - int s, h, w, s_best ; - double sa, sb ; - vl_sift_pix *octave, *pt ; - - /* shortcuts */ - vl_sift_pix *temp = f-> temp ; - int O = f-> O ; - int S = f-> S ; - int o_min = f-> o_min ; - int s_min = f-> s_min ; - int s_max = f-> s_max ; - double sigma0 = f-> sigma0 ; - double sigmak = f-> sigmak ; - double dsigma0 = f-> dsigma0 ; - - /* is there another octave ? */ - if (f->o_cur == o_min + O - 1) - return VL_ERR_EOF ; - - /* retrieve base */ - s_best = VL_MIN(s_min + S, s_max) ; - w = vl_sift_get_octave_width (f) ; - h = vl_sift_get_octave_height (f) ; - pt = vl_sift_get_octave (f, s_best) ; - octave = vl_sift_get_octave (f, s_min) ; - - /* next octave */ - copy_and_downsample (octave, pt, w, h, 1) ; - - f-> o_cur += 1 ; - f-> nkeys = 0 ; - w = f-> octave_width = VL_SHIFT_LEFT(f->width, - f->o_cur) ; - h = f-> octave_height = VL_SHIFT_LEFT(f->height, - f->o_cur) ; - - sa = sigma0 * powf (sigmak, s_min ) ; - sb = sigma0 * powf (sigmak, s_best - S) ; - - if (sa > sb) { - double sd = sqrt (sa*sa - sb*sb) ; - _vl_sift_smooth (f, octave, temp, octave, w, h, sd) ; - } - - /* ------------------------------------------------------------------ - * Fill octave - * --------------------------------------------------------------- */ - - for(s = s_min + 1 ; s <= s_max ; ++s) { - double sd = dsigma0 * pow (sigmak, s) ; - _vl_sift_smooth (f, vl_sift_get_octave(f, s), temp, - vl_sift_get_octave(f, s - 1), w, h, sd) ; - } - - return VL_ERR_OK ; -} - -/** ------------------------------------------------------------------ - ** @brief Detect keypoints - ** - ** The function detect keypoints in the current octave filling the - ** internal keypoint buffer. Keypoints can be retrieved by - ** ::vl_sift_get_keypoints(). - ** - ** @param f SIFT filter. - **/ - -VL_EXPORT -void -vl_sift_detect (VlSiftFilt * f) -{ - vl_sift_pix* dog = f-> dog ; - int s_min = f-> s_min ; - int s_max = f-> s_max ; - int w = f-> octave_width ; - int h = f-> octave_height ; - double te = f-> edge_thresh ; - double tp = f-> peak_thresh ; - - int const xo = 1 ; /* x-stride */ - int const yo = w ; /* y-stride */ - int const so = w * h ; /* s-stride */ - - double xper = pow (2.0, f->o_cur) ; - - int x, y, s, i, ii, jj ; - vl_sift_pix *pt, v ; - VlSiftKeypoint *k ; - - /* clear current list */ - f-> nkeys = 0 ; - - /* compute difference of gaussian (DoG) */ - pt = f-> dog ; - for (s = s_min ; s <= s_max - 1 ; ++s) { - vl_sift_pix* src_a = vl_sift_get_octave (f, s ) ; - vl_sift_pix* src_b = vl_sift_get_octave (f, s + 1) ; - vl_sift_pix* end_a = src_a + w * h ; - while (src_a != end_a) { - *pt++ = *src_b++ - *src_a++ ; - } - } - - /* ----------------------------------------------------------------- - * Find local maxima of DoG - * -------------------------------------------------------------- */ - - /* start from dog [1,1,s_min+1] */ - pt = dog + xo + yo + so ; - - for(s = s_min + 1 ; s <= s_max - 2 ; ++s) { - for(y = 1 ; y < h - 1 ; ++y) { - for(x = 1 ; x < w - 1 ; ++x) { - v = *pt ; - -#define CHECK_NEIGHBORS(CMP,SGN) \ - ( v CMP ## = SGN 0.8 * tp && \ - v CMP *(pt + xo) && \ - v CMP *(pt - xo) && \ - v CMP *(pt + so) && \ - v CMP *(pt - so) && \ - v CMP *(pt + yo) && \ - v CMP *(pt - yo) && \ - \ - v CMP *(pt + yo + xo) && \ - v CMP *(pt + yo - xo) && \ - v CMP *(pt - yo + xo) && \ - v CMP *(pt - yo - xo) && \ - \ - v CMP *(pt + xo + so) && \ - v CMP *(pt - xo + so) && \ - v CMP *(pt + yo + so) && \ - v CMP *(pt - yo + so) && \ - v CMP *(pt + yo + xo + so) && \ - v CMP *(pt + yo - xo + so) && \ - v CMP *(pt - yo + xo + so) && \ - v CMP *(pt - yo - xo + so) && \ - \ - v CMP *(pt + xo - so) && \ - v CMP *(pt - xo - so) && \ - v CMP *(pt + yo - so) && \ - v CMP *(pt - yo - so) && \ - v CMP *(pt + yo + xo - so) && \ - v CMP *(pt + yo - xo - so) && \ - v CMP *(pt - yo + xo - so) && \ - v CMP *(pt - yo - xo - so) ) - - if (CHECK_NEIGHBORS(>,+) || - CHECK_NEIGHBORS(<,-) ) { - - /* make room for more keypoints */ - if (f->nkeys >= f->keys_res) { - f->keys_res += 500 ; - if (f->keys) { - f->keys = vl_realloc (f->keys, - f->keys_res * - sizeof(VlSiftKeypoint)) ; - } else { - f->keys = vl_malloc (f->keys_res * - sizeof(VlSiftKeypoint)) ; - } - } - - k = f->keys + (f->nkeys ++) ; - - k-> ix = x ; - k-> iy = y ; - k-> is = s ; - } - pt += 1 ; - } - pt += 2 ; - } - pt += 2 * yo ; - } - - /* ----------------------------------------------------------------- - * Refine local maxima - * -------------------------------------------------------------- */ - - /* this pointer is used to write the keypoints back */ - k = f->keys ; - - for (i = 0 ; i < f->nkeys ; ++i) { - - int x = f-> keys [i] .ix ; - int y = f-> keys [i] .iy ; - int s = f-> keys [i]. is ; - - double Dx=0,Dy=0,Ds=0,Dxx=0,Dyy=0,Dss=0,Dxy=0,Dxs=0,Dys=0 ; - double A [3*3], b [3] ; - - int dx = 0 ; - int dy = 0 ; - - int iter, i, j ; - - for (iter = 0 ; iter < 5 ; ++iter) { - - x += dx ; - y += dy ; - - pt = dog - + xo * x - + yo * y - + so * (s - s_min) ; - - /** @brief Index GSS @internal */ -#define at(dx,dy,ds) (*( pt + (dx)*xo + (dy)*yo + (ds)*so)) - - /** @brief Index matrix A @internal */ -#define Aat(i,j) (A[(i)+(j)*3]) - - /* compute the gradient */ - Dx = 0.5 * (at(+1,0,0) - at(-1,0,0)) ; - Dy = 0.5 * (at(0,+1,0) - at(0,-1,0)); - Ds = 0.5 * (at(0,0,+1) - at(0,0,-1)) ; - - /* compute the Hessian */ - Dxx = (at(+1,0,0) + at(-1,0,0) - 2.0 * at(0,0,0)) ; - Dyy = (at(0,+1,0) + at(0,-1,0) - 2.0 * at(0,0,0)) ; - Dss = (at(0,0,+1) + at(0,0,-1) - 2.0 * at(0,0,0)) ; - - Dxy = 0.25 * ( at(+1,+1,0) + at(-1,-1,0) - at(-1,+1,0) - at(+1,-1,0) ) ; - Dxs = 0.25 * ( at(+1,0,+1) + at(-1,0,-1) - at(-1,0,+1) - at(+1,0,-1) ) ; - Dys = 0.25 * ( at(0,+1,+1) + at(0,-1,-1) - at(0,-1,+1) - at(0,+1,-1) ) ; - - /* solve linear system ....................................... */ - Aat(0,0) = Dxx ; - Aat(1,1) = Dyy ; - Aat(2,2) = Dss ; - Aat(0,1) = Aat(1,0) = Dxy ; - Aat(0,2) = Aat(2,0) = Dxs ; - Aat(1,2) = Aat(2,1) = Dys ; - - b[0] = - Dx ; - b[1] = - Dy ; - b[2] = - Ds ; - - /* Gauss elimination */ - for(j = 0 ; j < 3 ; ++j) { - double maxa = 0 ; - double maxabsa = 0 ; - int maxi = -1 ; - double tmp ; - - /* look for the maximally stable pivot */ - for (i = j ; i < 3 ; ++i) { - double a = Aat (i,j) ; - double absa = vl_abs_d (a) ; - if (absa > maxabsa) { - maxa = a ; - maxabsa = absa ; - maxi = i ; - } - } - - /* if singular give up */ - if (maxabsa < 1e-10f) { - b[0] = 0 ; - b[1] = 0 ; - b[2] = 0 ; - break ; - } - - i = maxi ; - - /* swap j-th row with i-th row and normalize j-th row */ - for(jj = j ; jj < 3 ; ++jj) { - tmp = Aat(i,jj) ; Aat(i,jj) = Aat(j,jj) ; Aat(j,jj) = tmp ; - Aat(j,jj) /= maxa ; - } - tmp = b[j] ; b[j] = b[i] ; b[i] = tmp ; - b[j] /= maxa ; - - /* elimination */ - for (ii = j+1 ; ii < 3 ; ++ii) { - double x = Aat(ii,j) ; - for (jj = j ; jj < 3 ; ++jj) { - Aat(ii,jj) -= x * Aat(j,jj) ; - } - b[ii] -= x * b[j] ; - } - } - - /* backward substitution */ - for (i = 2 ; i > 0 ; --i) { - double x = b[i] ; - for (ii = i-1 ; ii >= 0 ; --ii) { - b[ii] -= x * Aat(ii,i) ; - } - } - - /* .......................................................... */ - /* If the translation of the keypoint is big, move the keypoint - * and re-iterate the computation. Otherwise we are all set. - */ - - dx= ((b[0] > 0.6 && x < w - 2) ? 1 : 0) - + ((b[0] < -0.6 && x > 1 ) ? -1 : 0) ; - - dy= ((b[1] > 0.6 && y < h - 2) ? 1 : 0) - + ((b[1] < -0.6 && y > 1 ) ? -1 : 0) ; - - if (dx == 0 && dy == 0) break ; - } - - /* check threshold and other conditions */ - { - double val = at(0,0,0) - + 0.5 * (Dx * b[0] + Dy * b[1] + Ds * b[2]) ; - double score = (Dxx+Dyy)*(Dxx+Dyy) / (Dxx*Dyy - Dxy*Dxy) ; - double xn = x + b[0] ; - double yn = y + b[1] ; - double sn = s + b[2] ; - - vl_bool good = - vl_abs_d (val) > tp && - score < (te+1)*(te+1)/te && - score >= 0 && - vl_abs_d (b[0]) < 1.5 && - vl_abs_d (b[1]) < 1.5 && - vl_abs_d (b[2]) < 1.5 && - xn >= 0 && - xn <= w - 1 && - yn >= 0 && - yn <= h - 1 && - sn >= s_min && - sn <= s_max ; - - if (good) { - k-> o = f->o_cur ; - k-> ix = x ; - k-> iy = y ; - k-> is = s ; - k-> s = sn ; - k-> x = xn * xper ; - k-> y = yn * xper ; - k-> sigma = f->sigma0 * pow (2.0, sn/f->S) * xper ; - ++ k ; - } - - } /* done checking */ - } /* next keypoint to refine */ - - /* update keypoint count */ - f-> nkeys = (int)(k - f->keys) ; -} - - -/** ------------------------------------------------------------------ - ** @internal - ** @brief Update gradients to current GSS octave - ** - ** @param f SIFT filter. - ** - ** The function makes sure that the gradient buffer is up-to-date - ** with the current GSS data. - ** - ** @remark The minimum octave size is 2x2xS. - **/ - -static void -update_gradient (VlSiftFilt *f) -{ - int s_min = f->s_min ; - int s_max = f->s_max ; - int w = vl_sift_get_octave_width (f) ; - int h = vl_sift_get_octave_height (f) ; - int const xo = 1 ; - int const yo = w ; - int const so = h * w ; - int y, s ; - - if (f->grad_o == f->o_cur) return ; - - for (s = s_min + 1 ; - s <= s_max - 2 ; ++ s) { - - vl_sift_pix *src, *end, *grad, gx, gy ; - -#define SAVE_BACK \ - *grad++ = vl_fast_sqrt_f (gx*gx + gy*gy) ; \ - *grad++ = vl_mod_2pi_f (vl_fast_atan2_f (gy, gx) + 2*VL_PI) ; \ - ++src ; \ - - src = vl_sift_get_octave (f,s) ; - grad = f->grad + 2 * so * (s - s_min -1) ; - - /* first pixel of the first row */ - gx = src[+xo] - src[0] ; - gy = src[+yo] - src[0] ; - SAVE_BACK ; - - /* middle pixels of the first row */ - end = (src - 1) + w - 1 ; - while (src < end) { - gx = 0.5 * (src[+xo] - src[-xo]) ; - gy = src[+yo] - src[0] ; - SAVE_BACK ; - } - - /* last pixel of the first row */ - gx = src[0] - src[-xo] ; - gy = src[+yo] - src[0] ; - SAVE_BACK ; - - for (y = 1 ; y < h -1 ; ++y) { - - /* first pixel of the middle rows */ - gx = src[+xo] - src[0] ; - gy = 0.5 * (src[+yo] - src[-yo]) ; - SAVE_BACK ; - - /* middle pixels of the middle rows */ - end = (src - 1) + w - 1 ; - while (src < end) { - gx = 0.5 * (src[+xo] - src[-xo]) ; - gy = 0.5 * (src[+yo] - src[-yo]) ; - SAVE_BACK ; - } - - /* last pixel of the middle row */ - gx = src[0] - src[-xo] ; - gy = 0.5 * (src[+yo] - src[-yo]) ; - SAVE_BACK ; - } - - /* first pixel of the last row */ - gx = src[+xo] - src[0] ; - gy = src[ 0] - src[-yo] ; - SAVE_BACK ; - - /* middle pixels of the last row */ - end = (src - 1) + w - 1 ; - while (src < end) { - gx = 0.5 * (src[+xo] - src[-xo]) ; - gy = src[0] - src[-yo] ; - SAVE_BACK ; - } - - /* last pixel of the last row */ - gx = src[0] - src[-xo] ; - gy = src[0] - src[-yo] ; - SAVE_BACK ; - } - f->grad_o = f->o_cur ; -} - -/** ------------------------------------------------------------------ - ** @brief Calculate the keypoint orientation(s) - ** - ** @param f SIFT filter. - ** @param angles orientations (output). - ** @param k keypoint. - ** - ** The function computes the orientation(s) of the keypoint @a k. - ** The function returns the number of orientations found (up to - ** four). The orientations themselves are written to the vector @a - ** angles. - ** - ** @remark The function requires the keypoint octave @a k->o to be - ** equal to the filter current octave ::vl_sift_get_octave. If this - ** is not the case, the function returns zero orientations. - ** - ** @remark The function requires the keypoint scale level @c k->s to - ** be in the range @c s_min+1 and @c s_max-2 (where usually @c - ** s_min=0 and @c s_max=S+2). If this is not the case, the function - ** returns zero orientations. - ** - ** @return number of orientations found. - **/ - -VL_EXPORT -int -vl_sift_calc_keypoint_orientations (VlSiftFilt *f, - double angles [4], - VlSiftKeypoint const *k) -{ - double const winf = 1.5 ; - double xper = pow (2.0, f->o_cur) ; - - int w = f-> octave_width ; - int h = f-> octave_height ; - int const xo = 2 ; /* x-stride */ - int const yo = 2 * w ; /* y-stride */ - int const so = 2 * w * h ; /* s-stride */ - double x = k-> x / xper ; - double y = k-> y / xper ; - double sigma = k-> sigma / xper ; - - int xi = (int) (x + 0.5) ; - int yi = (int) (y + 0.5) ; - int si = k-> is ; - - double const sigmaw = winf * sigma ; - int W = VL_MAX(floor (3.0 * sigmaw), 1) ; - - int nangles= 0 ; - - enum {nbins = 36} ; - - double hist [nbins], maxh ; - vl_sift_pix const * pt ; - int xs, ys, iter, i ; - - /* skip if the keypoint octave is not current */ - if(k->o != f->o_cur) - return 0 ; - - /* skip the keypoint if it is out of bounds */ - if(xi < 0 || - xi > w - 1 || - yi < 0 || - yi > h - 1 || - si < f->s_min + 1 || - si > f->s_max - 2 ) { - return 0 ; - } - - /* make gradient up to date */ - update_gradient (f) ; - - /* clear histogram */ - memset (hist, 0, sizeof(double) * nbins) ; - - /* compute orientation histogram */ - pt = f-> grad + xo*xi + yo*yi + so*(si - f->s_min - 1) ; - -#undef at -#define at(dx,dy) (*(pt + xo * (dx) + yo * (dy))) - - for(ys = VL_MAX (- W, - yi) ; - ys <= VL_MIN (+ W, h - 1 - yi) ; ++ys) { - - for(xs = VL_MAX (- W, - xi) ; - xs <= VL_MIN (+ W, w - 1 - xi) ; ++xs) { - - - double dx = (double)(xi + xs) - x; - double dy = (double)(yi + ys) - y; - double r2 = dx*dx + dy*dy ; - double wgt, mod, ang, fbin ; - - /* limit to a circular window */ - if (r2 >= W*W + 0.6) continue ; - - wgt = fast_expn (r2 / (2*sigmaw*sigmaw)) ; - mod = *(pt + xs*xo + ys*yo ) ; - ang = *(pt + xs*xo + ys*yo + 1) ; - fbin = nbins * ang / (2 * VL_PI) ; - -#if defined(VL_SIFT_BILINEAR_ORIENTATIONS) - { - int bin = (int) vl_floor_d (fbin - 0.5) ; - double rbin = fbin - bin - 0.5 ; - hist [(bin + nbins) % nbins] += (1 - rbin) * mod * wgt ; - hist [(bin + 1 ) % nbins] += ( rbin) * mod * wgt ; - } -#else - { - int bin = vl_floor_d (fbin) ; - bin = vl_floor_d (nbins * ang / (2*VL_PI)) ; - hist [(bin) % nbins] += mod * wgt ; - } -#endif - - } /* for xs */ - } /* for ys */ - - /* smooth histogram */ - for (iter = 0; iter < 6; iter ++) { - double prev = hist [nbins - 1] ; - double first = hist [0] ; - int i ; - for (i = 0; i < nbins - 1; i++) { - double newh = (prev + hist[i] + hist[(i+1) % nbins]) / 3.0; - prev = hist[i] ; - hist[i] = newh ; - } - hist[i] = (prev + hist[i] + first) / 3.0 ; - } - - /* find the histogram maximum */ - maxh = 0 ; - for (i = 0 ; i < nbins ; ++i) - maxh = VL_MAX (maxh, hist [i]) ; - - /* find peaks within 80% from max */ - nangles = 0 ; - for(i = 0 ; i < nbins ; ++i) { - double h0 = hist [i] ; - double hm = hist [(i - 1 + nbins) % nbins] ; - double hp = hist [(i + 1 + nbins) % nbins] ; - - /* is this a peak? */ - if (h0 > 0.8*maxh && h0 > hm && h0 > hp) { - - /* quadratic interpolation */ - double di = - 0.5 * (hp - hm) / (hp + hm - 2 * h0) ; - double th = 2 * VL_PI * (i + di + 0.5) / nbins ; - angles [ nangles++ ] = th ; - if( nangles == 4 ) - goto enough_angles ; - } - } - enough_angles: - return nangles ; -} - - -/** ------------------------------------------------------------------ - ** @internal - ** @brief Normalizes in norm L_2 a descriptor - ** @param begin begin of histogram. - ** @param end end of histogram. - **/ - -VL_INLINE vl_sift_pix -normalize_histogram -(vl_sift_pix *begin, vl_sift_pix *end) -{ - vl_sift_pix* iter ; - vl_sift_pix norm = 0.0 ; - - for (iter = begin ; iter != end ; ++ iter) - norm += (*iter) * (*iter) ; - - norm = vl_fast_sqrt_f (norm) + VL_EPSILON_F ; - - for (iter = begin; iter != end ; ++ iter) - *iter /= norm ; - - return norm; -} - -/** ------------------------------------------------------------------ - ** @brief Run the SIFT descriptor on raw data - ** - ** @param f SIFT filter. - ** @param grad image gradients. - ** @param descr SIFT descriptor (output). - ** @param width image width. - ** @param height image height. - ** @param x keypoint x coordinate. - ** @param y keypoint y coordinate. - ** @param sigma keypoint scale. - ** @param angle0 keypoint orientation. - ** - ** The function runs the SIFT descriptor on raw data. Here @a image - ** is a 2 x @a width x @a height array (by convention, the memory - ** layout is a s such the first index is the fastest varying - ** one). The first @a width x @a height layer of the array contains - ** the gradient magnitude and the second the gradient angle (in - ** radians, between 0 and @f$ 2\pi @f$). @a x, @a y and @a sigma give - ** the keypoint center and scale respectively. - ** - ** In order to be equivalent to a standard SIFT descriptor the image - ** gradient must be computed at a smoothing level equal to the scale - ** of the keypoint. In practice, the actual SIFT algorithm makes the - ** following additional approximation, which influence the result: - ** - ** - Scale is discretized in @c S levels. - ** - The image is downsampled once for each octave (if you do this, - ** the parameters @a x, @a y and @a sigma must be - ** scaled too). - **/ - -VL_EXPORT -void -vl_sift_calc_raw_descriptor (VlSiftFilt const *f, - vl_sift_pix const* grad, - vl_sift_pix *descr, - int width, int height, - double x, double y, - double sigma, - double angle0) -{ - double const magnif = f-> magnif ; - - int w = width ; - int h = height ; - int const xo = 2 ; /* x-stride */ - int const yo = 2 * w ; /* y-stride */ - - int xi = (int) (x + 0.5) ; - int yi = (int) (y + 0.5) ; - - double const st0 = sin (angle0) ; - double const ct0 = cos (angle0) ; - double const SBP = magnif * sigma + VL_EPSILON_D ; - int const W = floor - (sqrt(2.0) * SBP * (NBP + 1) / 2.0 + 0.5) ; - - int const binto = 1 ; /* bin theta-stride */ - int const binyo = NBO * NBP ; /* bin y-stride */ - int const binxo = NBO ; /* bin x-stride */ - - int bin, dxi, dyi ; - vl_sift_pix const *pt ; - vl_sift_pix *dpt ; - - /* check bounds */ - if(xi < 0 || - xi >= w || - yi < 0 || - yi >= h - 1 ) - return ; - - /* clear descriptor */ - memset (descr, 0, sizeof(vl_sift_pix) * NBO*NBP*NBP) ; - - /* Center the scale space and the descriptor on the current keypoint. - * Note that dpt is pointing to the bin of center (SBP/2,SBP/2,0). - */ - pt = grad + xi*xo + yi*yo ; - dpt = descr + (NBP/2) * binyo + (NBP/2) * binxo ; - -#undef atd -#define atd(dbinx,dbiny,dbint) *(dpt + (dbint)*binto + (dbiny)*binyo + (dbinx)*binxo) - - /* - * Process pixels in the intersection of the image rectangle - * (1,1)-(M-1,N-1) and the keypoint bounding box. - */ - for(dyi = VL_MAX(- W, - yi ) ; - dyi <= VL_MIN(+ W, h - yi -1) ; ++ dyi) { - - for(dxi = VL_MAX(- W, - xi ) ; - dxi <= VL_MIN(+ W, w - xi -1) ; ++ dxi) { - - /* retrieve */ - vl_sift_pix mod = *( pt + dxi*xo + dyi*yo + 0 ) ; - vl_sift_pix angle = *( pt + dxi*xo + dyi*yo + 1 ) ; - vl_sift_pix theta = vl_mod_2pi_f (angle - angle0) ; - - /* fractional displacement */ - vl_sift_pix dx = xi + dxi - x; - vl_sift_pix dy = yi + dyi - y; - - /* get the displacement normalized w.r.t. the keypoint - orientation and extension */ - vl_sift_pix nx = ( ct0 * dx + st0 * dy) / SBP ; - vl_sift_pix ny = (-st0 * dx + ct0 * dy) / SBP ; - vl_sift_pix nt = NBO * theta / (2 * VL_PI) ; - - /* Get the Gaussian weight of the sample. The Gaussian window - * has a standard deviation equal to NBP/2. Note that dx and dy - * are in the normalized frame, so that -NBP/2 <= dx <= - * NBP/2. */ - vl_sift_pix const wsigma = f->windowSize ; - vl_sift_pix win = fast_expn - ((nx*nx + ny*ny)/(2.0 * wsigma * wsigma)) ; - - /* The sample will be distributed in 8 adjacent bins. - We start from the ``lower-left'' bin. */ - int binx = (int)vl_floor_f (nx - 0.5) ; - int biny = (int)vl_floor_f (ny - 0.5) ; - int bint = (int)vl_floor_f (nt) ; - vl_sift_pix rbinx = nx - (binx + 0.5) ; - vl_sift_pix rbiny = ny - (biny + 0.5) ; - vl_sift_pix rbint = nt - bint ; - int dbinx ; - int dbiny ; - int dbint ; - - /* Distribute the current sample into the 8 adjacent bins*/ - for(dbinx = 0 ; dbinx < 2 ; ++dbinx) { - for(dbiny = 0 ; dbiny < 2 ; ++dbiny) { - for(dbint = 0 ; dbint < 2 ; ++dbint) { - - if (binx + dbinx >= - (NBP/2) && - binx + dbinx < (NBP/2) && - biny + dbiny >= - (NBP/2) && - biny + dbiny < (NBP/2) ) { - vl_sift_pix weight = win - * mod - * vl_abs_f (1 - dbinx - rbinx) - * vl_abs_f (1 - dbiny - rbiny) - * vl_abs_f (1 - dbint - rbint) ; - - atd(binx+dbinx, biny+dbiny, (bint+dbint) % NBO) += weight ; - } - } - } - } - } - } - - /* Standard SIFT descriptors are normalized, truncated and normalized again */ - if(1) { - - /* normalize L2 norm */ - vl_sift_pix norm = normalize_histogram (descr, descr + NBO*NBP*NBP) ; - - /* - Set the descriptor to zero if it is lower than our - norm_threshold. We divide by the number of samples in the - descriptor region because the Gaussian window used in the - calculation of the descriptor is not normalized. - */ - int numSamples = - (VL_MIN(W, w - xi -1) - VL_MAX(-W, - xi) + 1) * - (VL_MIN(W, h - yi -1) - VL_MAX(-W, - yi) + 1) ; - - if(f-> norm_thresh && norm < f-> norm_thresh * numSamples) { - for(bin = 0; bin < NBO*NBP*NBP ; ++ bin) - descr [bin] = 0; - } - else { - /* truncate at 0.2. */ - for(bin = 0; bin < NBO*NBP*NBP ; ++ bin) { - if (descr [bin] > 0.2) descr [bin] = 0.2; - } - - /* normalize again. */ - normalize_histogram (descr, descr + NBO*NBP*NBP) ; - } - } -} - -/** ------------------------------------------------------------------ - ** @brief Compute the descriptor of a keypoint - ** - ** @param f SIFT filter. - ** @param descr SIFT descriptor (output) - ** @param k keypoint. - ** @param angle0 keypoint direction. - ** - ** The function computes the SIFT descriptor of the keypoint @a k of - ** orientation @a angle0. The function fills the buffer @a descr - ** which must be large enough to hold the descriptor. - ** - ** The function assumes that the keypoint is on the current octave. - ** If not, it does not do anything. - **/ - -VL_EXPORT -void -vl_sift_calc_keypoint_descriptor (VlSiftFilt *f, - vl_sift_pix *descr, - VlSiftKeypoint const* k, - double angle0) -{ - /* - The SIFT descriptor is a three dimensional histogram of the - position and orientation of the gradient. There are NBP bins for - each spatial dimension and NBO bins for the orientation dimension, - for a total of NBP x NBP x NBO bins. - - The support of each spatial bin has an extension of SBP = 3sigma - pixels, where sigma is the scale of the keypoint. Thus all the - bins together have a support SBP x NBP pixels wide. Since - weighting and interpolation of pixel is used, the support extends - by another half bin. Therefore, the support is a square window of - SBP x (NBP + 1) pixels. Finally, since the patch can be - arbitrarily rotated, we need to consider a window 2W += sqrt(2) x - SBP x (NBP + 1) pixels wide. - */ - - double const magnif = f-> magnif ; - - double xper = pow (2.0, f->o_cur) ; - - int w = f-> octave_width ; - int h = f-> octave_height ; - int const xo = 2 ; /* x-stride */ - int const yo = 2 * w ; /* y-stride */ - int const so = 2 * w * h ; /* s-stride */ - double x = k-> x / xper ; - double y = k-> y / xper ; - double sigma = k-> sigma / xper ; - - int xi = (int) (x + 0.5) ; - int yi = (int) (y + 0.5) ; - int si = k-> is ; - - double const st0 = sin (angle0) ; - double const ct0 = cos (angle0) ; - double const SBP = magnif * sigma + VL_EPSILON_D ; - int const W = floor - (sqrt(2.0) * SBP * (NBP + 1) / 2.0 + 0.5) ; - - int const binto = 1 ; /* bin theta-stride */ - int const binyo = NBO * NBP ; /* bin y-stride */ - int const binxo = NBO ; /* bin x-stride */ - - int bin, dxi, dyi ; - vl_sift_pix const *pt ; - vl_sift_pix *dpt ; - - /* check bounds */ - if(k->o != f->o_cur || - xi < 0 || - xi >= w || - yi < 0 || - yi >= h - 1 || - si < f->s_min + 1 || - si > f->s_max - 2 ) - return ; - - /* synchronize gradient buffer */ - update_gradient (f) ; - - /* VL_PRINTF("W = %d ; magnif = %g ; SBP = %g\n", W,magnif,SBP) ; */ - - /* clear descriptor */ - memset (descr, 0, sizeof(vl_sift_pix) * NBO*NBP*NBP) ; - - /* Center the scale space and the descriptor on the current keypoint. - * Note that dpt is pointing to the bin of center (SBP/2,SBP/2,0). - */ - pt = f->grad + xi*xo + yi*yo + (si - f->s_min - 1)*so ; - dpt = descr + (NBP/2) * binyo + (NBP/2) * binxo ; - -#undef atd -#define atd(dbinx,dbiny,dbint) *(dpt + (dbint)*binto + (dbiny)*binyo + (dbinx)*binxo) - - /* - * Process pixels in the intersection of the image rectangle - * (1,1)-(M-1,N-1) and the keypoint bounding box. - */ - for(dyi = VL_MAX (- W, 1 - yi ) ; - dyi <= VL_MIN (+ W, h - yi - 2) ; ++ dyi) { - - for(dxi = VL_MAX (- W, 1 - xi ) ; - dxi <= VL_MIN (+ W, w - xi - 2) ; ++ dxi) { - - /* retrieve */ - vl_sift_pix mod = *( pt + dxi*xo + dyi*yo + 0 ) ; - vl_sift_pix angle = *( pt + dxi*xo + dyi*yo + 1 ) ; - vl_sift_pix theta = vl_mod_2pi_f (angle - angle0) ; - - /* fractional displacement */ - vl_sift_pix dx = xi + dxi - x; - vl_sift_pix dy = yi + dyi - y; - - /* get the displacement normalized w.r.t. the keypoint - orientation and extension */ - vl_sift_pix nx = ( ct0 * dx + st0 * dy) / SBP ; - vl_sift_pix ny = (-st0 * dx + ct0 * dy) / SBP ; - vl_sift_pix nt = NBO * theta / (2 * VL_PI) ; - - /* Get the Gaussian weight of the sample. The Gaussian window - * has a standard deviation equal to NBP/2. Note that dx and dy - * are in the normalized frame, so that -NBP/2 <= dx <= - * NBP/2. */ - vl_sift_pix const wsigma = f->windowSize ; - vl_sift_pix win = fast_expn - ((nx*nx + ny*ny)/(2.0 * wsigma * wsigma)) ; - - /* The sample will be distributed in 8 adjacent bins. - We start from the ``lower-left'' bin. */ - int binx = (int)vl_floor_f (nx - 0.5) ; - int biny = (int)vl_floor_f (ny - 0.5) ; - int bint = (int)vl_floor_f (nt) ; - vl_sift_pix rbinx = nx - (binx + 0.5) ; - vl_sift_pix rbiny = ny - (biny + 0.5) ; - vl_sift_pix rbint = nt - bint ; - int dbinx ; - int dbiny ; - int dbint ; - - /* Distribute the current sample into the 8 adjacent bins*/ - for(dbinx = 0 ; dbinx < 2 ; ++dbinx) { - for(dbiny = 0 ; dbiny < 2 ; ++dbiny) { - for(dbint = 0 ; dbint < 2 ; ++dbint) { - - if (binx + dbinx >= - (NBP/2) && - binx + dbinx < (NBP/2) && - biny + dbiny >= - (NBP/2) && - biny + dbiny < (NBP/2) ) { - vl_sift_pix weight = win - * mod - * vl_abs_f (1 - dbinx - rbinx) - * vl_abs_f (1 - dbiny - rbiny) - * vl_abs_f (1 - dbint - rbint) ; - - atd(binx+dbinx, biny+dbiny, (bint+dbint) % NBO) += weight ; - } - } - } - } - } - } - - /* Standard SIFT descriptors are normalized, truncated and normalized again */ - if(1) { - - /* Normalize the histogram to L2 unit length. */ - vl_sift_pix norm = normalize_histogram (descr, descr + NBO*NBP*NBP) ; - - /* Set the descriptor to zero if it is lower than our norm_threshold */ - if(f-> norm_thresh && norm < f-> norm_thresh) { - for(bin = 0; bin < NBO*NBP*NBP ; ++ bin) - descr [bin] = 0; - } - else { - - /* Truncate at 0.2. */ - for(bin = 0; bin < NBO*NBP*NBP ; ++ bin) { - if (descr [bin] > 0.2) descr [bin] = 0.2; - } - - /* Normalize again. */ - normalize_histogram (descr, descr + NBO*NBP*NBP) ; - } - } - -} - -/** ------------------------------------------------------------------ - ** @brief Initialize a keypoint from its position and scale - ** - ** @param f SIFT filter. - ** @param k SIFT keypoint (output). - ** @param x x coordinate of the keypoint center. - ** @param y y coordinate of the keypoint center. - ** @param sigma keypoint scale. - ** - ** The function initializes a keypoint structure @a k from - ** the location @a x - ** and @a y and the scale @a sigma of the keypoint. The keypoint structure - ** maps the keypoint to an octave and scale level of the discretized - ** Gaussian scale space, which is required for instance to compute the - ** keypoint SIFT descriptor. - ** - ** @par Algorithm - ** - ** The formula linking the keypoint scale sigma to the octave and - ** scale indexes is - ** - ** @f[ \sigma(o,s) = \sigma_0 2^{o+s/S} @f] - ** - ** In addition to the scale index @e s (which can be fractional due - ** to scale interpolation) a keypoint has an integer scale index @e - ** is too (which is the index of the scale level where it was - ** detected in the DoG scale space). We have the constraints (@ref - ** sift-tech-detector see also the "SIFT detector"): - ** - ** - @e o is integer in the range @f$ [o_\mathrm{min}, - ** o_{\mathrm{min}}+O-1] @f$. - ** - @e is is integer in the range @f$ [s_\mathrm{min}+1, - ** s_\mathrm{max}-2] @f$. This depends on how the scale is - ** determined during detection, and must be so here because - ** gradients are computed only for this range of scale levels - ** and are required for the calculation of the SIFT descriptor. - ** - @f$ |s - is| < 0.5 @f$ for detected keypoints in most cases due - ** to the interpolation technique used during detection. However - ** this is not necessary. - ** - ** Thus octave o represents scales @f$ \{ \sigma(o, s) : s \in - ** [s_\mathrm{min}+1-.5, s_\mathrm{max}-2+.5] \} @f$. Note that some - ** scales may be represented more than once. For each scale, we - ** select the largest possible octave that contains it, i.e. - ** - ** @f[ - ** o(\sigma) - ** = \max \{ o \in \mathbb{Z} : - ** \sigma_0 2^{\frac{s_\mathrm{min}+1-.5}{S}} \leq \sigma \} - ** = \mathrm{floor}\,\left[ - ** \log_2(\sigma / \sigma_0) - \frac{s_\mathrm{min}+1-.5}{S}\right] - ** @f] - ** - ** and then - ** - ** @f[ - ** s(\sigma) = S \left[\log_2(\sigma / \sigma_0) - o(\sigma)\right], - ** \quad - ** is(\sigma) = \mathrm{round}\,(s(\sigma)) - ** @f] - ** - ** In practice, both @f$ o(\sigma) @f$ and @f$ is(\sigma) @f$ are - ** clamped to their feasible range as determined by the SIFT filter - ** parameters. - **/ - -VL_EXPORT -void -vl_sift_keypoint_init (VlSiftFilt const *f, - VlSiftKeypoint *k, - double x, - double y, - double sigma) -{ - int o, ix, iy, is ; - double s, phi, xper ; - - phi = log2 ((sigma + VL_EPSILON_D) / f->sigma0) ; - o = (int)vl_floor_d (phi - ((double) f->s_min + 0.5) / f->S) ; - o = VL_MIN (o, f->o_min + f->O - 1) ; - o = VL_MAX (o, f->o_min ) ; - s = f->S * (phi - o) ; - - is = (int)(s + 0.5) ; - is = VL_MIN(is, f->s_max - 2) ; - is = VL_MAX(is, f->s_min + 1) ; - - xper = pow (2.0, o) ; - ix = (int)(x / xper + 0.5) ; - iy = (int)(y / xper + 0.5) ; - - k -> o = o ; - - k -> ix = ix ; - k -> iy = iy ; - k -> is = is ; - - k -> x = x ; - k -> y = y ; - k -> s = s ; - - k->sigma = sigma ; -} diff --git a/opensfm/src/third_party/vlfeat/vl/sift.h b/opensfm/src/third_party/vlfeat/vl/sift.h deleted file mode 100644 index 50e03f434..000000000 --- a/opensfm/src/third_party/vlfeat/vl/sift.h +++ /dev/null @@ -1,418 +0,0 @@ -/** @file sift.h - ** @brief SIFT (@ref sift) - ** @author Andrea Vedaldi - **/ - -/* -Copyright (C) 2007-12 Andrea Vedaldi and Brian Fulkerson. -All rights reserved. - -This file is part of the VLFeat library and is made available under -the terms of the BSD license (see the COPYING file). -*/ - -#ifndef VL_SIFT_H -#define VL_SIFT_H - -#include -#include "generic.h" - -/** @brief SIFT filter pixel type */ -typedef float vl_sift_pix ; - -/** ------------------------------------------------------------------ - ** @brief SIFT filter keypoint - ** - ** This structure represent a keypoint as extracted by the SIFT - ** filter ::VlSiftFilt. - **/ - -typedef struct _VlSiftKeypoint -{ - int o ; /**< o coordinate (octave). */ - - int ix ; /**< Integer unnormalized x coordinate. */ - int iy ; /**< Integer unnormalized y coordinate. */ - int is ; /**< Integer s coordinate. */ - - float x ; /**< x coordinate. */ - float y ; /**< y coordinate. */ - float s ; /**< s coordinate. */ - float sigma ; /**< scale. */ -} VlSiftKeypoint ; - -/** ------------------------------------------------------------------ - ** @brief SIFT filter - ** - ** This filter implements the SIFT detector and descriptor. - **/ - -typedef struct _VlSiftFilt -{ - double sigman ; /**< nominal image smoothing. */ - double sigma0 ; /**< smoothing of pyramid base. */ - double sigmak ; /**< k-smoothing */ - double dsigma0 ; /**< delta-smoothing. */ - - int width ; /**< image width. */ - int height ; /**< image height. */ - int O ; /**< number of octaves. */ - int S ; /**< number of levels per octave. */ - int o_min ; /**< minimum octave index. */ - int s_min ; /**< minimum level index. */ - int s_max ; /**< maximum level index. */ - int o_cur ; /**< current octave. */ - - vl_sift_pix *temp ; /**< temporary pixel buffer. */ - vl_sift_pix *octave ; /**< current GSS data. */ - vl_sift_pix *dog ; /**< current DoG data. */ - int octave_width ; /**< current octave width. */ - int octave_height ; /**< current octave height. */ - - vl_sift_pix *gaussFilter ; /**< current Gaussian filter */ - double gaussFilterSigma ; /**< current Gaussian filter std */ - vl_size gaussFilterWidth ; /**< current Gaussian filter width */ - - VlSiftKeypoint* keys ;/**< detected keypoints. */ - int nkeys ; /**< number of detected keypoints. */ - int keys_res ; /**< size of the keys buffer. */ - - double peak_thresh ; /**< peak threshold. */ - double edge_thresh ; /**< edge threshold. */ - double norm_thresh ; /**< norm threshold. */ - double magnif ; /**< magnification factor. */ - double windowSize ; /**< size of Gaussian window (in spatial bins) */ - - vl_sift_pix *grad ; /**< GSS gradient data. */ - int grad_o ; /**< GSS gradient data octave. */ - -} VlSiftFilt ; - -/** @name Create and destroy - ** @{ - **/ -VL_EXPORT -VlSiftFilt* vl_sift_new (int width, int height, - int noctaves, int nlevels, - int o_min) ; -VL_EXPORT -void vl_sift_delete (VlSiftFilt *f) ; -/** @} */ - -/** @name Process data - ** @{ - **/ - -VL_EXPORT -int vl_sift_process_first_octave (VlSiftFilt *f, - vl_sift_pix const *im) ; - -VL_EXPORT -int vl_sift_process_next_octave (VlSiftFilt *f) ; - -VL_EXPORT -void vl_sift_detect (VlSiftFilt *f) ; - -VL_EXPORT -int vl_sift_calc_keypoint_orientations (VlSiftFilt *f, - double angles [4], - VlSiftKeypoint const*k); -VL_EXPORT -void vl_sift_calc_keypoint_descriptor (VlSiftFilt *f, - vl_sift_pix *descr, - VlSiftKeypoint const* k, - double angle) ; - -VL_EXPORT -void vl_sift_calc_raw_descriptor (VlSiftFilt const *f, - vl_sift_pix const* image, - vl_sift_pix *descr, - int widht, int height, - double x, double y, - double s, double angle0) ; - -VL_EXPORT -void vl_sift_keypoint_init (VlSiftFilt const *f, - VlSiftKeypoint *k, - double x, - double y, - double sigma) ; -/** @} */ - -/** @name Retrieve data and parameters - ** @{ - **/ -VL_INLINE int vl_sift_get_octave_index (VlSiftFilt const *f) ; -VL_INLINE int vl_sift_get_noctaves (VlSiftFilt const *f) ; -VL_INLINE int vl_sift_get_octave_first (VlSiftFilt const *f) ; -VL_INLINE int vl_sift_get_octave_width (VlSiftFilt const *f) ; -VL_INLINE int vl_sift_get_octave_height (VlSiftFilt const *f) ; -VL_INLINE int vl_sift_get_nlevels (VlSiftFilt const *f) ; -VL_INLINE int vl_sift_get_nkeypoints (VlSiftFilt const *f) ; -VL_INLINE double vl_sift_get_peak_thresh (VlSiftFilt const *f) ; -VL_INLINE double vl_sift_get_edge_thresh (VlSiftFilt const *f) ; -VL_INLINE double vl_sift_get_norm_thresh (VlSiftFilt const *f) ; -VL_INLINE double vl_sift_get_magnif (VlSiftFilt const *f) ; -VL_INLINE double vl_sift_get_window_size (VlSiftFilt const *f) ; - -VL_INLINE vl_sift_pix *vl_sift_get_octave (VlSiftFilt const *f, int s) ; -VL_INLINE VlSiftKeypoint const *vl_sift_get_keypoints (VlSiftFilt const *f) ; -/** @} */ - -/** @name Set parameters - ** @{ - **/ -VL_INLINE void vl_sift_set_peak_thresh (VlSiftFilt *f, double t) ; -VL_INLINE void vl_sift_set_edge_thresh (VlSiftFilt *f, double t) ; -VL_INLINE void vl_sift_set_norm_thresh (VlSiftFilt *f, double t) ; -VL_INLINE void vl_sift_set_magnif (VlSiftFilt *f, double m) ; -VL_INLINE void vl_sift_set_window_size (VlSiftFilt *f, double m) ; -/** @} */ - -/* ------------------------------------------------------------------- - * Inline functions implementation - * ---------------------------------------------------------------- */ - -/** ------------------------------------------------------------------ - ** @brief Get current octave index. - ** @param f SIFT filter. - ** @return index of the current octave. - **/ - -VL_INLINE int -vl_sift_get_octave_index (VlSiftFilt const *f) -{ - return f-> o_cur ; -} - -/** ------------------------------------------------------------------ - ** @brief Get number of octaves. - ** @param f SIFT filter. - ** @return number of octaves. - **/ - -VL_INLINE int -vl_sift_get_noctaves (VlSiftFilt const *f) -{ - return f-> O ; -} - -/**------------------------------------------------------------------- - ** @brief Get first octave. - ** @param f SIFT filter. - ** @return index of the first octave. - **/ - -VL_INLINE int -vl_sift_get_octave_first (VlSiftFilt const *f) -{ - return f-> o_min ; -} - -/** ------------------------------------------------------------------ - ** @brief Get current octave width - ** @param f SIFT filter. - ** @return current octave width. - **/ - -VL_INLINE int -vl_sift_get_octave_width (VlSiftFilt const *f) -{ - return f-> octave_width ; -} - -/** ------------------------------------------------------------------ - ** @brief Get current octave height - ** @param f SIFT filter. - ** @return current octave height. - **/ - -VL_INLINE int -vl_sift_get_octave_height (VlSiftFilt const *f) -{ - return f-> octave_height ; -} - -/** ------------------------------------------------------------------ - ** @brief Get current octave data - ** @param f SIFT filter. - ** @param s level index. - ** - ** The level index @a s ranges in the interval s_min = -1 - ** and s_max = S + 2, where @c S is the number of levels - ** per octave. - ** - ** @return pointer to the octave data for level @a s. - **/ - -VL_INLINE vl_sift_pix * -vl_sift_get_octave (VlSiftFilt const *f, int s) -{ - int w = vl_sift_get_octave_width (f) ; - int h = vl_sift_get_octave_height (f) ; - return f->octave + w * h * (s - f->s_min) ; -} - -/** ------------------------------------------------------------------ - ** @brief Get number of levels per octave - ** @param f SIFT filter. - ** @return number of leves per octave. - **/ - -VL_INLINE int -vl_sift_get_nlevels (VlSiftFilt const *f) -{ - return f-> S ; -} - -/** ------------------------------------------------------------------ - ** @brief Get number of keypoints. - ** @param f SIFT filter. - ** @return number of keypoints. - **/ - -VL_INLINE int -vl_sift_get_nkeypoints (VlSiftFilt const *f) -{ - return f-> nkeys ; -} - -/** ------------------------------------------------------------------ - ** @brief Get keypoints. - ** @param f SIFT filter. - ** @return pointer to the keypoints list. - **/ - -VL_INLINE VlSiftKeypoint const * -vl_sift_get_keypoints (VlSiftFilt const *f) -{ - return f-> keys ; -} - -/** ------------------------------------------------------------------ - ** @brief Get peaks treashold - ** @param f SIFT filter. - ** @return threshold ; - **/ - -VL_INLINE double -vl_sift_get_peak_thresh (VlSiftFilt const *f) -{ - return f -> peak_thresh ; -} - -/** ------------------------------------------------------------------ - ** @brief Get edges threshold - ** @param f SIFT filter. - ** @return threshold. - **/ - -VL_INLINE double -vl_sift_get_edge_thresh (VlSiftFilt const *f) -{ - return f -> edge_thresh ; -} - -/** ------------------------------------------------------------------ - ** @brief Get norm threshold - ** @param f SIFT filter. - ** @return threshold. - **/ - -VL_INLINE double -vl_sift_get_norm_thresh (VlSiftFilt const *f) -{ - return f -> norm_thresh ; -} - -/** ------------------------------------------------------------------ - ** @brief Get the magnification factor - ** @param f SIFT filter. - ** @return magnification factor. - **/ - -VL_INLINE double -vl_sift_get_magnif (VlSiftFilt const *f) -{ - return f -> magnif ; -} - -/** ------------------------------------------------------------------ - ** @brief Get the Gaussian window size. - ** @param f SIFT filter. - ** @return standard deviation of the Gaussian window (in spatial bin units). - **/ - -VL_INLINE double -vl_sift_get_window_size (VlSiftFilt const *f) -{ - return f -> windowSize ; -} - - - -/** ------------------------------------------------------------------ - ** @brief Set peaks threshold - ** @param f SIFT filter. - ** @param t threshold. - **/ - -VL_INLINE void -vl_sift_set_peak_thresh (VlSiftFilt *f, double t) -{ - f -> peak_thresh = t ; -} - -/** ------------------------------------------------------------------ - ** @brief Set edges threshold - ** @param f SIFT filter. - ** @param t threshold. - **/ - -VL_INLINE void -vl_sift_set_edge_thresh (VlSiftFilt *f, double t) -{ - f -> edge_thresh = t ; -} - -/** ------------------------------------------------------------------ - ** @brief Set norm threshold - ** @param f SIFT filter. - ** @param t threshold. - **/ - -VL_INLINE void -vl_sift_set_norm_thresh (VlSiftFilt *f, double t) -{ - f -> norm_thresh = t ; -} - -/** ------------------------------------------------------------------ - ** @brief Set the magnification factor - ** @param f SIFT filter. - ** @param m magnification factor. - **/ - -VL_INLINE void -vl_sift_set_magnif (VlSiftFilt *f, double m) -{ - f -> magnif = m ; -} - -/** ------------------------------------------------------------------ - ** @brief Set the Gaussian window size - ** @param f SIFT filter. - ** @param x Gaussian window size (in units of spatial bin). - ** - ** This is the parameter @f$ \hat \sigma_{\text{win}} @f$ of - ** the standard SIFT descriptor @ref sift-tech-descriptor-std. - **/ - -VL_INLINE void -vl_sift_set_window_size (VlSiftFilt *f, double x) -{ - f -> windowSize = x ; -} - -/* VL_SIFT_H */ -#endif diff --git a/opensfm/src/third_party/vlfeat/vl/slic.c b/opensfm/src/third_party/vlfeat/vl/slic.c deleted file mode 100644 index f6043e0b5..000000000 --- a/opensfm/src/third_party/vlfeat/vl/slic.c +++ /dev/null @@ -1,411 +0,0 @@ -/** @file slic.c - ** @brief SLIC superpixels - Definition - ** @author Andrea Vedaldi - **/ - -/* -Copyright (C) 2007-12 Andrea Vedaldi and Brian Fulkerson. -All rights reserved. - -This file is part of the VLFeat library and is made available under -the terms of the BSD license (see the COPYING file). -*/ - -/** - -@page slic Simple Linear Iterative Clustering (SLIC) -@author Andrea Vedaldi - - -@ref slic.h implements the *Simple Linear Iterative Clustering* (SLIC) -algorithm, an image segmentation method described in @cite{achanta10slic}. - -- @ref slic-overview -- @ref slic-usage -- @ref slic-tech - - -@section slic-overview Overview - - -SLIC @cite{achanta10slic} is a simple and efficient method to decompose -an image in visually homogeneous regions. It is based on a spatially -localized version of k-means clustering. Similar to mean shift or -quick shift (@ref quickshift.h), each pixel is associated to a feature -vector - -@f[ -\Psi(x,y) = -\left[ -\begin{array}{c} -\lambda x \\ -\lambda y \\ -I(x,y) -\end{array} -\right] -@f] - -and then k-means clustering is run on those. As discussed below, the -coefficient @f$ \lambda @f$ balances the spatial and appearance -components of the feature vectors, imposing a degree of spatial -regularization to the extracted regions. - -SLIC takes two parameters: the nominal size of the regions -(superpixels) @c regionSize and the strength of the spatial -regularization @c regularizer. The image is first divided into a grid -with step @c regionSize. The center of each grid tile is then used to -initialize a corresponding k-means (up to a small shift to avoid -image edges). Finally, the k-means centers and clusters are refined by -using the Lloyd algorithm, yielding segmenting the image. As a -further restriction and simplification, during the k-means iterations -each pixel can be assigned to only the 2 x 2 centers -corresponding to grid tiles adjacent to the pixel. - -The parameter @c regularizer sets the trade-off between clustering -appearance and spatial regularization. This is obtained by setting - -@f[ - \lambda = \frac{\mathtt{regularizer}}{\mathtt{regionSize}} -@f] - -in the definition of the feature @f$ \psi(x,y) @f$. - -After the k-means step, SLIC optionally -removes any segment whose area is smaller than a threshld @c minRegionSize -by merging them into larger ones. - - -@section slic-usage Usage from the C library - - -To compute the SLIC superpixels of an image use the function -::vl_slic_segment. - - -@section slic-tech Technical details - - -SLIC starts by dividing the image domain into a regular grid with @f$ -M \times N @f$ tiles, where - -@f[ - M = \lceil \frac{\mathtt{imageWidth}}{\mathtt{regionSize}} \rceil, - \quad - N = \lceil \frac{\mathtt{imageHeight}}{\mathtt{regionSize}} \rceil. -@f] - -A region (superpixel or k-means cluster) is initialized from each grid -center - -@f[ - x_i = \operatorname{round} i \frac{\mathtt{imageWidth}}{\mathtt{regionSize}} - \quad - y_j = \operatorname{round} j \frac{\mathtt{imageWidth}}{\mathtt{regionSize}}. -@f] - -In order to avoid placing these centers on top of image -discontinuities, the centers are then moved in a 3 x 3 -neighbourohood to minimize the edge strength - -@f[ - \operatorname{edge}(x,y) = - \| I(x+1,y) - I(x-1,y) \|_2^2 + - \| I(x,y+1) - I(x,y-1) \|_2^2. -@f] - -Then the regions are obtained by running k-means clustering, started -from the centers - -@f[ - C = \{ \Psi(x_i,y_j), i=0,1,\dots,M-1\ j=0,1,\dots,N-1 \} -@f] - -thus obtained. K-means uses the standard LLoyd algorithm alternating -assigning pixels to the clostest centers a re-estiamting the centers -as the average of the corresponding feature vectors of the pixel -assigned to them. The only difference compared to standard k-means is -that each pixel can be assigned only to the center originated from the -neighbour tiles. This guarantees that there are exactly four -pixel-to-center comparisons at each round of minimization, which -threfore cost @f$ O(n) @f$, where @f$ n @f$ is the number of -superpixels. - -After k-means has converged, SLIC eliminates any connected region whose -area is less than @c minRegionSize pixels. This is done by greedily -merging regions to neighbour ones: the pixels @f$ p @f$ are scanned in -lexicographical order and the corresponding connected components -are visited. If a region has already been visited, it is skipped; if not, -its area is computed and if this is less than @c minRegionSize its label -is changed to the one of a neighbour -region at @f$ p @f$ that has already been vistied (there is always one -except for the very first pixel). - -*/ - -#include "slic.h" -#include "mathop.h" -#include -#include - -/** @brief SLIC superpixel segmentation - ** @param segmentation segmentation. - ** @param image image to segment. - ** @param width image width. - ** @param height image height. - ** @param numChannels number of image channels (depth). - ** @param regionSize nominal size of the regions. - ** @param regularization trade-off between appearance and spatial terms. - ** @param minRegionSize minimum size of a segment. - ** - ** The function computes the SLIC superpixels of the specified image @a image. - ** @a image is a pointer to an @c width by @c height by @c by numChannles array of @c float. - ** @a segmentation is a pointer to a @c width by @c height array of @c vl_uint32. - ** @a segmentation contain the labels of each image pixels, from 0 to - ** the number of regions minus one. - ** - ** @sa @ref slic-overview, @ref slic-tech - **/ - -void -vl_slic_segment (vl_uint32 * segmentation, - float const * image, - vl_size width, - vl_size height, - vl_size numChannels, - vl_size regionSize, - float regularization, - vl_size minRegionSize) -{ - vl_index i, x, y, u, v, k, region ; - vl_uindex iter ; - vl_size const numRegionsX = (vl_size) ceil((double) width / regionSize) ; - vl_size const numRegionsY = (vl_size) ceil((double) height / regionSize) ; - vl_size const numRegions = numRegionsX * numRegionsY ; - vl_size const numPixels = width * height ; - float * centers ; - float * edgeMap ; - float previousEnergy = VL_INFINITY_F ; - float startingEnergy ; - vl_uint32 * masses ; - vl_size const maxNumIterations = 100 ; - - assert(segmentation) ; - assert(image) ; - assert(width >= 1) ; - assert(height >= 1) ; - assert(numChannels >= 1) ; - assert(regionSize >= 1) ; - assert(regularization >= 0) ; - -#define atimage(x,y,k) image[(x)+(y)*width+(k)*width*height] -#define atEdgeMap(x,y) edgeMap[(x)+(y)*width] - - edgeMap = vl_calloc(numPixels, sizeof(float)) ; - masses = vl_malloc(sizeof(vl_uint32) * numPixels) ; - centers = vl_malloc(sizeof(float) * (2 + numChannels) * numRegions) ; - - /* compute edge map (gradient strength) */ - for (k = 0 ; k < (signed)numChannels ; ++k) { - for (y = 1 ; y < (signed)height-1 ; ++y) { - for (x = 1 ; x < (signed)width-1 ; ++x) { - float a = atimage(x-1,y,k) ; - float b = atimage(x+1,y,k) ; - float c = atimage(x,y+1,k) ; - float d = atimage(x,y-1,k) ; - atEdgeMap(x,y) += (a - b) * (a - b) + (c - d) * (c - d) ; - } - } - } - - /* initialize K-means centers */ - i = 0 ; - for (v = 0 ; v < (signed)numRegionsY ; ++v) { - for (u = 0 ; u < (signed)numRegionsX ; ++u) { - vl_index xp ; - vl_index yp ; - vl_index centerx = 0 ; - vl_index centery = 0 ; - float minEdgeValue = VL_INFINITY_F ; - - x = (vl_index) vl_round_d(regionSize * (u + 0.5)) ; - y = (vl_index) vl_round_d(regionSize * (v + 0.5)) ; - - x = VL_MAX(VL_MIN(x, (signed)width-1),0) ; - y = VL_MAX(VL_MIN(y, (signed)height-1),0) ; - - /* search in a 3x3 neighbourhood the smallest edge response */ - for (yp = VL_MAX(0, y-1) ; yp <= VL_MIN((signed)height-1, y+1) ; ++ yp) { - for (xp = VL_MAX(0, x-1) ; xp <= VL_MIN((signed)width-1, x+1) ; ++ xp) { - float thisEdgeValue = atEdgeMap(xp,yp) ; - if (thisEdgeValue < minEdgeValue) { - minEdgeValue = thisEdgeValue ; - centerx = xp ; - centery = yp ; - } - } - } - - /* initialize the new center at this location */ - centers[i++] = (float) centerx ; - centers[i++] = (float) centery ; - for (k = 0 ; k < (signed)numChannels ; ++k) { - centers[i++] = atimage(centerx,centery,k) ; - } - } - } - - /* run k-means iterations */ - for (iter = 0 ; iter < maxNumIterations ; ++iter) { - float factor = regularization / (regionSize * regionSize) ; - float energy = 0 ; - - /* assign pixels to centers */ - for (y = 0 ; y < (signed)height ; ++y) { - for (x = 0 ; x < (signed)width ; ++x) { - vl_index u = floor((double)x / regionSize - 0.5) ; - vl_index v = floor((double)y / regionSize - 0.5) ; - vl_index up, vp ; - float minDistance = VL_INFINITY_F ; - - for (vp = VL_MAX(0, v) ; vp <= VL_MIN((signed)numRegionsY-1, v+1) ; ++vp) { - for (up = VL_MAX(0, u) ; up <= VL_MIN((signed)numRegionsX-1, u+1) ; ++up) { - vl_index region = up + vp * numRegionsX ; - float centerx = centers[(2 + numChannels) * region + 0] ; - float centery = centers[(2 + numChannels) * region + 1] ; - float spatial = (x - centerx) * (x - centerx) + (y - centery) * (y - centery) ; - float appearance = 0 ; - float distance ; - for (k = 0 ; k < (signed)numChannels ; ++k) { - float centerz = centers[(2 + numChannels) * region + k + 2] ; - float z = atimage(x,y,k) ; - appearance += (z - centerz) * (z - centerz) ; - } - distance = appearance + factor * spatial ; - if (minDistance > distance) { - minDistance = distance ; - segmentation[x + y * width] = (vl_uint32)region ; - } - } - } - energy += minDistance ; - } - } - - /* - VL_PRINTF("vl:slic: iter %d: energy: %g\n", iter, energy) ; - */ - - /* check energy termination conditions */ - if (iter == 0) { - startingEnergy = energy ; - } else { - if ((previousEnergy - energy) < 1e-5 * (startingEnergy - energy)) { - break ; - } - } - previousEnergy = energy ; - - /* recompute centers */ - memset(masses, 0, sizeof(vl_uint32) * width * height) ; - memset(centers, 0, sizeof(float) * (2 + numChannels) * numRegions) ; - - for (y = 0 ; y < (signed)height ; ++y) { - for (x = 0 ; x < (signed)width ; ++x) { - vl_index pixel = x + y * width ; - vl_index region = segmentation[pixel] ; - masses[region] ++ ; - centers[region * (2 + numChannels) + 0] += x ; - centers[region * (2 + numChannels) + 1] += y ; - for (k = 0 ; k < (signed)numChannels ; ++k) { - centers[region * (2 + numChannels) + k + 2] += atimage(x,y,k) ; - } - } - } - - for (region = 0 ; region < (signed)numRegions ; ++region) { - float mass = VL_MAX(masses[region], 1e-8) ; - for (i = (2 + numChannels) * region ; - i < (signed)(2 + numChannels) * (region + 1) ; - ++i) { - centers[i] /= mass ; - } - } - } - - vl_free(masses) ; - vl_free(centers) ; - vl_free(edgeMap) ; - - /* elimiate small regions */ - { - vl_uint32 * cleaned = vl_calloc(numPixels, sizeof(vl_uint32)) ; - vl_uindex * segment = vl_malloc(sizeof(vl_uindex) * numPixels) ; - vl_size segmentSize ; - vl_uint32 label ; - vl_uint32 cleanedLabel ; - vl_size numExpanded ; - vl_index const dx [] = {+1, -1, 0, 0} ; - vl_index const dy [] = { 0, 0, +1, -1} ; - vl_index direction ; - vl_index pixel ; - - for (pixel = 0 ; pixel < (signed)numPixels ; ++pixel) { - if (cleaned[pixel]) continue ; - label = segmentation[pixel] ; - numExpanded = 0 ; - segmentSize = 0 ; - segment[segmentSize++] = pixel ; - - /* - find cleanedLabel as the label of an already cleaned - region neihbour of this pixel - */ - cleanedLabel = label + 1 ; - cleaned[pixel] = label + 1 ; - x = pixel % width ; - y = pixel / width ; - for (direction = 0 ; direction < 4 ; ++direction) { - vl_index xp = x + dx[direction] ; - vl_index yp = y + dy[direction] ; - vl_index neighbor = xp + yp * width ; - if (0 <= xp && xp < (signed)width && - 0 <= yp && yp < (signed)height && - cleaned[neighbor]) { - cleanedLabel = cleaned[neighbor] ; - } - } - - /* expand the segment */ - while (numExpanded < segmentSize) { - vl_index open = segment[numExpanded++] ; - x = open % width ; - y = open / width ; - for (direction = 0 ; direction < 4 ; ++direction) { - vl_index xp = x + dx[direction] ; - vl_index yp = y + dy[direction] ; - vl_index neighbor = xp + yp * width ; - if (0 <= xp && xp < (signed)width && - 0 <= yp && yp < (signed)height && - cleaned[neighbor] == 0 && - segmentation[neighbor] == label) { - cleaned[neighbor] = label + 1 ; - segment[segmentSize++] = neighbor ; - } - } - } - - /* change label to cleanedLabel if the semgent is too small */ - if (segmentSize < minRegionSize) { - while (segmentSize > 0) { - cleaned[segment[--segmentSize]] = cleanedLabel ; - } - } - } - /* restore base 0 indexing of the regions */ - for (pixel = 0 ; pixel < (signed)numPixels ; ++pixel) cleaned[pixel] -- ; - - memcpy(segmentation, cleaned, numPixels * sizeof(vl_uint32)) ; - vl_free(cleaned) ; - vl_free(segment) ; - } -} diff --git a/opensfm/src/third_party/vlfeat/vl/slic.h b/opensfm/src/third_party/vlfeat/vl/slic.h deleted file mode 100644 index 1bffcdecf..000000000 --- a/opensfm/src/third_party/vlfeat/vl/slic.h +++ /dev/null @@ -1,30 +0,0 @@ -/** @file slic.h - ** @brief SLIC superpixels (@ref slic) - ** @author Andrea Vedaldi - **/ - -/* -Copyright (C) 2007-12 Andrea Vedaldi and Brian Fulkerson. -All rights reserved. - -This file is part of the VLFeat library and is made available under -the terms of the BSD license (see the COPYING file). -*/ - -#ifndef VL_SLIC_H -#define VL_SLIC_H - -#include "generic.h" - -VL_EXPORT void -vl_slic_segment (vl_uint32 * segmentation, - float const * image, - vl_size width, - vl_size height, - vl_size numChannels, - vl_size regionSize, - float regularization, - vl_size minRegionSize) ; - -/* VL_SLIC_H */ -#endif diff --git a/opensfm/src/third_party/vlfeat/vl/stringop.c b/opensfm/src/third_party/vlfeat/vl/stringop.c deleted file mode 100644 index 5f92df340..000000000 --- a/opensfm/src/third_party/vlfeat/vl/stringop.c +++ /dev/null @@ -1,462 +0,0 @@ -/** @file stringop.c - ** @brief String operations - Definition - ** @author Andrea Vedaldi - **/ - -/* -Copyright (C) 2007-12 Andrea Vedaldi and Brian Fulkerson. -All rights reserved. - -This file is part of the VLFeat library and is made available under -the terms of the BSD license (see the COPYING file). -*/ - -/** -@file stringop.h -@brief String operations -@author Andrea Vedaldi -@tableofcontents - -@ref stringop.h implements basic string operations. All functions that -write to strings use range checking, which makes them safer than some -standard POSIX equivalent (see @ref vl-stringop-err). - -@section vl-stringop-enumeration Enumerations - -@ref stringop.h defines a simple enumeration data type. This is given -by an array of enumeration members, represented by -instances of the ::VlEnumerator strucutre, each storing a -name-value pair. The enumeration must end by a member whose -name is set to @c NULL. - -Use ::vl_enumeration_get and ::vl_enumeration_get_casei -to retrieve an enumeration member by name. - -@section vl-stringop-file-protocols File protocols - -@ref stringop.h defines a few file "protocols" and helps parsing them -from URL-like formatted strings. The supported protocols are: - - - - - - -
File protocols
ProtocolCodeURL prefix
ASCII::VL_PROT_ASCIIascii://
BINARY::VL_PROT_BINARYbinary://
- -@section vl-stringop-err Detecting overflow - -@ref stringop.h functions that write a string to a character buffer take -both the buffer and its size @c n as input. If @c n is not large -enough, the output may be truncated but it is always a null terminated -string (provided that @c n >= 1). Such functions also return the -length of the string that would have been written @c r (which does not -include the terminating null character) had the buffer been large -enough. Hence an overflow can be detected by testing if @c r ->= @c n, @c r can be used to re-allocate a buffer large enough to -contain the result, and the operation can be repeated. -**/ - -#include "stringop.h" - -#include -#include - -/** ------------------------------------------------------------------ - ** @brief Extract the protocol prefix from a string - ** @param string string. - ** @param protocol protocol code (output). - ** @return pointer to the first character after the protocol prefix. - ** - ** The function extracts the prefix of the string @a string - ** terminated by the first occurrence of the @c :// substring (if - ** any). It then matches the suffix terminated by @c :// to the - ** supported @ref vl-stringop-file-protocols protocols. If @c protocol is not - ** @c NULL, the corresponding protocol code is written to @a protocol - ** - ** The function writes to @a protocol the value ::VL_PROT_NONE if no - ** suffix is detected and ::VL_PROT_UNKNOWN if there is a suffix but - ** it cannot be matched to any of the supported protocols. - **/ - -VL_EXPORT char * -vl_string_parse_protocol (char const *string, int *protocol) -{ - char const * cpt ; - int dummy ; - - /* handle the case prot = 0 */ - if (protocol == 0) - protocol = &dummy ; - - /* look for :// */ - cpt = strstr(string, "://") ; - - if (cpt == 0) { - *protocol = VL_PROT_NONE ; - cpt = string ; - } - else { - if (strncmp(string, "ascii", cpt - string) == 0) { - *protocol = VL_PROT_ASCII ; - } - else if (strncmp(string, "bin", cpt - string) == 0) { - *protocol = VL_PROT_BINARY ; - } - else { - *protocol = VL_PROT_UNKNOWN ; - } - cpt += 3 ; - } - return (char*) cpt ; -} - -/** ------------------------------------------------------------------ - ** @brief Get protocol name - ** @param protocol protocol code. - ** @return pointer protocol name string. - ** - ** The function returns a pointer to a string containing the name of - ** the protocol @a protocol (see the @a vl-file-protocols protocols - ** list). If the protocol is unknown the function returns the empty - ** string. - **/ - -VL_EXPORT char const * -vl_string_protocol_name (int protocol) -{ - switch (protocol) { - case VL_PROT_ASCII: - return "ascii" ; - case VL_PROT_BINARY: - return "bin" ; - case VL_PROT_NONE : - return "" ; - default: - return 0 ; - } -} - - -/** ------------------------------------------------------------------ - ** @brief Extract base of file name - ** @param destination destination buffer. - ** @param destinationSize size of destination buffer. - ** @param source input string. - ** @param maxNumStrippedExtensions maximum number of extensions to strip. - ** @return length of the destination string. - ** - ** The function removes the leading path and up to @c - ** maxNumStrippedExtensions trailing extensions from the string @a - ** source and writes the result to the buffer @a destination. - ** - ** The leading path is the longest suffix that ends with either the - ** @c \ or @c / characters. An extension is a string starting with - ** the . character not containing it. For instance, the string @c - ** file.png contains the extension .png and the string @c - ** file.tar.gz contains two extensions (.tar and @c .gz). - ** - ** @sa @ref vl-stringop-err. - **/ - -VL_EXPORT vl_size -vl_string_basename (char * destination, - vl_size destinationSize, - char const * source, - vl_size maxNumStrippedExtensions) -{ - char c ; - vl_uindex k = 0, beg, end ; - - /* find beginning */ - beg = 0 ; - for (k = 0 ; (c = source[k]) ; ++ k) { - if (c == '\\' || c == '/') beg = k + 1 ; - } - - /* find ending */ - end = strlen (source) ; - for (k = end ; k > beg ; --k) { - if (source[k - 1] == '.' && maxNumStrippedExtensions > 0) { - -- maxNumStrippedExtensions ; - end = k - 1 ; - } - } - - return vl_string_copy_sub (destination, destinationSize, - source + beg, source + end) ; -} - -/** ------------------------------------------------------------------ - ** @brief Replace wildcard characters by a string - ** @param destination output buffer. - ** @param destinationSize size of the output buffer. - ** @param source input string. - ** @param wildcardChar wildcard character. - ** @param escapeChar escape character. - ** @param replacement replacement string. - ** - ** The function replaces the occurrence of the specified wildcard - ** character @a wildcardChar by the string @a replacement. The result - ** is written to the buffer @a destination of size @a - ** destinationSize. - ** - ** Wildcard characters may be escaped by preceding them by the @a esc - ** character. More in general, anything following an occurrence of @a - ** esc character is copied verbatim. To disable the escape characters - ** simply set @a esc to 0. - ** - ** @return length of the result. - ** @sa @ref vl-stringop-err. - **/ - -VL_EXPORT vl_size -vl_string_replace_wildcard (char * destination, - vl_size destinationSize, - char const * source, - char wildcardChar, - char escapeChar, - char const * replacement) -{ - char c ; - vl_uindex k = 0 ; - vl_bool escape = 0 ; - - while ((c = *source++)) { - - /* enter escape mode ? */ - if (! escape && c == escapeChar) { - escape = 1 ; - continue ; - } - - /* wildcard or regular? */ - if (! escape && c == wildcardChar) { - char const * repl = replacement ; - while ((c = *repl++)) { - if (destination && k + 1 < destinationSize) { - destination[k] = c ; - } - ++ k ; - } - } - /* regular character */ - else { - if (destination && k + 1 < destinationSize) { - destination[k] = c ; - } - ++ k ; - } - escape = 0 ; - } - - /* add trailing 0 */ - if (destinationSize > 0) { - destination[VL_MIN(k, destinationSize - 1)] = 0 ; - } - return k ; -} - -/** ------------------------------------------------------------------ - ** @brief Copy string - ** @param destination output buffer. - ** @param destinationSize size of the output buffer. - ** @param source string to copy. - ** @return length of the source string. - ** - ** The function copies the string @a source to the buffer @a - ** destination of size @a destinationSize. - ** - ** @sa @ref vl-stringop-err. - **/ - -VL_EXPORT vl_size -vl_string_copy (char * destination, vl_size destinationSize, - char const * source) -{ - char c ; - vl_uindex k = 0 ; - - while ((c = *source++)) { - if (destination && k + 1 < destinationSize) { - destination[k] = c ; - } - ++ k ; - } - - /* finalize */ - if (destinationSize > 0) { - destination[VL_MIN(k, destinationSize - 1)] = 0 ; - } - return k ; -} - -/** ------------------------------------------------------------------ - ** @brief Copy substring - ** @param destination output buffer. - ** @param destinationSize size of output buffer. - ** @param beginning start of the substring. - ** @param end end of the substring. - ** @return length of the destination string. - ** - ** The function copies the substring from at @a beginning to @a end - ** (not included) to the buffer @a destination of size @a - ** destinationSize. If, however, the null character is found before - ** @a end, the substring terminates there. - ** - ** @sa @ref vl-stringop-err. - **/ - -VL_EXPORT vl_size -vl_string_copy_sub (char * destination, - vl_size destinationSize, - char const * beginning, - char const * end) -{ - char c ; - vl_uindex k = 0 ; - - while (beginning < end && (c = *beginning++)) { - if (destination && k + 1 < destinationSize) { - destination[k] = c ; - } - ++ k ; - } - - /* finalize */ - if (destinationSize > 0) { - destination[VL_MIN(k, destinationSize - 1)] = 0 ; - } - return k ; -} - -/** ------------------------------------------------------------------ - ** @brief Search character in reversed order - ** @param beginning pointer to the substring beginning. - ** @param end pointer to the substring end. - ** @param c character to search for. - ** @return pointer to last occurrence of @a c, or 0 if none. - ** - ** The function searches for the last occurrence of the character @a c - ** in the substring from @a beg to @a end (the latter not being included). - **/ - -VL_EXPORT char * -vl_string_find_char_rev (char const *beginning, char const* end, char c) -{ - while (end -- != beginning) { - if (*end == c) { - return (char*) end ; - } - } - return 0 ; -} - -/** ------------------------------------------------------------------ - ** @brief Calculate string length - ** @param string string. - ** @return string length. - **/ - -VL_EXPORT vl_size -vl_string_length (char const *string) -{ - vl_uindex i ; - for (i = 0 ; string[i] ; ++i) ; - return i ; -} - -/** ------------------------------------------------------------------ - ** @brief Compare strings case-insensitive - ** @param string1 fisrt string. - ** @param string2 second string. - ** @return an integer =,<,> 0 if @c string1 =,<,> @c string2 - **/ - -VL_EXPORT int -vl_string_casei_cmp (const char * string1, const char * string2) -{ - while (tolower((char unsigned)*string1) == - tolower((char unsigned)*string2)) - { - if (*string1 == 0) { - return 0 ; - } - string1 ++ ; - string2 ++ ; - } - return - (int)tolower((char unsigned)*string1) - - (int)tolower((char unsigned)*string2) ; -} - -/* ------------------------------------------------------------------- - * VlEnumeration - * ---------------------------------------------------------------- */ - -/** @brief Get a member of an enumeration by name - ** @param enumeration array of ::VlEnumerator objects. - ** @param name the name of the desired member. - ** @return enumerator matching @a name. - ** - ** If @a name is not found in the enumeration, then the value - ** @c NULL is returned. - ** - ** @sa vl-stringop-enumeration - **/ - -VL_EXPORT VlEnumerator * -vl_enumeration_get (VlEnumerator const *enumeration, char const *name) -{ - assert(enumeration) ; - while (enumeration->name) { - if (strcmp(name, enumeration->name) == 0) return (VlEnumerator*)enumeration ; - enumeration ++ ; - } - return NULL ; -} - -/** @brief Get a member of an enumeration by name (case insensitive) - ** @param enumeration array of ::VlEnumerator objects. - ** @param name the name of the desired member. - ** @return enumerator matching @a name. - ** - ** If @a name is not found in the enumeration, then the value - ** @c NULL is returned. @a string is matched case insensitive. - ** - ** @sa vl-stringop-enumeration - **/ - -VL_EXPORT VlEnumerator * -vl_enumeration_get_casei (VlEnumerator const *enumeration, char const *name) -{ - assert(enumeration) ; - while (enumeration->name) { - if (vl_string_casei_cmp(name, enumeration->name) == 0) return (VlEnumerator*)enumeration ; - enumeration ++ ; - } - return NULL ; -} - -/** @brief Get a member of an enumeration by value - ** @param enumeration array of ::VlEnumerator objects. - ** @param value value of the desired member. - ** @return enumerator matching @a value. - ** - ** If @a value is not found in the enumeration, then the value - ** @c NULL is returned. - ** - ** @sa vl-stringop-enumeration - **/ - -VL_EXPORT VlEnumerator * -vl_enumeration_get_by_value (VlEnumerator const *enumeration, vl_index value) -{ - assert(enumeration) ; - while (enumeration->name) { - if (enumeration->value == value) return (VlEnumerator*)enumeration ; - enumeration ++ ; - } - return NULL ; -} - diff --git a/opensfm/src/third_party/vlfeat/vl/stringop.h b/opensfm/src/third_party/vlfeat/vl/stringop.h deleted file mode 100644 index f5f6a524f..000000000 --- a/opensfm/src/third_party/vlfeat/vl/stringop.h +++ /dev/null @@ -1,58 +0,0 @@ -/** @file stringop.h - ** @brief String operations - ** @author Andrea Vedaldi - **/ - -/* -Copyright (C) 2007-12 Andrea Vedaldi and Brian Fulkerson. -All rights reserved. - -This file is part of the VLFeat library and is made available under -the terms of the BSD license (see the COPYING file). -*/ - -#ifndef VL_STRINGOP_H -#define VL_STRINGOP_H - -#include "generic.h" - -/** @brief File protocols */ -enum { - VL_PROT_UNKNOWN = -1, /**< unknown protocol */ - VL_PROT_NONE = 0, /**< no protocol */ - VL_PROT_ASCII, /**< ASCII protocol */ - VL_PROT_BINARY /**< Binary protocol */ -} ; - - -VL_EXPORT vl_size vl_string_copy (char *destination, vl_size destinationSize, char const *source) ; -VL_EXPORT vl_size vl_string_copy_sub (char *destination, vl_size destinationSize, - char const *beginning, char const *end) ; -VL_EXPORT char *vl_string_parse_protocol (char const *string, int *protocol) ; -VL_EXPORT char const *vl_string_protocol_name (int prot) ; -VL_EXPORT vl_size vl_string_basename (char *destination, vl_size destinationSize, - char const *source, vl_size maxNumStrippedExtension) ; -VL_EXPORT vl_size vl_string_replace_wildcard (char * destination, vl_size destinationSize, - char const *src, char wildcardChar, char escapeChar, - char const *replacement) ; -VL_EXPORT char *vl_string_find_char_rev (char const *beginning, char const *end, char c) ; -VL_EXPORT vl_size vl_string_length (char const *string) ; -VL_EXPORT int vl_string_casei_cmp (const char *string1, const char *string2) ; - -/** @name String enumerations - ** @{ */ - -/** @brief Member of an enumeration */ -typedef struct _VlEnumerator -{ - char const *name ; /**< enumeration member name. */ - vl_index value ; /**< enumeration member value. */ -} VlEnumerator ; - -VL_EXPORT VlEnumerator *vl_enumeration_get (VlEnumerator const *enumeration, char const *name) ; -VL_EXPORT VlEnumerator *vl_enumeration_get_casei (VlEnumerator const *enumeration, char const *name) ; -VL_EXPORT VlEnumerator *vl_enumeration_get_by_value (VlEnumerator const *enumeration, vl_index value) ; -/** @} */ - -/* VL_STRINGOP_H */ -#endif diff --git a/opensfm/src/third_party/vlfeat/vl/svm.c b/opensfm/src/third_party/vlfeat/vl/svm.c deleted file mode 100644 index 49af2ebe3..000000000 --- a/opensfm/src/third_party/vlfeat/vl/svm.c +++ /dev/null @@ -1,2172 +0,0 @@ -/** @file svm.c - ** @brief Support Vector Machines (SVM) - Implementation - ** @author Milan Sulc - ** @author Daniele Perrone - ** @author Andrea Vedaldi - **/ - -/* -Copyright (C) 2013 Milan Sulc. -Copyright (C) 2012 Daniele Perrone. -Copyright (C) 2011-13 Andrea Vedaldi. - -All rights reserved. - -This file is part of the VLFeat library and is made available under -the terms of the BSD license (see the COPYING file). -*/ - -/** @file svm.h - ** @see @ref svm. - **/ - -/** - -@page svm Support Vector Machines (SVM) -@author Milan Sulc -@author Daniele Perrone -@author Andrea Vedaldi -@tableofcontents - - -*Support Vector Machines* (SVMs) are one of the most popular types of -discriminate classifiers. VLFeat implements two solvers, SGD and SDCA, -capable of learning linear SVMs on a large scale. These linear solvers -can be combined with explicit feature maps to learn non-linear models -as well. The solver supports a few variants of the standard -SVM formulation, including using loss functions other than the hinge -loss. - -@ref svm-starting demonstrates how to use VLFeat to learn an SVM. -Information on SVMs and the corresponding optimization algorithms as -implemented by VLFeat are given in: - -- @subpage svm-fundamentals - Linear SVMs and their learning. -- @subpage svm-advanced - Loss functions, dual objective, and other details. -- @subpage svm-sgd - The SGD algorithm. -- @subpage svm-sdca - The SDCA algorithm. - - -@section svm-starting Getting started - - -This section demonstrates how to learn an SVM by using VLFeat. SVM -learning is implemented by the ::VlSvm object type. Let's -start by a complete example: - -@code -#include -#include - -int main() -{ - vl_size const numData = 4 ; - vl_size const dimension = 2 ; - double x [dimension * numData] = { - 0.0, -0.5, - 0.6, -0.3, - 0.0, 0.5 - 0.6, 0.0} ; - double y [numData] = {1, 1, -1, 1} ; - double lambda = 0.01; - double * const model ; - double bias ; - - VlSvm * svm = vl_svm_new(VlSvmSolverSgd, - x, dimension, numData, - y, - lambda) ; - vl_svm_train(svm) ; - - model = vl_svm_get_model(svm) ; - bias = vl_svm_get_bias(svm) ; - - printf("model w = [ %f , %f ] , bias b = %f \n", - model[0], - model[1], - bias); - - vl_svm_delete(svm) ; - return 0; -} -@endcode - -This code learns a binary linear SVM using the SGD algorithm on -four two-dimensional points using 0.01 as regularization parameter. - -::VlSvmSolverSdca can be specified in place of ::VlSvmSolverSdca -in orer to use the SDCA algorithm instead. - -Convergence and other diagnostic information can be obtained after -training by using the ::vl_svm_get_statistics function. Algorithms -regularly check for convergence (usally after each pass over the data). -The ::vl_svm_set_diagnostic_function can be used to specify a callback -to be invoked when diagnostic is run. This can be used, for example, -to dump information on the screen as the algorithm progresses. - -Convergence is reached after a maximum number of iterations -(::vl_svm_set_max_num_iterations) or after a given criterion falls -below a threshold (::vl_svm_set_epsilon). The meaning of these -may depend on the specific algorithm (see @ref svm for further details). - -::VlSvm is a quite powerful object. Algorithms only need to perform -inner product and accumulation operation on the data (see @ref svm-advanced). -This is used to abstract from the data type and support almost anything -by speciying just two functions (::vl_svm_set_data_functions). - -A simple interface to this advanced functionality is provided by the -::VlSvmDataset object. This supports natively @c float and @c double -data types, as well as applying on the fly the homogeneous kernel map -(@ref homkermap). This is exemplified in @ref svmdataset-starting. - -*/ - -/** - -@page svm-fundamentals SVM fundamentals -@tableofcontents - - -This page introduces the SVM formulation used in VLFeat. See @ref svm -for more information on VLFeat SVM support. - -Let $ \bx \in \real^d $ be a vector representing, for example, an -image, an audio track, or a fragment of text. Our goal is to design a -*classifier*, i.e. a function that associates to each vector $\bx$ a -positive or negative label based on a desired criterion, for example -the fact that the image contains or not a cat, that the audio track -contains or not English speech, or that the text is or not a -scientific paper. - -The vector $\bx$ is classified by looking at the sign of a *linear -scoring function* $\langle \bx, \bw \rangle$. The goal of learning is -to estimate the parameter $\bw \in \real^d$ in such a way that the -score is positive if the vector $\bx$ belongs to the positive class -and negative otherwise. In fact, in the standard SVM formulation the -the goal is to have a score of *at least 1* in the first case, and of -*at most -1* in the second one, imposing a *margin*. - -The parameter $\bw$ is estimated or *learned* by fitting the scoring -function to a training set of $n$ example pairs $(\bx_i,y_i), -i=1,\dots,n$. Here $y_i \in \{-1,1\}$ are the *ground truth labels* of -the corresponding example vectors. The fit quality is measured by a -*loss function* which, in standard SVMs, is the *hinge loss*: - -\[ -\ell_i(\langle \bw,\bx\rangle) = \max\{0, 1 - y_i \langle \bw,\bx\rangle\}. -\] - -Note that the hinge loss is zero only if the score $\langle -\bw,\bx\rangle$ is at least 1 or at most -1, depending on the label -$y_i$. - -Fitting the training data is usually insufficient. In order for the -scoring function *generalize to future data* as well, it is usually -preferable to trade off the fitting accuracy with the *regularity* of -the learned scoring function $\langle \bx, \bw \rangle$. Regularity in -the standard formulation is measured by the norm of the parameter -vector $\|\bw\|^2$ (see @ref svm-advanced). Averaging the loss on all -training samples and adding to it the regularizer weighed by a -parameter $\lambda$ yields the *regularized loss objective* - -@f{equation}{ -\boxed{\displaystyle -E(\bw) = \frac{\lambda}{2} \left\| \bw \right\|^2 -+ \frac{1}{n} \sum_{i=1}^n \max\{0, 1 - y_i \langle \bw,\bx\rangle\}. -\label{e:svm-primal-hinge} -} -@f} - -Note that this objective function is *convex*, so that there exists a -single global optimum. - -The scoring function $\langle \bx, \bw \rangle$ considered so far has -been linear and unbiased. @ref svm-bias discusses how a bias term can -be added to the SVM and @ref svm-feature-maps shows how non-linear -SVMs can be reduced to the linear case by computing suitable feature -maps. - -@ref svm-learning shows how VLFeat can be used to learn an SVM by -minimizing $E(\bw)$. - - -@section svm-learning Learning - - -Learning an SVM amounts to finding the minimizer $\bw^*$ of the cost -function $E(\bw)$. While there are dozens of methods that can be used -to do so, VLFeat implements two large scale methods, designed to work -with linear SVMs (see @ref svm-feature-maps to go beyond linear): - -- @ref svm-sgd -- @ref svm-sdca - -Using these solvers is exemplified in @ref svm-starting. - - -@section svm-bias Adding a bias - - -It is common to add to the SVM scoring function a *bias term* $b$, and -to consider the score $\langle \bx,\bw \rangle + b$. In practice the -bias term can be crucial to fit the training data optimally, as there -is no reason why the inner products $\langle \bx,\bw \rangle$ should -be naturally centered at zero. - -Some SVM learning algorithms can estimate both $\bw$ and $b$ -directly. However, other algorithms such as SGD and SDCA cannot. In -this case, a simple workaround is to add a constant component $B > 0$ -(we call this constant the *bias multiplier*) to the data, -i.e. consider the extended data vectors: -\[ -\bar \bx = \begin{bmatrix} \bx \\ B \end{bmatrix}, -\quad -\bar \bw = \begin{bmatrix} \bw \\ w_b \end{bmatrix}. -\] -In this manner the scoring function incorporates implicitly a bias $b = B w_b$: -\[ -\langle \bar\bx, \bar\bw \rangle = -\langle \bx, \bw \rangle + B w_b. -\] - -The disadvantage of this reduction is that the term $w_b^2$ becomes -part of the SVM regularizer, which shrinks the bias $b$ towards -zero. This effect can be alleviated by making $B$ sufficiently large, -because in this case $\|\bw\|^2 \gg w_b^2$ and the shrinking effect is -negligible. - -Unfortunately, making $B$ too large makes the problem numerically -unbalanced, so a reasonable trade-off between shrinkage and stability -is generally sought. Typically, a good trade-off is obtained by -normalizing the data to have unitary Euclidean norm and then choosing -$B \in [1, 10]$. - -Specific implementations of SGD and SDCA may provide explicit support -to learn the bias in this manner, but it is important to understand -the implications on speed and accuracy of the learning if this is -done. - - -@section svm-feature-maps Non-linear SVMs and feature maps - - -So far only linear scoring function $\langle \bx,\bw \rangle$ have -been considered. Implicitly, however, this assumes that the objects to -be classified (e.g. images) have been encoded as vectors $\bx$ in a -way that makes linear classification possible. This encoding step can -be made explicit by introducing the *feature map* $\Phi(\bx) \in -\real^d$. Including the feature map yields a scoring function -*non-linear* in $\bx$: -\[ -\bx\in\mathcal{X} \quad\longrightarrow\quad \langle \Phi(\bx), \bw \rangle. -\] -The nature of the input space $\mathcal{X}$ can be arbitrary and might -not have a vector space structure at all. - -The representation or encoding captures a notion of *similarity* -between objects: if two vectors $\Phi(\bx_1)$ and $\Phi(\bx_2)$ are -similar, then their scores will also be similar. Note that choosing a -feature map amounts to incorporating this information in the model -*prior* to learning. - -The relation of feature maps to similarity functions is formalized by -the notion of a *kernel*, a positive definite function $K(\bx,\bx')$ -measuring the similarity of a pair of objects. A feature map defines a -kernel by - -\[ -K(\bx,\bx') = \langle \Phi(\bx),\Phi(\bx') \rangle. -\] - -Viceversa, any kernel function can be represented by a feature map in -this manner, establishing an equivalence. - -So far, all solvers in VLFeat assume that the feature map $\Psi(\bx)$ -can be explicitly computed. Although classically kernels were -introduced to generalize solvers to non-linear SVMs for which a -feature map *cannot* be computed (e.g. for a Gaussian kernel the -feature map is infinite dimensional), in practice using explicit -feature representations allow to use much faster solvers, so it makes -sense to *reverse* this process. -*/ - -/** - -@page svm-advanced Advanced SVM topics -@tableofcontents - - -This page discusses advanced SVM topics. For an introduction to SVMs, -please refer to @ref svm and @ref svm-fundamentals. - - -@section svm-loss-functions Loss functions - - -The SVM formulation given in @ref svm-fundamentals uses the -hinge loss, which is only one of a variety of loss functions that -are often used for SVMs. More in general, one -can consider the objective - -@f{equation}{ -E(\bw) = \frac{\lambda}{2} \left\| \bw \right\|^2 + \frac{1}{n} \sum_{i=1}^n \ell_i(\langle \bw,\bx\rangle). -\label{e:svm-primal} -@f} - -where the loss $\ell_i(z)$ is a convex function of the scalar variable -$z$. Losses differ by: (i) their purpose (some are suitable for -classification, other for regression), (ii) their smoothness (which -usually affects how quickly the SVM objective function can be -minimized), and (iii) their statistical interpretation (for example -the logistic loss can be used to learn logistic models). - -Concrete examples are the: - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
NameLoss $\ell_i(z)$Description
Hinge$\max\{0, 1-y_i z\}$The standard SVM loss function.
Square hinge$\max\{0, 1-y_i z\}^2$The standard SVM loss function, but squared. This version is -smoother and may yield numerically easier problems.
Square or l2$(y_i - z)^2$This loss yields the ridge regression model (l2 regularised least -square).
Linear or l1$|y_i - z|$Another loss suitable for regression, usually more robust but -harder to optimize than the squared one.
Insensitive l1$\max\{0, |y_i - z| - \epsilon\}$.This is a variant of the previous loss, proposed in the original -Support Vector Regression formulation. Differently from the previous -two losses, the insensitivity may yield to a sparse selection of -support vectors.
Logistic$\log(1 + e^{-y_i z})$This corresponds to regularized logisitc regression. The loss can -be seen as a negative log-likelihood: $\ell_i(z) = -\log P[y_i | z] = -- \log \sigma(y_iz/2)$, where $\sigma(z) = e^z/(1 + e^z)$ is the -sigmoid function, mapping a score $z$ to a probability. The $1/2$ -factor in the sigmoid is due to the fact that labels are in $\{-1,1\}$ -rather than $\{0,1\}$ as more common for the standard sigmoid -model.
- - -@section svm-data-abstraction Data abstraction: working with compressed data - - -VLFeat learning algorithms (SGD and SDCA) access the data by means of -only two operations: - -- *inner product*: computing the inner product between the model and -a data vector, i.e. $\langle \bw, \bx \rangle$. -- *accumulation*: summing a data vector to the model, i.e. $\bw -\leftarrow \bw + \beta \bx$. - -VLFeat learning algorithms are *parameterized* in these two -operations. As a consequence, the data can be stored in any format -suitable to the user (e.g. dense matrices, sparse matrices, -block-sparse matrices, disk caches, and so on) provided that these two -operations can be implemented efficiently. Differently from the data, -however, the model vector $\bw$ is represented simply as a dense array -of doubles. This choice is adequate in almost any case. - -A particularly useful aspect of this design choice is that the -training data can be store in *compressed format* (for example by -using product quantization (PQ)). Furthermore, higher-dimensional -encodings such as the homogeneous kernel map (@ref homkermap) and the -intersection kernel map can be *computed on the fly*. Such techniques -are very important when dealing with GBs of data. - - -@section svm-dual-problem Dual problem - - -In optimization, the *dual objective* $D(\balpha)$ of the SVM -objective $E(\bw)$ is of great interest. To obtain the dual objective, -one starts by approximating each loss term from below by a family of planes: -\[ -\ell_i(z) = \sup_{u} (u z - \ell_i^*(u) ), -\qquad -\ell_i^*(u) = \sup_{z} (z u - \ell_i(z) ) -\] -where $\ell_i^*(u)$ is the *dual conjugate* of the loss and gives the -intercept of each approximating plane as a function of the slope. When -the loss function is convex, the approximation is in fact exact. Examples -include: - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
NameLoss $\ell_i(z)$Conjugate loss $\ell_i^*(u)$
Hinge$\max\{0, 1-y_i z\}$\[ -\ell_i^*(u) = -\begin{cases} -y_i u, & -1 \leq y_i u \leq 0, \\ -+\infty, & \text{otherwise} -\end{cases} -\]
Square hinge$\max\{0, 1-y_i z\}^2$\[\ell_i^*(u) = -\begin{cases} -y_i u + \frac{u^2}{4}, & y_i u \leq 0, \\ -+\infty, & \text{otherwise} \\ -\end{cases}\]
Linear or l1$|y_i - z|$\[\ell_i^*(u) = -\begin{cases} -y_i u, & -1 \leq y_i u \leq 1, \\ -+\infty, & \text{otherwise} \\ -\end{cases}\]
Square or l2$(y_i - z)^2$\[\ell_i^*(u)=y_iu + \frac{u^2}{4}\]
Insensitive l1$\max\{0, |y_i - z| - \epsilon\}$.
Logistic$\log(1 + e^{-y_i z})$\[\ell_i^*(u) = - \begin{cases} - (1+u) \log(1+u) - u \log(-u), & -1 \leq y_i u \leq 0, \\ - +\infty, & \text{otherwise} \\ - \end{cases}\] -
- -Since each plane $- z \alpha_i - \ell^*_i(-\alpha_i) \leq \ell_i(z)$ -bounds the loss from below, by substituting in $E(\bw)$ one can write -a lower bound for the SVM objective -\[ -F(\bw,\balpha) = \frac{\lambda}{2} \|\bw\|^2 - -\frac{1}{n}\sum_{i=1}^n (\bw^\top \bx_i\alpha_i + \ell_i^*(-\alpha_i)) -\leq E(\bw). -\] -for each setting of the *dual variables* $\alpha_i$. The dual -objective function $D(\balpha)$ is obtained by minimizing the lower -bound $F(\bw,\balpha)$ w.r.t. to $\bw$: -\[ -D(\balpha) = \inf_{\bw} F(\bw,\balpha) \leq E(\bw). -\] -The minimizer and the dual objective are now easy to find: -\[ -\boxed{\displaystyle -\bw(\balpha) = -\frac{1}{\lambda n} -\sum_{i=1}^n \bx_i \alpha_i = \frac{1}{\lambda n} X\balpha, -\quad -D(\balpha) = - \frac{1}{2\lambda n^2} \balpha^\top X^\top X \balpha + -\frac{1}{n} \sum_{i=1}^n - \ell_i^*(-\alpha_i) -} -\] -where $X = [\bx_1, \dots, \bx_n]$ is the data matrix. Since the dual -is uniformly smaller than the primal, one has the *duality gap* bound: -\[ -D(\balpha) \leq P(\bw^*) \leq P(\bw(\balpha)) -\] -This bound can be used to evaluate how far off $\bw(\balpha)$ is from -the primal minimizer $\bw^*$. In fact, due to convexity, this bound -can be shown to be zero when $\balpha^*$ is the dual maximizer (strong -duality): -\[ -D(\balpha^*) = P(\bw^*) = P(\bw(\balpha^*)), -\quad \bw^* = \bw(\balpha^*). -\] - - -@section svm-C Parametrization in C - - -Often a slightly different form of the SVM objective is considered, -where a parameter $C$ is used to scale the loss instead of the regularizer: - -\[ -E_C(\bw) = \frac{1}{2} \|\bw\|^2 + C \sum_{i=1}^n \ell_i(\langle \bx_i, \bw\rangle) -\] - -This and the objective function $E(\bw)$ in $\lambda$ are equivalent -(proportional) if - -\[ -\lambda = \frac{1}{nC}, -\qquad C = \frac{1}{n\lambda}. -\] up to an overall scaling factor to the problem. - -**/ - -/** - - -@page svm-sdca Stochastic Dual Coordinate Ascent -@tableofcontents - - -This page describes the *Stochastic Dual Coordinate Ascent* (SDCA) -linear SVM solver. Please see @ref svm for an overview of VLFeat SVM -support. - -SDCA maximizes the dual SVM objective (see @ref svm-dual-problem -for a derivation of this expression): - -\[ -D(\balpha) = - \frac{1}{2\lambda n^2} \balpha^\top X^\top X \balpha + -\frac{1}{n} \sum_{i=1}^n - \ell_i^*(-\alpha_i) -\] - -where $X$ is the data matrix. Recall that the primal parameter -corresponding to a given setting of the dual variables is: - -\[ -\bw(\balpha) = \frac{1}{\lambda n} \sum_{i=1}^n \bx_i \alpha_i = \frac{1}{\lambda n} X\balpha -\] - -In its most basic form, the *SDCA algorithm* can be summarized as follows: - -- Let $\balpha_0 = 0$. -- Until the duality gap $P(\bw(\balpha_t)) - D(\balpha_t) < \epsilon$ - - Pick a dual variable $q$ uniformly at random in $1, \dots, n$. - - Maximize the dual with respect to this variable: $\Delta\alpha_q = \max_{\Delta\alpha_q} D(\balpha_t + \Delta\alpha_q \be_q )$ - - Update $\balpha_{t+1} = \balpha_{t} + \be_q \Delta\alpha_q$. - -In VLFeat, we partially use the nomenclature from @cite{shwartz13a-dual} and @cite{hsieh08a-dual}. - - -@section svm-sdca-dual-max Dual coordinate maximization - - -The updated dual objective can be expanded as: -\[ -D(\balpha_t + \be_q \Delta\alpha_q) = -\text{const.} -- \frac{1}{2\lambda n^2} \bx_q^\top \bx_q (\Delta\alpha_q)^2 -- \frac{1}{n} \bx_q^\top \frac{X\alpha_t}{\lambda n} \Delta\alpha_q -- \frac{1}{n} \ell^*_q(- \alpha_q - \Delta\alpha_q) -\] -This can also be written as -@f{align*} -D(\balpha_t + \be_q \Delta\alpha_q) &\propto -- \frac{A}{2} (\Delta\alpha_q)^2 -- B \Delta\alpha_q -- \ell^*_q(- \alpha_q - \Delta\alpha_q), -\\ -A &= \frac{1}{\lambda n} \bx_q^\top \bx_q = \frac{1}{\lambda n} \| \bx_q \|^2, -\\ -B &= \bx_q^\top \frac{X\balpha_t}{\lambda n} = \bx_q^\top \bw_t. -@f} -Maximizing this quantity in the scalar variable $\Delta\balpha$ is usually -not difficult. It is convenient to store and incrementally -update the model $\bw_t$ after the optimal step $\Delta\balpha$ has been -determined: -\[ -\bw_t = \frac{X \balpha_t}{\lambda n}, -\quad \bw_{t+1} = \bw_t + \frac{1}{\lambda n }\bx_q \be_q \Delta\alpha_q. -\] - -For example, consider the hinge loss as given in @ref svm-advanced : -\[ -\ell_q^*(u) = -\begin{cases} -y_q u, & -1 \leq y_q u \leq 0, \\ -+\infty, & \text{otherwise}. -\end{cases} -\] -The maximizer $\Delta\alpha_q$ of the update objective must be in the -range where the conjugate loss is not infinite. Ignoring such bounds, -the update can be obtained by setting the derivative of the objective -to zero, obtaining -\[ -\tilde {\Delta \alpha_q}= \frac{y_q - B}{A}. -\] -Note that $B$ is simply current score associated by the SVM to -the sample $\bx_q$. Incorporating the constraint $-1 \leq - y_q -(\alpha_q + \Delta \alpha_q) \leq 0$, -i.e. $0 \leq y_q (\alpha_q + \Delta \alpha_q) \leq 1$, one obtains the update -\[ -\Delta\alpha_q = y_q \max\{0, \min\{1, y_q (\tilde {\Delta\alpha_q } + \alpha_q)\}\} - \alpha_q. -\] - - -@section svm-sdca-details Implementation details - - -Rather than visiting points completely at random, VLFeat SDCA follows -the best practice of visiting all the points at every epoch (pass -through the data), changing the order of the visit randomly by picking -every time a new random permutation. -**/ - -/** - -@page svm-sgd Stochastic Gradient Descent -@tableofcontents - - -This page describes the *Stochastic Gradient Descent* (SGD) linear SVM -solver. SGD minimizes directly the primal SVM objective (see @ref svm): - -\[ -E(\bw) = \frac{\lambda}{2} \left\| \bw \right\|^2 + \frac{1}{n} \sum_{i=1}^n -\ell_i(\langle \bw,\bx\rangle) -\] - -Firts, rewrite the objective as the average - -\[ -E(\bw) = \frac{1}{n} \sum_{i=1}^n E_i(\bw), -\quad -E_i(\bw) = \frac{\lambda}{2} \left\| \bw \right\|^2 + \ell_i(\langle \bw,\bx\rangle). -\] - -Then SGD performs gradient steps by considering at each iteration -one term $E_i(\bw)$ selected at random from this average. -In its most basic form, the algorithm is: - -- Start with $\bw_0 = 0$. -- For $t=1,2,\dots T$: - - Sample one index $i$ in $1,\dots,n$ uniformly at random. - - Compute a subgradient $\bg_t$ of $E_i(\bw)$ at $\bw_t$. - - Compute the learning rate $\eta_t$. - - Update $\bw_{t+1} = \bw_t - \eta_t \bg_t$. - -Provided that the learning rate $\eta_t$ is chosen correctly, this -simple algorithm is guaranteed to converge to the minimizer $\bw^*$ of -$E$. - - -@section svm-sgd-convergence Convergence and speed - - -The goal of the SGD algorithm is to bring the *primal suboptimality* -below a threshold $\epsilon_P$: -\[ -E(\bw_t) - E(\bw^*) \leq \epsilon_P. -\] - -If the learning rate $\eta_t$ is selected appropriately, SGD can be -shown to converge properly. For example, -@cite{shalev-shwartz07pegasos} show that, since $E(\bw)$ is -$\lambda$-strongly convex, then using the learning rate -\[ -\boxed{\eta_t = \frac{1}{\lambda t}} -\] -guarantees that the algorithm reaches primal-suboptimality $\epsilon_P$ in -\[ -\tilde O\left( \frac{1}{\lambda \epsilon_P} \right). -\] -iterations. This particular SGD variant is sometimes known as PEGASOS -@cite{shalev-shwartz07pegasos} and is the version implemented in -VLFeat. - -The *convergence speed* is not sufficient to tell the *learning speed*, -i.e. how quickly an algorithm can learn an SVM that performs optimally -on the test set. The following two observations -can be used to link convergence speed to learning speed: - -- The regularizer strength is often heuristically selected to be - inversely proportional to the number of training samples: $\lambda = - \lambda_0 /n$. This reflects the fact that with more training data - the prior should count less. -- The primal suboptimality $\epsilon_P$ should be about the same as - the estimation error of the SVM primal. This estimation error is due - to the finite training set size and can be shown to be of the order - of $1/\lambda n = 1 / \lambda_0$. - -Under these two assumptions, PEGASOS can learn a linear SVM in time -$\tilde O(n)$, which is *linear in the number of training -examples*. This fares much better with $O(n^2)$ or worse of non-linear -SVM solvers. - - -@section svm-sgd-bias The bias term - - -Adding a bias $b$ to the SVM scoring function $\langle \bw, \bx -\rangle +b$ is done, as explained in @ref svm-bias, by appending a -constant feature $B$ (the *bias multiplier*) to the data vectors $\bx$ -and a corresponding weight element $w_b$ to the weight vector $\bw$, -so that $b = B w_b$ As noted, the bias multiplier should be -relatively large in order to avoid shrinking the bias towards zero, -but small to make the optimization stable. In particular, setting $B$ -to zero learns an unbiased SVM (::vl_svm_set_bias_multiplier). - -To counter instability caused by a large bias multiplier, the learning -rate of the bias is slowed down by multiplying the overall learning -rate $\eta_t$ by a bias-specific rate coefficient -(::vl_svm_set_bias_learning_rate). - -As a rule of thumb, if the data vectors $\bx$ are $l^2$ normalized (as -they typically should for optimal performance), then a reasonable bias -multiplier is in the range 1 to 10 and a reasonable bias learning rate -is somewhere in the range of the inverse of that (in this manner the -two parts of the extended feature vector $(\bx, B)$ are balanced). - - -@section svm-sgd-starting-iteration Adjusting the learning rate - - -Initially, the learning rate $\eta_t = 1/\lambda t$ is usually too -fast: as usually $\lambda \ll 1$, $\eta_1 \gg 1$. But this is clearly -excessive (for example, without a loss term, the best learning rate at -the first iteration is simply $\eta_1=1$, as this nails the optimum in -one step). Thus, the learning rate formula is modified to be $\eta_t = -1 / \lambda (t + t_0)$, where $t_0 \approx 2/\lambda$, which is -equivalent to start $t_0$ iterations later. In this manner $\eta_1 -\approx 1/2$. - - -@subsection svm-sgd-warm-start Warm start - - -Starting from a given model $\bw$ is easy in SGD as the optimization -runs in the primal. However, the starting iteration index $t$ should -also be advanced for a warm start, as otherwise the initial setting of -$\bw$ is rapidly forgot (::vl_svm_set_model, ::vl_svm_set_bias, -::vl_svm_set_iteration_number). - - -@section svm-sgd-details Implementation details - - -@par "Random sampling of points" - -Rather than visiting points completely at random, VLFeat SDCA follows -the best practice of visiting all the points at every epoch (pass -through the data), changing the order of the visit randomly by picking -every time a new random permutation. - -@par "Factored representation" - -At each iteration, the SGD algorithm updates the vector $\bw$ -(including the additional bias component $w_b$) as $\bw_{t+1} -\leftarrow \bw_t - \lambda \eta_t \bw_t - \eta_t \bg_t$, where -$\eta_t$ is the learning rate. If the subgradient of the loss function -$\bg_t$ is zero at a given iteration, this amounts to simply shrink -$\bw$ towards the origin by multiplying it by the factor $1 - \lambda -\eta_t$. Thus such an iteration can be accelerated significantly by -representing internally $\bw_t = f_t \bu_t$, where $f_t$ is a scaling -factor. Then, the update becomes -\[ - f_{t+1} \bu_{t+1} - = f_{t} \bu_{t} - \lambda \eta_t f_{t} \bu_{t} - \eta_t \bg_t - = (1-\lambda \eta_t) f_{t} \bu_{t} - \eta_t \bg_t. -\] -Setting $f_{t+1} = (1-\lambda \eta_t) f_{t}$, this gives the update -equation for $\bu_t$ -\[ -\bu_{t+1} = \bu_{t} - \frac{\eta_t}{f_{t+1}} \bg_t. -\] -but this step can be skipped whenever $\bg_t$ is equal to zero. - -When the bias component has a different learning rate, this scheme -must be adjusted slightly by adding a separated factor for the bias, -but it is otherwise identical. - - -**/ - -/* - - -@section svm-pegasos PEGASOS - - - -@subsection svm-pegasos-algorithm Algorithm - - -PEGASOS @cite{shalev-shwartz07pegasos} is a stochastic subgradient -optimizer. At the t-th iteration the algorithm: - -- Samples uniformly at random as subset @f$ A_t @f$ of k of -training pairs @f$(x,y)@f$ from the m pairs provided for -training (this subset is called mini batch). -- Computes a subgradient @f$ \nabla_t @f$ of the function @f$ E_t(w) = -\frac{1}{2}\|w\|^2 + \frac{1}{k} \sum_{(x,y) \in A_t} \ell(w;(x,y)) -@f$ (this is the SVM objective function restricted to the -minibatch). -- Compute an intermediate weight vector @f$ w_{t+1/2} @f$ by doing a -step @f$ w_{t+1/2} = w_t - \alpha_t \nabla_t @f$ with learning rate -@f$ \alpha_t = 1/(\eta t) @f$ along the subgradient. Note that the -learning rate is inversely proportional to the iteration number. -- Back projects the weight vector @f$ w_{t+1/2} @f$ on the -hypersphere of radius @f$ \sqrt{\lambda} @f$ to obtain the next -model estimate @f$ w_{t+1} @f$: -@f[ -w_t = \min\{1, \sqrt{\lambda}/\|w\|\} w_{t+1/2}. -@f] -The hypersphere is guaranteed to contain the optimal weight vector -@f$ w^* @f$. - -VLFeat implementation fixes to one the size of the mini batches @f$ k -@f$. - - - -@subsection svm-pegasos-permutation Permutation - - -VLFeat PEGASOS can use a user-defined permutation to decide the order -in which data points are visited (instead of using random -sampling). By specifying a permutation the algorithm is guaranteed to -visit each data point exactly once in each loop. The permutation needs -not to be bijective. This can be used to visit certain data samples -more or less often than others, implicitly reweighting their relative -importance in the SVM objective function. This can be used to balance -the data. - - -@subsection svm-pegasos-kernels Non-linear kernels - - -PEGASOS can be extended to non-linear kernels, but the algorithm is -not particularly efficient in this setting [1]. When possible, it may -be preferable to work with explicit feature maps. - -Let @f$ k(x,y) @f$ be a positive definite kernel. A feature -map is a function @f$ \Psi(x) @f$ such that @f$ k(x,y) = \langle -\Psi(x), \Psi(y) \rangle @f$. Using this representation the non-linear -SVM learning objective function writes: - -@f[ -\min_{w} \frac{\lambda}{2} \|w\|^2 + \frac{1}{m} \sum_{i=1}^n -\ell(w; (\Psi(x)_i,y_i)). -@f] - -Thus the only difference with the linear case is that the feature @f$ -\Psi(x) @f$ is used in place of the data @f$ x @f$. - -@f$ \Psi(x) @f$ can be learned off-line, for instance by using the -incomplete Cholesky decomposition @f$ V^\top V @f$ of the Gram matrix -@f$ K = [k(x_i,x_j)] @f$ (in this case @f$ \Psi(x_i) @f$ is the -i-th columns of V). Alternatively, for additive -kernels (e.g. intersection, Chi2) the explicit feature map computed by -@ref homkermap.h can be used. - -For additive kernels it is also possible to perform the feature -expansion online inside the solver, setting the specific feature map -via ::vl_svmdataset_set_map. This is particular useful to keep the -size of the training data small, when the number of the samples is big -or the memory is limited. -*/ - -#include "svm.h" -#include "mathop.h" -#include - -struct VlSvm_ { - VlSvmSolverType solver ; /**< SVM solver type. */ - - vl_size dimension ; /**< Model dimension. */ - double * model ; /**< Model ($\bw$ vector). */ - double bias ; /**< Bias. */ - double biasMultiplier ; /**< Bias feature multiplier. */ - - /* valid during a run */ - double lambda ; /**< Regularizer multiplier. */ - void const * data ; - vl_size numData ; - double const * labels ; /**< Data labels. */ - double const * weights ; /**< Data weights. */ - - VlSvmDataset * ownDataset ; /**< Optional owned dataset. */ - - VlSvmDiagnosticFunction diagnosticFn ; - void * diagnosticFnData ; - vl_size diagnosticFrequency ; /**< Frequency of diagnostic. */ - - VlSvmLossFunction lossFn ; - VlSvmLossFunction conjugateLossFn ; - VlSvmLossFunction lossDerivativeFn ; - VlSvmDcaUpdateFunction dcaUpdateFn ; - VlSvmInnerProductFunction innerProductFn ; - VlSvmAccumulateFunction accumulateFn ; - - vl_size iteration ; /**< Current iterations number. */ - vl_size maxNumIterations ; /**< Maximum number of iterations. */ - double epsilon ; /**< Stopping threshold. */ - - /* Book keeping */ - VlSvmStatistics statistics ; /**< Statistcs. */ - double * scores ; - - /* SGD specific */ - double biasLearningRate ; /**< Bias learning rate. */ - - /* SDCA specific */ - double * alpha ; /**< Dual variables. */ -} ; - -/* ---------------------------------------------------------------- */ - -/** @brief Create a new object with plain data. - ** @param type type of SMV solver. - ** @param data a pointer to a matrix of data. - ** @param dimension dimension of the SVM model. - ** @param numData number of training samples. - ** @param labels training labels. - ** @param lambda regularizer parameter. - ** @return the new object. - ** - ** @a data has one column per sample, in @c double format. - ** More advanced inputs can be used with ::vl_svm_new_with_dataset - ** and ::vl_svm_new_with_abstract_data. - ** - ** @sa ::vl_svm_delete - **/ - -VlSvm * -vl_svm_new (VlSvmSolverType type, - double const * data, - vl_size dimension, - vl_size numData, - double const * labels, - double lambda) -{ - VlSvmDataset * dataset = vl_svmdataset_new(VL_TYPE_DOUBLE, (void*)data, dimension, numData) ; - VlSvm * self = vl_svm_new_with_dataset (type, dataset, labels, lambda) ; - self->ownDataset = dataset ; - return self ; -} - -/** @brief Create a new object with a dataset. - ** @param solver type of SMV solver. - ** @param dataset SVM dataset object - ** @param labels training samples labels. - ** @param lambda regularizer parameter. - ** @return the new object. - ** @sa ::vl_svm_delete - **/ - -VlSvm * -vl_svm_new_with_dataset (VlSvmSolverType solver, - VlSvmDataset * dataset, - double const * labels, - double lambda) -{ - VlSvm * self = vl_svm_new_with_abstract_data (solver, - dataset, - vl_svmdataset_get_dimension(dataset), - vl_svmdataset_get_num_data(dataset), - labels, - lambda) ; - vl_svm_set_data_functions (self, - vl_svmdataset_get_inner_product_function(dataset), - vl_svmdataset_get_accumulate_function(dataset)) ; - return self ; -} - -/** @brief Create a new object with abstract data. - ** @param solver type of SMV solver. - ** @param data pointer to the data. - ** @param dimension dimension of the SVM model. - ** @param numData num training samples. - ** @param labels training samples labels. - ** @param lambda regularizer parameter. - ** @return the new object. - ** - ** After calling this function, ::vl_svm_set_data_functions *must* - ** be used to setup suitable callbacks for the inner product - ** and accumulation operations (@see svm-data-abstraction). - ** - ** @sa ::vl_svm_delete - **/ - -VlSvm * -vl_svm_new_with_abstract_data (VlSvmSolverType solver, - void * data, - vl_size dimension, - vl_size numData, - double const * labels, - double lambda) -{ - VlSvm * self = vl_calloc(1,sizeof(VlSvm)) ; - - assert(dimension >= 1) ; - assert(numData >= 1) ; - assert(labels) ; - - self->solver = solver ; - - self->dimension = dimension ; - self->model = 0 ; - self->bias = 0 ; - self->biasMultiplier = 1.0 ; - - self->lambda = lambda ; - self->data = data ; - self->numData = numData ; - self->labels = labels ; - - self->diagnosticFrequency = numData ; - self->diagnosticFn = 0 ; - self->diagnosticFnData = 0 ; - - self->lossFn = vl_svm_hinge_loss ; - self->conjugateLossFn = vl_svm_hinge_conjugate_loss ; - self->lossDerivativeFn = vl_svm_hinge_loss_derivative ; - self->dcaUpdateFn = vl_svm_hinge_dca_update ; - - self->innerProductFn = 0 ; - self->accumulateFn = 0 ; - - self->iteration = 0 ; - self->maxNumIterations = VL_MAX((double)numData, vl_ceil_f(10.0 / lambda)) ; - self->epsilon = 1e-2 ; - - /* SGD */ - self->biasLearningRate = 0.01 ; - - /* SDCA */ - self->alpha = 0 ; - - /* allocations */ - self->model = vl_calloc(dimension, sizeof(double)) ; - if (self->model == NULL) goto err_alloc ; - - if (self->solver == VlSvmSolverSdca) { - self->alpha = vl_calloc(self->numData, sizeof(double)) ; - if (self->alpha == NULL) goto err_alloc ; - } - - self->scores = vl_calloc(numData, sizeof(double)) ; - if (self->scores == NULL) goto err_alloc ; - - return self ; - -err_alloc: - if (self->scores) { - vl_free (self->scores) ; - self->scores = 0 ; - } - if (self->model) { - vl_free (self->model) ; - self->model = 0 ; - } - if (self->alpha) { - vl_free (self->alpha) ; - self->alpha = 0 ; - } - return 0 ; -} - -/** @brief Delete object. - ** @param self object. - ** @sa ::vl_svm_new - **/ - -void -vl_svm_delete (VlSvm * self) -{ - if (self->model) { - vl_free (self->model) ; - self->model = 0 ; - } - if (self->alpha) { - vl_free (self->alpha) ; - self->alpha = 0 ; - } - if (self->ownDataset) { - vl_svmdataset_delete(self->ownDataset) ; - self->ownDataset = 0 ; - } - vl_free (self) ; -} - -/* ---------------------------------------------------------------- */ -/* Setters and getters */ -/* ---------------------------------------------------------------- */ - -/** @brief Set the convergence threshold - ** @param self object - ** @param epsilon threshold (non-negative). - **/ - -void vl_svm_set_epsilon (VlSvm *self, double epsilon) -{ - assert(self) ; - assert(epsilon >= 0) ; - self->epsilon = epsilon ; -} - -/** @brief Get the convergence threshold - ** @param self object - ** @return epsilon threshold. - **/ - -double vl_svm_get_epsilon (VlSvm const *self) -{ - assert(self) ; - return self->epsilon ; -} - -/** @brief Set the bias learning rate - ** @param self object - ** @param rate bias learning rate (positive). - ** - ** This parameter applies only to the SGD solver. - **/ - -void vl_svm_set_bias_learning_rate (VlSvm *self, double rate) -{ - assert(self) ; - assert(rate > 0) ; - self->biasLearningRate = rate ; -} - -/** @brief Get the bias leraning rate. - ** @param self object - ** @return bias learning rate. - **/ - -double vl_svm_get_bias_learning_rate (VlSvm const *self) -{ - assert(self) ; - return self->biasLearningRate ; -} - -/** @brief Set the bias multiplier. - ** @param self object - ** @param b bias multiplier. - ** - ** The *bias multiplier* is the value of the constant feature - ** appended to the data vectors to implement the bias (@ref svm-bias). - **/ - -void vl_svm_set_bias_multiplier (VlSvm * self, double b) -{ - assert(self) ; - assert(b >= 0) ; - self->biasMultiplier = b ; -} - -/** @brief Get the bias multiplier. - ** @param self object. - ** @return bias multiplier. - **/ - -double vl_svm_get_bias_multiplier (VlSvm const * self) -{ - assert(self) ; - return self->biasMultiplier ; -} - -/** @brief Set the current iteratio number. - ** @param self object. - ** @param n iteration number. - ** - ** If called before training, - ** this can be used with SGD for a warm start, as the net - ** effect is to slow down the learning rate. - **/ - -void vl_svm_set_iteration_number (VlSvm *self, vl_uindex n) -{ - assert(self) ; - self->iteration = n ; -} - -/** @brief Get the current iteration number. - ** @param self object. - ** @return current iteration number. - **/ - -vl_size vl_svm_get_iteration_number (VlSvm const *self) -{ - assert(self) ; - return self->iteration ; -} - -/** @brief Set the maximum number of iterations. - ** @param self object. - ** @param n maximum number of iterations. - **/ - -void vl_svm_set_max_num_iterations (VlSvm *self, vl_size n) -{ - assert(self) ; - self->maxNumIterations = n ; -} - -/** @brief Get the maximum number of iterations. - ** @param self object. - ** @return maximum number of iterations. - **/ - -vl_size vl_svm_get_max_num_iterations (VlSvm const *self) -{ - assert(self) ; - return self->maxNumIterations ; -} - -/** @brief Set the diagnostic frequency. - ** @param self object. - ** @param f diagnostic frequency (@c >= 1). - ** - ** A diagnostic round (to test for convergence and to printout - ** information) is performed every @a f iterations. - **/ - -void vl_svm_set_diagnostic_frequency (VlSvm *self, vl_size f) -{ - assert(self) ; - assert(f > 0) ; - self->diagnosticFrequency = f ; -} - -/** @brief Get the diagnostic frequency. - ** @param self object. - ** @return diagnostic frequency. - **/ - -vl_size vl_svm_get_diagnostic_frequency (VlSvm const *self) -{ - assert(self) ; - return self->diagnosticFrequency ; -} - -/** @brief Get the SVM solver type. - ** @param self object. - ** @return SVM solver type. - **/ - -VlSvmSolverType vl_svm_get_solver (VlSvm const * self) -{ - assert(self) ; - return self->solver ; -} - -/** @brief Set the regularizer parameter lambda. - ** @param self object. - ** @param lambda regularizer parameter. - ** - ** Note that @a lambda is usually set when calling a - ** constructor for ::VlSvm as certain parameters, such - ** as the maximum number of iterations, are tuned accordingly. - ** This tuning is not performed when @a lambda is changed - ** using this function. - **/ - -void vl_svm_set_lambda (VlSvm * self, double lambda) -{ - assert(self) ; - assert(lambda >= 0) ; - self->lambda = lambda ; -} - -/** @brief Get the regularizer parameter lambda. - ** @param self object. - ** @return diagnostic frequency. - **/ - -double vl_svm_get_lambda (VlSvm const * self) -{ - assert(self) ; - return self->lambda ; -} - -/** @brief Set the data weights. - ** @param self object. - ** @param weights data weights. - ** - ** @a weights must be an array of non-negative weights. - ** The loss of each data point is multiplied by the corresponding - ** weight. - ** - ** Set @a weights to @c NULL to weight the data uniformly by 1 (default). - ** - ** Note that the @a weights array is *not* copied and must be valid - ** througout the object lifetime (unless it is replaced). - **/ - -void vl_svm_set_weights (VlSvm * self, double const *weights) -{ - assert(self) ; - self->weights = weights ; -} - -/** @brief Get the data weights. - ** @param self object. - ** @return data weights. - **/ - -double const *vl_svm_get_weights (VlSvm const * self) -{ - assert(self) ; - return self->weights ; -} - -/* ---------------------------------------------------------------- */ -/* Get data */ -/* ---------------------------------------------------------------- */ - -/** @brief Get the model dimenison. - ** @param self object. - ** @return model dimension. - ** - ** This is the dimensionality of the weight vector $\bw$. - **/ - -vl_size vl_svm_get_dimension (VlSvm *self) -{ - assert(self) ; - return self->dimension ; -} - -/** @brief Get the number of data samples. - ** @param self object. - ** @return model number of data samples - ** - ** This is the dimensionality of the weight vector $\bw$. - **/ - -vl_size vl_svm_get_num_data (VlSvm *self) -{ - assert(self) ; - return self->numData ; -} - -/** @brief Get the SVM model. - ** @param self object. - ** @return model. - ** - ** This is the weight vector $\bw$. - **/ - -double const * vl_svm_get_model (VlSvm const *self) -{ - assert(self) ; - return self->model ; -} - -/** @brief Set the SVM model. - ** @param self object. - ** @param model model. - ** - ** The function *copies* the content of the vector @a model to the - ** internal model buffer. This operation can be used for warm start - ** with the SGD algorithm, but has undefined effect with the SDCA algorithm. - **/ - -void vl_svm_set_model (VlSvm *self, double const *model) -{ - assert(self) ; - assert(model) ; - memcpy(self->model, model, sizeof(double) * vl_svm_get_dimension(self)) ; -} - -/** @brief Set the SVM bias. - ** @param self object. - ** @param b bias. - ** - ** The function set the internal representation of the SVM bias to - ** be equal to @a b (the bias multiplier - ** is applied). The same remark - ** that applies to ::vl_svm_set_model applies here too. - **/ - -void vl_svm_set_bias (VlSvm *self, double b) -{ - assert(self); - if (self->biasMultiplier) { - self->bias = b / self->biasMultiplier ; - } -} - -/** @brief Get the value of the bias. - ** @param self object. - ** @return bias $b$. - ** - ** The value of the bias returned already include the effect of - ** bias mutliplier. - **/ - -double vl_svm_get_bias (VlSvm const *self) -{ - assert(self) ; - return self->bias * self->biasMultiplier ; -} - -/** @brief Get the solver statistics. - ** @param self object. - ** @return statistics. - **/ - -VlSvmStatistics const * vl_svm_get_statistics (VlSvm const *self) -{ - assert(self) ; - return &self->statistics ; -} - -/** @brief Get the scores of the data points. - ** @param self object. - ** @return vector of scores. - ** - ** After training or during the diagnostic callback, - ** this function can be used to retrieve the scores - ** of the points, i.e. $\langle \bx_i, \bw \rangle + b$. - **/ - -double const * vl_svm_get_scores (VlSvm const *self) -{ - return self->scores ; -} - -/* ---------------------------------------------------------------- */ -/* Callbacks */ -/* ---------------------------------------------------------------- */ - -/** @typedef VlSvmDiagnosticFunction - ** @brief SVM diagnostic function pointer. - ** @param svm is an instance of ::VlSvm . - **/ - -/** @typedef VlSvmAccumulateFunction - ** @brief Pointer to a function that adds to @a model the data point at - ** position @a element multiplied by the constant @a multiplier. - **/ - -/** @typedef VlSvmInnerProductFunction - ** @brief Pointer to a function that defines the inner product - ** between the data point at position @a element and the SVM model - **/ - -/** @brief Set the diagnostic function callback - ** @param self object. - ** @param f diagnostic function pointer. - ** @param data pointer to data used by the diagnostic function. - **/ - -void -vl_svm_set_diagnostic_function (VlSvm *self, VlSvmDiagnosticFunction f, void *data) { - self->diagnosticFn = f ; - self->diagnosticFnData = data ; -} - -/** @brief Set the data functions. - ** @param self object. - ** @param inner inner product function. - ** @param acc accumulate function. - ** - ** See @ref svm-data-abstraction. - **/ - -void vl_svm_set_data_functions (VlSvm *self, VlSvmInnerProductFunction inner, VlSvmAccumulateFunction acc) -{ - assert(self) ; - assert(inner) ; - assert(acc) ; - self->innerProductFn = inner ; - self->accumulateFn = acc ; -} - -/** @brief Set the loss function callback. - ** @param self object. - ** @param f loss function callback. - ** - ** Note that setting up a loss requires specifying more than just one - ** callback. See @ref svm-loss-functions for details. - **/ - -void vl_svm_set_loss_function (VlSvm *self, VlSvmLossFunction f) -{ - assert(self) ; - self->lossFn = f ; -} - -/** @brief Set the loss derivative function callback. - ** @copydetails vl_svm_set_loss_function. - **/ - -void vl_svm_set_loss_derivative_function (VlSvm *self, VlSvmLossFunction f) -{ - assert(self) ; - self->lossDerivativeFn = f ; -} - -/** @brief Set the conjugate loss function callback. - ** @copydetails vl_svm_set_loss_function. - **/ - -void vl_svm_set_conjugate_loss_function (VlSvm *self, VlSvmLossFunction f) -{ - assert(self) ; - self->conjugateLossFn = f ; -} - -/** @brief Set the DCA update function callback. - ** @copydetails vl_svm_set_loss_function. - **/ - -void vl_svm_set_dca_update_function (VlSvm *self, VlSvmDcaUpdateFunction f) -{ - assert(self) ; - self->dcaUpdateFn = f ; -} - -/** @brief Set the loss function to one of the default types. - ** @param self object. - ** @param loss type of loss function. - ** @sa @ref svm-loss-functions. - **/ - -void -vl_svm_set_loss (VlSvm *self, VlSvmLossType loss) -{ -#define SETLOSS(x,y) \ -case VlSvmLoss ## x: \ - vl_svm_set_loss_function(self, vl_svm_ ## y ## _loss) ; \ - vl_svm_set_loss_derivative_function(self, vl_svm_ ## y ## _loss_derivative) ; \ - vl_svm_set_conjugate_loss_function(self, vl_svm_ ## y ## _conjugate_loss) ; \ - vl_svm_set_dca_update_function(self, vl_svm_ ## y ## _dca_update) ; \ - break; - - switch (loss) { - SETLOSS(Hinge, hinge) ; - SETLOSS(Hinge2, hinge2) ; - SETLOSS(L1, l1) ; - SETLOSS(L2, l2) ; - SETLOSS(Logistic, logistic) ; - default: - assert(0) ; - } -} - -/* ---------------------------------------------------------------- */ -/* Pre-defined losses */ -/* ---------------------------------------------------------------- */ - -/** @typedef VlSvmLossFunction - ** @brief SVM loss function pointer. - ** @param inner inner product between sample and model $\bw^\top \bx$. - ** @param label sample label $y$. - ** @return value of the loss. - ** - ** The interface is the same for a loss function, its derivative, - ** or the conjugate loss. - ** - ** @sa @ref svm-fundamentals - **/ - -/** @typedef VlSvmDcaUpdateFunction - ** @brief SVM SDCA update function pointer. - ** @param alpha current value of the dual variable. - ** @param inner inner product $\bw^\top \bx$ of the sample with the SVM model. - ** @param norm2 normalization factor $\|\bx\|^2/\lambda n$. - ** @param label label $y$ of the sample. - ** @return incremental update $\Delta\alpha$ of the dual variable. - ** - ** @sa @ref svm-sdca - **/ - -/** @brief SVM hinge loss - ** @copydetails VlSvmLossFunction */ -double -vl_svm_hinge_loss (double inner, double label) -{ - return VL_MAX(1 - label * inner, 0.0); -} - -/** @brief SVM hinge loss derivative - ** @copydetails VlSvmLossFunction */ -double -vl_svm_hinge_loss_derivative (double inner, double label) -{ - if (label * inner < 1.0) { - return - label ; - } else { - return 0.0 ; - } -} - -/** @brief SVM hinge loss conjugate - ** @param u dual variable. - ** @param label label value. - ** @return conjugate loss. - **/ -double -vl_svm_hinge_conjugate_loss (double u, double label) { - double z = label * u ; - if (-1 <= z && z <= 0) { - return label * u ; - } else { - return VL_INFINITY_D ; - } -} - -/** @brief SVM hinge loss DCA update - ** @copydetails VlSvmDcaUpdateFunction */ -double -vl_svm_hinge_dca_update (double alpha, double inner, double norm2, double label) { - double palpha = (label - inner) / norm2 + alpha ; - return label * VL_MAX(0, VL_MIN(1, label * palpha)) - alpha ; -} - -/** @brief SVM square hinge loss - ** @copydetails VlSvmLossFunction */ -double -vl_svm_hinge2_loss (double inner,double label) -{ - double z = VL_MAX(1 - label * inner, 0.0) ; - return z*z ; -} - -/** @brief SVM square hinge loss derivative - ** @copydetails VlSvmLossFunction */ -double -vl_svm_hinge2_loss_derivative (double inner, double label) -{ - if (label * inner < 1.0) { - return 2 * (inner - label) ; - } else { - return 0 ; - } -} - -/** @brief SVM square hinge loss conjugate - ** @copydetails vl_svm_hinge_conjugate_loss */ -double -vl_svm_hinge2_conjugate_loss (double u, double label) { - if (label * u <= 0) { - return (label + u/4) * u ; - } else { - return VL_INFINITY_D ; - } -} - -/** @brief SVM square hinge loss DCA update - ** @copydetails VlSvmDcaUpdateFunction */ -double -vl_svm_hinge2_dca_update (double alpha, double inner, double norm2, double label) { - double palpha = (label - inner - 0.5*alpha) / (norm2 + 0.5) + alpha ; - return label * VL_MAX(0, label * palpha) - alpha ; -} - -/** @brief SVM l1 loss - ** @copydetails VlSvmLossFunction */ -double -vl_svm_l1_loss (double inner,double label) -{ - return vl_abs_d(label - inner) ; -} - -/** @brief SVM l1 loss derivative - ** @copydetails VlSvmLossFunction */ -double -vl_svm_l1_loss_derivative (double inner, double label) -{ - if (label > inner) { - return - 1.0 ; - } else { - return + 1.0 ; - } -} - -/** @brief SVM l1 loss conjugate - ** @copydetails vl_svm_hinge_conjugate_loss */ -double -vl_svm_l1_conjugate_loss (double u, double label) { - if (vl_abs_d(u) <= 1) { - return label*u ; - } else { - return VL_INFINITY_D ; - } -} - -/** @brief SVM l1 loss DCA update - ** @copydetails VlSvmDcaUpdateFunction */ -double -vl_svm_l1_dca_update (double alpha, double inner, double norm2, double label) { - if (vl_abs_d(alpha) <= 1) { - double palpha = (label - inner) / norm2 + alpha ; - return VL_MAX(-1.0, VL_MIN(1.0, palpha)) - alpha ; - } else { - return VL_INFINITY_D ; - } -} - -/** @brief SVM l2 loss - ** @copydetails VlSvmLossFunction */ -double -vl_svm_l2_loss (double inner,double label) -{ - double z = label - inner ; - return z*z ; -} - -/** @brief SVM l2 loss derivative - ** @copydetails VlSvmLossFunction */ -double -vl_svm_l2_loss_derivative (double inner, double label) -{ - return - 2 * (label - inner) ; -} - -/** @brief SVM l2 loss conjugate - ** @copydetails vl_svm_hinge_conjugate_loss */ -double -vl_svm_l2_conjugate_loss (double u, double label) { - return (label + u/4) * u ; -} - -/** @brief SVM l2 loss DCA update - ** @copydetails VlSvmDcaUpdateFunction */ -double -vl_svm_l2_dca_update (double alpha, double inner, double norm2, double label) { - return (label - inner - 0.5*alpha) / (norm2 + 0.5) ; -} - -/** @brief SVM l2 loss - ** @copydetails VlSvmLossFunction */ -double -vl_svm_logistic_loss (double inner,double label) -{ - double z = label * inner ; - if (z >= 0) { - return log(1.0 + exp(-z)) ; - } else { - return -z + log(exp(z) + 1.0) ; - } -} - -/** @brief SVM l2 loss derivative - ** @copydetails VlSvmLossFunction */ -double -vl_svm_logistic_loss_derivative (double inner, double label) -{ - double z = label * inner ; - double t = 1 / (1 + exp(-z)) ; /* this is stable for z << 0 too */ - return label * (t - 1) ; /* = -label exp(-z) / (1 + exp(-z)) */ -} - -VL_INLINE double xlogx(double x) -{ - if (x <= 1e-10) return 0 ; - return x*log(x) ; -} - -/** @brief SVM l2 loss conjugate - ** @copydetails vl_svm_hinge_conjugate_loss */ -double -vl_svm_logistic_conjugate_loss (double u, double label) { - double z = label * u ; - if (-1 <= z && z <= 0) { - return xlogx(-z) + xlogx(1+z) ; - } else { - return VL_INFINITY_D ; - } -} - -/** @brief SVM l2 loss DCA update - ** @copydetails VlSvmDcaUpdateFunction */ -double -vl_svm_logistic_dca_update (double alpha, double inner, double norm2, double label) { - /* - The goal is to solve the problem - - min_delta A/2 delta^2 + B delta + l*(-alpha - delta|y), -1 <= - y (alpha+delta) <= 0 - - where A = norm2, B = inner, and y = label. To simplify the notation, we set - - f(beta) = beta * log(beta) + (1 - beta) * log(1 - beta) - - where beta = y(alpha + delta) such that - - l*(-alpha - delta |y) = f(beta). - - Hence 0 <= beta <= 1, delta = + y beta - alpha. Substituting - - min_beta A/2 beta^2 + y (B - A alpha) beta + f(beta) + const - - The Newton step is then given by - - beta = beta - (A beta + y(B - A alpha) + df) / (A + ddf). - - However, the function is singluar for beta=0 and beta=1 (infinite - first and second order derivatives). Since the function is monotonic - (second derivarive always strictly greater than zero) and smooth, - we canuse bisection to find the zero crossing of the first derivative. - Once one is sufficiently close to the optimum, a one or two Newton - steps are sufficien to land on it with excellent accuracy. - */ - - double df, ddf, der, dder ; - vl_index t ; - - /* bisection */ - double beta1 = 0 ; - double beta2 = 1 ; - double beta = 0.5 ; - - for (t = 0 ; t < 5 ; ++t) { - df = log(beta) - log(1-beta) ; - der = norm2 * beta + label * (inner - norm2*alpha) + df ; - if (der >= 0) { - beta2 = beta ; - } else { - beta1 = beta ; - } - beta = 0.5 * (beta1 + beta2) ; - } - -#if 1 - /* a final Newton step, but not too close to the singularities */ - for (t = 0 ; (t < 2) & (beta > VL_EPSILON_D) & (beta < 1-VL_EPSILON_D) ; ++t) { - df = log(beta) - log(1-beta) ; - ddf = 1 / (beta * (1-beta)) ; - der = norm2 * beta + label * (inner - norm2*alpha) + df ; - dder = norm2 + ddf ; - beta -= der / dder ; - beta = VL_MAX(0, VL_MIN(1, beta)) ; - } -#endif - - return label * beta - alpha ; -} - -/* ---------------------------------------------------------------- */ - -/** @internal @brief Update SVM statistics - ** @param self object. - **/ - -void _vl_svm_update_statistics (VlSvm *self) -{ - vl_size i, k ; - double inner, p ; - - memset(&self->statistics, 0, sizeof(VlSvmStatistics)) ; - - self->statistics.regularizer = self->bias * self->bias ; - for (i = 0; i < self->dimension; i++) { - self->statistics.regularizer += self->model[i] * self->model[i] ; - } - self->statistics.regularizer *= self->lambda * 0.5 ; - - for (k = 0; k < self->numData ; k++) { - p = (self->weights) ? self->weights[k] : 1.0 ; - if (p <= 0) continue ; - inner = self->innerProductFn(self->data, k, self->model) ; - inner += self->bias * self->biasMultiplier ; - self->scores[k] = inner ; - self->statistics.loss += p * self->lossFn(inner, self->labels[k]) ; - if (self->solver == VlSvmSolverSdca) { - - self->statistics.dualLoss -= p * self->conjugateLossFn(- self->alpha[k] / p, self->labels[k]) ; - } - } - - self->statistics.loss /= self->numData ; - self->statistics.objective = self->statistics.regularizer + self->statistics.loss ; - - if (self->solver == VlSvmSolverSdca) { - self->statistics.dualLoss /= self->numData ; - self->statistics.dualObjective = - self->statistics.regularizer + self->statistics.dualLoss ; - self->statistics.dualityGap = self->statistics.objective - self->statistics.dualObjective ; - } -} - -/* ---------------------------------------------------------------- */ -/* Evaluate rather than solve */ -/* ---------------------------------------------------------------- */ - -void _vl_svm_evaluate (VlSvm *self) -{ - double startTime = vl_get_cpu_time () ; - - _vl_svm_update_statistics (self) ; - - self->statistics.elapsedTime = vl_get_cpu_time() - startTime ; - self->statistics.iteration = 0 ; - self->statistics.epoch = 0 ; - self->statistics.status = VlSvmStatusConverged ; - - if (self->diagnosticFn) { - self->diagnosticFn(self, self->diagnosticFnData) ; - } -} - -/* ---------------------------------------------------------------- */ -/* Stochastic Dual Coordinate Ascent Solver */ -/* ---------------------------------------------------------------- */ - -void _vl_svm_sdca_train (VlSvm *self) -{ - double * norm2 ; - vl_index * permutation ; - vl_uindex i, t ; - double inner, delta, multiplier, p ; - - double startTime = vl_get_cpu_time () ; - VlRand * rand = vl_get_rand() ; - - norm2 = (double*) vl_calloc(self->numData, sizeof(double)); - permutation = vl_calloc(self->numData, sizeof(vl_index)) ; - - { - double * buffer = vl_calloc(self->dimension, sizeof(double)) ; - for (i = 0 ; i < (unsigned)self->numData; i++) { - double n2 ; - permutation [i] = i ; - memset(buffer, 0, self->dimension * sizeof(double)) ; - self->accumulateFn (self->data, i, buffer, 1) ; - n2 = self->innerProductFn (self->data, i, buffer) ; - n2 += self->biasMultiplier * self->biasMultiplier ; - norm2[i] = n2 / (self->lambda * self->numData) ; - } - vl_free(buffer) ; - } - - for (t = 0 ; 1 ; ++t) { - - if (t % self->numData == 0) { - /* once a new epoch is reached (all data have been visited), - change permutation */ - vl_rand_permute_indexes(rand, permutation, self->numData) ; - } - - /* pick a sample and compute update */ - i = permutation[t % self->numData] ; - p = (self->weights) ? self->weights[i] : 1.0 ; - if (p > 0) { - inner = self->innerProductFn(self->data, i, self->model) ; - inner += self->bias * self->biasMultiplier ; - delta = p * self->dcaUpdateFn(self->alpha[i] / p, inner, p * norm2[i], self->labels[i]) ; - } else { - delta = 0 ; - } - - /* apply update */ - if (delta != 0) { - self->alpha[i] += delta ; - multiplier = delta / (self->numData * self->lambda) ; - self->accumulateFn(self->data,i,self->model,multiplier) ; - self->bias += self->biasMultiplier * multiplier; - } - - /* call diagnostic occasionally */ - if ((t + 1) % self->diagnosticFrequency == 0 || t + 1 == self->maxNumIterations) { - _vl_svm_update_statistics (self) ; - self->statistics.elapsedTime = vl_get_cpu_time() - startTime ; - self->statistics.iteration = t ; - self->statistics.epoch = t / self->numData ; - - self->statistics.status = VlSvmStatusTraining ; - if (self->statistics.dualityGap < self->epsilon) { - self->statistics.status = VlSvmStatusConverged ; - } - else if (t + 1 == self->maxNumIterations) { - self->statistics.status = VlSvmStatusMaxNumIterationsReached ; - } - - if (self->diagnosticFn) { - self->diagnosticFn(self, self->diagnosticFnData) ; - } - - if (self->statistics.status != VlSvmStatusTraining) { - break ; - } - } - } /* next iteration */ - - vl_free (norm2) ; - vl_free (permutation) ; -} - -/* ---------------------------------------------------------------- */ -/* Stochastic Gradient Descent Solver */ -/* ---------------------------------------------------------------- */ - -void _vl_svm_sgd_train (VlSvm *self) -{ - vl_index * permutation ; - double * scores ; - double * previousScores ; - vl_uindex i, t, k ; - double inner, gradient, rate, biasRate, p ; - double factor = 1.0 ; - double biasFactor = 1.0 ; /* to allow slower bias learning rate */ - vl_index t0 = VL_MAX(2, vl_ceil_d(1.0 / self->lambda)) ; - //t0=2 ; - - double startTime = vl_get_cpu_time () ; - VlRand * rand = vl_get_rand() ; - - permutation = vl_calloc(self->numData, sizeof(vl_index)) ; - scores = vl_calloc(self->numData * 2, sizeof(double)) ; - previousScores = scores + self->numData ; - - for (i = 0 ; i < (unsigned)self->numData; i++) { - permutation [i] = i ; - previousScores [i] = - VL_INFINITY_D ; - } - - /* - We store the w vector as the product fw (factor * model). - We also use a different factor for the bias: biasFactor * biasMultiplier - to enable a slower learning rate for the bias. - - Given this representation, it is easy to carry the two key operations: - - * Inner product: = f - - * Model update: fp wp = fw - rate * lambda * w - rate * g - = f(1 - rate * lambda) w - rate * g - - Thus the update equations are: - - fp = f(1 - rate * lambda), and - wp = w + rate / fp * g ; - - * Realization of the scaling factor. Before the statistics function - is called, or training finishes, the factor (and biasFactor) - are explicitly applied to the model and the bias. - */ - - for (t = 0 ; 1 ; ++t) { - - if (t % self->numData == 0) { - /* once a new epoch is reached (all data have been visited), - change permutation */ - vl_rand_permute_indexes(rand, permutation, self->numData) ; - } - - /* pick a sample and compute update */ - i = permutation[t % self->numData] ; - p = (self->weights) ? self->weights[i] : 1.0 ; - p = VL_MAX(0.0, p) ; /* we assume non-negative weights, so this is just for robustness */ - inner = factor * self->innerProductFn(self->data, i, self->model) ; - inner += biasFactor * (self->biasMultiplier * self->bias) ; - gradient = p * self->lossDerivativeFn(inner, self->labels[i]) ; - previousScores[i] = scores[i] ; - scores[i] = inner ; - - /* apply update */ - rate = 1.0 / (self->lambda * (t + t0)) ; - biasRate = rate * self->biasLearningRate ; - factor *= (1.0 - self->lambda * rate) ; - biasFactor *= (1.0 - self->lambda * biasRate) ; - - /* debug: realize the scaling factor all the times */ - /* - for (k = 0 ; k < self->dimension ; ++k) self->model[k] *= factor ; - self->bias *= biasFactor; - factor = 1.0 ; - biasFactor = 1.0 ; - */ - - if (gradient != 0) { - self->accumulateFn(self->data, i, self->model, - gradient * rate / factor) ; - self->bias += self->biasMultiplier * (- gradient * biasRate / biasFactor) ; - } - - /* call diagnostic occasionally */ - if ((t + 1) % self->diagnosticFrequency == 0 || t + 1 == self->maxNumIterations) { - - /* realize factor before computing statistics or completing training */ - for (k = 0 ; k < self->dimension ; ++k) self->model[k] *= factor ; - self->bias *= biasFactor; - factor = 1.0 ; - biasFactor = 1.0 ; - - _vl_svm_update_statistics (self) ; - - for (k = 0 ; k < self->numData ; ++k) { - double delta = scores[k] - previousScores[k] ; - self->statistics.scoresVariation += delta * delta ; - } - self->statistics.scoresVariation = sqrt(self->statistics.scoresVariation) / self->numData ; - - self->statistics.elapsedTime = vl_get_cpu_time() - startTime ; - self->statistics.iteration = t ; - self->statistics.epoch = t / self->numData ; - - self->statistics.status = VlSvmStatusTraining ; - if (self->statistics.scoresVariation < self->epsilon) { - self->statistics.status = VlSvmStatusConverged ; - } - else if (t + 1 == self->maxNumIterations) { - self->statistics.status = VlSvmStatusMaxNumIterationsReached ; - } - - if (self->diagnosticFn) { - self->diagnosticFn(self, self->diagnosticFnData) ; - } - - if (self->statistics.status != VlSvmStatusTraining) { - break ; - } - } - } /* next iteration */ - - vl_free (scores) ; - vl_free (permutation) ; -} - -/* ---------------------------------------------------------------- */ -/* Dispatcher */ -/* ---------------------------------------------------------------- */ - -/** @brief Run the SVM solver - ** @param self object. - ** - ** The data on which the SVM operates is passed upon the cration of - ** the ::VlSvm object. This function runs a solver to learn a - ** corresponding model. See @ref svm-starting. - **/ - -void vl_svm_train (VlSvm * self) -{ - assert (self) ; - switch (self->solver) { - case VlSvmSolverSdca: - _vl_svm_sdca_train(self) ; - break ; - case VlSvmSolverSgd: - _vl_svm_sgd_train(self) ; - break ; - case VlSvmSolverNone: - _vl_svm_evaluate(self) ; - break ; - default: - assert(0) ; - } -} diff --git a/opensfm/src/third_party/vlfeat/vl/svm.h b/opensfm/src/third_party/vlfeat/vl/svm.h deleted file mode 100644 index 1fcc6d474..000000000 --- a/opensfm/src/third_party/vlfeat/vl/svm.h +++ /dev/null @@ -1,195 +0,0 @@ -/** @file svm.h - ** @brief Support Vector Machines (@ref svm) - ** @author Milan Sulc - ** @author Daniele Perrone - ** @author Andrea Vedaldi - **/ - -/* -Copyright (C) 2013 Milan Sulc. -Copyright (C) 2012 Daniele Perrone. -Copyright (C) 2011-13 Andrea Vedaldi. - -All rights reserved. - -This file is part of the VLFeat library and is made available under -the terms of the BSD license (see the COPYING file). -*/ - -#ifndef VL_SVM_H -#define VL_SVM_H - -#include "generic.h" -#include "svmdataset.h" - -/** @typedef VlSvm - ** @brief SVM solver. - ** This object implements VLFeat SVM solvers (see @ref svm.h). - **/ - -#ifndef __DOXYGEN__ -struct VlSvm_ ; -typedef struct VlSvm_ VlSvm ; -#else -typedef OPAQUE VlSvm ; -#endif - -/** @brief Type of SVM solver */ -typedef enum -{ - VlSvmSolverNone = 0, /**< No solver (used to evaluate an SVM). */ - VlSvmSolverSgd = 1, /**< SGD algorithm (@ref svm-sgd). */ - VlSvmSolverSdca /**< SDCA algorithm (@ref svm-sdca). */ -} VlSvmSolverType ; - -/** @brief Type of SVM loss - ** - ** Default SVM loss types. The loss can be set by using ::vl_svm_set_loss. - ** Note that custom losses can be used too by using ::vl_svm_set_loss_function, - ** ::vl_svm_set_loss_derivative_function, etc. - ** - ** @sa svm-loss-functions - **/ -typedef enum -{ - VlSvmLossHinge = 0, /**< Standard hinge loss. */ - VlSvmLossHinge2 = 1, /**< Hinge loss squared. */ - VlSvmLossL1, /**< L1 loss. */ - VlSvmLossL2, /**< L2 loss. */ - VlSvmLossLogistic /**< Logistic loss. */ -} VlSvmLossType ; - -/** @brief Solver status */ -typedef enum -{ - VlSvmStatusTraining = 1, /**< Optimization in progress. */ - VlSvmStatusConverged, /**< Optimization finished because the convergence criterion was met. */ - VlSvmStatusMaxNumIterationsReached /**< Optimization finished without convergence. */ -} VlSvmSolverStatus ; - -/** @brief SVM statistics - ** This structure contains statistics characterising the state of - ** the SVM solver, such as the current value of the objective function. - ** - ** Not all fields are used by all solvers. - **/ -typedef struct VlSvmStatistics_ { - VlSvmSolverStatus status ; /**< Solver status. */ - vl_size iteration ; /**< Solver iteration. */ - vl_size epoch ; /**< Solver epoch (iteration / num samples). */ - double objective ; /**< Objective function value. */ - double regularizer ; /**< Regularizer value. */ - double loss ; /**< Loss value. */ - double dualObjective ; /**< Dual objective value. */ - double dualLoss ; /**< Dual loss value. */ - double dualityGap ; /**< Duality gap = objective - dualObjective. */ - double scoresVariation ; /**< Variance of the score updates. */ - double elapsedTime ; /**< Time elapsed from the start of training. */ -} VlSvmStatistics ; - -/** @name Create and destroy - ** @{ */ -VL_EXPORT VlSvm * vl_svm_new (VlSvmSolverType type, - double const * data, - vl_size dimension, - vl_size numData, - double const * labels, - double lambda) ; - -VL_EXPORT VlSvm * vl_svm_new_with_dataset (VlSvmSolverType type, - VlSvmDataset * dataset, - double const * labels, - double lambda) ; - -VL_EXPORT VlSvm * vl_svm_new_with_abstract_data (VlSvmSolverType type, - void * data, - vl_size dimension, - vl_size numData, - double const * labels, - double lambda) ; - -VL_EXPORT void vl_svm_delete (VlSvm * self) ; -/** @} */ - -/** @name Retrieve parameters and data - ** @{ */ -VL_EXPORT VlSvmStatistics const * vl_svm_get_statistics (VlSvm const *self) ; -VL_EXPORT double const * vl_svm_get_model (VlSvm const *self) ; -VL_EXPORT double vl_svm_get_bias (VlSvm const *self) ; -VL_EXPORT vl_size vl_svm_get_dimension (VlSvm *self) ; -VL_EXPORT vl_size vl_svm_get_num_data (VlSvm *self) ; -VL_EXPORT double vl_svm_get_epsilon (VlSvm const *self) ; -VL_EXPORT double vl_svm_get_bias_learning_rate (VlSvm const *self) ; -VL_EXPORT vl_size vl_svm_get_max_num_iterations (VlSvm const *self) ; -VL_EXPORT vl_size vl_svm_get_diagnostic_frequency (VlSvm const *self) ; -VL_EXPORT VlSvmSolverType vl_svm_get_solver (VlSvm const *self) ; -VL_EXPORT double vl_svm_get_bias_multiplier (VlSvm const *self) ; -VL_EXPORT double vl_svm_get_lambda (VlSvm const *self) ; -VL_EXPORT vl_size vl_svm_get_iteration_number (VlSvm const *self) ; -VL_EXPORT double const * vl_svm_get_scores (VlSvm const *self) ; -VL_EXPORT double const * vl_svm_get_weights (VlSvm const *self) ; -/** @} */ - -/** @name Set parameters - ** @{ */ -VL_EXPORT void vl_svm_set_epsilon (VlSvm *self, double epsilon) ; -VL_EXPORT void vl_svm_set_bias_learning_rate (VlSvm *self, double rate) ; -VL_EXPORT void vl_svm_set_max_num_iterations (VlSvm *self, vl_size maxNumIterations) ; -VL_EXPORT void vl_svm_set_diagnostic_frequency (VlSvm *self, vl_size f) ; -VL_EXPORT void vl_svm_set_bias_multiplier (VlSvm *self, double b) ; -VL_EXPORT void vl_svm_set_model (VlSvm *self, double const *model) ; -VL_EXPORT void vl_svm_set_bias (VlSvm *self, double b) ; -VL_EXPORT void vl_svm_set_iteration_number (VlSvm *self, vl_uindex n) ; -VL_EXPORT void vl_svm_set_weights (VlSvm *self, double const *weights) ; - -VL_EXPORT void vl_svm_set_diagnostic_function (VlSvm *self, VlSvmDiagnosticFunction f, void *data) ; -VL_EXPORT void vl_svm_set_loss_function (VlSvm *self, VlSvmLossFunction f) ; -VL_EXPORT void vl_svm_set_loss_derivative_function (VlSvm *self, VlSvmLossFunction f) ; -VL_EXPORT void vl_svm_set_conjugate_loss_function (VlSvm *self, VlSvmLossFunction f) ; -VL_EXPORT void vl_svm_set_dca_update_function (VlSvm *self, VlSvmDcaUpdateFunction f) ; -VL_EXPORT void vl_svm_set_data_functions (VlSvm *self, VlSvmInnerProductFunction inner, VlSvmAccumulateFunction acc) ; -VL_EXPORT void vl_svm_set_loss (VlSvm *self, VlSvmLossType loss) ; -/** @} */ - -/** @name Process data - ** @{ */ -VL_EXPORT void vl_svm_train (VlSvm * self) ; -/** @} */ - -/** @name Loss functions - ** @sa @ref svm-advanced - ** @{ */ - -/* hinge */ -VL_EXPORT double vl_svm_hinge_loss (double label, double inner) ; -VL_EXPORT double vl_svm_hinge_loss_derivative (double label, double inner) ; -VL_EXPORT double vl_svm_hinge_conjugate_loss (double label, double u) ; -VL_EXPORT double vl_svm_hinge_dca_update (double alpha, double inner, double norm2, double label) ; - -/* square hinge */ -VL_EXPORT double vl_svm_hinge2_loss (double label, double inner) ; -VL_EXPORT double vl_svm_hinge2_loss_derivative (double label, double inner) ; -VL_EXPORT double vl_svm_hinge2_conjugate_loss (double label, double u) ; -VL_EXPORT double vl_svm_hinge2_dca_update (double alpha, double inner, double norm2, double label) ; - -/* l1 */ -VL_EXPORT double vl_svm_l1_loss (double label, double inner) ; -VL_EXPORT double vl_svm_l1_loss_derivative (double label, double inner) ; -VL_EXPORT double vl_svm_l1_conjugate_loss (double label, double u) ; -VL_EXPORT double vl_svm_l1_dca_update (double alpha, double inner, double norm2, double label) ; - -/* l2 */ -VL_EXPORT double vl_svm_l2_loss (double label, double inner) ; -VL_EXPORT double vl_svm_l2_loss_derivative (double label, double inner) ; -VL_EXPORT double vl_svm_l2_conjugate_loss (double label, double u) ; -VL_EXPORT double vl_svm_l2_dca_update (double alpha, double inner, double norm2, double label) ; - -/* logistic */ -VL_EXPORT double vl_svm_logistic_loss (double label, double inner) ; -VL_EXPORT double vl_svm_logistic_loss_derivative (double label, double inner) ; -VL_EXPORT double vl_svm_logistic_conjugate_loss (double label, double u) ; -VL_EXPORT double vl_svm_logistic_dca_update (double alpha, double inner, double norm2, double label) ; -/** } */ - -/* VL_SVM_H */ -#endif diff --git a/opensfm/src/third_party/vlfeat/vl/svmdataset.c b/opensfm/src/third_party/vlfeat/vl/svmdataset.c deleted file mode 100644 index a4100d11c..000000000 --- a/opensfm/src/third_party/vlfeat/vl/svmdataset.c +++ /dev/null @@ -1,407 +0,0 @@ -/** @file svmdataset.c - ** @brief SVM Dataset - Definition - ** @author Daniele Perrone - ** @author Andrea Vedaldi - **/ - -/* -Copyright (C) 2012 Daniele Perrone. -Copyright (C) 2013 Andrea Vedaldi. -All rights reserved. - -This file is part of the VLFeat library and is made available under -the terms of the BSD license (see the COPYING file). -*/ - -/** -@file svmdataset.h -@tableofcontents -@author Daniele Perrone -@author Andrea Vedaldi - -The SVM solver object ::VlSvm, supporting SVM learning in VLFeat, -uses an abstraction mechanism to work on arbitrary data types. -This module provides an helper object, ::VlSvmDataset, -that simplify taking advantage of this functionality, supporting for example -different data types and the computation of feature maps out of the box. - - -@section svmdataset-starting Getting started - - -As discussed in @ref svm-advanced, most linear SVM solvers, -such as the ones implemented in VLFeat in @ref svm, require only two -operations to be defined on the data: - -- *Inner product* between a data point $\bx$ and the model vector $\bw$. - This is implemented by a function of type ::VlSvmInnerProductFunction. -- *Accumulation* of a dataobint $\bx$ to the model vector $\bw$: - $\bw \leftarrow \bw + \alpha \bx$. This is implemented - by a function of the type ::VlSvmAccumulateFunction . - -The SVM solver needs to know nothing about the data once these two -operations are defined. These functions can do any number of things, -such as supporting different formats for the data (dense or sparse, -float or double), computing feature maps, or expanding compressed -representations such as Product Quantization. - -VLFeat provides the helper object ::VlSvmDataset to support some -of these functionalities out of the box (it is important to remark -that its use with the SVM solver ::VlSvm is entirely optional). - -Presently, ::VlSvmDataset supports: - -- @c float and @c double dense arrays. -- The on-the-fly application of the homogeneous kernel map to implement - additive non-linear kernels (see @ref homkermap). - -For example, to learn a linear SVM on SINGLE data: - -@code -int main() -{ - vl_size const numData = 4 ; - vl_size const dimension = 2 ; - single x [dimension * numData] = { - 0.0, -0.5, - 0.6, -0.3, - 0.0, 0.5, - 0.6, 0.0} ; - double y [numData] = {1, 1, -1, 1} ; - double lambda = 0.01; - double * const model ; - double bias ; - - VlSvmDataset * dataset = vl_svmdataset_new (VL_TYPE_SINGLE, x, dimension, numData) ; - VlSvm * svm = vl_svm_new_with_dataset (VlSvmSolverSgd, dataset, y, lambda) ; - - vl_svm_train(svm) ; - - model = vl_svm_get_model(svm) ; - bias = vl_svm_get_bias(svm) ; - - printf("model w = [ %f , %f ] , bias b = %f \n", - model[0], - model[1], - bias); - - vl_svm_delete(svm) ; - vl_svmdataset_delete(dataset) ; - return 0; -} -@endcode - -**/ - -/* ---------------------------------------------------------------- */ -#ifndef VL_SVMDATASET_INSTANTIATING -/* ---------------------------------------------------------------- */ - -#include "svmdataset.h" -#include -#include - -struct VlSvmDataset_ { - vl_type dataType ; /**< Data type. */ - void * data ; /**< Pointer to data. */ - vl_size numData ; /**< Number of wrapped data. */ - vl_size dimension ; /**< Data point dimension. */ - VlHomogeneousKernelMap * hom ; /**< Homogeneous kernel map (optional). */ - void * homBuffer ; /**< Homogeneous kernel map buffer. */ - vl_size homDimension ; /**< Homogeneous kernel map dimension. */ -} ; - -/* templetized parts of the implementation */ -#define FLT VL_TYPE_FLOAT -#define VL_SVMDATASET_INSTANTIATING -#include "svmdataset.c" - -#define FLT VL_TYPE_DOUBLE -#define VL_SVMDATASET_INSTANTIATING -#include "svmdataset.c" - -/** @brief Create a new object wrapping a dataset. - ** @param dataType of data (@c float and @c double supported). - ** @param data pointer to the data. - ** @param dimension the dimension of a data vector. - ** @param numData number of wrapped data vectors. - ** @return new object. - ** - ** The function allocates and returns a new SVM dataset object - ** wrapping the data pointed by @a data. Note that no copy is made - ** of data, so the caller should keep the data allocated as the object exists. - ** - ** @sa ::vl_svmdataset_delete - **/ - -VlSvmDataset* -vl_svmdataset_new (vl_type dataType, void *data, vl_size dimension, vl_size numData) -{ - VlSvmDataset * self ; - assert(dataType == VL_TYPE_DOUBLE || dataType == VL_TYPE_FLOAT) ; - assert(data) ; - - self = vl_calloc(1, sizeof(VlSvmDataset)) ; - if (self == NULL) return NULL ; - - self->dataType = dataType ; - self->data = data ; - self->dimension = dimension ; - self->numData = numData ; - self->hom = NULL ; - self->homBuffer = NULL ; - return self ; -} - -/** @brief Delete the object. - ** @param self object to delete. - ** - ** The function frees the resources allocated by - ** ::vl_svmdataset_new(). Notice that the wrapped data will *not* - ** be freed as it is not owned by the object. - **/ - -void vl_svmdataset_delete (VlSvmDataset *self) -{ - if (self->homBuffer) { - vl_free(self->homBuffer) ; - self->homBuffer = 0 ; - } - vl_free (self) ; -} - -/** @brief Get the wrapped data. - ** @param self object. - ** @return a pointer to the wrapped data. - **/ - -void* -vl_svmdataset_get_data (VlSvmDataset const *self) -{ - return self->data ; -} - -/** @brief Get the number of wrapped data elements. - ** @param self object. - ** @return number of wrapped data elements. - **/ - -vl_size -vl_svmdataset_get_num_data (VlSvmDataset const *self) -{ - return self->numData ; -} - -/** @brief Get the dimension of the wrapped data. - ** @param self object. - ** @return dimension of the wrapped data. - **/ - -vl_size -vl_svmdataset_get_dimension (VlSvmDataset const *self) -{ - if (self->hom) { - return self->dimension * vl_homogeneouskernelmap_get_dimension(self->hom) ; - } - return self->dimension ; -} - -/** @brief Get the homogeneous kernel map object. - ** @param self object. - ** @return homogenoeus kernel map object (or @c NULL if any). - **/ - -VlHomogeneousKernelMap * -vl_svmdataset_get_homogeneous_kernel_map (VlSvmDataset const *self) -{ - assert(self) ; - return self->hom ; -} - -/** @brief Set the homogeneous kernel map object. - ** @param self object. - ** @param hom homogeneous kernel map object to use. - ** - ** After changing the kernel map, the inner product and accumulator - ** function should be queried again (::vl_svmdataset_get_inner_product_function - ** adn ::vl_svmdataset_get_accumulate_function). - ** - ** Set this to @c NULL to avoid using a kernel map. - ** - ** Note that this does *not* transfer the ownership of the object - ** to the function. Furthermore, ::VlSvmDataset holds to the - ** object until it is destroyed or the object is replaced or removed - ** by calling this function again. - **/ - -void -vl_svmdataset_set_homogeneous_kernel_map (VlSvmDataset * self, - VlHomogeneousKernelMap * hom) -{ - assert(self) ; - self->hom = hom ; - self->homDimension = 0 ; - if (self->homBuffer) { - vl_free (self->homBuffer) ; - self->homBuffer = 0 ; - } - if (self->hom) { - self->homDimension = vl_homogeneouskernelmap_get_dimension(self->hom) ; - self->homBuffer = vl_calloc(self->homDimension, vl_get_type_size(self->dataType)) ; - } -} - -/** @brief Get the accumulate function - ** @param self object. - ** @return a pointer to the accumulate function to use with this data. - **/ - -VlSvmAccumulateFunction -vl_svmdataset_get_accumulate_function(VlSvmDataset const *self) -{ - if (self->hom == NULL) { - switch (self->dataType) { - case VL_TYPE_FLOAT: - return (VlSvmAccumulateFunction) vl_svmdataset_accumulate_f ; - break ; - case VL_TYPE_DOUBLE: - return (VlSvmAccumulateFunction) vl_svmdataset_accumulate_d ; - break ; - } - } else { - switch (self->dataType) { - case VL_TYPE_FLOAT: - return (VlSvmAccumulateFunction) vl_svmdataset_accumulate_hom_f ; - break ; - case VL_TYPE_DOUBLE: - return (VlSvmAccumulateFunction) vl_svmdataset_accumulate_hom_d ; - break ; - } - } - assert(0) ; - return NULL ; -} - -/** @brief Get the inner product function. - ** @param self object. - ** @return a pointer to the inner product function to use with this data. - **/ - -VlSvmInnerProductFunction -vl_svmdataset_get_inner_product_function (VlSvmDataset const *self) -{ - if (self->hom == NULL) { - switch (self->dataType) { - case VL_TYPE_FLOAT: - return (VlSvmInnerProductFunction) _vl_svmdataset_inner_product_f ; - break ; - case VL_TYPE_DOUBLE: - return (VlSvmInnerProductFunction) _vl_svmdataset_inner_product_d ; - break ; - default: - assert(0) ; - } - } else { - switch (self->dataType) { - case VL_TYPE_FLOAT: - return (VlSvmInnerProductFunction) _vl_svmdataset_inner_product_hom_f ; - break ; - case VL_TYPE_DOUBLE: - return (VlSvmInnerProductFunction) _vl_svmdataset_inner_product_hom_d ; - break ; - default: - assert(0) ; - } - } - - return NULL; -} - -/* VL_SVMDATASET_INSTANTIATING */ -#endif - -/* ---------------------------------------------------------------- */ -#ifdef VL_SVMDATASET_INSTANTIATING -/* ---------------------------------------------------------------- */ - -#include "float.h" - -double -VL_XCAT(_vl_svmdataset_inner_product_,SFX) (VlSvmDataset const *self, - vl_uindex element, - double const *model) -{ - double product = 0 ; - T* data = ((T*)self->data) + self->dimension * element ; - T* end = data + self->dimension ; - while (data != end) { - product += (*data++) * (*model++) ; - } - return product ; -} - -void -VL_XCAT(vl_svmdataset_accumulate_,SFX)(VlSvmDataset const *self, - vl_uindex element, - double *model, - const double multiplier) -{ - T* data = ((T*)self->data) + self->dimension * element ; - T* end = data + self->dimension ; - while (data != end) { - *model += (*data++) * multiplier ; - model++ ; - } -} - -double -VL_XCAT(_vl_svmdataset_inner_product_hom_,SFX) (VlSvmDataset const *self, - vl_uindex element, - double const *model) -{ - double product = 0 ; - T* data = ((T*)self->data) + self->dimension * element ; - T* end = data + self->dimension ; - T* bufEnd = ((T*)self->homBuffer)+ self->homDimension ; - while (data != end) { - /* TODO: zeros in data could be optimized by skipping over them */ - T* buf = self->homBuffer ; - VL_XCAT(vl_homogeneouskernelmap_evaluate_,SFX)(self->hom, - self->homBuffer, - 1, - (*data++)) ; - while (buf != bufEnd) { - product += (*buf++) * (*model++) ; - } - } - return product ; -} - -void -VL_XCAT(vl_svmdataset_accumulate_hom_,SFX)(VlSvmDataset const *self, - vl_uindex element, - double *model, - const double multiplier) -{ - T* data = ((T*)self->data) + self->dimension * element ; - T* end = data + self->dimension ; - T* bufEnd = ((T*)self->homBuffer)+ self->homDimension ; - while (data != end) { - /* TODO: zeros in data could be optimized by skipping over them */ - T* buf = self->homBuffer ; - VL_XCAT(vl_homogeneouskernelmap_evaluate_,SFX)(self->hom, - self->homBuffer, - 1, - (*data++)) ; - while (buf != bufEnd) { - *model += (*buf++) * multiplier ; - model++ ; - } - } -} - -#undef FLT -#undef VL_SVMDATASET_INSTANTIATING - -/* VL_SVMDATASET_INSTANTIATING */ -#endif diff --git a/opensfm/src/third_party/vlfeat/vl/svmdataset.h b/opensfm/src/third_party/vlfeat/vl/svmdataset.h deleted file mode 100644 index c2e1c6204..000000000 --- a/opensfm/src/third_party/vlfeat/vl/svmdataset.h +++ /dev/null @@ -1,82 +0,0 @@ -/** @file svmdataset.h - ** @brief SVM Dataset - ** @author Daniele Perrone - ** @author Andrea Vedaldi - **/ - -/* -Copyright (C) 2012 Daniele Perrone. -Copyright (C) 2013 Andrea Vedaldi. -All rights reserved. - -This file is part of the VLFeat library and is made available under -the terms of the BSD license (see the COPYING file). -*/ - -#ifndef VL_SVMDATASET_H -#define VL_SVMDATASET_H - -#include "generic.h" -#include "homkermap.h" - -struct VlSvm_ ; - -/** @typedef VlSvmDataset - ** @brief SVM dataset object - ** - ** This objects contain a training set to be used in combination with - ** the SVM solver object ::VlSvm. Its main purpose is to implement - ** the two basic operations inner product (::VlSvmInnerProductFunction) - ** and accumulation (::VlSvmAccumulateFunction). - ** - ** See @ref svm and @ref svm-advanced for further information. - **/ - -#ifndef __DOXYGEN__ -struct VlSvmDataset_ ; -typedef struct VlSvmDataset_ VlSvmDataset ; -#else -typedef OPAQUE VlSvmDataset ; -#endif - -/** @name SVM callbacks - ** @{ */ -typedef void (*VlSvmDiagnosticFunction) (struct VlSvm_ *svm, void *data) ; -typedef double (*VlSvmLossFunction) (double inner, double label) ; -typedef double (*VlSvmDcaUpdateFunction) (double alpha, double inner, double norm2, double label) ; -typedef double (*VlSvmInnerProductFunction)(const void *data, vl_uindex element, double *model) ; -typedef void (*VlSvmAccumulateFunction) (const void *data, vl_uindex element, double *model, double multiplier) ; -/* typedef double (*VlSvmSquareNormFunction) (const void *data, vl_uindex element) ; */ -/** @} */ - -/** @name Create and destroy - ** @{ - **/ -VL_EXPORT VlSvmDataset* vl_svmdataset_new (vl_type dataType, void *data, vl_size dimension, vl_size numData) ; -VL_EXPORT void vl_svmdataset_delete (VlSvmDataset * dataset) ; -/** @} */ - -/** @name Set parameters - ** @{ - **/ -VL_EXPORT void vl_svmdataset_set_homogeneous_kernel_map (VlSvmDataset * self, - VlHomogeneousKernelMap * hom) ; -/** @} */ - -/** @name Get data and parameters - ** @{ - **/ -VL_EXPORT void* vl_svmdataset_get_data (VlSvmDataset const *self) ; -VL_EXPORT vl_size vl_svmdataset_get_num_data (VlSvmDataset const *self) ; -VL_EXPORT vl_size vl_svmdataset_get_dimension (VlSvmDataset const *self) ; -VL_EXPORT void* vl_svmdataset_get_map (VlSvmDataset const *self) ; -VL_EXPORT vl_size vl_svmdataset_get_mapDim (VlSvmDataset const *self) ; -VL_EXPORT VlSvmAccumulateFunction vl_svmdataset_get_accumulate_function (VlSvmDataset const *self) ; -VL_EXPORT VlSvmInnerProductFunction vl_svmdataset_get_inner_product_function (VlSvmDataset const * self) ; -VL_EXPORT VlHomogeneousKernelMap * vl_svmdataset_get_homogeneous_kernel_map (VlSvmDataset const * self) ; -/** @} */ - -/* VL_SVMDATASET_H */ -#endif - - diff --git a/opensfm/src/third_party/vlfeat/vl/vlad.c b/opensfm/src/third_party/vlfeat/vl/vlad.c deleted file mode 100644 index 8b6bd6ac1..000000000 --- a/opensfm/src/third_party/vlfeat/vl/vlad.c +++ /dev/null @@ -1,323 +0,0 @@ -/** @file vlad.c - ** @brief VLAD - Declaration - ** @author David Novotny - ** @author Andrea Vedaldi - **/ - -/* -Copyright (C) 2013 David Novotny and Andera Vedaldi. -All rights reserved. - -This file is part of the VLFeat library and is made available under -the terms of the BSD license (see the COPYING file). -*/ - -/** - -@page vlad Vector of Locally Aggregated Descriptors (VLAD) encoding -@author David Novotny -@author Andrea Vedaldi - - -@ref vlad.h implements the *Vector of Linearly Aggregated Descriptors* -(VLAD) image representation @cite{jegou10aggregating} -@cite{arandjelovic13all-about}. - -@ref vlad-starting demonstreates how to use the C API to compute the -VLAD representation of an image. For further details on the VLAD image -representation refer to: - -- @subpage vlad-fundamentals - VLAD definition and computation. - - -@section vlad-starting Getting started with VLAD - - -The VLAD encoding of a set of features is obtained by using the -function ::vl_vlad_encode. The function can be applied to both @c -float or @c double data types. - -::vl_vlad_encode requires a visual dictionary, for example obtained by -using @ref kmeans. Furthermore, the assignments of features to -dictionary elements must be pre-computed, for example by using @ref -kdtree. - -In the following example code, the vocabulary is first created using -the KMeans clustering, then the points, that are to be encoded are -assigned to its corresponding nearest vocabulary words, after that the -original vlad encoding routine without any normalization option takes place. -At the end of the process the encoding is stored in the @c enc variable. - -@code -vl_uint32 * indexes; -float * assignments; -float * enc -int i; - -// create a KMeans object and run clustering to get vocabulary words (centers) -kmeans = vl_kmeans_new (VLDistanceL2, VL_TYPE_FLOAT) ; -vl_kmeans_cluster (kmeans, - data, - dimension, - numData, - numCenters) ; - -// find nearest cliuster centers for the data that should be encoded -indexes = vl_malloc(sizeof(vl_uint32) * numDataToEncode); -vl_kmeans_quantize(kmeans,indexes,dataToEncode,numDataToEncode); - -// convert indexes array to assignments array, -// which can be processed by vl_vlad_encode -assignments = vl_malloc(sizeof(float) * numDataToEncode * numCenters); -memset(assignments, 0, sizeof(float) * numDataToEncode * numCenters); -for(i = 0; i < numDataToEncode; i++) { - assignments[i * numCenters + indexes[i]] = 1.; -} - -// allocate space for vlad encoding -enc = vl_malloc(sizeof(TYPE) * dimension * numCenters); - -// do the encoding job -vl_vlad_encode (enc, VL_F_TYPE, - vl_kmeans_get_centers(kmeans), dimension, numCenters, - data, numData, - assignments, - 0) ; -@endcode - -Various @ref vlad-normalization normalizations can be applied to the -VLAD vectors. These are controlled by the parameter @a flag of -::vl_vlad_encode. - - -@page vlad-fundamentals VLAD fundamentals -@tableofcontents - - -This page describes the *Vector of Locally Aggregated Descriptors* -(VLAD) image encoding of @cite{jegou10aggregating}. See @ref vlad for -an overview of the C API. - -VLAD is a *feature encoding and pooling* method, similar to @ref -fisher "Fisher vectors". VLAD encodes a set of local feature -descriptors $I=(\bx_1,\dots,\bx_n)$ extracted from an image using a -dictionary built using a clustering method such as @ref gmm or @ref -kmeans. Let $q_{ik}$ be the strength of the association of data vector -$\bx_i$ to cluster $\mu_k$, such that $q_{ik} \geq 0$ and -$\sum_{k=1}^K q_{ik} = 1$. The association may be either soft -(e.g. obtained as the posterior probabilities of the GMM clusters) or -hard (e.g. obtained by vector quantization with K-means). - -$\mu_k$ are the cluster *means*, vectors of the same dimension as the -data $\bx_i$. VLAD encodes feature $\bx$ by considering the *residuals* -\[ - \bv_k = \sum_{i=1}^{N} q_{ik} (\bx_{i} - \mu_k). -\] -The residulas are stacked together to obtain the vector -\[ -\hat\Phi(I) = -\begin{bmatrix} -\vdots \\ -\bv_k \\ -\vdots -\end{bmatrix} -\] - -Before the VLAD encoding is used it is usually normalized, as -explained @ref vlad-normalization next. - - -@section vlad-normalization VLAD normalization - - -VLFeat VLAD implementation supports a number of different -normalization strategies. These are optionally applied in this order: - -- **Component-wise mass normalization.** Each vector $\bv_k$ is - divided by the total mass of features associated to it $\sum_{i=1}^N - q_{ik}$. - -- **Square-rooting.** The function $\sign(z)\sqrt{|z|}$ is applied to - all scalar components of the VLAD descriptor. - -- **Component-wise $l^2$ normalization.** The vectors $\bv_k$ are - divided by their norm $\|\bv_k\|_2$. - -- **Global $l^2$ normalization.** The VLAD descriptor $\hat\Phi(I)$ is - divided by its norm $\|\hat\Phi(I)\|_2$. -*/ - -#include "vlad.h" -#include "mathop.h" -#include -#include -#include - -#if defined(_OPENMP) -#include -#endif - -/* ================================================================ */ -#ifdef VL_VLAD_INSTANTIATING - -static void -VL_XCAT(_vl_vlad_encode_, SFX) -(TYPE * enc, - TYPE const * means, vl_size dimension, vl_size numClusters, - TYPE const * data, vl_size numData, - TYPE const * assignments, - int flags) -{ - vl_uindex dim ; - vl_index i_cl, i_d ; - - memset(enc, 0, sizeof(TYPE) * dimension * numClusters) ; - -#if defined(_OPENMP) -#pragma omp parallel for default(shared) private(i_cl,i_d,dim) num_threads(vl_get_max_threads()) -#endif - for (i_cl = 0; i_cl < (signed)numClusters; i_cl++) { - double clusterMass = 0 ; - for (i_d = 0; i_d < (signed)numData; i_d++) { - if (assignments[i_d*numClusters + i_cl] > 0) { - double q = assignments[i_d*numClusters+i_cl] ; - clusterMass += q ; - for(dim = 0; dim < dimension; dim++) { - enc [i_cl * dimension + dim] += q * data [i_d * dimension + dim] ; - } - } - } - - if (clusterMass > 0) { - if (flags & VL_VLAD_FLAG_NORMALIZE_MASS) { - for(dim = 0; dim < dimension; dim++) { - enc[i_cl*dimension + dim] /= clusterMass ; - enc[i_cl*dimension + dim] -= means[i_cl*dimension+dim]; - } - } else { - for(dim = 0; dim < dimension; dim++) { - enc[i_cl*dimension + dim] -= clusterMass * means[i_cl*dimension+dim]; - } - } - } - - if (flags & VL_VLAD_FLAG_SQUARE_ROOT) { - for(dim = 0; dim < dimension; dim++) { - TYPE z = enc[i_cl*dimension + dim] ; - if (z >= 0) { - enc[i_cl*dimension + dim] = VL_XCAT(vl_sqrt_, SFX)(z) ; - } else { - enc[i_cl*dimension + dim] = - VL_XCAT(vl_sqrt_, SFX)(- z) ; - } - } - } - - if (flags & VL_VLAD_FLAG_NORMALIZE_COMPONENTS) { - TYPE n = 0 ; - dim = 0 ; - for(dim = 0; dim < dimension; dim++) { - TYPE z = enc[i_cl*dimension + dim] ; - n += z * z ; - } - n = VL_XCAT(vl_sqrt_, SFX)(n) ; - n = VL_MAX(n, 1e-12) ; - for(dim = 0; dim < dimension; dim++) { - enc[i_cl*dimension + dim] /= n ; - } - } - } - - if (! (flags & VL_VLAD_FLAG_UNNORMALIZED)) { - TYPE n = 0 ; - for(dim = 0 ; dim < dimension * numClusters ; dim++) { - TYPE z = enc [dim] ; - n += z * z ; - } - n = VL_XCAT(vl_sqrt_, SFX)(n) ; - n = VL_MAX(n, 1e-12) ; - for(dim = 0 ; dim < dimension * numClusters ; dim++) { - enc[dim] /= n ; - } - } -} - -/* VL_FISHER_INSTANTIATING */ -#else - -#ifndef __DOXYGEN__ -#define FLT VL_TYPE_FLOAT -#define TYPE float -#define SFX f -#define VL_VLAD_INSTANTIATING -#include "vlad.c" - -#define FLT VL_TYPE_DOUBLE -#define TYPE double -#define SFX d -#define VL_VLAD_INSTANTIATING -#include "vlad.c" -#endif - -/* VL_VLAD_INSTANTIATING */ -#endif - -/* ================================================================ */ -#ifndef VL_VLAD_INSTANTIATING - -/** @brief VLAD encoding of a set of vectors. - ** @param enc output VLAD encoding (out). - ** @param dataType the type of the input data (::VL_TYPE_DOUBLE or ::VL_TYPE_FLOAT). - ** @param numData number of data vectors to encode. - ** @param means cluster means. - ** @param numClusters number of clusters. - ** @param data the data vectors to encode. - ** @param dimension dimensionality of the data. - ** @param assignments data to cluster soft assignments. - ** @param flags options. - ** - ** @a enc is the VLAD vector of size @a numClusters by - ** @a dimension. @a means is a matrix with @a numClusters columns and - ** @a dimension rows. @a data is the matrix of vectors to be encoded, - ** with @a dimension rows and @a numData columns. @a assignments is a - ** matrix with @a numClusters rows and @a numData columns. - ** All the matrices should be stored in column-major order. - ** - ** @a flag allows controlling further options: - ** ::VL_VLAD_FLAG_NORMALIZE_COMPONENTS, ::VL_VLAD_FLAG_SQUARE_ROOT, - ** ::VL_VLAD_FLAG_UNNORMALIZED, and ::VL_VLAD_FLAG_NORMALIZE_MASS. - ** - ** @sa @ref vlad - **/ - -void -vl_vlad_encode (void * enc, vl_type dataType, - void const * means, vl_size dimension, vl_size numClusters, - void const * data, vl_size numData, - void const * assignments, - int flags) -{ - switch(dataType) { - case VL_TYPE_FLOAT: - _vl_vlad_encode_f ((float *) enc, - (float const *) means, dimension, numClusters, - (float const *) data, numData, - (float const *) assignments, flags) ; - break; - case VL_TYPE_DOUBLE: - _vl_vlad_encode_d ((double *) enc, - (double const *) means, dimension, numClusters, - (double const *) data, numData, - (double const *) assignments, flags) ; - break; - default: - abort(); - } -} - -/* ! VL_VLAD_INSTANTIATING */ -#endif - -#undef SFX -#undef TYPE -#undef FLT -#undef VL_VLAD_INSTANTIATING diff --git a/opensfm/src/third_party/vlfeat/vl/vlad.h b/opensfm/src/third_party/vlfeat/vl/vlad.h deleted file mode 100644 index 72ca6dc93..000000000 --- a/opensfm/src/third_party/vlfeat/vl/vlad.h +++ /dev/null @@ -1,53 +0,0 @@ -/** @file vlad.h - ** @brief VLAD encoding (@ref vlad) - ** @author David Novotny - ** @author Andrea Vedaldi - ** @see @ref vlad - **/ - -/* -Copyright (C) 2013 David Novotny and Andera Vedaldi. -All rights reserved. - -This file is part of the VLFeat library and is made available under -the terms of the BSD license (see the COPYING file). -*/ - -#ifndef VL_VLAD_H -#define VL_VLAD_H - -#include "generic.h" - -/** @name VLAD options - ** @{ */ -#define VL_VLAD_FLAG_NORMALIZE_COMPONENTS (0x1 << 0) -#define VL_VLAD_FLAG_SQUARE_ROOT (0x1 << 1) -#define VL_VLAD_FLAG_UNNORMALIZED (0x1 << 2) -#define VL_VLAD_FLAG_NORMALIZE_MASS (0x1 << 3) - -/** @def VL_VLAD_FLAG_NORMALIZE_COMPONENTS - ** @brief Normalize each VLAD component individually. - **/ - -/** @def VL_VLAD_FLAG_SQUARE_ROOT - ** @brief Use signed squared-root. - **/ - -/** @def VL_VLAD_FLAG_UNNORMALIZED - ** @brief Do not globally normalize the VLAD descriptor. - **/ - -/** @def VL_VLAD_FLAG_NORMALIZE_MASS - ** @brief Normalize each component by the number of features assigned to it. - **/ -/** @} */ - -VL_EXPORT void vl_vlad_encode - (void * enc, vl_type dataType, - void const * means, vl_size dimension, vl_size numClusters, - void const * data, vl_size numData, - void const * assignments, - int flags) ; - -/* VL_VLAD_H */ -#endif