1 // Copyright (c) 2018, ETH Zurich and UNC Chapel Hill.
2 // All rights reserved.
3 //
4 // Redistribution and use in source and binary forms, with or without
5 // modification, are permitted provided that the following conditions are met:
6 //
7 //     * Redistributions of source code must retain the above copyright
8 //       notice, this list of conditions and the following disclaimer.
9 //
10 //     * Redistributions in binary form must reproduce the above copyright
11 //       notice, this list of conditions and the following disclaimer in the
12 //       documentation and/or other materials provided with the distribution.
13 //
14 //     * Neither the name of ETH Zurich and UNC Chapel Hill nor the names of
15 //       its contributors may be used to endorse or promote products derived
16 //       from this software without specific prior written permission.
17 //
18 // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
19 // AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
20 // IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
21 // ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS OR CONTRIBUTORS BE
22 // LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
23 // CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
24 // SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
25 // INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
26 // CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
27 // ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
28 // POSSIBILITY OF SUCH DAMAGE.
29 //
30 // Author: Johannes L. Schoenberger (jsch-at-demuc-dot-de)
31 
32 #define TEST_NAME "feature/types"
33 #include "util/testing.h"
34 
35 #include <unordered_set>
36 
37 #include "feature/types.h"
38 #include "util/math.h"
39 
40 using namespace colmap;
41 
BOOST_AUTO_TEST_CASE(TestFeatureKeypoints)42 BOOST_AUTO_TEST_CASE(TestFeatureKeypoints) {
43   FeatureKeypoint keypoint;
44   BOOST_CHECK_EQUAL(keypoint.x, 0.0f);
45   BOOST_CHECK_EQUAL(keypoint.y, 0.0f);
46   BOOST_CHECK_EQUAL(keypoint.a11, 1.0f);
47   BOOST_CHECK_EQUAL(keypoint.a12, 0.0f);
48   BOOST_CHECK_EQUAL(keypoint.a21, 0.0f);
49   BOOST_CHECK_EQUAL(keypoint.a22, 1.0f);
50 
51   FeatureKeypoints keypoints(1);
52   BOOST_CHECK_EQUAL(keypoints.size(), 1);
53   BOOST_CHECK_EQUAL(keypoints[0].x, 0.0f);
54   BOOST_CHECK_EQUAL(keypoints[0].y, 0.0f);
55   BOOST_CHECK_EQUAL(keypoints[0].a11, 1.0f);
56   BOOST_CHECK_EQUAL(keypoints[0].a12, 0.0f);
57   BOOST_CHECK_EQUAL(keypoints[0].a21, 0.0f);
58   BOOST_CHECK_EQUAL(keypoints[0].a22, 1.0f);
59 
60   keypoint = FeatureKeypoint(1, 2);
61   BOOST_CHECK_EQUAL(keypoint.x, 1.0f);
62   BOOST_CHECK_EQUAL(keypoint.y, 2.0f);
63   BOOST_CHECK_EQUAL(keypoint.a11, 1.0f);
64   BOOST_CHECK_EQUAL(keypoint.a12, 0.0f);
65   BOOST_CHECK_EQUAL(keypoint.a21, 0.0f);
66   BOOST_CHECK_EQUAL(keypoint.a22, 1.0f);
67   BOOST_CHECK_LT(std::abs(keypoint.ComputeScale() - 1.0f), 1e-6);
68   BOOST_CHECK_LT(std::abs(keypoint.ComputeScaleX() - 1.0f), 1e-6);
69   BOOST_CHECK_LT(std::abs(keypoint.ComputeScaleY() - 1.0f), 1e-6);
70   BOOST_CHECK_LT(std::abs(keypoint.ComputeOrientation() - 0.0f), 1e-6);
71   BOOST_CHECK_LT(std::abs(keypoint.ComputeShear() - 0.0f), 1e-6);
72 
73   keypoint = FeatureKeypoint(1, 2, 0, 0);
74   BOOST_CHECK_EQUAL(keypoint.x, 1.0f);
75   BOOST_CHECK_EQUAL(keypoint.y, 2.0f);
76   BOOST_CHECK_EQUAL(keypoint.a11, 0.0f);
77   BOOST_CHECK_EQUAL(keypoint.a12, 0.0f);
78   BOOST_CHECK_EQUAL(keypoint.a21, 0.0f);
79   BOOST_CHECK_EQUAL(keypoint.a22, 0.0f);
80 
81   keypoint = FeatureKeypoint(1, 2, 1, 0);
82   BOOST_CHECK_EQUAL(keypoint.x, 1.0f);
83   BOOST_CHECK_EQUAL(keypoint.y, 2.0f);
84   BOOST_CHECK_EQUAL(keypoint.a11, 1.0f);
85   BOOST_CHECK_EQUAL(keypoint.a12, 0.0f);
86   BOOST_CHECK_EQUAL(keypoint.a21, 0.0f);
87   BOOST_CHECK_EQUAL(keypoint.a22, 1.0f);
88   BOOST_CHECK_LT(std::abs(keypoint.ComputeScale() - 1.0f), 1e-6);
89   BOOST_CHECK_LT(std::abs(keypoint.ComputeScaleX() - 1.0f), 1e-6);
90   BOOST_CHECK_LT(std::abs(keypoint.ComputeScaleY() - 1.0f), 1e-6);
91   BOOST_CHECK_LT(std::abs(keypoint.ComputeOrientation() - 0.0f), 1e-6);
92   BOOST_CHECK_LT(std::abs(keypoint.ComputeShear() - 0.0f), 1e-6);
93 
94   keypoint = FeatureKeypoint(1, 2, 1, M_PI / 2);
95   BOOST_CHECK_EQUAL(keypoint.x, 1.0f);
96   BOOST_CHECK_EQUAL(keypoint.y, 2.0f);
97   BOOST_CHECK_LT(std::abs(keypoint.a11 - 0.0f), 1e-6);
98   BOOST_CHECK_LT(std::abs(keypoint.a12 - -1.0f), 1e-6);
99   BOOST_CHECK_LT(std::abs(keypoint.a21 - 1.0f), 1e-6);
100   BOOST_CHECK_LT(std::abs(keypoint.a22 - 0.0f), 1e-6);
101   BOOST_CHECK_LT(std::abs(keypoint.ComputeScale() - 1.0f), 1e-6);
102   BOOST_CHECK_LT(std::abs(keypoint.ComputeScaleX() - 1.0f), 1e-6);
103   BOOST_CHECK_LT(std::abs(keypoint.ComputeScaleY() - 1.0f), 1e-6);
104   BOOST_CHECK_LT(std::abs(keypoint.ComputeOrientation() - M_PI / 2), 1e-6);
105   BOOST_CHECK_LT(std::abs(keypoint.ComputeShear() - 0.0f), 1e-6);
106 
107   keypoint = FeatureKeypoint(1, 2, 2, M_PI / 2);
108   BOOST_CHECK_EQUAL(keypoint.x, 1.0f);
109   BOOST_CHECK_EQUAL(keypoint.y, 2.0f);
110   BOOST_CHECK_LT(std::abs(keypoint.a11 - 0.0f), 1e-6);
111   BOOST_CHECK_LT(std::abs(keypoint.a12 - -2.0f), 1e-6);
112   BOOST_CHECK_LT(std::abs(keypoint.a21 - 2.0f), 1e-6);
113   BOOST_CHECK_LT(std::abs(keypoint.a22 - 0.0f), 1e-6);
114   BOOST_CHECK_LT(std::abs(keypoint.ComputeScale() - 2.0f), 1e-6);
115   BOOST_CHECK_LT(std::abs(keypoint.ComputeScaleX() - 2.0f), 1e-6);
116   BOOST_CHECK_LT(std::abs(keypoint.ComputeScaleY() - 2.0f), 1e-6);
117   BOOST_CHECK_LT(std::abs(keypoint.ComputeOrientation() - M_PI / 2), 1e-6);
118   BOOST_CHECK_LT(std::abs(keypoint.ComputeShear() - 0.0f), 1e-6);
119 
120   keypoint = FeatureKeypoint(1, 2, 2, M_PI);
121   BOOST_CHECK_EQUAL(keypoint.x, 1.0f);
122   BOOST_CHECK_EQUAL(keypoint.y, 2.0f);
123   BOOST_CHECK_LT(std::abs(keypoint.a11 - -2.0f), 1e-6);
124   BOOST_CHECK_LT(std::abs(keypoint.a12 - 0.0f), 1e-6);
125   BOOST_CHECK_LT(std::abs(keypoint.a21 - 0.0), 1e-6);
126   BOOST_CHECK_LT(std::abs(keypoint.a22 - -2.0f), 1e-6);
127   BOOST_CHECK_LT(std::abs(keypoint.ComputeScale() - 2.0f), 1e-6);
128   BOOST_CHECK_LT(std::abs(keypoint.ComputeScaleX() - 2.0f), 1e-6);
129   BOOST_CHECK_LT(std::abs(keypoint.ComputeScaleY() - 2.0f), 1e-6);
130   BOOST_CHECK(std::abs(keypoint.ComputeOrientation() - M_PI) < 1e-6 ||
131               std::abs(keypoint.ComputeOrientation() + M_PI) < 1e-6);
132   BOOST_CHECK_LT(std::abs(keypoint.ComputeShear() - 0.0f), 1e-6);
133 
134   keypoint = FeatureKeypoint::FromParameters(1, 2, 2, 2, M_PI, 0);
135   BOOST_CHECK_EQUAL(keypoint.x, 1.0f);
136   BOOST_CHECK_EQUAL(keypoint.y, 2.0f);
137   BOOST_CHECK_LT(std::abs(keypoint.a11 - -2.0f), 1e-6);
138   BOOST_CHECK_LT(std::abs(keypoint.a12 - 0.0f), 1e-6);
139   BOOST_CHECK_LT(std::abs(keypoint.a21 - 0.0), 1e-6);
140   BOOST_CHECK_LT(std::abs(keypoint.a22 - -2.0f), 1e-6);
141   BOOST_CHECK_LT(std::abs(keypoint.ComputeScale() - 2.0f), 1e-6);
142   BOOST_CHECK_LT(std::abs(keypoint.ComputeScaleX() - 2.0f), 1e-6);
143   BOOST_CHECK_LT(std::abs(keypoint.ComputeScaleY() - 2.0f), 1e-6);
144   BOOST_CHECK(std::abs(keypoint.ComputeOrientation() - M_PI) < 1e-6 ||
145               std::abs(keypoint.ComputeOrientation() + M_PI) < 1e-6);
146   BOOST_CHECK_LT(std::abs(keypoint.ComputeShear() - 0.0f), 1e-6);
147 
148   keypoint = FeatureKeypoint::FromParameters(1, 2, 2, 3, M_PI, 0);
149   BOOST_CHECK_EQUAL(keypoint.x, 1.0f);
150   BOOST_CHECK_EQUAL(keypoint.y, 2.0f);
151   BOOST_CHECK_LT(std::abs(keypoint.a11 - -2.0f), 1e-6);
152   BOOST_CHECK_LT(std::abs(keypoint.a12 - 0.0f), 1e-6);
153   BOOST_CHECK_LT(std::abs(keypoint.a21 - 0.0), 1e-6);
154   BOOST_CHECK_LT(std::abs(keypoint.a22 - -3.0f), 1e-6);
155   BOOST_CHECK_LT(std::abs(keypoint.ComputeScale() - 2.5f), 1e-6);
156   BOOST_CHECK_LT(std::abs(keypoint.ComputeScaleX() - 2.0f), 1e-6);
157   BOOST_CHECK_LT(std::abs(keypoint.ComputeScaleY() - 3.0f), 1e-6);
158   BOOST_CHECK(std::abs(keypoint.ComputeOrientation() - M_PI) < 1e-6 ||
159               std::abs(keypoint.ComputeOrientation() + M_PI) < 1e-6);
160   BOOST_CHECK_LT(std::abs(keypoint.ComputeShear() - 0.0f), 1e-6);
161 
162   keypoint = FeatureKeypoint::FromParameters(1, 2, 2, 3, -M_PI / 2, M_PI / 4);
163   BOOST_CHECK_EQUAL(keypoint.x, 1.0f);
164   BOOST_CHECK_EQUAL(keypoint.y, 2.0f);
165   BOOST_CHECK_LT(std::abs(keypoint.a11 - 0.0f), 1e-6);
166   BOOST_CHECK_LT(std::abs(keypoint.a12 - 2.12132025f), 1e-6);
167   BOOST_CHECK_LT(std::abs(keypoint.a21 - -2.0f), 1e-6);
168   BOOST_CHECK_LT(std::abs(keypoint.a22 - 2.12132025f), 1e-6);
169   BOOST_CHECK_LT(std::abs(keypoint.ComputeScale() - 2.5f), 1e-6);
170   BOOST_CHECK_LT(std::abs(keypoint.ComputeScaleX() - 2.0f), 1e-6);
171   BOOST_CHECK_LT(std::abs(keypoint.ComputeScaleY() - 3.0f), 1e-6);
172   BOOST_CHECK_LT(std::abs(keypoint.ComputeOrientation() - -M_PI / 2), 1e-6);
173   BOOST_CHECK_LT(std::abs(keypoint.ComputeShear() - M_PI / 4), 1e-6);
174 
175   keypoint = FeatureKeypoint::FromParameters(1, 2, 2, 3, M_PI / 2, M_PI / 4);
176   BOOST_CHECK_EQUAL(keypoint.x, 1.0f);
177   BOOST_CHECK_EQUAL(keypoint.y, 2.0f);
178   BOOST_CHECK_LT(std::abs(keypoint.a11 - 0.0f), 1e-6);
179   BOOST_CHECK_LT(std::abs(keypoint.a12 - -2.12132025f), 1e-6);
180   BOOST_CHECK_LT(std::abs(keypoint.a21 - 2.0f), 1e-6);
181   BOOST_CHECK_LT(std::abs(keypoint.a22 - -2.12132025f), 1e-6);
182   BOOST_CHECK_LT(std::abs(keypoint.ComputeScale() - 2.5f), 1e-6);
183   BOOST_CHECK_LT(std::abs(keypoint.ComputeScaleX() - 2.0f), 1e-6);
184   BOOST_CHECK_LT(std::abs(keypoint.ComputeScaleY() - 3.0f), 1e-6);
185   BOOST_CHECK_LT(std::abs(keypoint.ComputeOrientation() - M_PI / 2), 1e-6);
186   BOOST_CHECK_LT(std::abs(keypoint.ComputeShear() - M_PI / 4), 1e-6);
187 
188   keypoint.Rescale(2, 2);
189   BOOST_CHECK_EQUAL(keypoint.x, 2.0f);
190   BOOST_CHECK_EQUAL(keypoint.y, 4.0f);
191   BOOST_CHECK_LT(std::abs(keypoint.a11 - 2 * 0.0f), 1e-6);
192   BOOST_CHECK_LT(std::abs(keypoint.a12 - 2 * -2.12132025f), 1e-6);
193   BOOST_CHECK_LT(std::abs(keypoint.a21 - 2 * 2.0f), 1e-6);
194   BOOST_CHECK_LT(std::abs(keypoint.a22 - 2 * -2.12132025f), 1e-6);
195   BOOST_CHECK_LT(std::abs(keypoint.ComputeScale() - 2 * 2.5f), 1e-6);
196   BOOST_CHECK_LT(std::abs(keypoint.ComputeScaleX() - 2 * 2.0f), 1e-6);
197   BOOST_CHECK_LT(std::abs(keypoint.ComputeScaleY() - 2 * 3.0f), 1e-6);
198   BOOST_CHECK_LT(std::abs(keypoint.ComputeOrientation() - M_PI / 2), 1e-6);
199   BOOST_CHECK_LT(std::abs(keypoint.ComputeShear() - M_PI / 4), 1e-6);
200 
201   keypoint.Rescale(1, 0.5);
202   BOOST_CHECK_EQUAL(keypoint.x, 2.0f);
203   BOOST_CHECK_EQUAL(keypoint.y, 2.0f);
204   BOOST_CHECK_LT(std::abs(keypoint.a11 - 2 * 0.0f), 1e-6);
205   BOOST_CHECK_LT(std::abs(keypoint.a12 - -2.12132025f), 1e-6);
206   BOOST_CHECK_LT(std::abs(keypoint.a21 - 2 * 2.0f), 1e-6);
207   BOOST_CHECK_LT(std::abs(keypoint.a22 - -2.12132025f), 1e-6);
208   BOOST_CHECK_LT(std::abs(keypoint.ComputeScale() - 3.5f), 1e-6);
209   BOOST_CHECK_LT(std::abs(keypoint.ComputeScaleX() - 2 * 2.0f), 1e-6);
210   BOOST_CHECK_LT(std::abs(keypoint.ComputeScaleY() - 3.0f), 1e-6);
211   BOOST_CHECK_LT(std::abs(keypoint.ComputeOrientation() - M_PI / 2), 1e-6);
212   BOOST_CHECK_LT(std::abs(keypoint.ComputeShear() - M_PI / 4), 1e-6);
213 }
214 
BOOST_AUTO_TEST_CASE(TestFeatureDescriptors)215 BOOST_AUTO_TEST_CASE(TestFeatureDescriptors) {
216   FeatureDescriptors descriptors = FeatureDescriptors::Random(2, 3);
217   BOOST_CHECK_EQUAL(descriptors.rows(), 2);
218   BOOST_CHECK_EQUAL(descriptors.cols(), 3);
219   BOOST_CHECK_EQUAL(descriptors(0, 0), descriptors.data()[0]);
220   BOOST_CHECK_EQUAL(descriptors(0, 1), descriptors.data()[1]);
221   BOOST_CHECK_EQUAL(descriptors(0, 2), descriptors.data()[2]);
222   BOOST_CHECK_EQUAL(descriptors(1, 0), descriptors.data()[3]);
223   BOOST_CHECK_EQUAL(descriptors(1, 1), descriptors.data()[4]);
224   BOOST_CHECK_EQUAL(descriptors(1, 2), descriptors.data()[5]);
225 }
226 
BOOST_AUTO_TEST_CASE(TestFeatureMatches)227 BOOST_AUTO_TEST_CASE(TestFeatureMatches) {
228   FeatureMatch match;
229   BOOST_CHECK_EQUAL(match.point2D_idx1, kInvalidPoint2DIdx);
230   BOOST_CHECK_EQUAL(match.point2D_idx2, kInvalidPoint2DIdx);
231   FeatureMatches matches(1);
232   BOOST_CHECK_EQUAL(matches.size(), 1);
233   BOOST_CHECK_EQUAL(matches[0].point2D_idx1, kInvalidPoint2DIdx);
234   BOOST_CHECK_EQUAL(matches[0].point2D_idx2, kInvalidPoint2DIdx);
235 }
236 
BOOST_AUTO_TEST_CASE(TestFeatureMatchHashing)237 BOOST_AUTO_TEST_CASE(TestFeatureMatchHashing) {
238   std::unordered_set<std::pair<point2D_t, point2D_t>> set;
239   set.emplace(1, 2);
240   BOOST_CHECK_EQUAL(set.size(), 1);
241   set.emplace(1, 2);
242   BOOST_CHECK_EQUAL(set.size(), 1);
243   BOOST_CHECK_EQUAL(set.count(std::make_pair(0, 0)), 0);
244   BOOST_CHECK_EQUAL(set.count(std::make_pair(1, 2)), 1);
245   BOOST_CHECK_EQUAL(set.count(std::make_pair(2, 1)), 0);
246   set.emplace(2, 1);
247   BOOST_CHECK_EQUAL(set.size(), 2);
248   BOOST_CHECK_EQUAL(set.count(std::make_pair(0, 0)), 0);
249   BOOST_CHECK_EQUAL(set.count(std::make_pair(1, 2)), 1);
250   BOOST_CHECK_EQUAL(set.count(std::make_pair(2, 1)), 1);
251 }
252