openCV library for Renesas RZ/A
Dependents: RZ_A2M_Mbed_samples
include/opencv2/flann/kdtree_index.h@0:0e0631af0305, 2021-01-29 (annotated)
- Committer:
- RyoheiHagimoto
- Date:
- Fri Jan 29 04:53:38 2021 +0000
- Revision:
- 0:0e0631af0305
copied from https://github.com/d-kato/opencv-lib.
Who changed what in which revision?
User | Revision | Line number | New contents of line |
---|---|---|---|
RyoheiHagimoto | 0:0e0631af0305 | 1 | /*********************************************************************** |
RyoheiHagimoto | 0:0e0631af0305 | 2 | * Software License Agreement (BSD License) |
RyoheiHagimoto | 0:0e0631af0305 | 3 | * |
RyoheiHagimoto | 0:0e0631af0305 | 4 | * Copyright 2008-2009 Marius Muja (mariusm@cs.ubc.ca). All rights reserved. |
RyoheiHagimoto | 0:0e0631af0305 | 5 | * Copyright 2008-2009 David G. Lowe (lowe@cs.ubc.ca). All rights reserved. |
RyoheiHagimoto | 0:0e0631af0305 | 6 | * |
RyoheiHagimoto | 0:0e0631af0305 | 7 | * THE BSD LICENSE |
RyoheiHagimoto | 0:0e0631af0305 | 8 | * |
RyoheiHagimoto | 0:0e0631af0305 | 9 | * Redistribution and use in source and binary forms, with or without |
RyoheiHagimoto | 0:0e0631af0305 | 10 | * modification, are permitted provided that the following conditions |
RyoheiHagimoto | 0:0e0631af0305 | 11 | * are met: |
RyoheiHagimoto | 0:0e0631af0305 | 12 | * |
RyoheiHagimoto | 0:0e0631af0305 | 13 | * 1. Redistributions of source code must retain the above copyright |
RyoheiHagimoto | 0:0e0631af0305 | 14 | * notice, this list of conditions and the following disclaimer. |
RyoheiHagimoto | 0:0e0631af0305 | 15 | * 2. Redistributions in binary form must reproduce the above copyright |
RyoheiHagimoto | 0:0e0631af0305 | 16 | * notice, this list of conditions and the following disclaimer in the |
RyoheiHagimoto | 0:0e0631af0305 | 17 | * documentation and/or other materials provided with the distribution. |
RyoheiHagimoto | 0:0e0631af0305 | 18 | * |
RyoheiHagimoto | 0:0e0631af0305 | 19 | * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR |
RyoheiHagimoto | 0:0e0631af0305 | 20 | * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES |
RyoheiHagimoto | 0:0e0631af0305 | 21 | * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. |
RyoheiHagimoto | 0:0e0631af0305 | 22 | * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, |
RyoheiHagimoto | 0:0e0631af0305 | 23 | * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT |
RyoheiHagimoto | 0:0e0631af0305 | 24 | * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, |
RyoheiHagimoto | 0:0e0631af0305 | 25 | * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY |
RyoheiHagimoto | 0:0e0631af0305 | 26 | * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT |
RyoheiHagimoto | 0:0e0631af0305 | 27 | * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF |
RyoheiHagimoto | 0:0e0631af0305 | 28 | * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
RyoheiHagimoto | 0:0e0631af0305 | 29 | *************************************************************************/ |
RyoheiHagimoto | 0:0e0631af0305 | 30 | |
RyoheiHagimoto | 0:0e0631af0305 | 31 | #ifndef OPENCV_FLANN_KDTREE_INDEX_H_ |
RyoheiHagimoto | 0:0e0631af0305 | 32 | #define OPENCV_FLANN_KDTREE_INDEX_H_ |
RyoheiHagimoto | 0:0e0631af0305 | 33 | |
RyoheiHagimoto | 0:0e0631af0305 | 34 | #include <algorithm> |
RyoheiHagimoto | 0:0e0631af0305 | 35 | #include <map> |
RyoheiHagimoto | 0:0e0631af0305 | 36 | #include <cassert> |
RyoheiHagimoto | 0:0e0631af0305 | 37 | #include <cstring> |
RyoheiHagimoto | 0:0e0631af0305 | 38 | |
RyoheiHagimoto | 0:0e0631af0305 | 39 | #include "general.h" |
RyoheiHagimoto | 0:0e0631af0305 | 40 | #include "nn_index.h" |
RyoheiHagimoto | 0:0e0631af0305 | 41 | #include "dynamic_bitset.h" |
RyoheiHagimoto | 0:0e0631af0305 | 42 | #include "matrix.h" |
RyoheiHagimoto | 0:0e0631af0305 | 43 | #include "result_set.h" |
RyoheiHagimoto | 0:0e0631af0305 | 44 | #include "heap.h" |
RyoheiHagimoto | 0:0e0631af0305 | 45 | #include "allocator.h" |
RyoheiHagimoto | 0:0e0631af0305 | 46 | #include "random.h" |
RyoheiHagimoto | 0:0e0631af0305 | 47 | #include "saving.h" |
RyoheiHagimoto | 0:0e0631af0305 | 48 | |
RyoheiHagimoto | 0:0e0631af0305 | 49 | |
RyoheiHagimoto | 0:0e0631af0305 | 50 | namespace cvflann |
RyoheiHagimoto | 0:0e0631af0305 | 51 | { |
RyoheiHagimoto | 0:0e0631af0305 | 52 | |
RyoheiHagimoto | 0:0e0631af0305 | 53 | struct KDTreeIndexParams : public IndexParams |
RyoheiHagimoto | 0:0e0631af0305 | 54 | { |
RyoheiHagimoto | 0:0e0631af0305 | 55 | KDTreeIndexParams(int trees = 4) |
RyoheiHagimoto | 0:0e0631af0305 | 56 | { |
RyoheiHagimoto | 0:0e0631af0305 | 57 | (*this)["algorithm"] = FLANN_INDEX_KDTREE; |
RyoheiHagimoto | 0:0e0631af0305 | 58 | (*this)["trees"] = trees; |
RyoheiHagimoto | 0:0e0631af0305 | 59 | } |
RyoheiHagimoto | 0:0e0631af0305 | 60 | }; |
RyoheiHagimoto | 0:0e0631af0305 | 61 | |
RyoheiHagimoto | 0:0e0631af0305 | 62 | |
RyoheiHagimoto | 0:0e0631af0305 | 63 | /** |
RyoheiHagimoto | 0:0e0631af0305 | 64 | * Randomized kd-tree index |
RyoheiHagimoto | 0:0e0631af0305 | 65 | * |
RyoheiHagimoto | 0:0e0631af0305 | 66 | * Contains the k-d trees and other information for indexing a set of points |
RyoheiHagimoto | 0:0e0631af0305 | 67 | * for nearest-neighbor matching. |
RyoheiHagimoto | 0:0e0631af0305 | 68 | */ |
RyoheiHagimoto | 0:0e0631af0305 | 69 | template <typename Distance> |
RyoheiHagimoto | 0:0e0631af0305 | 70 | class KDTreeIndex : public NNIndex<Distance> |
RyoheiHagimoto | 0:0e0631af0305 | 71 | { |
RyoheiHagimoto | 0:0e0631af0305 | 72 | public: |
RyoheiHagimoto | 0:0e0631af0305 | 73 | typedef typename Distance::ElementType ElementType; |
RyoheiHagimoto | 0:0e0631af0305 | 74 | typedef typename Distance::ResultType DistanceType; |
RyoheiHagimoto | 0:0e0631af0305 | 75 | |
RyoheiHagimoto | 0:0e0631af0305 | 76 | |
RyoheiHagimoto | 0:0e0631af0305 | 77 | /** |
RyoheiHagimoto | 0:0e0631af0305 | 78 | * KDTree constructor |
RyoheiHagimoto | 0:0e0631af0305 | 79 | * |
RyoheiHagimoto | 0:0e0631af0305 | 80 | * Params: |
RyoheiHagimoto | 0:0e0631af0305 | 81 | * inputData = dataset with the input features |
RyoheiHagimoto | 0:0e0631af0305 | 82 | * params = parameters passed to the kdtree algorithm |
RyoheiHagimoto | 0:0e0631af0305 | 83 | */ |
RyoheiHagimoto | 0:0e0631af0305 | 84 | KDTreeIndex(const Matrix<ElementType>& inputData, const IndexParams& params = KDTreeIndexParams(), |
RyoheiHagimoto | 0:0e0631af0305 | 85 | Distance d = Distance() ) : |
RyoheiHagimoto | 0:0e0631af0305 | 86 | dataset_(inputData), index_params_(params), distance_(d) |
RyoheiHagimoto | 0:0e0631af0305 | 87 | { |
RyoheiHagimoto | 0:0e0631af0305 | 88 | size_ = dataset_.rows; |
RyoheiHagimoto | 0:0e0631af0305 | 89 | veclen_ = dataset_.cols; |
RyoheiHagimoto | 0:0e0631af0305 | 90 | |
RyoheiHagimoto | 0:0e0631af0305 | 91 | trees_ = get_param(index_params_,"trees",4); |
RyoheiHagimoto | 0:0e0631af0305 | 92 | tree_roots_ = new NodePtr[trees_]; |
RyoheiHagimoto | 0:0e0631af0305 | 93 | |
RyoheiHagimoto | 0:0e0631af0305 | 94 | // Create a permutable array of indices to the input vectors. |
RyoheiHagimoto | 0:0e0631af0305 | 95 | vind_.resize(size_); |
RyoheiHagimoto | 0:0e0631af0305 | 96 | for (size_t i = 0; i < size_; ++i) { |
RyoheiHagimoto | 0:0e0631af0305 | 97 | vind_[i] = int(i); |
RyoheiHagimoto | 0:0e0631af0305 | 98 | } |
RyoheiHagimoto | 0:0e0631af0305 | 99 | |
RyoheiHagimoto | 0:0e0631af0305 | 100 | mean_ = new DistanceType[veclen_]; |
RyoheiHagimoto | 0:0e0631af0305 | 101 | var_ = new DistanceType[veclen_]; |
RyoheiHagimoto | 0:0e0631af0305 | 102 | } |
RyoheiHagimoto | 0:0e0631af0305 | 103 | |
RyoheiHagimoto | 0:0e0631af0305 | 104 | |
RyoheiHagimoto | 0:0e0631af0305 | 105 | KDTreeIndex(const KDTreeIndex&); |
RyoheiHagimoto | 0:0e0631af0305 | 106 | KDTreeIndex& operator=(const KDTreeIndex&); |
RyoheiHagimoto | 0:0e0631af0305 | 107 | |
RyoheiHagimoto | 0:0e0631af0305 | 108 | /** |
RyoheiHagimoto | 0:0e0631af0305 | 109 | * Standard destructor |
RyoheiHagimoto | 0:0e0631af0305 | 110 | */ |
RyoheiHagimoto | 0:0e0631af0305 | 111 | ~KDTreeIndex() |
RyoheiHagimoto | 0:0e0631af0305 | 112 | { |
RyoheiHagimoto | 0:0e0631af0305 | 113 | if (tree_roots_!=NULL) { |
RyoheiHagimoto | 0:0e0631af0305 | 114 | delete[] tree_roots_; |
RyoheiHagimoto | 0:0e0631af0305 | 115 | } |
RyoheiHagimoto | 0:0e0631af0305 | 116 | delete[] mean_; |
RyoheiHagimoto | 0:0e0631af0305 | 117 | delete[] var_; |
RyoheiHagimoto | 0:0e0631af0305 | 118 | } |
RyoheiHagimoto | 0:0e0631af0305 | 119 | |
RyoheiHagimoto | 0:0e0631af0305 | 120 | /** |
RyoheiHagimoto | 0:0e0631af0305 | 121 | * Builds the index |
RyoheiHagimoto | 0:0e0631af0305 | 122 | */ |
RyoheiHagimoto | 0:0e0631af0305 | 123 | void buildIndex() |
RyoheiHagimoto | 0:0e0631af0305 | 124 | { |
RyoheiHagimoto | 0:0e0631af0305 | 125 | /* Construct the randomized trees. */ |
RyoheiHagimoto | 0:0e0631af0305 | 126 | for (int i = 0; i < trees_; i++) { |
RyoheiHagimoto | 0:0e0631af0305 | 127 | /* Randomize the order of vectors to allow for unbiased sampling. */ |
RyoheiHagimoto | 0:0e0631af0305 | 128 | std::random_shuffle(vind_.begin(), vind_.end()); |
RyoheiHagimoto | 0:0e0631af0305 | 129 | tree_roots_[i] = divideTree(&vind_[0], int(size_) ); |
RyoheiHagimoto | 0:0e0631af0305 | 130 | } |
RyoheiHagimoto | 0:0e0631af0305 | 131 | } |
RyoheiHagimoto | 0:0e0631af0305 | 132 | |
RyoheiHagimoto | 0:0e0631af0305 | 133 | |
RyoheiHagimoto | 0:0e0631af0305 | 134 | flann_algorithm_t getType() const |
RyoheiHagimoto | 0:0e0631af0305 | 135 | { |
RyoheiHagimoto | 0:0e0631af0305 | 136 | return FLANN_INDEX_KDTREE; |
RyoheiHagimoto | 0:0e0631af0305 | 137 | } |
RyoheiHagimoto | 0:0e0631af0305 | 138 | |
RyoheiHagimoto | 0:0e0631af0305 | 139 | |
RyoheiHagimoto | 0:0e0631af0305 | 140 | void saveIndex(FILE* stream) |
RyoheiHagimoto | 0:0e0631af0305 | 141 | { |
RyoheiHagimoto | 0:0e0631af0305 | 142 | save_value(stream, trees_); |
RyoheiHagimoto | 0:0e0631af0305 | 143 | for (int i=0; i<trees_; ++i) { |
RyoheiHagimoto | 0:0e0631af0305 | 144 | save_tree(stream, tree_roots_[i]); |
RyoheiHagimoto | 0:0e0631af0305 | 145 | } |
RyoheiHagimoto | 0:0e0631af0305 | 146 | } |
RyoheiHagimoto | 0:0e0631af0305 | 147 | |
RyoheiHagimoto | 0:0e0631af0305 | 148 | |
RyoheiHagimoto | 0:0e0631af0305 | 149 | |
RyoheiHagimoto | 0:0e0631af0305 | 150 | void loadIndex(FILE* stream) |
RyoheiHagimoto | 0:0e0631af0305 | 151 | { |
RyoheiHagimoto | 0:0e0631af0305 | 152 | load_value(stream, trees_); |
RyoheiHagimoto | 0:0e0631af0305 | 153 | if (tree_roots_!=NULL) { |
RyoheiHagimoto | 0:0e0631af0305 | 154 | delete[] tree_roots_; |
RyoheiHagimoto | 0:0e0631af0305 | 155 | } |
RyoheiHagimoto | 0:0e0631af0305 | 156 | tree_roots_ = new NodePtr[trees_]; |
RyoheiHagimoto | 0:0e0631af0305 | 157 | for (int i=0; i<trees_; ++i) { |
RyoheiHagimoto | 0:0e0631af0305 | 158 | load_tree(stream,tree_roots_[i]); |
RyoheiHagimoto | 0:0e0631af0305 | 159 | } |
RyoheiHagimoto | 0:0e0631af0305 | 160 | |
RyoheiHagimoto | 0:0e0631af0305 | 161 | index_params_["algorithm"] = getType(); |
RyoheiHagimoto | 0:0e0631af0305 | 162 | index_params_["trees"] = tree_roots_; |
RyoheiHagimoto | 0:0e0631af0305 | 163 | } |
RyoheiHagimoto | 0:0e0631af0305 | 164 | |
RyoheiHagimoto | 0:0e0631af0305 | 165 | /** |
RyoheiHagimoto | 0:0e0631af0305 | 166 | * Returns size of index. |
RyoheiHagimoto | 0:0e0631af0305 | 167 | */ |
RyoheiHagimoto | 0:0e0631af0305 | 168 | size_t size() const |
RyoheiHagimoto | 0:0e0631af0305 | 169 | { |
RyoheiHagimoto | 0:0e0631af0305 | 170 | return size_; |
RyoheiHagimoto | 0:0e0631af0305 | 171 | } |
RyoheiHagimoto | 0:0e0631af0305 | 172 | |
RyoheiHagimoto | 0:0e0631af0305 | 173 | /** |
RyoheiHagimoto | 0:0e0631af0305 | 174 | * Returns the length of an index feature. |
RyoheiHagimoto | 0:0e0631af0305 | 175 | */ |
RyoheiHagimoto | 0:0e0631af0305 | 176 | size_t veclen() const |
RyoheiHagimoto | 0:0e0631af0305 | 177 | { |
RyoheiHagimoto | 0:0e0631af0305 | 178 | return veclen_; |
RyoheiHagimoto | 0:0e0631af0305 | 179 | } |
RyoheiHagimoto | 0:0e0631af0305 | 180 | |
RyoheiHagimoto | 0:0e0631af0305 | 181 | /** |
RyoheiHagimoto | 0:0e0631af0305 | 182 | * Computes the inde memory usage |
RyoheiHagimoto | 0:0e0631af0305 | 183 | * Returns: memory used by the index |
RyoheiHagimoto | 0:0e0631af0305 | 184 | */ |
RyoheiHagimoto | 0:0e0631af0305 | 185 | int usedMemory() const |
RyoheiHagimoto | 0:0e0631af0305 | 186 | { |
RyoheiHagimoto | 0:0e0631af0305 | 187 | return int(pool_.usedMemory+pool_.wastedMemory+dataset_.rows*sizeof(int)); // pool memory and vind array memory |
RyoheiHagimoto | 0:0e0631af0305 | 188 | } |
RyoheiHagimoto | 0:0e0631af0305 | 189 | |
RyoheiHagimoto | 0:0e0631af0305 | 190 | /** |
RyoheiHagimoto | 0:0e0631af0305 | 191 | * Find set of nearest neighbors to vec. Their indices are stored inside |
RyoheiHagimoto | 0:0e0631af0305 | 192 | * the result object. |
RyoheiHagimoto | 0:0e0631af0305 | 193 | * |
RyoheiHagimoto | 0:0e0631af0305 | 194 | * Params: |
RyoheiHagimoto | 0:0e0631af0305 | 195 | * result = the result object in which the indices of the nearest-neighbors are stored |
RyoheiHagimoto | 0:0e0631af0305 | 196 | * vec = the vector for which to search the nearest neighbors |
RyoheiHagimoto | 0:0e0631af0305 | 197 | * maxCheck = the maximum number of restarts (in a best-bin-first manner) |
RyoheiHagimoto | 0:0e0631af0305 | 198 | */ |
RyoheiHagimoto | 0:0e0631af0305 | 199 | void findNeighbors(ResultSet<DistanceType>& result, const ElementType* vec, const SearchParams& searchParams) |
RyoheiHagimoto | 0:0e0631af0305 | 200 | { |
RyoheiHagimoto | 0:0e0631af0305 | 201 | int maxChecks = get_param(searchParams,"checks", 32); |
RyoheiHagimoto | 0:0e0631af0305 | 202 | float epsError = 1+get_param(searchParams,"eps",0.0f); |
RyoheiHagimoto | 0:0e0631af0305 | 203 | |
RyoheiHagimoto | 0:0e0631af0305 | 204 | if (maxChecks==FLANN_CHECKS_UNLIMITED) { |
RyoheiHagimoto | 0:0e0631af0305 | 205 | getExactNeighbors(result, vec, epsError); |
RyoheiHagimoto | 0:0e0631af0305 | 206 | } |
RyoheiHagimoto | 0:0e0631af0305 | 207 | else { |
RyoheiHagimoto | 0:0e0631af0305 | 208 | getNeighbors(result, vec, maxChecks, epsError); |
RyoheiHagimoto | 0:0e0631af0305 | 209 | } |
RyoheiHagimoto | 0:0e0631af0305 | 210 | } |
RyoheiHagimoto | 0:0e0631af0305 | 211 | |
RyoheiHagimoto | 0:0e0631af0305 | 212 | IndexParams getParameters() const |
RyoheiHagimoto | 0:0e0631af0305 | 213 | { |
RyoheiHagimoto | 0:0e0631af0305 | 214 | return index_params_; |
RyoheiHagimoto | 0:0e0631af0305 | 215 | } |
RyoheiHagimoto | 0:0e0631af0305 | 216 | |
RyoheiHagimoto | 0:0e0631af0305 | 217 | private: |
RyoheiHagimoto | 0:0e0631af0305 | 218 | |
RyoheiHagimoto | 0:0e0631af0305 | 219 | |
RyoheiHagimoto | 0:0e0631af0305 | 220 | /*--------------------- Internal Data Structures --------------------------*/ |
RyoheiHagimoto | 0:0e0631af0305 | 221 | struct Node |
RyoheiHagimoto | 0:0e0631af0305 | 222 | { |
RyoheiHagimoto | 0:0e0631af0305 | 223 | /** |
RyoheiHagimoto | 0:0e0631af0305 | 224 | * Dimension used for subdivision. |
RyoheiHagimoto | 0:0e0631af0305 | 225 | */ |
RyoheiHagimoto | 0:0e0631af0305 | 226 | int divfeat; |
RyoheiHagimoto | 0:0e0631af0305 | 227 | /** |
RyoheiHagimoto | 0:0e0631af0305 | 228 | * The values used for subdivision. |
RyoheiHagimoto | 0:0e0631af0305 | 229 | */ |
RyoheiHagimoto | 0:0e0631af0305 | 230 | DistanceType divval; |
RyoheiHagimoto | 0:0e0631af0305 | 231 | /** |
RyoheiHagimoto | 0:0e0631af0305 | 232 | * The child nodes. |
RyoheiHagimoto | 0:0e0631af0305 | 233 | */ |
RyoheiHagimoto | 0:0e0631af0305 | 234 | Node* child1, * child2; |
RyoheiHagimoto | 0:0e0631af0305 | 235 | }; |
RyoheiHagimoto | 0:0e0631af0305 | 236 | typedef Node* NodePtr; |
RyoheiHagimoto | 0:0e0631af0305 | 237 | typedef BranchStruct<NodePtr, DistanceType> BranchSt; |
RyoheiHagimoto | 0:0e0631af0305 | 238 | typedef BranchSt* Branch; |
RyoheiHagimoto | 0:0e0631af0305 | 239 | |
RyoheiHagimoto | 0:0e0631af0305 | 240 | |
RyoheiHagimoto | 0:0e0631af0305 | 241 | |
RyoheiHagimoto | 0:0e0631af0305 | 242 | void save_tree(FILE* stream, NodePtr tree) |
RyoheiHagimoto | 0:0e0631af0305 | 243 | { |
RyoheiHagimoto | 0:0e0631af0305 | 244 | save_value(stream, *tree); |
RyoheiHagimoto | 0:0e0631af0305 | 245 | if (tree->child1!=NULL) { |
RyoheiHagimoto | 0:0e0631af0305 | 246 | save_tree(stream, tree->child1); |
RyoheiHagimoto | 0:0e0631af0305 | 247 | } |
RyoheiHagimoto | 0:0e0631af0305 | 248 | if (tree->child2!=NULL) { |
RyoheiHagimoto | 0:0e0631af0305 | 249 | save_tree(stream, tree->child2); |
RyoheiHagimoto | 0:0e0631af0305 | 250 | } |
RyoheiHagimoto | 0:0e0631af0305 | 251 | } |
RyoheiHagimoto | 0:0e0631af0305 | 252 | |
RyoheiHagimoto | 0:0e0631af0305 | 253 | |
RyoheiHagimoto | 0:0e0631af0305 | 254 | void load_tree(FILE* stream, NodePtr& tree) |
RyoheiHagimoto | 0:0e0631af0305 | 255 | { |
RyoheiHagimoto | 0:0e0631af0305 | 256 | tree = pool_.allocate<Node>(); |
RyoheiHagimoto | 0:0e0631af0305 | 257 | load_value(stream, *tree); |
RyoheiHagimoto | 0:0e0631af0305 | 258 | if (tree->child1!=NULL) { |
RyoheiHagimoto | 0:0e0631af0305 | 259 | load_tree(stream, tree->child1); |
RyoheiHagimoto | 0:0e0631af0305 | 260 | } |
RyoheiHagimoto | 0:0e0631af0305 | 261 | if (tree->child2!=NULL) { |
RyoheiHagimoto | 0:0e0631af0305 | 262 | load_tree(stream, tree->child2); |
RyoheiHagimoto | 0:0e0631af0305 | 263 | } |
RyoheiHagimoto | 0:0e0631af0305 | 264 | } |
RyoheiHagimoto | 0:0e0631af0305 | 265 | |
RyoheiHagimoto | 0:0e0631af0305 | 266 | |
RyoheiHagimoto | 0:0e0631af0305 | 267 | /** |
RyoheiHagimoto | 0:0e0631af0305 | 268 | * Create a tree node that subdivides the list of vecs from vind[first] |
RyoheiHagimoto | 0:0e0631af0305 | 269 | * to vind[last]. The routine is called recursively on each sublist. |
RyoheiHagimoto | 0:0e0631af0305 | 270 | * Place a pointer to this new tree node in the location pTree. |
RyoheiHagimoto | 0:0e0631af0305 | 271 | * |
RyoheiHagimoto | 0:0e0631af0305 | 272 | * Params: pTree = the new node to create |
RyoheiHagimoto | 0:0e0631af0305 | 273 | * first = index of the first vector |
RyoheiHagimoto | 0:0e0631af0305 | 274 | * last = index of the last vector |
RyoheiHagimoto | 0:0e0631af0305 | 275 | */ |
RyoheiHagimoto | 0:0e0631af0305 | 276 | NodePtr divideTree(int* ind, int count) |
RyoheiHagimoto | 0:0e0631af0305 | 277 | { |
RyoheiHagimoto | 0:0e0631af0305 | 278 | NodePtr node = pool_.allocate<Node>(); // allocate memory |
RyoheiHagimoto | 0:0e0631af0305 | 279 | |
RyoheiHagimoto | 0:0e0631af0305 | 280 | /* If too few exemplars remain, then make this a leaf node. */ |
RyoheiHagimoto | 0:0e0631af0305 | 281 | if ( count == 1) { |
RyoheiHagimoto | 0:0e0631af0305 | 282 | node->child1 = node->child2 = NULL; /* Mark as leaf node. */ |
RyoheiHagimoto | 0:0e0631af0305 | 283 | node->divfeat = *ind; /* Store index of this vec. */ |
RyoheiHagimoto | 0:0e0631af0305 | 284 | } |
RyoheiHagimoto | 0:0e0631af0305 | 285 | else { |
RyoheiHagimoto | 0:0e0631af0305 | 286 | int idx; |
RyoheiHagimoto | 0:0e0631af0305 | 287 | int cutfeat; |
RyoheiHagimoto | 0:0e0631af0305 | 288 | DistanceType cutval; |
RyoheiHagimoto | 0:0e0631af0305 | 289 | meanSplit(ind, count, idx, cutfeat, cutval); |
RyoheiHagimoto | 0:0e0631af0305 | 290 | |
RyoheiHagimoto | 0:0e0631af0305 | 291 | node->divfeat = cutfeat; |
RyoheiHagimoto | 0:0e0631af0305 | 292 | node->divval = cutval; |
RyoheiHagimoto | 0:0e0631af0305 | 293 | node->child1 = divideTree(ind, idx); |
RyoheiHagimoto | 0:0e0631af0305 | 294 | node->child2 = divideTree(ind+idx, count-idx); |
RyoheiHagimoto | 0:0e0631af0305 | 295 | } |
RyoheiHagimoto | 0:0e0631af0305 | 296 | |
RyoheiHagimoto | 0:0e0631af0305 | 297 | return node; |
RyoheiHagimoto | 0:0e0631af0305 | 298 | } |
RyoheiHagimoto | 0:0e0631af0305 | 299 | |
RyoheiHagimoto | 0:0e0631af0305 | 300 | |
RyoheiHagimoto | 0:0e0631af0305 | 301 | /** |
RyoheiHagimoto | 0:0e0631af0305 | 302 | * Choose which feature to use in order to subdivide this set of vectors. |
RyoheiHagimoto | 0:0e0631af0305 | 303 | * Make a random choice among those with the highest variance, and use |
RyoheiHagimoto | 0:0e0631af0305 | 304 | * its variance as the threshold value. |
RyoheiHagimoto | 0:0e0631af0305 | 305 | */ |
RyoheiHagimoto | 0:0e0631af0305 | 306 | void meanSplit(int* ind, int count, int& index, int& cutfeat, DistanceType& cutval) |
RyoheiHagimoto | 0:0e0631af0305 | 307 | { |
RyoheiHagimoto | 0:0e0631af0305 | 308 | memset(mean_,0,veclen_*sizeof(DistanceType)); |
RyoheiHagimoto | 0:0e0631af0305 | 309 | memset(var_,0,veclen_*sizeof(DistanceType)); |
RyoheiHagimoto | 0:0e0631af0305 | 310 | |
RyoheiHagimoto | 0:0e0631af0305 | 311 | /* Compute mean values. Only the first SAMPLE_MEAN values need to be |
RyoheiHagimoto | 0:0e0631af0305 | 312 | sampled to get a good estimate. |
RyoheiHagimoto | 0:0e0631af0305 | 313 | */ |
RyoheiHagimoto | 0:0e0631af0305 | 314 | int cnt = std::min((int)SAMPLE_MEAN+1, count); |
RyoheiHagimoto | 0:0e0631af0305 | 315 | for (int j = 0; j < cnt; ++j) { |
RyoheiHagimoto | 0:0e0631af0305 | 316 | ElementType* v = dataset_[ind[j]]; |
RyoheiHagimoto | 0:0e0631af0305 | 317 | for (size_t k=0; k<veclen_; ++k) { |
RyoheiHagimoto | 0:0e0631af0305 | 318 | mean_[k] += v[k]; |
RyoheiHagimoto | 0:0e0631af0305 | 319 | } |
RyoheiHagimoto | 0:0e0631af0305 | 320 | } |
RyoheiHagimoto | 0:0e0631af0305 | 321 | for (size_t k=0; k<veclen_; ++k) { |
RyoheiHagimoto | 0:0e0631af0305 | 322 | mean_[k] /= cnt; |
RyoheiHagimoto | 0:0e0631af0305 | 323 | } |
RyoheiHagimoto | 0:0e0631af0305 | 324 | |
RyoheiHagimoto | 0:0e0631af0305 | 325 | /* Compute variances (no need to divide by count). */ |
RyoheiHagimoto | 0:0e0631af0305 | 326 | for (int j = 0; j < cnt; ++j) { |
RyoheiHagimoto | 0:0e0631af0305 | 327 | ElementType* v = dataset_[ind[j]]; |
RyoheiHagimoto | 0:0e0631af0305 | 328 | for (size_t k=0; k<veclen_; ++k) { |
RyoheiHagimoto | 0:0e0631af0305 | 329 | DistanceType dist = v[k] - mean_[k]; |
RyoheiHagimoto | 0:0e0631af0305 | 330 | var_[k] += dist * dist; |
RyoheiHagimoto | 0:0e0631af0305 | 331 | } |
RyoheiHagimoto | 0:0e0631af0305 | 332 | } |
RyoheiHagimoto | 0:0e0631af0305 | 333 | /* Select one of the highest variance indices at random. */ |
RyoheiHagimoto | 0:0e0631af0305 | 334 | cutfeat = selectDivision(var_); |
RyoheiHagimoto | 0:0e0631af0305 | 335 | cutval = mean_[cutfeat]; |
RyoheiHagimoto | 0:0e0631af0305 | 336 | |
RyoheiHagimoto | 0:0e0631af0305 | 337 | int lim1, lim2; |
RyoheiHagimoto | 0:0e0631af0305 | 338 | planeSplit(ind, count, cutfeat, cutval, lim1, lim2); |
RyoheiHagimoto | 0:0e0631af0305 | 339 | |
RyoheiHagimoto | 0:0e0631af0305 | 340 | if (lim1>count/2) index = lim1; |
RyoheiHagimoto | 0:0e0631af0305 | 341 | else if (lim2<count/2) index = lim2; |
RyoheiHagimoto | 0:0e0631af0305 | 342 | else index = count/2; |
RyoheiHagimoto | 0:0e0631af0305 | 343 | |
RyoheiHagimoto | 0:0e0631af0305 | 344 | /* If either list is empty, it means that all remaining features |
RyoheiHagimoto | 0:0e0631af0305 | 345 | * are identical. Split in the middle to maintain a balanced tree. |
RyoheiHagimoto | 0:0e0631af0305 | 346 | */ |
RyoheiHagimoto | 0:0e0631af0305 | 347 | if ((lim1==count)||(lim2==0)) index = count/2; |
RyoheiHagimoto | 0:0e0631af0305 | 348 | } |
RyoheiHagimoto | 0:0e0631af0305 | 349 | |
RyoheiHagimoto | 0:0e0631af0305 | 350 | |
RyoheiHagimoto | 0:0e0631af0305 | 351 | /** |
RyoheiHagimoto | 0:0e0631af0305 | 352 | * Select the top RAND_DIM largest values from v and return the index of |
RyoheiHagimoto | 0:0e0631af0305 | 353 | * one of these selected at random. |
RyoheiHagimoto | 0:0e0631af0305 | 354 | */ |
RyoheiHagimoto | 0:0e0631af0305 | 355 | int selectDivision(DistanceType* v) |
RyoheiHagimoto | 0:0e0631af0305 | 356 | { |
RyoheiHagimoto | 0:0e0631af0305 | 357 | int num = 0; |
RyoheiHagimoto | 0:0e0631af0305 | 358 | size_t topind[RAND_DIM]; |
RyoheiHagimoto | 0:0e0631af0305 | 359 | |
RyoheiHagimoto | 0:0e0631af0305 | 360 | /* Create a list of the indices of the top RAND_DIM values. */ |
RyoheiHagimoto | 0:0e0631af0305 | 361 | for (size_t i = 0; i < veclen_; ++i) { |
RyoheiHagimoto | 0:0e0631af0305 | 362 | if ((num < RAND_DIM)||(v[i] > v[topind[num-1]])) { |
RyoheiHagimoto | 0:0e0631af0305 | 363 | /* Put this element at end of topind. */ |
RyoheiHagimoto | 0:0e0631af0305 | 364 | if (num < RAND_DIM) { |
RyoheiHagimoto | 0:0e0631af0305 | 365 | topind[num++] = i; /* Add to list. */ |
RyoheiHagimoto | 0:0e0631af0305 | 366 | } |
RyoheiHagimoto | 0:0e0631af0305 | 367 | else { |
RyoheiHagimoto | 0:0e0631af0305 | 368 | topind[num-1] = i; /* Replace last element. */ |
RyoheiHagimoto | 0:0e0631af0305 | 369 | } |
RyoheiHagimoto | 0:0e0631af0305 | 370 | /* Bubble end value down to right location by repeated swapping. */ |
RyoheiHagimoto | 0:0e0631af0305 | 371 | int j = num - 1; |
RyoheiHagimoto | 0:0e0631af0305 | 372 | while (j > 0 && v[topind[j]] > v[topind[j-1]]) { |
RyoheiHagimoto | 0:0e0631af0305 | 373 | std::swap(topind[j], topind[j-1]); |
RyoheiHagimoto | 0:0e0631af0305 | 374 | --j; |
RyoheiHagimoto | 0:0e0631af0305 | 375 | } |
RyoheiHagimoto | 0:0e0631af0305 | 376 | } |
RyoheiHagimoto | 0:0e0631af0305 | 377 | } |
RyoheiHagimoto | 0:0e0631af0305 | 378 | /* Select a random integer in range [0,num-1], and return that index. */ |
RyoheiHagimoto | 0:0e0631af0305 | 379 | int rnd = rand_int(num); |
RyoheiHagimoto | 0:0e0631af0305 | 380 | return (int)topind[rnd]; |
RyoheiHagimoto | 0:0e0631af0305 | 381 | } |
RyoheiHagimoto | 0:0e0631af0305 | 382 | |
RyoheiHagimoto | 0:0e0631af0305 | 383 | |
RyoheiHagimoto | 0:0e0631af0305 | 384 | /** |
RyoheiHagimoto | 0:0e0631af0305 | 385 | * Subdivide the list of points by a plane perpendicular on axe corresponding |
RyoheiHagimoto | 0:0e0631af0305 | 386 | * to the 'cutfeat' dimension at 'cutval' position. |
RyoheiHagimoto | 0:0e0631af0305 | 387 | * |
RyoheiHagimoto | 0:0e0631af0305 | 388 | * On return: |
RyoheiHagimoto | 0:0e0631af0305 | 389 | * dataset[ind[0..lim1-1]][cutfeat]<cutval |
RyoheiHagimoto | 0:0e0631af0305 | 390 | * dataset[ind[lim1..lim2-1]][cutfeat]==cutval |
RyoheiHagimoto | 0:0e0631af0305 | 391 | * dataset[ind[lim2..count]][cutfeat]>cutval |
RyoheiHagimoto | 0:0e0631af0305 | 392 | */ |
RyoheiHagimoto | 0:0e0631af0305 | 393 | void planeSplit(int* ind, int count, int cutfeat, DistanceType cutval, int& lim1, int& lim2) |
RyoheiHagimoto | 0:0e0631af0305 | 394 | { |
RyoheiHagimoto | 0:0e0631af0305 | 395 | /* Move vector indices for left subtree to front of list. */ |
RyoheiHagimoto | 0:0e0631af0305 | 396 | int left = 0; |
RyoheiHagimoto | 0:0e0631af0305 | 397 | int right = count-1; |
RyoheiHagimoto | 0:0e0631af0305 | 398 | for (;; ) { |
RyoheiHagimoto | 0:0e0631af0305 | 399 | while (left<=right && dataset_[ind[left]][cutfeat]<cutval) ++left; |
RyoheiHagimoto | 0:0e0631af0305 | 400 | while (left<=right && dataset_[ind[right]][cutfeat]>=cutval) --right; |
RyoheiHagimoto | 0:0e0631af0305 | 401 | if (left>right) break; |
RyoheiHagimoto | 0:0e0631af0305 | 402 | std::swap(ind[left], ind[right]); ++left; --right; |
RyoheiHagimoto | 0:0e0631af0305 | 403 | } |
RyoheiHagimoto | 0:0e0631af0305 | 404 | lim1 = left; |
RyoheiHagimoto | 0:0e0631af0305 | 405 | right = count-1; |
RyoheiHagimoto | 0:0e0631af0305 | 406 | for (;; ) { |
RyoheiHagimoto | 0:0e0631af0305 | 407 | while (left<=right && dataset_[ind[left]][cutfeat]<=cutval) ++left; |
RyoheiHagimoto | 0:0e0631af0305 | 408 | while (left<=right && dataset_[ind[right]][cutfeat]>cutval) --right; |
RyoheiHagimoto | 0:0e0631af0305 | 409 | if (left>right) break; |
RyoheiHagimoto | 0:0e0631af0305 | 410 | std::swap(ind[left], ind[right]); ++left; --right; |
RyoheiHagimoto | 0:0e0631af0305 | 411 | } |
RyoheiHagimoto | 0:0e0631af0305 | 412 | lim2 = left; |
RyoheiHagimoto | 0:0e0631af0305 | 413 | } |
RyoheiHagimoto | 0:0e0631af0305 | 414 | |
RyoheiHagimoto | 0:0e0631af0305 | 415 | /** |
RyoheiHagimoto | 0:0e0631af0305 | 416 | * Performs an exact nearest neighbor search. The exact search performs a full |
RyoheiHagimoto | 0:0e0631af0305 | 417 | * traversal of the tree. |
RyoheiHagimoto | 0:0e0631af0305 | 418 | */ |
RyoheiHagimoto | 0:0e0631af0305 | 419 | void getExactNeighbors(ResultSet<DistanceType>& result, const ElementType* vec, float epsError) |
RyoheiHagimoto | 0:0e0631af0305 | 420 | { |
RyoheiHagimoto | 0:0e0631af0305 | 421 | // checkID -= 1; /* Set a different unique ID for each search. */ |
RyoheiHagimoto | 0:0e0631af0305 | 422 | |
RyoheiHagimoto | 0:0e0631af0305 | 423 | if (trees_ > 1) { |
RyoheiHagimoto | 0:0e0631af0305 | 424 | fprintf(stderr,"It doesn't make any sense to use more than one tree for exact search"); |
RyoheiHagimoto | 0:0e0631af0305 | 425 | } |
RyoheiHagimoto | 0:0e0631af0305 | 426 | if (trees_>0) { |
RyoheiHagimoto | 0:0e0631af0305 | 427 | searchLevelExact(result, vec, tree_roots_[0], 0.0, epsError); |
RyoheiHagimoto | 0:0e0631af0305 | 428 | } |
RyoheiHagimoto | 0:0e0631af0305 | 429 | assert(result.full()); |
RyoheiHagimoto | 0:0e0631af0305 | 430 | } |
RyoheiHagimoto | 0:0e0631af0305 | 431 | |
RyoheiHagimoto | 0:0e0631af0305 | 432 | /** |
RyoheiHagimoto | 0:0e0631af0305 | 433 | * Performs the approximate nearest-neighbor search. The search is approximate |
RyoheiHagimoto | 0:0e0631af0305 | 434 | * because the tree traversal is abandoned after a given number of descends in |
RyoheiHagimoto | 0:0e0631af0305 | 435 | * the tree. |
RyoheiHagimoto | 0:0e0631af0305 | 436 | */ |
RyoheiHagimoto | 0:0e0631af0305 | 437 | void getNeighbors(ResultSet<DistanceType>& result, const ElementType* vec, int maxCheck, float epsError) |
RyoheiHagimoto | 0:0e0631af0305 | 438 | { |
RyoheiHagimoto | 0:0e0631af0305 | 439 | int i; |
RyoheiHagimoto | 0:0e0631af0305 | 440 | BranchSt branch; |
RyoheiHagimoto | 0:0e0631af0305 | 441 | |
RyoheiHagimoto | 0:0e0631af0305 | 442 | int checkCount = 0; |
RyoheiHagimoto | 0:0e0631af0305 | 443 | Heap<BranchSt>* heap = new Heap<BranchSt>((int)size_); |
RyoheiHagimoto | 0:0e0631af0305 | 444 | DynamicBitset checked(size_); |
RyoheiHagimoto | 0:0e0631af0305 | 445 | |
RyoheiHagimoto | 0:0e0631af0305 | 446 | /* Search once through each tree down to root. */ |
RyoheiHagimoto | 0:0e0631af0305 | 447 | for (i = 0; i < trees_; ++i) { |
RyoheiHagimoto | 0:0e0631af0305 | 448 | searchLevel(result, vec, tree_roots_[i], 0, checkCount, maxCheck, epsError, heap, checked); |
RyoheiHagimoto | 0:0e0631af0305 | 449 | } |
RyoheiHagimoto | 0:0e0631af0305 | 450 | |
RyoheiHagimoto | 0:0e0631af0305 | 451 | /* Keep searching other branches from heap until finished. */ |
RyoheiHagimoto | 0:0e0631af0305 | 452 | while ( heap->popMin(branch) && (checkCount < maxCheck || !result.full() )) { |
RyoheiHagimoto | 0:0e0631af0305 | 453 | searchLevel(result, vec, branch.node, branch.mindist, checkCount, maxCheck, epsError, heap, checked); |
RyoheiHagimoto | 0:0e0631af0305 | 454 | } |
RyoheiHagimoto | 0:0e0631af0305 | 455 | |
RyoheiHagimoto | 0:0e0631af0305 | 456 | delete heap; |
RyoheiHagimoto | 0:0e0631af0305 | 457 | |
RyoheiHagimoto | 0:0e0631af0305 | 458 | assert(result.full()); |
RyoheiHagimoto | 0:0e0631af0305 | 459 | } |
RyoheiHagimoto | 0:0e0631af0305 | 460 | |
RyoheiHagimoto | 0:0e0631af0305 | 461 | |
RyoheiHagimoto | 0:0e0631af0305 | 462 | /** |
RyoheiHagimoto | 0:0e0631af0305 | 463 | * Search starting from a given node of the tree. Based on any mismatches at |
RyoheiHagimoto | 0:0e0631af0305 | 464 | * higher levels, all exemplars below this level must have a distance of |
RyoheiHagimoto | 0:0e0631af0305 | 465 | * at least "mindistsq". |
RyoheiHagimoto | 0:0e0631af0305 | 466 | */ |
RyoheiHagimoto | 0:0e0631af0305 | 467 | void searchLevel(ResultSet<DistanceType>& result_set, const ElementType* vec, NodePtr node, DistanceType mindist, int& checkCount, int maxCheck, |
RyoheiHagimoto | 0:0e0631af0305 | 468 | float epsError, Heap<BranchSt>* heap, DynamicBitset& checked) |
RyoheiHagimoto | 0:0e0631af0305 | 469 | { |
RyoheiHagimoto | 0:0e0631af0305 | 470 | if (result_set.worstDist()<mindist) { |
RyoheiHagimoto | 0:0e0631af0305 | 471 | // printf("Ignoring branch, too far\n"); |
RyoheiHagimoto | 0:0e0631af0305 | 472 | return; |
RyoheiHagimoto | 0:0e0631af0305 | 473 | } |
RyoheiHagimoto | 0:0e0631af0305 | 474 | |
RyoheiHagimoto | 0:0e0631af0305 | 475 | /* If this is a leaf node, then do check and return. */ |
RyoheiHagimoto | 0:0e0631af0305 | 476 | if ((node->child1 == NULL)&&(node->child2 == NULL)) { |
RyoheiHagimoto | 0:0e0631af0305 | 477 | /* Do not check same node more than once when searching multiple trees. |
RyoheiHagimoto | 0:0e0631af0305 | 478 | Once a vector is checked, we set its location in vind to the |
RyoheiHagimoto | 0:0e0631af0305 | 479 | current checkID. |
RyoheiHagimoto | 0:0e0631af0305 | 480 | */ |
RyoheiHagimoto | 0:0e0631af0305 | 481 | int index = node->divfeat; |
RyoheiHagimoto | 0:0e0631af0305 | 482 | if ( checked.test(index) || ((checkCount>=maxCheck)&& result_set.full()) ) return; |
RyoheiHagimoto | 0:0e0631af0305 | 483 | checked.set(index); |
RyoheiHagimoto | 0:0e0631af0305 | 484 | checkCount++; |
RyoheiHagimoto | 0:0e0631af0305 | 485 | |
RyoheiHagimoto | 0:0e0631af0305 | 486 | DistanceType dist = distance_(dataset_[index], vec, veclen_); |
RyoheiHagimoto | 0:0e0631af0305 | 487 | result_set.addPoint(dist,index); |
RyoheiHagimoto | 0:0e0631af0305 | 488 | |
RyoheiHagimoto | 0:0e0631af0305 | 489 | return; |
RyoheiHagimoto | 0:0e0631af0305 | 490 | } |
RyoheiHagimoto | 0:0e0631af0305 | 491 | |
RyoheiHagimoto | 0:0e0631af0305 | 492 | /* Which child branch should be taken first? */ |
RyoheiHagimoto | 0:0e0631af0305 | 493 | ElementType val = vec[node->divfeat]; |
RyoheiHagimoto | 0:0e0631af0305 | 494 | DistanceType diff = val - node->divval; |
RyoheiHagimoto | 0:0e0631af0305 | 495 | NodePtr bestChild = (diff < 0) ? node->child1 : node->child2; |
RyoheiHagimoto | 0:0e0631af0305 | 496 | NodePtr otherChild = (diff < 0) ? node->child2 : node->child1; |
RyoheiHagimoto | 0:0e0631af0305 | 497 | |
RyoheiHagimoto | 0:0e0631af0305 | 498 | /* Create a branch record for the branch not taken. Add distance |
RyoheiHagimoto | 0:0e0631af0305 | 499 | of this feature boundary (we don't attempt to correct for any |
RyoheiHagimoto | 0:0e0631af0305 | 500 | use of this feature in a parent node, which is unlikely to |
RyoheiHagimoto | 0:0e0631af0305 | 501 | happen and would have only a small effect). Don't bother |
RyoheiHagimoto | 0:0e0631af0305 | 502 | adding more branches to heap after halfway point, as cost of |
RyoheiHagimoto | 0:0e0631af0305 | 503 | adding exceeds their value. |
RyoheiHagimoto | 0:0e0631af0305 | 504 | */ |
RyoheiHagimoto | 0:0e0631af0305 | 505 | |
RyoheiHagimoto | 0:0e0631af0305 | 506 | DistanceType new_distsq = mindist + distance_.accum_dist(val, node->divval, node->divfeat); |
RyoheiHagimoto | 0:0e0631af0305 | 507 | // if (2 * checkCount < maxCheck || !result.full()) { |
RyoheiHagimoto | 0:0e0631af0305 | 508 | if ((new_distsq*epsError < result_set.worstDist())|| !result_set.full()) { |
RyoheiHagimoto | 0:0e0631af0305 | 509 | heap->insert( BranchSt(otherChild, new_distsq) ); |
RyoheiHagimoto | 0:0e0631af0305 | 510 | } |
RyoheiHagimoto | 0:0e0631af0305 | 511 | |
RyoheiHagimoto | 0:0e0631af0305 | 512 | /* Call recursively to search next level down. */ |
RyoheiHagimoto | 0:0e0631af0305 | 513 | searchLevel(result_set, vec, bestChild, mindist, checkCount, maxCheck, epsError, heap, checked); |
RyoheiHagimoto | 0:0e0631af0305 | 514 | } |
RyoheiHagimoto | 0:0e0631af0305 | 515 | |
RyoheiHagimoto | 0:0e0631af0305 | 516 | /** |
RyoheiHagimoto | 0:0e0631af0305 | 517 | * Performs an exact search in the tree starting from a node. |
RyoheiHagimoto | 0:0e0631af0305 | 518 | */ |
RyoheiHagimoto | 0:0e0631af0305 | 519 | void searchLevelExact(ResultSet<DistanceType>& result_set, const ElementType* vec, const NodePtr node, DistanceType mindist, const float epsError) |
RyoheiHagimoto | 0:0e0631af0305 | 520 | { |
RyoheiHagimoto | 0:0e0631af0305 | 521 | /* If this is a leaf node, then do check and return. */ |
RyoheiHagimoto | 0:0e0631af0305 | 522 | if ((node->child1 == NULL)&&(node->child2 == NULL)) { |
RyoheiHagimoto | 0:0e0631af0305 | 523 | int index = node->divfeat; |
RyoheiHagimoto | 0:0e0631af0305 | 524 | DistanceType dist = distance_(dataset_[index], vec, veclen_); |
RyoheiHagimoto | 0:0e0631af0305 | 525 | result_set.addPoint(dist,index); |
RyoheiHagimoto | 0:0e0631af0305 | 526 | return; |
RyoheiHagimoto | 0:0e0631af0305 | 527 | } |
RyoheiHagimoto | 0:0e0631af0305 | 528 | |
RyoheiHagimoto | 0:0e0631af0305 | 529 | /* Which child branch should be taken first? */ |
RyoheiHagimoto | 0:0e0631af0305 | 530 | ElementType val = vec[node->divfeat]; |
RyoheiHagimoto | 0:0e0631af0305 | 531 | DistanceType diff = val - node->divval; |
RyoheiHagimoto | 0:0e0631af0305 | 532 | NodePtr bestChild = (diff < 0) ? node->child1 : node->child2; |
RyoheiHagimoto | 0:0e0631af0305 | 533 | NodePtr otherChild = (diff < 0) ? node->child2 : node->child1; |
RyoheiHagimoto | 0:0e0631af0305 | 534 | |
RyoheiHagimoto | 0:0e0631af0305 | 535 | /* Create a branch record for the branch not taken. Add distance |
RyoheiHagimoto | 0:0e0631af0305 | 536 | of this feature boundary (we don't attempt to correct for any |
RyoheiHagimoto | 0:0e0631af0305 | 537 | use of this feature in a parent node, which is unlikely to |
RyoheiHagimoto | 0:0e0631af0305 | 538 | happen and would have only a small effect). Don't bother |
RyoheiHagimoto | 0:0e0631af0305 | 539 | adding more branches to heap after halfway point, as cost of |
RyoheiHagimoto | 0:0e0631af0305 | 540 | adding exceeds their value. |
RyoheiHagimoto | 0:0e0631af0305 | 541 | */ |
RyoheiHagimoto | 0:0e0631af0305 | 542 | |
RyoheiHagimoto | 0:0e0631af0305 | 543 | DistanceType new_distsq = mindist + distance_.accum_dist(val, node->divval, node->divfeat); |
RyoheiHagimoto | 0:0e0631af0305 | 544 | |
RyoheiHagimoto | 0:0e0631af0305 | 545 | /* Call recursively to search next level down. */ |
RyoheiHagimoto | 0:0e0631af0305 | 546 | searchLevelExact(result_set, vec, bestChild, mindist, epsError); |
RyoheiHagimoto | 0:0e0631af0305 | 547 | |
RyoheiHagimoto | 0:0e0631af0305 | 548 | if (new_distsq*epsError<=result_set.worstDist()) { |
RyoheiHagimoto | 0:0e0631af0305 | 549 | searchLevelExact(result_set, vec, otherChild, new_distsq, epsError); |
RyoheiHagimoto | 0:0e0631af0305 | 550 | } |
RyoheiHagimoto | 0:0e0631af0305 | 551 | } |
RyoheiHagimoto | 0:0e0631af0305 | 552 | |
RyoheiHagimoto | 0:0e0631af0305 | 553 | |
RyoheiHagimoto | 0:0e0631af0305 | 554 | private: |
RyoheiHagimoto | 0:0e0631af0305 | 555 | |
RyoheiHagimoto | 0:0e0631af0305 | 556 | enum |
RyoheiHagimoto | 0:0e0631af0305 | 557 | { |
RyoheiHagimoto | 0:0e0631af0305 | 558 | /** |
RyoheiHagimoto | 0:0e0631af0305 | 559 | * To improve efficiency, only SAMPLE_MEAN random values are used to |
RyoheiHagimoto | 0:0e0631af0305 | 560 | * compute the mean and variance at each level when building a tree. |
RyoheiHagimoto | 0:0e0631af0305 | 561 | * A value of 100 seems to perform as well as using all values. |
RyoheiHagimoto | 0:0e0631af0305 | 562 | */ |
RyoheiHagimoto | 0:0e0631af0305 | 563 | SAMPLE_MEAN = 100, |
RyoheiHagimoto | 0:0e0631af0305 | 564 | /** |
RyoheiHagimoto | 0:0e0631af0305 | 565 | * Top random dimensions to consider |
RyoheiHagimoto | 0:0e0631af0305 | 566 | * |
RyoheiHagimoto | 0:0e0631af0305 | 567 | * When creating random trees, the dimension on which to subdivide is |
RyoheiHagimoto | 0:0e0631af0305 | 568 | * selected at random from among the top RAND_DIM dimensions with the |
RyoheiHagimoto | 0:0e0631af0305 | 569 | * highest variance. A value of 5 works well. |
RyoheiHagimoto | 0:0e0631af0305 | 570 | */ |
RyoheiHagimoto | 0:0e0631af0305 | 571 | RAND_DIM=5 |
RyoheiHagimoto | 0:0e0631af0305 | 572 | }; |
RyoheiHagimoto | 0:0e0631af0305 | 573 | |
RyoheiHagimoto | 0:0e0631af0305 | 574 | |
RyoheiHagimoto | 0:0e0631af0305 | 575 | /** |
RyoheiHagimoto | 0:0e0631af0305 | 576 | * Number of randomized trees that are used |
RyoheiHagimoto | 0:0e0631af0305 | 577 | */ |
RyoheiHagimoto | 0:0e0631af0305 | 578 | int trees_; |
RyoheiHagimoto | 0:0e0631af0305 | 579 | |
RyoheiHagimoto | 0:0e0631af0305 | 580 | /** |
RyoheiHagimoto | 0:0e0631af0305 | 581 | * Array of indices to vectors in the dataset. |
RyoheiHagimoto | 0:0e0631af0305 | 582 | */ |
RyoheiHagimoto | 0:0e0631af0305 | 583 | std::vector<int> vind_; |
RyoheiHagimoto | 0:0e0631af0305 | 584 | |
RyoheiHagimoto | 0:0e0631af0305 | 585 | /** |
RyoheiHagimoto | 0:0e0631af0305 | 586 | * The dataset used by this index |
RyoheiHagimoto | 0:0e0631af0305 | 587 | */ |
RyoheiHagimoto | 0:0e0631af0305 | 588 | const Matrix<ElementType> dataset_; |
RyoheiHagimoto | 0:0e0631af0305 | 589 | |
RyoheiHagimoto | 0:0e0631af0305 | 590 | IndexParams index_params_; |
RyoheiHagimoto | 0:0e0631af0305 | 591 | |
RyoheiHagimoto | 0:0e0631af0305 | 592 | size_t size_; |
RyoheiHagimoto | 0:0e0631af0305 | 593 | size_t veclen_; |
RyoheiHagimoto | 0:0e0631af0305 | 594 | |
RyoheiHagimoto | 0:0e0631af0305 | 595 | |
RyoheiHagimoto | 0:0e0631af0305 | 596 | DistanceType* mean_; |
RyoheiHagimoto | 0:0e0631af0305 | 597 | DistanceType* var_; |
RyoheiHagimoto | 0:0e0631af0305 | 598 | |
RyoheiHagimoto | 0:0e0631af0305 | 599 | |
RyoheiHagimoto | 0:0e0631af0305 | 600 | /** |
RyoheiHagimoto | 0:0e0631af0305 | 601 | * Array of k-d trees used to find neighbours. |
RyoheiHagimoto | 0:0e0631af0305 | 602 | */ |
RyoheiHagimoto | 0:0e0631af0305 | 603 | NodePtr* tree_roots_; |
RyoheiHagimoto | 0:0e0631af0305 | 604 | |
RyoheiHagimoto | 0:0e0631af0305 | 605 | /** |
RyoheiHagimoto | 0:0e0631af0305 | 606 | * Pooled memory allocator. |
RyoheiHagimoto | 0:0e0631af0305 | 607 | * |
RyoheiHagimoto | 0:0e0631af0305 | 608 | * Using a pooled memory allocator is more efficient |
RyoheiHagimoto | 0:0e0631af0305 | 609 | * than allocating memory directly when there is a large |
RyoheiHagimoto | 0:0e0631af0305 | 610 | * number small of memory allocations. |
RyoheiHagimoto | 0:0e0631af0305 | 611 | */ |
RyoheiHagimoto | 0:0e0631af0305 | 612 | PooledAllocator pool_; |
RyoheiHagimoto | 0:0e0631af0305 | 613 | |
RyoheiHagimoto | 0:0e0631af0305 | 614 | Distance distance_; |
RyoheiHagimoto | 0:0e0631af0305 | 615 | |
RyoheiHagimoto | 0:0e0631af0305 | 616 | |
RyoheiHagimoto | 0:0e0631af0305 | 617 | }; // class KDTreeForest |
RyoheiHagimoto | 0:0e0631af0305 | 618 | |
RyoheiHagimoto | 0:0e0631af0305 | 619 | } |
RyoheiHagimoto | 0:0e0631af0305 | 620 | |
RyoheiHagimoto | 0:0e0631af0305 | 621 | #endif //OPENCV_FLANN_KDTREE_INDEX_H_ |