ReconstructMe SDK  2.6.43-0
Real-time 3D reconstruction engine
example_reconstructmesdk_sensor_multi_independent.cpp

Content

This example shows how to use multiple sensors on a single volume. Two Scenarios are possible:

This example is prepared for both scenarios. Both scenarios just differ from the initial sensor position.

Determining the first scenario (scanning without known extrinisc calibration), the first sensor (master sensor) will define the world frame. Thus, the second senosor (slave sensor) has to estimate its position. In this case, we assume the sensors to be close to each other, thus both sensor will initially set to be in front of the volume. The slave sensor also gets a tracking hint for global alignment to be able to find the inital position. See the following code snippet for this scenario.

// Enable registration of second sensor. Note, it is required to place the sensor
// pysically close to the first sensor and let them view in the same direction
// Set default positon
puts("Using default postions for sensors");

Determining the second scenario (scanning with known extrinsic calibration), we are able to load positions of the master and slave sensor. Thus, for both sensors we avoid sensor tracking for the first iteration, and just integrate to the volume. This is defined by setting the trackin hint to don't track. See the following code snippet

// Load sensor positions
if (position_from_file("sensor0.pos", &pos[0][0], 16)) {
reme_sensor_set_position(c, sensor[0], &pos[0][0]);
// Note, inital tracking is not required, since position is known
puts("Loaded sensor0.pos");
}
if (position_from_file("sensor1.pos", &pos[1][0], 16)) {
reme_sensor_set_position(c, sensor[1], &pos[1][0]);
// Note, inital tracking is not required, since position is known
puts("Loaded sensor1.pos");
}

During the scanning loop, the user is able to save the current positions to the filesystem by pressing 's' on the keyboard.

reme_sensor_get_position(c, sensor[0], &pos[0][0]);
reme_sensor_get_position(c, sensor[1], &pos[1][0]);
if (position_to_file("sensor0.pos", &pos[0][0], 16)) {
puts("Saved sensor0.pos");
}
if (position_to_file("sensor1.pos", &pos[1][0], 16)) {
puts("Saved sensor1.pos");
}

The next video below shows both scenarios:

Note, Boost is only used to generate examples and is not necessary for working with this SDK.

#include <boost/test/unit_test.hpp>
#include <conio.h>
#include <stdio.h>
BOOST_AUTO_TEST_SUITE(example_reconstructmesdk)
bool position_from_file(const char* file_name, float* position, int length) {
FILE * pFile;
pFile = fopen(file_name, "rb");
if (pFile != NULL) {
fread(position, sizeof(float), length, pFile);
fclose(pFile);
return true;
}
return false;
}
bool position_to_file(const char* file_name, float* position, int length) {
FILE * pFile;
pFile = fopen(file_name, "wb");
if (pFile != NULL) {
fwrite(position, sizeof(float), length, pFile);
fclose(pFile);
return true;
}
return false;
}
BOOST_AUTO_TEST_CASE(sensor_multi_independent) {
// Create a new context
// Create a license object
reme_error_t e = reme_license_authenticate(c, l, "license.txt.sgn");
// Create a new volume
// Create a two sensors, both pointing to different sources
// In this case we have two parameter files where only the
// device_id is changed.
reme_sensor_t sensor[2];
reme_sensor_create(c, "openni1.txt", false, &sensor[0]);
reme_sensor_create(c, "openni2.txt", false, &sensor[1]);
reme_sensor_open(c, sensor[0]);
reme_sensor_open(c, sensor[1]);
float pos[2][16];
puts("Load camera position (y/n)?");
if (_getch() == 'y') {
// Load sensor positions
if (position_from_file("sensor0.pos", &pos[0][0], 16)) {
reme_sensor_set_position(c, sensor[0], &pos[0][0]);
// Note, inital tracking is not required, since position is known
puts("Loaded sensor0.pos");
}
if (position_from_file("sensor1.pos", &pos[1][0], 16)) {
reme_sensor_set_position(c, sensor[1], &pos[1][0]);
// Note, inital tracking is not required, since position is known
puts("Loaded sensor1.pos");
}
} else {
// Enable registration of second sensor. Note, it is required to place the sensor
// pysically close to the first sensor and let them view in the same direction
// Set default positon
puts("Using default postions for sensors");
}
// Prepare viewers
reme_viewer_t viewer;
reme_viewer_create_image(c, "This is ReconstructMeSDK", &viewer);
reme_image_t imgs[4];
reme_image_create(c, &imgs[0]);
reme_image_create(c, &imgs[1]);
reme_image_create(c, &imgs[2]);
reme_image_create(c, &imgs[3]);
reme_viewer_add_image(c, viewer, imgs[0]);
reme_viewer_add_image(c, viewer, imgs[1]);
reme_viewer_add_image(c, viewer, imgs[2]);
reme_viewer_add_image(c, viewer, imgs[3]);
puts("Key mapping");
puts("s: save current sensor positions");
puts("x: exit scanning loop");
puts("All keys need to be pressed with the command line in the foreground");
bool continue_grabbing = true;
while ((REME_SUCCESS(grab[0]) || REME_SUCCESS(grab[1])) && continue_grabbing) {
// Grab from both sensors.
grab[0] = reme_sensor_grab(c, sensor[0]);
grab[1] = reme_sensor_grab(c, sensor[1]);
// Update the volume from both sensors when we sensor tracking succeeded.
for (int i = 0; i < 2; ++i) {
if (REME_SUCCESS(grab[i])) {
}
}
}
reme_sensor_get_image(c, sensor[0], REME_IMAGE_DEPTH, imgs[0]);
reme_sensor_get_image(c, sensor[0], REME_IMAGE_VOLUME, imgs[1]);
reme_sensor_get_image(c, sensor[1], REME_IMAGE_DEPTH, imgs[2]);
reme_sensor_get_image(c, sensor[1], REME_IMAGE_VOLUME, imgs[3]);
reme_viewer_update(c, viewer);
if (_kbhit()) {
switch (_getch()) {
case 'x':
puts("stopping grabbing");
continue_grabbing = false;
break;
case 's':
reme_sensor_get_position(c, sensor[0], &pos[0][0]);
reme_sensor_get_position(c, sensor[1], &pos[1][0]);
if (position_to_file("sensor0.pos", &pos[0][0], 16)) {
puts("Saved sensor0.pos");
}
if (position_to_file("sensor1.pos", &pos[1][0], 16)) {
puts("Saved sensor1.pos");
}
break;
}
}
}
// Create a new empty surface
// Extract surface from volume.
// Visualize resulting surface
reme_viewer_t viewer_surface;
reme_viewer_create_surface(c, m, "This is ReconstructMeSDK", &viewer_surface);
reme_viewer_wait(c, viewer_surface);
// Export mesh
reme_surface_save_to_file(c, m, "test.ply");
// Print pending errors
// Make sure to release all memory acquired
}
BOOST_AUTO_TEST_SUITE_END()