openCV library for Renesas RZ/A
Dependents: RZ_A2M_Mbed_samples
include/opencv2/flann/kdtree_single_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_SINGLE_INDEX_H_ |
RyoheiHagimoto | 0:0e0631af0305 | 32 | #define OPENCV_FLANN_KDTREE_SINGLE_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 "matrix.h" |
RyoheiHagimoto | 0:0e0631af0305 | 42 | #include "result_set.h" |
RyoheiHagimoto | 0:0e0631af0305 | 43 | #include "heap.h" |
RyoheiHagimoto | 0:0e0631af0305 | 44 | #include "allocator.h" |
RyoheiHagimoto | 0:0e0631af0305 | 45 | #include "random.h" |
RyoheiHagimoto | 0:0e0631af0305 | 46 | #include "saving.h" |
RyoheiHagimoto | 0:0e0631af0305 | 47 | |
RyoheiHagimoto | 0:0e0631af0305 | 48 | namespace cvflann |
RyoheiHagimoto | 0:0e0631af0305 | 49 | { |
RyoheiHagimoto | 0:0e0631af0305 | 50 | |
RyoheiHagimoto | 0:0e0631af0305 | 51 | struct KDTreeSingleIndexParams : public IndexParams |
RyoheiHagimoto | 0:0e0631af0305 | 52 | { |
RyoheiHagimoto | 0:0e0631af0305 | 53 | KDTreeSingleIndexParams(int leaf_max_size = 10, bool reorder = true, int dim = -1) |
RyoheiHagimoto | 0:0e0631af0305 | 54 | { |
RyoheiHagimoto | 0:0e0631af0305 | 55 | (*this)["algorithm"] = FLANN_INDEX_KDTREE_SINGLE; |
RyoheiHagimoto | 0:0e0631af0305 | 56 | (*this)["leaf_max_size"] = leaf_max_size; |
RyoheiHagimoto | 0:0e0631af0305 | 57 | (*this)["reorder"] = reorder; |
RyoheiHagimoto | 0:0e0631af0305 | 58 | (*this)["dim"] = dim; |
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 KDTreeSingleIndex : 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 | KDTreeSingleIndex(const Matrix<ElementType>& inputData, const IndexParams& params = KDTreeSingleIndexParams(), |
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 | dim_ = dataset_.cols; |
RyoheiHagimoto | 0:0e0631af0305 | 90 | int dim_param = get_param(params,"dim",-1); |
RyoheiHagimoto | 0:0e0631af0305 | 91 | if (dim_param>0) dim_ = dim_param; |
RyoheiHagimoto | 0:0e0631af0305 | 92 | leaf_max_size_ = get_param(params,"leaf_max_size",10); |
RyoheiHagimoto | 0:0e0631af0305 | 93 | reorder_ = get_param(params,"reorder",true); |
RyoheiHagimoto | 0:0e0631af0305 | 94 | |
RyoheiHagimoto | 0:0e0631af0305 | 95 | // Create a permutable array of indices to the input vectors. |
RyoheiHagimoto | 0:0e0631af0305 | 96 | vind_.resize(size_); |
RyoheiHagimoto | 0:0e0631af0305 | 97 | for (size_t i = 0; i < size_; i++) { |
RyoheiHagimoto | 0:0e0631af0305 | 98 | vind_[i] = (int)i; |
RyoheiHagimoto | 0:0e0631af0305 | 99 | } |
RyoheiHagimoto | 0:0e0631af0305 | 100 | } |
RyoheiHagimoto | 0:0e0631af0305 | 101 | |
RyoheiHagimoto | 0:0e0631af0305 | 102 | KDTreeSingleIndex(const KDTreeSingleIndex&); |
RyoheiHagimoto | 0:0e0631af0305 | 103 | KDTreeSingleIndex& operator=(const KDTreeSingleIndex&); |
RyoheiHagimoto | 0:0e0631af0305 | 104 | |
RyoheiHagimoto | 0:0e0631af0305 | 105 | /** |
RyoheiHagimoto | 0:0e0631af0305 | 106 | * Standard destructor |
RyoheiHagimoto | 0:0e0631af0305 | 107 | */ |
RyoheiHagimoto | 0:0e0631af0305 | 108 | ~KDTreeSingleIndex() |
RyoheiHagimoto | 0:0e0631af0305 | 109 | { |
RyoheiHagimoto | 0:0e0631af0305 | 110 | if (reorder_) delete[] data_.data; |
RyoheiHagimoto | 0:0e0631af0305 | 111 | } |
RyoheiHagimoto | 0:0e0631af0305 | 112 | |
RyoheiHagimoto | 0:0e0631af0305 | 113 | /** |
RyoheiHagimoto | 0:0e0631af0305 | 114 | * Builds the index |
RyoheiHagimoto | 0:0e0631af0305 | 115 | */ |
RyoheiHagimoto | 0:0e0631af0305 | 116 | void buildIndex() |
RyoheiHagimoto | 0:0e0631af0305 | 117 | { |
RyoheiHagimoto | 0:0e0631af0305 | 118 | computeBoundingBox(root_bbox_); |
RyoheiHagimoto | 0:0e0631af0305 | 119 | root_node_ = divideTree(0, (int)size_, root_bbox_ ); // construct the tree |
RyoheiHagimoto | 0:0e0631af0305 | 120 | |
RyoheiHagimoto | 0:0e0631af0305 | 121 | if (reorder_) { |
RyoheiHagimoto | 0:0e0631af0305 | 122 | delete[] data_.data; |
RyoheiHagimoto | 0:0e0631af0305 | 123 | data_ = cvflann::Matrix<ElementType>(new ElementType[size_*dim_], size_, dim_); |
RyoheiHagimoto | 0:0e0631af0305 | 124 | for (size_t i=0; i<size_; ++i) { |
RyoheiHagimoto | 0:0e0631af0305 | 125 | for (size_t j=0; j<dim_; ++j) { |
RyoheiHagimoto | 0:0e0631af0305 | 126 | data_[i][j] = dataset_[vind_[i]][j]; |
RyoheiHagimoto | 0:0e0631af0305 | 127 | } |
RyoheiHagimoto | 0:0e0631af0305 | 128 | } |
RyoheiHagimoto | 0:0e0631af0305 | 129 | } |
RyoheiHagimoto | 0:0e0631af0305 | 130 | else { |
RyoheiHagimoto | 0:0e0631af0305 | 131 | data_ = dataset_; |
RyoheiHagimoto | 0:0e0631af0305 | 132 | } |
RyoheiHagimoto | 0:0e0631af0305 | 133 | } |
RyoheiHagimoto | 0:0e0631af0305 | 134 | |
RyoheiHagimoto | 0:0e0631af0305 | 135 | flann_algorithm_t getType() const |
RyoheiHagimoto | 0:0e0631af0305 | 136 | { |
RyoheiHagimoto | 0:0e0631af0305 | 137 | return FLANN_INDEX_KDTREE_SINGLE; |
RyoheiHagimoto | 0:0e0631af0305 | 138 | } |
RyoheiHagimoto | 0:0e0631af0305 | 139 | |
RyoheiHagimoto | 0:0e0631af0305 | 140 | |
RyoheiHagimoto | 0:0e0631af0305 | 141 | void saveIndex(FILE* stream) |
RyoheiHagimoto | 0:0e0631af0305 | 142 | { |
RyoheiHagimoto | 0:0e0631af0305 | 143 | save_value(stream, size_); |
RyoheiHagimoto | 0:0e0631af0305 | 144 | save_value(stream, dim_); |
RyoheiHagimoto | 0:0e0631af0305 | 145 | save_value(stream, root_bbox_); |
RyoheiHagimoto | 0:0e0631af0305 | 146 | save_value(stream, reorder_); |
RyoheiHagimoto | 0:0e0631af0305 | 147 | save_value(stream, leaf_max_size_); |
RyoheiHagimoto | 0:0e0631af0305 | 148 | save_value(stream, vind_); |
RyoheiHagimoto | 0:0e0631af0305 | 149 | if (reorder_) { |
RyoheiHagimoto | 0:0e0631af0305 | 150 | save_value(stream, data_); |
RyoheiHagimoto | 0:0e0631af0305 | 151 | } |
RyoheiHagimoto | 0:0e0631af0305 | 152 | save_tree(stream, root_node_); |
RyoheiHagimoto | 0:0e0631af0305 | 153 | } |
RyoheiHagimoto | 0:0e0631af0305 | 154 | |
RyoheiHagimoto | 0:0e0631af0305 | 155 | |
RyoheiHagimoto | 0:0e0631af0305 | 156 | void loadIndex(FILE* stream) |
RyoheiHagimoto | 0:0e0631af0305 | 157 | { |
RyoheiHagimoto | 0:0e0631af0305 | 158 | load_value(stream, size_); |
RyoheiHagimoto | 0:0e0631af0305 | 159 | load_value(stream, dim_); |
RyoheiHagimoto | 0:0e0631af0305 | 160 | load_value(stream, root_bbox_); |
RyoheiHagimoto | 0:0e0631af0305 | 161 | load_value(stream, reorder_); |
RyoheiHagimoto | 0:0e0631af0305 | 162 | load_value(stream, leaf_max_size_); |
RyoheiHagimoto | 0:0e0631af0305 | 163 | load_value(stream, vind_); |
RyoheiHagimoto | 0:0e0631af0305 | 164 | if (reorder_) { |
RyoheiHagimoto | 0:0e0631af0305 | 165 | load_value(stream, data_); |
RyoheiHagimoto | 0:0e0631af0305 | 166 | } |
RyoheiHagimoto | 0:0e0631af0305 | 167 | else { |
RyoheiHagimoto | 0:0e0631af0305 | 168 | data_ = dataset_; |
RyoheiHagimoto | 0:0e0631af0305 | 169 | } |
RyoheiHagimoto | 0:0e0631af0305 | 170 | load_tree(stream, root_node_); |
RyoheiHagimoto | 0:0e0631af0305 | 171 | |
RyoheiHagimoto | 0:0e0631af0305 | 172 | |
RyoheiHagimoto | 0:0e0631af0305 | 173 | index_params_["algorithm"] = getType(); |
RyoheiHagimoto | 0:0e0631af0305 | 174 | index_params_["leaf_max_size"] = leaf_max_size_; |
RyoheiHagimoto | 0:0e0631af0305 | 175 | index_params_["reorder"] = reorder_; |
RyoheiHagimoto | 0:0e0631af0305 | 176 | } |
RyoheiHagimoto | 0:0e0631af0305 | 177 | |
RyoheiHagimoto | 0:0e0631af0305 | 178 | /** |
RyoheiHagimoto | 0:0e0631af0305 | 179 | * Returns size of index. |
RyoheiHagimoto | 0:0e0631af0305 | 180 | */ |
RyoheiHagimoto | 0:0e0631af0305 | 181 | size_t size() const |
RyoheiHagimoto | 0:0e0631af0305 | 182 | { |
RyoheiHagimoto | 0:0e0631af0305 | 183 | return size_; |
RyoheiHagimoto | 0:0e0631af0305 | 184 | } |
RyoheiHagimoto | 0:0e0631af0305 | 185 | |
RyoheiHagimoto | 0:0e0631af0305 | 186 | /** |
RyoheiHagimoto | 0:0e0631af0305 | 187 | * Returns the length of an index feature. |
RyoheiHagimoto | 0:0e0631af0305 | 188 | */ |
RyoheiHagimoto | 0:0e0631af0305 | 189 | size_t veclen() const |
RyoheiHagimoto | 0:0e0631af0305 | 190 | { |
RyoheiHagimoto | 0:0e0631af0305 | 191 | return dim_; |
RyoheiHagimoto | 0:0e0631af0305 | 192 | } |
RyoheiHagimoto | 0:0e0631af0305 | 193 | |
RyoheiHagimoto | 0:0e0631af0305 | 194 | /** |
RyoheiHagimoto | 0:0e0631af0305 | 195 | * Computes the inde memory usage |
RyoheiHagimoto | 0:0e0631af0305 | 196 | * Returns: memory used by the index |
RyoheiHagimoto | 0:0e0631af0305 | 197 | */ |
RyoheiHagimoto | 0:0e0631af0305 | 198 | int usedMemory() const |
RyoheiHagimoto | 0:0e0631af0305 | 199 | { |
RyoheiHagimoto | 0:0e0631af0305 | 200 | return (int)(pool_.usedMemory+pool_.wastedMemory+dataset_.rows*sizeof(int)); // pool memory and vind array memory |
RyoheiHagimoto | 0:0e0631af0305 | 201 | } |
RyoheiHagimoto | 0:0e0631af0305 | 202 | |
RyoheiHagimoto | 0:0e0631af0305 | 203 | |
RyoheiHagimoto | 0:0e0631af0305 | 204 | /** |
RyoheiHagimoto | 0:0e0631af0305 | 205 | * \brief Perform k-nearest neighbor search |
RyoheiHagimoto | 0:0e0631af0305 | 206 | * \param[in] queries The query points for which to find the nearest neighbors |
RyoheiHagimoto | 0:0e0631af0305 | 207 | * \param[out] indices The indices of the nearest neighbors found |
RyoheiHagimoto | 0:0e0631af0305 | 208 | * \param[out] dists Distances to the nearest neighbors found |
RyoheiHagimoto | 0:0e0631af0305 | 209 | * \param[in] knn Number of nearest neighbors to return |
RyoheiHagimoto | 0:0e0631af0305 | 210 | * \param[in] params Search parameters |
RyoheiHagimoto | 0:0e0631af0305 | 211 | */ |
RyoheiHagimoto | 0:0e0631af0305 | 212 | void knnSearch(const Matrix<ElementType>& queries, Matrix<int>& indices, Matrix<DistanceType>& dists, int knn, const SearchParams& params) |
RyoheiHagimoto | 0:0e0631af0305 | 213 | { |
RyoheiHagimoto | 0:0e0631af0305 | 214 | assert(queries.cols == veclen()); |
RyoheiHagimoto | 0:0e0631af0305 | 215 | assert(indices.rows >= queries.rows); |
RyoheiHagimoto | 0:0e0631af0305 | 216 | assert(dists.rows >= queries.rows); |
RyoheiHagimoto | 0:0e0631af0305 | 217 | assert(int(indices.cols) >= knn); |
RyoheiHagimoto | 0:0e0631af0305 | 218 | assert(int(dists.cols) >= knn); |
RyoheiHagimoto | 0:0e0631af0305 | 219 | |
RyoheiHagimoto | 0:0e0631af0305 | 220 | KNNSimpleResultSet<DistanceType> resultSet(knn); |
RyoheiHagimoto | 0:0e0631af0305 | 221 | for (size_t i = 0; i < queries.rows; i++) { |
RyoheiHagimoto | 0:0e0631af0305 | 222 | resultSet.init(indices[i], dists[i]); |
RyoheiHagimoto | 0:0e0631af0305 | 223 | findNeighbors(resultSet, queries[i], params); |
RyoheiHagimoto | 0:0e0631af0305 | 224 | } |
RyoheiHagimoto | 0:0e0631af0305 | 225 | } |
RyoheiHagimoto | 0:0e0631af0305 | 226 | |
RyoheiHagimoto | 0:0e0631af0305 | 227 | IndexParams getParameters() const |
RyoheiHagimoto | 0:0e0631af0305 | 228 | { |
RyoheiHagimoto | 0:0e0631af0305 | 229 | return index_params_; |
RyoheiHagimoto | 0:0e0631af0305 | 230 | } |
RyoheiHagimoto | 0:0e0631af0305 | 231 | |
RyoheiHagimoto | 0:0e0631af0305 | 232 | /** |
RyoheiHagimoto | 0:0e0631af0305 | 233 | * Find set of nearest neighbors to vec. Their indices are stored inside |
RyoheiHagimoto | 0:0e0631af0305 | 234 | * the result object. |
RyoheiHagimoto | 0:0e0631af0305 | 235 | * |
RyoheiHagimoto | 0:0e0631af0305 | 236 | * Params: |
RyoheiHagimoto | 0:0e0631af0305 | 237 | * result = the result object in which the indices of the nearest-neighbors are stored |
RyoheiHagimoto | 0:0e0631af0305 | 238 | * vec = the vector for which to search the nearest neighbors |
RyoheiHagimoto | 0:0e0631af0305 | 239 | * maxCheck = the maximum number of restarts (in a best-bin-first manner) |
RyoheiHagimoto | 0:0e0631af0305 | 240 | */ |
RyoheiHagimoto | 0:0e0631af0305 | 241 | void findNeighbors(ResultSet<DistanceType>& result, const ElementType* vec, const SearchParams& searchParams) |
RyoheiHagimoto | 0:0e0631af0305 | 242 | { |
RyoheiHagimoto | 0:0e0631af0305 | 243 | float epsError = 1+get_param(searchParams,"eps",0.0f); |
RyoheiHagimoto | 0:0e0631af0305 | 244 | |
RyoheiHagimoto | 0:0e0631af0305 | 245 | std::vector<DistanceType> dists(dim_,0); |
RyoheiHagimoto | 0:0e0631af0305 | 246 | DistanceType distsq = computeInitialDistances(vec, dists); |
RyoheiHagimoto | 0:0e0631af0305 | 247 | searchLevel(result, vec, root_node_, distsq, dists, epsError); |
RyoheiHagimoto | 0:0e0631af0305 | 248 | } |
RyoheiHagimoto | 0:0e0631af0305 | 249 | |
RyoheiHagimoto | 0:0e0631af0305 | 250 | private: |
RyoheiHagimoto | 0:0e0631af0305 | 251 | |
RyoheiHagimoto | 0:0e0631af0305 | 252 | |
RyoheiHagimoto | 0:0e0631af0305 | 253 | /*--------------------- Internal Data Structures --------------------------*/ |
RyoheiHagimoto | 0:0e0631af0305 | 254 | struct Node |
RyoheiHagimoto | 0:0e0631af0305 | 255 | { |
RyoheiHagimoto | 0:0e0631af0305 | 256 | /** |
RyoheiHagimoto | 0:0e0631af0305 | 257 | * Indices of points in leaf node |
RyoheiHagimoto | 0:0e0631af0305 | 258 | */ |
RyoheiHagimoto | 0:0e0631af0305 | 259 | int left, right; |
RyoheiHagimoto | 0:0e0631af0305 | 260 | /** |
RyoheiHagimoto | 0:0e0631af0305 | 261 | * Dimension used for subdivision. |
RyoheiHagimoto | 0:0e0631af0305 | 262 | */ |
RyoheiHagimoto | 0:0e0631af0305 | 263 | int divfeat; |
RyoheiHagimoto | 0:0e0631af0305 | 264 | /** |
RyoheiHagimoto | 0:0e0631af0305 | 265 | * The values used for subdivision. |
RyoheiHagimoto | 0:0e0631af0305 | 266 | */ |
RyoheiHagimoto | 0:0e0631af0305 | 267 | DistanceType divlow, divhigh; |
RyoheiHagimoto | 0:0e0631af0305 | 268 | /** |
RyoheiHagimoto | 0:0e0631af0305 | 269 | * The child nodes. |
RyoheiHagimoto | 0:0e0631af0305 | 270 | */ |
RyoheiHagimoto | 0:0e0631af0305 | 271 | Node* child1, * child2; |
RyoheiHagimoto | 0:0e0631af0305 | 272 | }; |
RyoheiHagimoto | 0:0e0631af0305 | 273 | typedef Node* NodePtr; |
RyoheiHagimoto | 0:0e0631af0305 | 274 | |
RyoheiHagimoto | 0:0e0631af0305 | 275 | |
RyoheiHagimoto | 0:0e0631af0305 | 276 | struct Interval |
RyoheiHagimoto | 0:0e0631af0305 | 277 | { |
RyoheiHagimoto | 0:0e0631af0305 | 278 | DistanceType low, high; |
RyoheiHagimoto | 0:0e0631af0305 | 279 | }; |
RyoheiHagimoto | 0:0e0631af0305 | 280 | |
RyoheiHagimoto | 0:0e0631af0305 | 281 | typedef std::vector<Interval> BoundingBox; |
RyoheiHagimoto | 0:0e0631af0305 | 282 | |
RyoheiHagimoto | 0:0e0631af0305 | 283 | typedef BranchStruct<NodePtr, DistanceType> BranchSt; |
RyoheiHagimoto | 0:0e0631af0305 | 284 | typedef BranchSt* Branch; |
RyoheiHagimoto | 0:0e0631af0305 | 285 | |
RyoheiHagimoto | 0:0e0631af0305 | 286 | |
RyoheiHagimoto | 0:0e0631af0305 | 287 | |
RyoheiHagimoto | 0:0e0631af0305 | 288 | |
RyoheiHagimoto | 0:0e0631af0305 | 289 | void save_tree(FILE* stream, NodePtr tree) |
RyoheiHagimoto | 0:0e0631af0305 | 290 | { |
RyoheiHagimoto | 0:0e0631af0305 | 291 | save_value(stream, *tree); |
RyoheiHagimoto | 0:0e0631af0305 | 292 | if (tree->child1!=NULL) { |
RyoheiHagimoto | 0:0e0631af0305 | 293 | save_tree(stream, tree->child1); |
RyoheiHagimoto | 0:0e0631af0305 | 294 | } |
RyoheiHagimoto | 0:0e0631af0305 | 295 | if (tree->child2!=NULL) { |
RyoheiHagimoto | 0:0e0631af0305 | 296 | save_tree(stream, tree->child2); |
RyoheiHagimoto | 0:0e0631af0305 | 297 | } |
RyoheiHagimoto | 0:0e0631af0305 | 298 | } |
RyoheiHagimoto | 0:0e0631af0305 | 299 | |
RyoheiHagimoto | 0:0e0631af0305 | 300 | |
RyoheiHagimoto | 0:0e0631af0305 | 301 | void load_tree(FILE* stream, NodePtr& tree) |
RyoheiHagimoto | 0:0e0631af0305 | 302 | { |
RyoheiHagimoto | 0:0e0631af0305 | 303 | tree = pool_.allocate<Node>(); |
RyoheiHagimoto | 0:0e0631af0305 | 304 | load_value(stream, *tree); |
RyoheiHagimoto | 0:0e0631af0305 | 305 | if (tree->child1!=NULL) { |
RyoheiHagimoto | 0:0e0631af0305 | 306 | load_tree(stream, tree->child1); |
RyoheiHagimoto | 0:0e0631af0305 | 307 | } |
RyoheiHagimoto | 0:0e0631af0305 | 308 | if (tree->child2!=NULL) { |
RyoheiHagimoto | 0:0e0631af0305 | 309 | load_tree(stream, tree->child2); |
RyoheiHagimoto | 0:0e0631af0305 | 310 | } |
RyoheiHagimoto | 0:0e0631af0305 | 311 | } |
RyoheiHagimoto | 0:0e0631af0305 | 312 | |
RyoheiHagimoto | 0:0e0631af0305 | 313 | |
RyoheiHagimoto | 0:0e0631af0305 | 314 | void computeBoundingBox(BoundingBox& bbox) |
RyoheiHagimoto | 0:0e0631af0305 | 315 | { |
RyoheiHagimoto | 0:0e0631af0305 | 316 | bbox.resize(dim_); |
RyoheiHagimoto | 0:0e0631af0305 | 317 | for (size_t i=0; i<dim_; ++i) { |
RyoheiHagimoto | 0:0e0631af0305 | 318 | bbox[i].low = (DistanceType)dataset_[0][i]; |
RyoheiHagimoto | 0:0e0631af0305 | 319 | bbox[i].high = (DistanceType)dataset_[0][i]; |
RyoheiHagimoto | 0:0e0631af0305 | 320 | } |
RyoheiHagimoto | 0:0e0631af0305 | 321 | for (size_t k=1; k<dataset_.rows; ++k) { |
RyoheiHagimoto | 0:0e0631af0305 | 322 | for (size_t i=0; i<dim_; ++i) { |
RyoheiHagimoto | 0:0e0631af0305 | 323 | if (dataset_[k][i]<bbox[i].low) bbox[i].low = (DistanceType)dataset_[k][i]; |
RyoheiHagimoto | 0:0e0631af0305 | 324 | if (dataset_[k][i]>bbox[i].high) bbox[i].high = (DistanceType)dataset_[k][i]; |
RyoheiHagimoto | 0:0e0631af0305 | 325 | } |
RyoheiHagimoto | 0:0e0631af0305 | 326 | } |
RyoheiHagimoto | 0:0e0631af0305 | 327 | } |
RyoheiHagimoto | 0:0e0631af0305 | 328 | |
RyoheiHagimoto | 0:0e0631af0305 | 329 | |
RyoheiHagimoto | 0:0e0631af0305 | 330 | /** |
RyoheiHagimoto | 0:0e0631af0305 | 331 | * Create a tree node that subdivides the list of vecs from vind[first] |
RyoheiHagimoto | 0:0e0631af0305 | 332 | * to vind[last]. The routine is called recursively on each sublist. |
RyoheiHagimoto | 0:0e0631af0305 | 333 | * Place a pointer to this new tree node in the location pTree. |
RyoheiHagimoto | 0:0e0631af0305 | 334 | * |
RyoheiHagimoto | 0:0e0631af0305 | 335 | * Params: pTree = the new node to create |
RyoheiHagimoto | 0:0e0631af0305 | 336 | * first = index of the first vector |
RyoheiHagimoto | 0:0e0631af0305 | 337 | * last = index of the last vector |
RyoheiHagimoto | 0:0e0631af0305 | 338 | */ |
RyoheiHagimoto | 0:0e0631af0305 | 339 | NodePtr divideTree(int left, int right, BoundingBox& bbox) |
RyoheiHagimoto | 0:0e0631af0305 | 340 | { |
RyoheiHagimoto | 0:0e0631af0305 | 341 | NodePtr node = pool_.allocate<Node>(); // allocate memory |
RyoheiHagimoto | 0:0e0631af0305 | 342 | |
RyoheiHagimoto | 0:0e0631af0305 | 343 | /* If too few exemplars remain, then make this a leaf node. */ |
RyoheiHagimoto | 0:0e0631af0305 | 344 | if ( (right-left) <= leaf_max_size_) { |
RyoheiHagimoto | 0:0e0631af0305 | 345 | node->child1 = node->child2 = NULL; /* Mark as leaf node. */ |
RyoheiHagimoto | 0:0e0631af0305 | 346 | node->left = left; |
RyoheiHagimoto | 0:0e0631af0305 | 347 | node->right = right; |
RyoheiHagimoto | 0:0e0631af0305 | 348 | |
RyoheiHagimoto | 0:0e0631af0305 | 349 | // compute bounding-box of leaf points |
RyoheiHagimoto | 0:0e0631af0305 | 350 | for (size_t i=0; i<dim_; ++i) { |
RyoheiHagimoto | 0:0e0631af0305 | 351 | bbox[i].low = (DistanceType)dataset_[vind_[left]][i]; |
RyoheiHagimoto | 0:0e0631af0305 | 352 | bbox[i].high = (DistanceType)dataset_[vind_[left]][i]; |
RyoheiHagimoto | 0:0e0631af0305 | 353 | } |
RyoheiHagimoto | 0:0e0631af0305 | 354 | for (int k=left+1; k<right; ++k) { |
RyoheiHagimoto | 0:0e0631af0305 | 355 | for (size_t i=0; i<dim_; ++i) { |
RyoheiHagimoto | 0:0e0631af0305 | 356 | if (bbox[i].low>dataset_[vind_[k]][i]) bbox[i].low=(DistanceType)dataset_[vind_[k]][i]; |
RyoheiHagimoto | 0:0e0631af0305 | 357 | if (bbox[i].high<dataset_[vind_[k]][i]) bbox[i].high=(DistanceType)dataset_[vind_[k]][i]; |
RyoheiHagimoto | 0:0e0631af0305 | 358 | } |
RyoheiHagimoto | 0:0e0631af0305 | 359 | } |
RyoheiHagimoto | 0:0e0631af0305 | 360 | } |
RyoheiHagimoto | 0:0e0631af0305 | 361 | else { |
RyoheiHagimoto | 0:0e0631af0305 | 362 | int idx; |
RyoheiHagimoto | 0:0e0631af0305 | 363 | int cutfeat; |
RyoheiHagimoto | 0:0e0631af0305 | 364 | DistanceType cutval; |
RyoheiHagimoto | 0:0e0631af0305 | 365 | middleSplit_(&vind_[0]+left, right-left, idx, cutfeat, cutval, bbox); |
RyoheiHagimoto | 0:0e0631af0305 | 366 | |
RyoheiHagimoto | 0:0e0631af0305 | 367 | node->divfeat = cutfeat; |
RyoheiHagimoto | 0:0e0631af0305 | 368 | |
RyoheiHagimoto | 0:0e0631af0305 | 369 | BoundingBox left_bbox(bbox); |
RyoheiHagimoto | 0:0e0631af0305 | 370 | left_bbox[cutfeat].high = cutval; |
RyoheiHagimoto | 0:0e0631af0305 | 371 | node->child1 = divideTree(left, left+idx, left_bbox); |
RyoheiHagimoto | 0:0e0631af0305 | 372 | |
RyoheiHagimoto | 0:0e0631af0305 | 373 | BoundingBox right_bbox(bbox); |
RyoheiHagimoto | 0:0e0631af0305 | 374 | right_bbox[cutfeat].low = cutval; |
RyoheiHagimoto | 0:0e0631af0305 | 375 | node->child2 = divideTree(left+idx, right, right_bbox); |
RyoheiHagimoto | 0:0e0631af0305 | 376 | |
RyoheiHagimoto | 0:0e0631af0305 | 377 | node->divlow = left_bbox[cutfeat].high; |
RyoheiHagimoto | 0:0e0631af0305 | 378 | node->divhigh = right_bbox[cutfeat].low; |
RyoheiHagimoto | 0:0e0631af0305 | 379 | |
RyoheiHagimoto | 0:0e0631af0305 | 380 | for (size_t i=0; i<dim_; ++i) { |
RyoheiHagimoto | 0:0e0631af0305 | 381 | bbox[i].low = std::min(left_bbox[i].low, right_bbox[i].low); |
RyoheiHagimoto | 0:0e0631af0305 | 382 | bbox[i].high = std::max(left_bbox[i].high, right_bbox[i].high); |
RyoheiHagimoto | 0:0e0631af0305 | 383 | } |
RyoheiHagimoto | 0:0e0631af0305 | 384 | } |
RyoheiHagimoto | 0:0e0631af0305 | 385 | |
RyoheiHagimoto | 0:0e0631af0305 | 386 | return node; |
RyoheiHagimoto | 0:0e0631af0305 | 387 | } |
RyoheiHagimoto | 0:0e0631af0305 | 388 | |
RyoheiHagimoto | 0:0e0631af0305 | 389 | void computeMinMax(int* ind, int count, int dim, ElementType& min_elem, ElementType& max_elem) |
RyoheiHagimoto | 0:0e0631af0305 | 390 | { |
RyoheiHagimoto | 0:0e0631af0305 | 391 | min_elem = dataset_[ind[0]][dim]; |
RyoheiHagimoto | 0:0e0631af0305 | 392 | max_elem = dataset_[ind[0]][dim]; |
RyoheiHagimoto | 0:0e0631af0305 | 393 | for (int i=1; i<count; ++i) { |
RyoheiHagimoto | 0:0e0631af0305 | 394 | ElementType val = dataset_[ind[i]][dim]; |
RyoheiHagimoto | 0:0e0631af0305 | 395 | if (val<min_elem) min_elem = val; |
RyoheiHagimoto | 0:0e0631af0305 | 396 | if (val>max_elem) max_elem = val; |
RyoheiHagimoto | 0:0e0631af0305 | 397 | } |
RyoheiHagimoto | 0:0e0631af0305 | 398 | } |
RyoheiHagimoto | 0:0e0631af0305 | 399 | |
RyoheiHagimoto | 0:0e0631af0305 | 400 | void middleSplit(int* ind, int count, int& index, int& cutfeat, DistanceType& cutval, const BoundingBox& bbox) |
RyoheiHagimoto | 0:0e0631af0305 | 401 | { |
RyoheiHagimoto | 0:0e0631af0305 | 402 | // find the largest span from the approximate bounding box |
RyoheiHagimoto | 0:0e0631af0305 | 403 | ElementType max_span = bbox[0].high-bbox[0].low; |
RyoheiHagimoto | 0:0e0631af0305 | 404 | cutfeat = 0; |
RyoheiHagimoto | 0:0e0631af0305 | 405 | cutval = (bbox[0].high+bbox[0].low)/2; |
RyoheiHagimoto | 0:0e0631af0305 | 406 | for (size_t i=1; i<dim_; ++i) { |
RyoheiHagimoto | 0:0e0631af0305 | 407 | ElementType span = bbox[i].high-bbox[i].low; |
RyoheiHagimoto | 0:0e0631af0305 | 408 | if (span>max_span) { |
RyoheiHagimoto | 0:0e0631af0305 | 409 | max_span = span; |
RyoheiHagimoto | 0:0e0631af0305 | 410 | cutfeat = i; |
RyoheiHagimoto | 0:0e0631af0305 | 411 | cutval = (bbox[i].high+bbox[i].low)/2; |
RyoheiHagimoto | 0:0e0631af0305 | 412 | } |
RyoheiHagimoto | 0:0e0631af0305 | 413 | } |
RyoheiHagimoto | 0:0e0631af0305 | 414 | |
RyoheiHagimoto | 0:0e0631af0305 | 415 | // compute exact span on the found dimension |
RyoheiHagimoto | 0:0e0631af0305 | 416 | ElementType min_elem, max_elem; |
RyoheiHagimoto | 0:0e0631af0305 | 417 | computeMinMax(ind, count, cutfeat, min_elem, max_elem); |
RyoheiHagimoto | 0:0e0631af0305 | 418 | cutval = (min_elem+max_elem)/2; |
RyoheiHagimoto | 0:0e0631af0305 | 419 | max_span = max_elem - min_elem; |
RyoheiHagimoto | 0:0e0631af0305 | 420 | |
RyoheiHagimoto | 0:0e0631af0305 | 421 | // check if a dimension of a largest span exists |
RyoheiHagimoto | 0:0e0631af0305 | 422 | size_t k = cutfeat; |
RyoheiHagimoto | 0:0e0631af0305 | 423 | for (size_t i=0; i<dim_; ++i) { |
RyoheiHagimoto | 0:0e0631af0305 | 424 | if (i==k) continue; |
RyoheiHagimoto | 0:0e0631af0305 | 425 | ElementType span = bbox[i].high-bbox[i].low; |
RyoheiHagimoto | 0:0e0631af0305 | 426 | if (span>max_span) { |
RyoheiHagimoto | 0:0e0631af0305 | 427 | computeMinMax(ind, count, i, min_elem, max_elem); |
RyoheiHagimoto | 0:0e0631af0305 | 428 | span = max_elem - min_elem; |
RyoheiHagimoto | 0:0e0631af0305 | 429 | if (span>max_span) { |
RyoheiHagimoto | 0:0e0631af0305 | 430 | max_span = span; |
RyoheiHagimoto | 0:0e0631af0305 | 431 | cutfeat = i; |
RyoheiHagimoto | 0:0e0631af0305 | 432 | cutval = (min_elem+max_elem)/2; |
RyoheiHagimoto | 0:0e0631af0305 | 433 | } |
RyoheiHagimoto | 0:0e0631af0305 | 434 | } |
RyoheiHagimoto | 0:0e0631af0305 | 435 | } |
RyoheiHagimoto | 0:0e0631af0305 | 436 | int lim1, lim2; |
RyoheiHagimoto | 0:0e0631af0305 | 437 | planeSplit(ind, count, cutfeat, cutval, lim1, lim2); |
RyoheiHagimoto | 0:0e0631af0305 | 438 | |
RyoheiHagimoto | 0:0e0631af0305 | 439 | if (lim1>count/2) index = lim1; |
RyoheiHagimoto | 0:0e0631af0305 | 440 | else if (lim2<count/2) index = lim2; |
RyoheiHagimoto | 0:0e0631af0305 | 441 | else index = count/2; |
RyoheiHagimoto | 0:0e0631af0305 | 442 | } |
RyoheiHagimoto | 0:0e0631af0305 | 443 | |
RyoheiHagimoto | 0:0e0631af0305 | 444 | |
RyoheiHagimoto | 0:0e0631af0305 | 445 | void middleSplit_(int* ind, int count, int& index, int& cutfeat, DistanceType& cutval, const BoundingBox& bbox) |
RyoheiHagimoto | 0:0e0631af0305 | 446 | { |
RyoheiHagimoto | 0:0e0631af0305 | 447 | const float EPS=0.00001f; |
RyoheiHagimoto | 0:0e0631af0305 | 448 | DistanceType max_span = bbox[0].high-bbox[0].low; |
RyoheiHagimoto | 0:0e0631af0305 | 449 | for (size_t i=1; i<dim_; ++i) { |
RyoheiHagimoto | 0:0e0631af0305 | 450 | DistanceType span = bbox[i].high-bbox[i].low; |
RyoheiHagimoto | 0:0e0631af0305 | 451 | if (span>max_span) { |
RyoheiHagimoto | 0:0e0631af0305 | 452 | max_span = span; |
RyoheiHagimoto | 0:0e0631af0305 | 453 | } |
RyoheiHagimoto | 0:0e0631af0305 | 454 | } |
RyoheiHagimoto | 0:0e0631af0305 | 455 | DistanceType max_spread = -1; |
RyoheiHagimoto | 0:0e0631af0305 | 456 | cutfeat = 0; |
RyoheiHagimoto | 0:0e0631af0305 | 457 | for (size_t i=0; i<dim_; ++i) { |
RyoheiHagimoto | 0:0e0631af0305 | 458 | DistanceType span = bbox[i].high-bbox[i].low; |
RyoheiHagimoto | 0:0e0631af0305 | 459 | if (span>(DistanceType)((1-EPS)*max_span)) { |
RyoheiHagimoto | 0:0e0631af0305 | 460 | ElementType min_elem, max_elem; |
RyoheiHagimoto | 0:0e0631af0305 | 461 | computeMinMax(ind, count, cutfeat, min_elem, max_elem); |
RyoheiHagimoto | 0:0e0631af0305 | 462 | DistanceType spread = (DistanceType)(max_elem-min_elem); |
RyoheiHagimoto | 0:0e0631af0305 | 463 | if (spread>max_spread) { |
RyoheiHagimoto | 0:0e0631af0305 | 464 | cutfeat = (int)i; |
RyoheiHagimoto | 0:0e0631af0305 | 465 | max_spread = spread; |
RyoheiHagimoto | 0:0e0631af0305 | 466 | } |
RyoheiHagimoto | 0:0e0631af0305 | 467 | } |
RyoheiHagimoto | 0:0e0631af0305 | 468 | } |
RyoheiHagimoto | 0:0e0631af0305 | 469 | // split in the middle |
RyoheiHagimoto | 0:0e0631af0305 | 470 | DistanceType split_val = (bbox[cutfeat].low+bbox[cutfeat].high)/2; |
RyoheiHagimoto | 0:0e0631af0305 | 471 | ElementType min_elem, max_elem; |
RyoheiHagimoto | 0:0e0631af0305 | 472 | computeMinMax(ind, count, cutfeat, min_elem, max_elem); |
RyoheiHagimoto | 0:0e0631af0305 | 473 | |
RyoheiHagimoto | 0:0e0631af0305 | 474 | if (split_val<min_elem) cutval = (DistanceType)min_elem; |
RyoheiHagimoto | 0:0e0631af0305 | 475 | else if (split_val>max_elem) cutval = (DistanceType)max_elem; |
RyoheiHagimoto | 0:0e0631af0305 | 476 | else cutval = split_val; |
RyoheiHagimoto | 0:0e0631af0305 | 477 | |
RyoheiHagimoto | 0:0e0631af0305 | 478 | int lim1, lim2; |
RyoheiHagimoto | 0:0e0631af0305 | 479 | planeSplit(ind, count, cutfeat, cutval, lim1, lim2); |
RyoheiHagimoto | 0:0e0631af0305 | 480 | |
RyoheiHagimoto | 0:0e0631af0305 | 481 | if (lim1>count/2) index = lim1; |
RyoheiHagimoto | 0:0e0631af0305 | 482 | else if (lim2<count/2) index = lim2; |
RyoheiHagimoto | 0:0e0631af0305 | 483 | else index = count/2; |
RyoheiHagimoto | 0:0e0631af0305 | 484 | } |
RyoheiHagimoto | 0:0e0631af0305 | 485 | |
RyoheiHagimoto | 0:0e0631af0305 | 486 | |
RyoheiHagimoto | 0:0e0631af0305 | 487 | /** |
RyoheiHagimoto | 0:0e0631af0305 | 488 | * Subdivide the list of points by a plane perpendicular on axe corresponding |
RyoheiHagimoto | 0:0e0631af0305 | 489 | * to the 'cutfeat' dimension at 'cutval' position. |
RyoheiHagimoto | 0:0e0631af0305 | 490 | * |
RyoheiHagimoto | 0:0e0631af0305 | 491 | * On return: |
RyoheiHagimoto | 0:0e0631af0305 | 492 | * dataset[ind[0..lim1-1]][cutfeat]<cutval |
RyoheiHagimoto | 0:0e0631af0305 | 493 | * dataset[ind[lim1..lim2-1]][cutfeat]==cutval |
RyoheiHagimoto | 0:0e0631af0305 | 494 | * dataset[ind[lim2..count]][cutfeat]>cutval |
RyoheiHagimoto | 0:0e0631af0305 | 495 | */ |
RyoheiHagimoto | 0:0e0631af0305 | 496 | void planeSplit(int* ind, int count, int cutfeat, DistanceType cutval, int& lim1, int& lim2) |
RyoheiHagimoto | 0:0e0631af0305 | 497 | { |
RyoheiHagimoto | 0:0e0631af0305 | 498 | /* Move vector indices for left subtree to front of list. */ |
RyoheiHagimoto | 0:0e0631af0305 | 499 | int left = 0; |
RyoheiHagimoto | 0:0e0631af0305 | 500 | int right = count-1; |
RyoheiHagimoto | 0:0e0631af0305 | 501 | for (;; ) { |
RyoheiHagimoto | 0:0e0631af0305 | 502 | while (left<=right && dataset_[ind[left]][cutfeat]<cutval) ++left; |
RyoheiHagimoto | 0:0e0631af0305 | 503 | while (left<=right && dataset_[ind[right]][cutfeat]>=cutval) --right; |
RyoheiHagimoto | 0:0e0631af0305 | 504 | if (left>right) break; |
RyoheiHagimoto | 0:0e0631af0305 | 505 | std::swap(ind[left], ind[right]); ++left; --right; |
RyoheiHagimoto | 0:0e0631af0305 | 506 | } |
RyoheiHagimoto | 0:0e0631af0305 | 507 | /* If either list is empty, it means that all remaining features |
RyoheiHagimoto | 0:0e0631af0305 | 508 | * are identical. Split in the middle to maintain a balanced tree. |
RyoheiHagimoto | 0:0e0631af0305 | 509 | */ |
RyoheiHagimoto | 0:0e0631af0305 | 510 | lim1 = left; |
RyoheiHagimoto | 0:0e0631af0305 | 511 | right = count-1; |
RyoheiHagimoto | 0:0e0631af0305 | 512 | for (;; ) { |
RyoheiHagimoto | 0:0e0631af0305 | 513 | while (left<=right && dataset_[ind[left]][cutfeat]<=cutval) ++left; |
RyoheiHagimoto | 0:0e0631af0305 | 514 | while (left<=right && dataset_[ind[right]][cutfeat]>cutval) --right; |
RyoheiHagimoto | 0:0e0631af0305 | 515 | if (left>right) break; |
RyoheiHagimoto | 0:0e0631af0305 | 516 | std::swap(ind[left], ind[right]); ++left; --right; |
RyoheiHagimoto | 0:0e0631af0305 | 517 | } |
RyoheiHagimoto | 0:0e0631af0305 | 518 | lim2 = left; |
RyoheiHagimoto | 0:0e0631af0305 | 519 | } |
RyoheiHagimoto | 0:0e0631af0305 | 520 | |
RyoheiHagimoto | 0:0e0631af0305 | 521 | DistanceType computeInitialDistances(const ElementType* vec, std::vector<DistanceType>& dists) |
RyoheiHagimoto | 0:0e0631af0305 | 522 | { |
RyoheiHagimoto | 0:0e0631af0305 | 523 | DistanceType distsq = 0.0; |
RyoheiHagimoto | 0:0e0631af0305 | 524 | |
RyoheiHagimoto | 0:0e0631af0305 | 525 | for (size_t i = 0; i < dim_; ++i) { |
RyoheiHagimoto | 0:0e0631af0305 | 526 | if (vec[i] < root_bbox_[i].low) { |
RyoheiHagimoto | 0:0e0631af0305 | 527 | dists[i] = distance_.accum_dist(vec[i], root_bbox_[i].low, (int)i); |
RyoheiHagimoto | 0:0e0631af0305 | 528 | distsq += dists[i]; |
RyoheiHagimoto | 0:0e0631af0305 | 529 | } |
RyoheiHagimoto | 0:0e0631af0305 | 530 | if (vec[i] > root_bbox_[i].high) { |
RyoheiHagimoto | 0:0e0631af0305 | 531 | dists[i] = distance_.accum_dist(vec[i], root_bbox_[i].high, (int)i); |
RyoheiHagimoto | 0:0e0631af0305 | 532 | distsq += dists[i]; |
RyoheiHagimoto | 0:0e0631af0305 | 533 | } |
RyoheiHagimoto | 0:0e0631af0305 | 534 | } |
RyoheiHagimoto | 0:0e0631af0305 | 535 | |
RyoheiHagimoto | 0:0e0631af0305 | 536 | return distsq; |
RyoheiHagimoto | 0:0e0631af0305 | 537 | } |
RyoheiHagimoto | 0:0e0631af0305 | 538 | |
RyoheiHagimoto | 0:0e0631af0305 | 539 | /** |
RyoheiHagimoto | 0:0e0631af0305 | 540 | * Performs an exact search in the tree starting from a node. |
RyoheiHagimoto | 0:0e0631af0305 | 541 | */ |
RyoheiHagimoto | 0:0e0631af0305 | 542 | void searchLevel(ResultSet<DistanceType>& result_set, const ElementType* vec, const NodePtr node, DistanceType mindistsq, |
RyoheiHagimoto | 0:0e0631af0305 | 543 | std::vector<DistanceType>& dists, const float epsError) |
RyoheiHagimoto | 0:0e0631af0305 | 544 | { |
RyoheiHagimoto | 0:0e0631af0305 | 545 | /* If this is a leaf node, then do check and return. */ |
RyoheiHagimoto | 0:0e0631af0305 | 546 | if ((node->child1 == NULL)&&(node->child2 == NULL)) { |
RyoheiHagimoto | 0:0e0631af0305 | 547 | DistanceType worst_dist = result_set.worstDist(); |
RyoheiHagimoto | 0:0e0631af0305 | 548 | for (int i=node->left; i<node->right; ++i) { |
RyoheiHagimoto | 0:0e0631af0305 | 549 | int index = reorder_ ? i : vind_[i]; |
RyoheiHagimoto | 0:0e0631af0305 | 550 | DistanceType dist = distance_(vec, data_[index], dim_, worst_dist); |
RyoheiHagimoto | 0:0e0631af0305 | 551 | if (dist<worst_dist) { |
RyoheiHagimoto | 0:0e0631af0305 | 552 | result_set.addPoint(dist,vind_[i]); |
RyoheiHagimoto | 0:0e0631af0305 | 553 | } |
RyoheiHagimoto | 0:0e0631af0305 | 554 | } |
RyoheiHagimoto | 0:0e0631af0305 | 555 | return; |
RyoheiHagimoto | 0:0e0631af0305 | 556 | } |
RyoheiHagimoto | 0:0e0631af0305 | 557 | |
RyoheiHagimoto | 0:0e0631af0305 | 558 | /* Which child branch should be taken first? */ |
RyoheiHagimoto | 0:0e0631af0305 | 559 | int idx = node->divfeat; |
RyoheiHagimoto | 0:0e0631af0305 | 560 | ElementType val = vec[idx]; |
RyoheiHagimoto | 0:0e0631af0305 | 561 | DistanceType diff1 = val - node->divlow; |
RyoheiHagimoto | 0:0e0631af0305 | 562 | DistanceType diff2 = val - node->divhigh; |
RyoheiHagimoto | 0:0e0631af0305 | 563 | |
RyoheiHagimoto | 0:0e0631af0305 | 564 | NodePtr bestChild; |
RyoheiHagimoto | 0:0e0631af0305 | 565 | NodePtr otherChild; |
RyoheiHagimoto | 0:0e0631af0305 | 566 | DistanceType cut_dist; |
RyoheiHagimoto | 0:0e0631af0305 | 567 | if ((diff1+diff2)<0) { |
RyoheiHagimoto | 0:0e0631af0305 | 568 | bestChild = node->child1; |
RyoheiHagimoto | 0:0e0631af0305 | 569 | otherChild = node->child2; |
RyoheiHagimoto | 0:0e0631af0305 | 570 | cut_dist = distance_.accum_dist(val, node->divhigh, idx); |
RyoheiHagimoto | 0:0e0631af0305 | 571 | } |
RyoheiHagimoto | 0:0e0631af0305 | 572 | else { |
RyoheiHagimoto | 0:0e0631af0305 | 573 | bestChild = node->child2; |
RyoheiHagimoto | 0:0e0631af0305 | 574 | otherChild = node->child1; |
RyoheiHagimoto | 0:0e0631af0305 | 575 | cut_dist = distance_.accum_dist( val, node->divlow, idx); |
RyoheiHagimoto | 0:0e0631af0305 | 576 | } |
RyoheiHagimoto | 0:0e0631af0305 | 577 | |
RyoheiHagimoto | 0:0e0631af0305 | 578 | /* Call recursively to search next level down. */ |
RyoheiHagimoto | 0:0e0631af0305 | 579 | searchLevel(result_set, vec, bestChild, mindistsq, dists, epsError); |
RyoheiHagimoto | 0:0e0631af0305 | 580 | |
RyoheiHagimoto | 0:0e0631af0305 | 581 | DistanceType dst = dists[idx]; |
RyoheiHagimoto | 0:0e0631af0305 | 582 | mindistsq = mindistsq + cut_dist - dst; |
RyoheiHagimoto | 0:0e0631af0305 | 583 | dists[idx] = cut_dist; |
RyoheiHagimoto | 0:0e0631af0305 | 584 | if (mindistsq*epsError<=result_set.worstDist()) { |
RyoheiHagimoto | 0:0e0631af0305 | 585 | searchLevel(result_set, vec, otherChild, mindistsq, dists, epsError); |
RyoheiHagimoto | 0:0e0631af0305 | 586 | } |
RyoheiHagimoto | 0:0e0631af0305 | 587 | dists[idx] = dst; |
RyoheiHagimoto | 0:0e0631af0305 | 588 | } |
RyoheiHagimoto | 0:0e0631af0305 | 589 | |
RyoheiHagimoto | 0:0e0631af0305 | 590 | private: |
RyoheiHagimoto | 0:0e0631af0305 | 591 | |
RyoheiHagimoto | 0:0e0631af0305 | 592 | /** |
RyoheiHagimoto | 0:0e0631af0305 | 593 | * The dataset used by this index |
RyoheiHagimoto | 0:0e0631af0305 | 594 | */ |
RyoheiHagimoto | 0:0e0631af0305 | 595 | const Matrix<ElementType> dataset_; |
RyoheiHagimoto | 0:0e0631af0305 | 596 | |
RyoheiHagimoto | 0:0e0631af0305 | 597 | IndexParams index_params_; |
RyoheiHagimoto | 0:0e0631af0305 | 598 | |
RyoheiHagimoto | 0:0e0631af0305 | 599 | int leaf_max_size_; |
RyoheiHagimoto | 0:0e0631af0305 | 600 | bool reorder_; |
RyoheiHagimoto | 0:0e0631af0305 | 601 | |
RyoheiHagimoto | 0:0e0631af0305 | 602 | |
RyoheiHagimoto | 0:0e0631af0305 | 603 | /** |
RyoheiHagimoto | 0:0e0631af0305 | 604 | * Array of indices to vectors in the dataset. |
RyoheiHagimoto | 0:0e0631af0305 | 605 | */ |
RyoheiHagimoto | 0:0e0631af0305 | 606 | std::vector<int> vind_; |
RyoheiHagimoto | 0:0e0631af0305 | 607 | |
RyoheiHagimoto | 0:0e0631af0305 | 608 | Matrix<ElementType> data_; |
RyoheiHagimoto | 0:0e0631af0305 | 609 | |
RyoheiHagimoto | 0:0e0631af0305 | 610 | size_t size_; |
RyoheiHagimoto | 0:0e0631af0305 | 611 | size_t dim_; |
RyoheiHagimoto | 0:0e0631af0305 | 612 | |
RyoheiHagimoto | 0:0e0631af0305 | 613 | /** |
RyoheiHagimoto | 0:0e0631af0305 | 614 | * Array of k-d trees used to find neighbours. |
RyoheiHagimoto | 0:0e0631af0305 | 615 | */ |
RyoheiHagimoto | 0:0e0631af0305 | 616 | NodePtr root_node_; |
RyoheiHagimoto | 0:0e0631af0305 | 617 | |
RyoheiHagimoto | 0:0e0631af0305 | 618 | BoundingBox root_bbox_; |
RyoheiHagimoto | 0:0e0631af0305 | 619 | |
RyoheiHagimoto | 0:0e0631af0305 | 620 | /** |
RyoheiHagimoto | 0:0e0631af0305 | 621 | * Pooled memory allocator. |
RyoheiHagimoto | 0:0e0631af0305 | 622 | * |
RyoheiHagimoto | 0:0e0631af0305 | 623 | * Using a pooled memory allocator is more efficient |
RyoheiHagimoto | 0:0e0631af0305 | 624 | * than allocating memory directly when there is a large |
RyoheiHagimoto | 0:0e0631af0305 | 625 | * number small of memory allocations. |
RyoheiHagimoto | 0:0e0631af0305 | 626 | */ |
RyoheiHagimoto | 0:0e0631af0305 | 627 | PooledAllocator pool_; |
RyoheiHagimoto | 0:0e0631af0305 | 628 | |
RyoheiHagimoto | 0:0e0631af0305 | 629 | Distance distance_; |
RyoheiHagimoto | 0:0e0631af0305 | 630 | }; // class KDTree |
RyoheiHagimoto | 0:0e0631af0305 | 631 | |
RyoheiHagimoto | 0:0e0631af0305 | 632 | } |
RyoheiHagimoto | 0:0e0631af0305 | 633 | |
RyoheiHagimoto | 0:0e0631af0305 | 634 | #endif //OPENCV_FLANN_KDTREE_SINGLE_INDEX_H_ |