10 pair_mat_t getBoundingBox(Mat &data)
14 data.row(0).copyTo(min);
15 data.row(0).copyTo(max);
16 T * pMin = min.ptr<T>(0);
17 T * pMax = max.ptr<T>(0);
18 for (
int y = 1; y < data.rows; y++) {
19 T * pData = data.ptr<T>(y);
20 for (
int x = 0; x < data.cols; x++) {
21 if (pMin[x] > pData[x]) pMin[x] = pData[x];
22 if (pMax[x] < pData[x]) pMax[x] = pData[x];
26 return std::make_pair(min, max);
30 int getSplitDimension(pair_mat_t &boundingBox)
33 Mat diff = boundingBox.second - boundingBox.first;
34 T max = diff.at<T>(0, 0);
35 Mat maxMasc(1, diff.cols, CV_8UC1);
36 for (
int x = 0; x < diff.cols; x++) {
37 if (max == diff.at<T>(0, x)) {
38 maxMasc.at<byte>(0, x) = 1;
40 else if (max > diff.at<T>(0, x)) {
41 maxMasc.at<byte>(0, x) = 0;
43 else if (max < diff.at<T>(0, x)) {
44 maxMasc.at<byte>(0, x) = 1;
45 maxMasc(Rect(0, 0, x, 1)).setTo(0);
46 max = diff.at<T>(0, x);
51 int nMaxs = countNonZero(maxMasc);
52 if (nMaxs == 1)
return res;
56 int n = random::u<int>(1, nMaxs);
57 for (x = 0; x < diff.cols; x++) {
58 if (maxMasc.at<byte>(0, x) == 1) n--;
68 DGM_WARNING(
"The k-D tree is not built");
71 FILE *pFile = fopen(fileName.c_str(),
"wb");
74 int k =
m_root->getBoundingBox().first.cols;
75 fwrite(&k,
sizeof(
int), 1, pFile);
82 FILE *pFile = fopen(fileName.c_str(),
"rb");
85 fread(&k,
sizeof(
int), 1, pFile);
93 DGM_WARNING(
"The data is empty");
96 DGM_ASSERT_MSG(keys.type() == CV_8UC1,
"Incorrect type of the keys");
97 DGM_ASSERT_MSG(values.type() == CV_8UC1,
"Incorrect type of the values");
98 DGM_ASSERT_MSG(keys.rows == values.rows,
"The amount of keys (%d) does not crrespond to the amount of values (%d)", keys.rows, values.rows);
100 pair_mat_t boundingBox = getBoundingBox<byte>(keys);
101 hconcat(keys, values, keys);
104 parallel::sortRows<byte>(keys);
106 int y = keys.rows - 1;
108 if (!mathop::isEqual<byte>(keys.row(y), keys.row(y - 1))) data.push_back(keys.row(y));
111 data.push_back(keys.row(0));
119 const float searchRadius_extension = 2.0f;
121 std::vector<std::shared_ptr<const CKDNode>> nearestNeighbors;
122 nearestNeighbors.reserve(maxNeighbors);
125 DGM_WARNING(
"The k-D tree is not built");
126 return nearestNeighbors;
130 nearestNeighbors.push_back(nearestNode);
131 float searchRadius = mathop::Euclidian<byte, float>(key, nearestNode->getKey());
132 if (maxNeighbors > 1) searchRadius *= searchRadius_extension;
133 searchRadius += 0.5f;
136 pair_mat_t searchBox;
137 searchBox.first = key - searchRadius;
138 searchBox.second = key + searchRadius;
140 m_root->findNearestNeighbors(key, maxNeighbors, searchBox, searchRadius, nearestNeighbors);
142 return nearestNeighbors;
149 fread(&_isLeaf,
sizeof(byte), 1, pFile);
151 Mat key(1, k, CV_8UC1);
154 fread(key.data,
sizeof(byte), k, pFile);
155 fread(&value,
sizeof(byte), 1, pFile);
157 std::shared_ptr<CKDNode> res(
new CKDNode(key, value));
160 pair_mat_t boundingBox = std::make_pair(Mat(1, k, CV_8UC1), Mat(1, k, CV_8UC1));
164 fread(boundingBox.first.data,
sizeof(byte), k, pFile);
165 fread(boundingBox.second.data,
sizeof(byte), k, pFile);
166 fread(&splitVal,
sizeof(byte), 1, pFile);
167 fread(&splitDim,
sizeof(
int), 1, pFile);
168 std::shared_ptr<CKDNode> left =
loadTree(pFile, k);
169 std::shared_ptr<CKDNode> right =
loadTree(pFile, k);
171 std::shared_ptr<CKDNode> res(
new CKDNode(boundingBox, splitVal, splitDim, left, right));
181 if (data.rows == 1) {
182 std::shared_ptr<CKDNode> res(
new CKDNode(lvalue_cast(data(Rect(0, 0, data.cols - 1, 1))), data.at<byte>(0, data.cols - 1)));
185 else if (data.rows == 2) {
187 int splitDim = getSplitDimension<byte>(boundingBox);
188 byte splitVal = (data.at<byte>(0, splitDim) + data.at<byte>(1, splitDim)) / 2;
189 std::shared_ptr<CKDNode> left, right;
190 if (data.at<byte>(0, splitDim) < data.at<byte>(1, splitDim)) {
191 left = std::shared_ptr<CKDNode>(
new CKDNode(lvalue_cast(data.row(0)(Rect(0, 0, data.cols - 1, 1))), data.at<byte>(0, data.cols - 1)));
192 right = std::shared_ptr<CKDNode>(
new CKDNode(lvalue_cast(data.row(1)(Rect(0, 0, data.cols - 1, 1))), data.at<byte>(1, data.cols - 1)));
195 left = std::shared_ptr<CKDNode>(
new CKDNode(lvalue_cast(data.row(1)(Rect(0, 0, data.cols - 1, 1))), data.at<byte>(1, data.cols - 1)));
196 right = std::shared_ptr<CKDNode>(
new CKDNode(lvalue_cast(data.row(0)(Rect(0, 0, data.cols - 1, 1))), data.at<byte>(0, data.cols - 1)));
198 std::shared_ptr<CKDNode> res(
new CKDNode(boundingBox, splitVal, splitDim, left, right));
203 int splitDim = getSplitDimension<byte>(boundingBox);
205 parallel::sortRows<byte>(data, splitDim);
206 int splitIdx = data.rows / 2;
207 byte splitVal = data.at<byte>(splitIdx, splitDim);
209 pair_mat_t boundingBoxLeft, boundingBoxRight;
210 boundingBox.first.copyTo(boundingBoxLeft.first);
211 boundingBox.second.copyTo(boundingBoxLeft.second);
212 boundingBox.first.copyTo(boundingBoxRight.first);
213 boundingBox.second.copyTo(boundingBoxRight.second);
215 boundingBoxLeft.second.at<byte>(0, splitDim) = splitVal > 0 ? splitVal - 1 : 0;
216 boundingBoxRight.first.at<byte>(0, splitDim) = splitVal;
218 std::shared_ptr<CKDNode> left =
buildTree(lvalue_cast(data(Rect(0, 0, data.cols, splitIdx))), boundingBoxLeft);
219 std::shared_ptr<CKDNode> right =
buildTree(lvalue_cast(data(Rect(0, data.rows / 2, data.cols, data.rows - data.rows / 2))), boundingBoxRight);
220 std::shared_ptr<CKDNode> res(
new CKDNode(boundingBox, splitVal, splitDim, left, right));
227 std::shared_ptr<CKDNode> node(
m_root);
229 while (!node->isLeaf()) {
230 std::shared_ptr<CKDNode> n = std::static_pointer_cast<
CKDNode>(node);
231 if (key.at<byte>(0, n->getSplitDim()) < n->getSplitVal()) node = n->
Left();
232 else node = n->Right();
235 return std::static_pointer_cast<
CKDNode>(node);
k-D Node class for the k-D Tree data structure
std::shared_ptr< const CKDNode > findNearestNode(const Mat &key) const
std::shared_ptr< CKDNode > buildTree(Mat &data, pair_mat_t &boundingBox)
std::shared_ptr< CKDNode > loadTree(FILE *pFile, int k)
std::shared_ptr< CKDNode > m_root
void build(Mat &keys, Mat &values)
Builds a k-d tree on keys with corresponding values.
std::vector< std::shared_ptr< const CKDNode > > findNearestNeighbors(const Mat &key, size_t maxNeighbors) const
Finds up to maxNeighbors nearest neighbors to the key.
void load(const std::string &fileName)
Loads a tree from the file.
void save(const std::string &fileName) const
Saves the tree into a file.
std::shared_ptr< CKDNode > Left(void) const
Returns the pointer to the left child.