-
Notifications
You must be signed in to change notification settings - Fork 83
/
test_scene.h
372 lines (333 loc) · 12 KB
/
test_scene.h
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
// This file is part of KWIVER, and is distributed under the
// OSI-approved BSD 3-Clause License. See top-level LICENSE file or
// https://github.com/Kitware/kwiver/blob/master/LICENSE for details.
/**
* \file
*
* \brief Various functions for creating a simple SBA test scene
*
* These functions are based on VITAL core and shared by various tests
*/
#ifndef VITAL_TEST_TEST_SCENE_H_
#define VITAL_TEST_TEST_SCENE_H_
#include "test_random_point.h"
#include <vital/math_constants.h>
#include <vital/types/camera_map.h>
#include <vital/types/camera_perspective.h>
#include <vital/types/feature_track_set.h>
#include <vital/types/landmark_map.h>
#include <vital/types/mesh.h>
namespace kwiver {
namespace testing {
// construct a map of landmarks at the corners of a cube centered at c
// with a side length of s
kwiver::vital::landmark_map_sptr
cube_corners( double s, const kwiver::vital::vector_3d& c = kwiver::vital::vector_3d(0, 0, 0) )
{
using namespace kwiver::vital;
// create corners of a cube
landmark_map::map_landmark_t landmarks;
s /= 2.0;
landmarks[0] = landmark_sptr( new landmark_d( c + vector_3d( -s, -s, -s ) ) );
landmarks[1] = landmark_sptr( new landmark_d( c + vector_3d( -s, -s, s ) ) );
landmarks[2] = landmark_sptr( new landmark_d( c + vector_3d( -s, s, -s ) ) );
landmarks[3] = landmark_sptr( new landmark_d( c + vector_3d( -s, s, s ) ) );
landmarks[4] = landmark_sptr( new landmark_d( c + vector_3d( s, -s, -s ) ) );
landmarks[5] = landmark_sptr( new landmark_d( c + vector_3d( s, -s, s ) ) );
landmarks[6] = landmark_sptr( new landmark_d( c + vector_3d( s, s, -s ) ) );
landmarks[7] = landmark_sptr( new landmark_d( c + vector_3d( s, s, s ) ) );
return landmark_map_sptr( new simple_landmark_map( landmarks ) );
}
// construct a cube mesh centered at c with a side length of s
kwiver::vital::mesh_sptr
cube_mesh(double s, const kwiver::vital::vector_3d& c = { 0.0, 0.0, 0.0 })
{
using namespace kwiver::vital;
s /= 2.0;
auto verts = new mesh_vertex_array<3> { {-s, -s, -s},
{-s, -s, s},
{-s, s, -s},
{-s, s, s},
{ s, -s, -s},
{ s, -s, s},
{ s, s, -s},
{ s, s, s} };
for (auto & vert : *verts)
{
vert += c;
}
auto faces = new mesh_regular_face_array<4> { {0, 1, 3, 2},
{4, 6, 7, 5},
{5, 7, 3, 1},
{6, 4, 0, 2},
{7, 6, 2, 3},
{1, 0, 4, 5} };
return std::make_shared<mesh>(std::unique_ptr<mesh_vertex_array_base>(verts),
std::unique_ptr<mesh_face_array_base>(faces));
}
// construct a square mesh in XY centered at c with a side length of s
kwiver::vital::mesh_sptr
grid_mesh(unsigned width, unsigned height, double scale = 1.0,
const kwiver::vital::vector_3d& origin = { 0.0, 0.0, 0.0 })
{
using namespace kwiver::vital;
auto verts = new mesh_vertex_array<3>;
auto faces = new mesh_regular_face_array<3>;
unsigned index = 0;
for (unsigned h = 0; h <= height; ++h)
{
for (unsigned w = 0; w <= width; ++w)
{
vector_3d vert{ scale * w, scale * h, 0.0 };
verts->push_back(origin + vert);
if (w > 0 && h > 0)
{
unsigned prev_x = index - 1;
unsigned prev_y = index - width - 1;
unsigned prev_xy = prev_y - 1;
faces->push_back({index, prev_xy, prev_y});
faces->push_back({index, prev_x, prev_xy});
}
++index;
}
}
return std::make_shared<mesh>(std::unique_ptr<mesh_vertex_array_base>(verts),
std::unique_ptr<mesh_face_array_base>(faces));
}
// construct map of landmarks will all locations at c
kwiver::vital::landmark_map_sptr
init_landmarks( kwiver::vital::landmark_id_t num_lm,
const kwiver::vital::vector_3d& c = kwiver::vital::vector_3d(0, 0, 0) )
{
using namespace kwiver::vital;
landmark_map::map_landmark_t lm_map;
for ( landmark_id_t i = 0; i < num_lm; ++i )
{
lm_map[i] = landmark_sptr( new landmark_d( c ) );
}
return landmark_map_sptr( new simple_landmark_map( lm_map ) );
}
// add Gaussian noise to the landmark positions
kwiver::vital::landmark_map_sptr
noisy_landmarks( kwiver::vital::landmark_map_sptr landmarks,
double stdev = 1.0 )
{
using namespace kwiver::vital;
kwiver::testing::rng_t rng( 1 );
landmark_map::map_landmark_t lm_map = landmarks->landmarks();
for( landmark_map::map_landmark_t::value_type& p : lm_map )
{
landmark_sptr l = p.second->clone();
landmark_d& lm = dynamic_cast<landmark_d&>(*l);
lm.set_loc( lm.get_loc() + random_point3d( stdev, rng ) );
lm_map[p.first] = l;
}
return landmark_map_sptr( new simple_landmark_map( lm_map ) );
}
// create a camera sequence (elliptical path)
kwiver::vital::camera_map_sptr
camera_seq(kwiver::vital::frame_id_t num_cams,
kwiver::vital::camera_intrinsics_sptr K,
double scale = 1.0,
double degree_span = 115)
{
using namespace kwiver::vital;
camera_map::map_camera_t cameras;
const double angle = degree_span * deg_to_rad;
// create a camera sequence (elliptical path)
rotation_d R; // identity
for ( frame_id_t i = 0; i < num_cams; ++i )
{
double frac = static_cast< double > ( i ) / num_cams;
double x = 4 * std::cos( angle * frac );
double y = 3 * std::sin( angle * frac );
simple_camera_perspective* cam =
new simple_camera_perspective(scale * vector_3d(x,y,2+frac), R, K);
// look at the origin
cam->look_at( vector_3d( 0, 0, 0 ) );
cameras[i] = camera_sptr( cam );
}
return camera_map_sptr( new simple_camera_map( cameras ) );
}
// create a camera sequence (elliptical path)
kwiver::vital::camera_map_sptr
camera_seq(kwiver::vital::frame_id_t num_cams = 20,
kwiver::vital::simple_camera_intrinsics K =
kwiver::vital::simple_camera_intrinsics(
1000, { 640, 480 }, 1.0, 0.0, {}, 1280, 960),
double scale = 1.0,
double degree_span = 115)
{
return camera_seq(num_cams, K.clone(), scale, degree_span);
}
// create an initial camera sequence with all cameras at the same location
kwiver::vital::camera_map_sptr
init_cameras(kwiver::vital::frame_id_t num_cams,
kwiver::vital::camera_intrinsics_sptr K)
{
using namespace kwiver::vital;
camera_map::map_camera_t cameras;
// create a camera sequence (elliptical path)
rotation_d R; // identity
vector_3d c( 0, 0, 1 );
for ( frame_id_t i = 0; i < num_cams; ++i )
{
simple_camera_perspective* cam = new simple_camera_perspective(c, R, K);
// look at the origin
cam->look_at( vector_3d( 0, 0, 0 ), vector_3d( 0, 1, 0 ) );
cameras[i] = camera_sptr( cam );
}
return camera_map_sptr( new simple_camera_map( cameras ) );
}
// create an initial camera sequence with all cameras at the same location
kwiver::vital::camera_map_sptr
init_cameras(kwiver::vital::frame_id_t num_cams = 20,
kwiver::vital::simple_camera_intrinsics K =
kwiver::vital::simple_camera_intrinsics(1000, kwiver::vital::vector_2d(640, 480)))
{
return init_cameras(num_cams, K.clone());
}
// add positional and rotational Gaussian noise to cameras
kwiver::vital::camera_map_sptr
noisy_cameras( kwiver::vital::camera_map_sptr cameras,
double pos_stdev = 1.0, double rot_stdev = 1.0 )
{
using namespace kwiver::vital;
camera_map::map_camera_t cam_map;
kwiver::testing::rng_t rng( 1 );
for( camera_map::map_camera_t::value_type const& p : cameras->cameras() )
{
auto cam_ptr = std::dynamic_pointer_cast<vital::camera_perspective>(p.second);
auto c = std::dynamic_pointer_cast<vital::camera_perspective>(cam_ptr->clone());
simple_camera_perspective& cam =
dynamic_cast<simple_camera_perspective&>(*c);
cam.set_center( cam.get_center() + random_point3d( pos_stdev, rng ) );
rotation_d rand_rot( random_point3d( rot_stdev, rng ) );
cam.set_rotation( cam.get_rotation() * rand_rot );
cam_map[p.first] = c;
}
return camera_map_sptr( new simple_camera_map( cam_map ) );
}
// randomly drop a fraction of the track states
kwiver::vital::feature_track_set_sptr
subset_tracks( kwiver::vital::feature_track_set_sptr in_tracks, double keep_frac = 0.75 )
{
using namespace kwiver::vital;
std::srand( 0 );
std::vector< track_sptr > tracks = in_tracks->tracks();
std::vector< track_sptr > new_tracks;
const int rand_thresh = static_cast< int > ( keep_frac * RAND_MAX );
for( const track_sptr &t : tracks )
{
auto nt = track::create();
nt->set_id( t->id() );
std::cout << "track " << t->id() << ":";
for( auto const& ts : *t )
{
if ( std::rand() < rand_thresh )
{
nt->append( ts->clone() );
std::cout << " .";
}
else
{
std::cout << " X";
}
}
std::cout << std::endl;
new_tracks.push_back( nt );
}
return std::make_shared<feature_track_set>( new_tracks );
}
// add Gaussian noise to track feature locations
kwiver::vital::feature_track_set_sptr
noisy_tracks( kwiver::vital::feature_track_set_sptr in_tracks, double stdev = 1.0 )
{
using namespace kwiver::vital;
std::vector< track_sptr > tracks = in_tracks->tracks();
std::vector< track_sptr > new_tracks;
kwiver::testing::rng_t rng( 1 );
for( const track_sptr &t : tracks )
{
auto nt = track::create();
nt->set_id(t->id());
for(track::history_const_itr it=t->begin(); it!=t->end(); ++it)
{
auto fts = std::dynamic_pointer_cast<feature_track_state>(*it);
if( !fts || !fts->feature )
{
continue;
}
vector_2d loc = fts->feature->loc() + random_point2d( stdev, rng );
auto new_fts = std::make_shared<feature_track_state>(*fts);
new_fts->feature = std::make_shared<feature_d>(loc);
nt->append(new_fts);
}
new_tracks.push_back(nt);
}
return std::make_shared<feature_track_set>( new_tracks );
}
// randomly select a fraction of the track states to make outliers
// outliers are created by adding random noise with large standard deviation
kwiver::vital::feature_track_set_sptr
add_outliers_to_tracks(kwiver::vital::feature_track_set_sptr in_tracks,
double outlier_frac=0.1,
double stdev=20.0)
{
using namespace kwiver::vital;
kwiver::testing::rng_t rng( 1 );
std::vector<track_sptr> tracks = in_tracks->tracks();
std::vector<track_sptr> new_tracks;
const int rand_thresh = static_cast<int>(outlier_frac * RAND_MAX);
for(const track_sptr& t : tracks)
{
track_sptr nt = track::create();
nt->set_id( t->id() );
for( const auto &ts : *t )
{
auto fts = std::dynamic_pointer_cast<feature_track_state>(ts);
if( !fts || !fts->feature )
{
std::cout << " X";
continue;
}
if(std::rand() < rand_thresh)
{
vector_2d loc = fts->feature->loc() + random_point2d( stdev, rng );
auto new_fts = std::make_shared<feature_track_state>(*fts);
new_fts->feature = std::make_shared<feature_d>(loc);
nt->append( new_fts );
std::cout << " M";
}
else
{
std::cout << " .";
nt->append(ts->clone());
}
}
std::cout << std::endl;
new_tracks.push_back( nt );
}
return std::make_shared<feature_track_set>( new_tracks );
}
// set inlier state on all track states
void
reset_inlier_flag( kwiver::vital::feature_track_set_sptr tracks,
bool target_state=false )
{
using namespace kwiver::vital;
for( track_sptr t : tracks->tracks() )
{
for( auto fts : *t | as_feature_track )
{
if( !fts )
{
continue;
}
fts->inlier = target_state;
}
}
}
} // end namespace testing
} // end namespace kwiver
#endif // VITAL_TEST_TEST_SCENE_H_