SDK Sample

Capture tutorial

This tutorial describes how to use the DaoAI SDK to capture point clouds and 2D images.

Prerequisites

  • install DaoAI Camera Studio

Helper Functions

// Helper for checking error information from a returned SlcSdkError object.
bool hasError(DaoAI::SlcSdkError error_info) {
    if (error_info.status() == DaoAI::SlcSdkSuccess) { // A status code of SlcSdkSuccess indicates that no error is detected.
        return false;
    }
    else {
        // Consult documentation or header error.h for the meaning of different error status codes.
        // Most errors will come with a detailed description, helpful for debugging. See SlcSdkError.details().
        //      NOTE: The details section may still include warnings even when the status code is SlcSdkSuccess.
        std::cout << "ERROR " << error_info.status() << ": " << error_info.details() << std::endl;
        return true;
    }
}

Setup

// Setup ==========================================================================================================
// Declare an error return object to check for errors throughout the application.
DaoAI::SlcSdkError ret;

// Create a new DaoAI application instance.
DaoAI::Application* app = new DaoAI::Application();

// Specify directory for logging. Logs contain detailed error and process information.
std::string logging_directory = "../../Logs/";
ret = app->startLogging(logging_directory);
if (hasError(ret)) { return -1; } // Check for errors

// If using remote cameras, specify remote IP address
std::string remote_ip = "192.168.1.2";

// Declare camera map that will be used to fetch all connected DaoAI Cameras.
std::map<std::string, DaoAI::Camera*> cameras;

// Get cameras from application. This step must be completed before attempting to connect to any camera.
ret = app->getCameras(cameras, remote_ip);
if (hasError(ret)) { return -1; } // Check for errors

if (cameras.size() == 0) {
   return -1; // Must detect at least one camera.
}
std::cout << cameras.size() << " cameras detected." << std::endl;
for (std::pair<std::string, DaoAI::Camera*> pair : cameras) {
   std::cout << "      " << pair.first << std::endl; // Print serial numbers of detected cameras.
}

// Declare pointer to DaoAI Camera object.
DaoAI::Camera* cam;

Connecting to a Camera

Connecting to camera can have 3 Options.

// Connecting to a camera =========================================================================================
// A DaoAI Camera must be connected before it can be used for captures.
// OPTION 1: Connecting to the first detected DaoAI Camera.
ret = app->connectCamera(cam);
if (hasError(ret)) { return -1; } // Check for errors
ret = cam->disConnect();
if (hasError(ret)) { return -1; } // Check for errors

// OPTION 2: Connect to specific camera by serial number.
std::string serial_num = cameras.begin()->first; // Grab serial number from first camera in map.
// Method A
ret = app->connectCamera(serial_num, cam);
if (hasError(ret)) { return -1; } // Check for errors
ret = app->disconnectCamera(serial_num); // Can also disconnect cam by serial number.
if (hasError(ret)) { return -1; } // Check for errors
// Method B
cam = cameras[serial_num];
ret = cam->connect();
if (hasError(ret)) { return -1; } // Check for errors
ret = app->disconnectCamera(serial_num);
if (hasError(ret)) { return -1; } // Check for errors

// OPTION 3: Connecting any camera found in camera map.
if (cameras.size() > 0) {
   cam = cameras.begin()->second;
}
ret = cam->connect();
if (hasError(ret)) { return -1; } // Check for errors

Camera Actions

Get serial number, camera intrinsic parameters, and camera settings information.

// Camera Actions =================================================================================================
// Some camera actions will require the camera to be connected, be sure to check documentation and error messages.
// Check if a camera is connected.
if (!cam->isConnected()) {
   return -1;
}

// Get serial number of this camera.
serial_num = cam->getSerialNumber();
std::cout << "Serial number of connected camera is " << serial_num << std::endl;

// Get camera intrinsic parameters.
std::vector<float> intrinsic_params;
ret = cam->getIntrinsicParam(intrinsic_params);
if (hasError(ret)) { return -1; } // Check for errors

// Get current settings used by this camera.
DaoAI::Settings settings = cam->getSettings();

Camera Settings

Create camera settings and load from camera setting file.

// Camera Settings ================================================================================================
// DaoAI Settings can be used with a camera to tweak parameters during capture and the reconstruction process.
DaoAI::Settings new_settings;
int icurr, imin, imax; // Use these to inquire integer settings.
double dcurr, dmin, dmax; // Use these to inquire double settings.
bool bcurr; // Use this to inquire boolean settings.
std::string scurr; // Use this to inquire string settings.
bool is_enabled; // Use this to check if a setting is enabled.
int inewval; // Use this to set a new integer value to a setting.
double dnewval; // Use this to set a new double value to a setting.
bool bnewval; // Use this to set a new boolean value to a setting.
// Creating new empty Camera Settings
new_settings = DaoAI::Settings();
// Loading existing Camera Settings from file.
std::string path_to_settings = "../../Examples/sample_settings.cfg";
new_settings = DaoAI::Settings(path_to_settings);
// Cloning settings
new_settings = DaoAI::Settings(settings);

Acquisition Frames

Configure Acquisition frames parameters.

// Acquisition Frames
// Acquisition frames specify parameters to be used during image capture. A settings object can support up to 10.
//     Each acquisition frame has three modififiable parameters: Brightness, Gain and ExposureStop.
//     See documentation for details.
DaoAI::AcquisitionFrame af;

// Create default AcquisitionFrame
af = DaoAI::AcquisitionFrame();

// Create AcquisitionFrame with initial values
int brightness = 3;
double gain = 2.0;
int exposure_stop = -1;
af = DaoAI::AcquisitionFrame(brightness, gain, exposure_stop);

// View the current value and acceptable bounds for any AcquisitionFrame parameter.
ret = af.inquireSetting(DaoAI::AcquisitionFrame::ExposureStop, icurr, imin, imax);
if (hasError(ret)) { return -1; } // Check for errors
std::cout << "Current exposure stop: " << icurr << ". Exposure stop can be configured to any value between " << imin << " - " << imax << std::endl;
ret = af.inquireSetting(DaoAI::AcquisitionFrame::ExposureStop, icurr); // Inquire only current value.
if (hasError(ret)) { return -1; } // Check for errors

// Configure any AcquisitionFrame parameter to a custom value.
ret = af.configureSetting(DaoAI::AcquisitionFrame::ExposureStop, 2);
if (hasError(ret)) { return -1; } // Check for errors

// Double parameters can also be retreived and modified with double values.
ret = af.inquireSetting(DaoAI::AcquisitionFrame::Gain, dcurr, dmin, dmax);
if (hasError(ret)) { return -1; } // Check for errors
std::cout << "Current gain: " << dcurr << ". Gain can be configured to any value between " << dmin << " - " << dmax << std::endl;
ret = af.inquireSetting(DaoAI::AcquisitionFrame::Gain, dcurr); // Inquire only current value.
if (hasError(ret)) { return -1; } // Check for errors

ret = af.configureSetting(DaoAI::AcquisitionFrame::Gain, 2);
if (hasError(ret)) { return -1; } // Check for errors

// Using the incorrect type to configure or inquire a parameter will be successful but will return a warning.
ret = af.inquireSetting(DaoAI::AcquisitionFrame::Gain, icurr, imin, imax);
if (hasError(ret)) { return -1; } // Check for errors
std::cout << ret.details() << std::endl; // Warning about possible data loss, attempting to read double as int.
dnewval = 1.5;
ret = af.configureSetting(DaoAI::AcquisitionFrame::ExposureStop, dnewval);
if (hasError(ret)) { return -1; } // Check for errors
std::cout << ret.details() << std::endl; // Warning about possible data loss, attempting to set int with double.

// Add acquisition frame to settings.
int index; // Index of added acquisition frame.
ret = new_settings.addAcquisitionFrame(af, index);
if (hasError(ret)) { return -1; } // Check for errors

// Get acquisition frame
DaoAI::AcquisitionFrame returned_af;
ret = new_settings.getAcquisitionFrame(returned_af, 1);
if (hasError(ret)) { return -1; } // Check for errors

// Delete acquisition frame at index.
ret = new_settings.deleteAcquisitionFrame(index);
if (hasError(ret)) { return -1; } // Check for errors

// Add acquisition frame without getting index.
ret = new_settings.addAcquisitionFrame(af);
if (hasError(ret)) { return -1; } // Check for errors

// Modify and replace the acquisition frame at index 1.
ret = af.configureSetting(DaoAI::AcquisitionFrame::Brightness, 2);
if (hasError(ret)) { return -1; } // Check for errors
ret = new_settings.modifyAcquisitionFrame(af, 1);
if (hasError(ret)) { return -1; } // Check for errors

std::map<int, DaoAI::AcquisitionFrame> mofaf;
// Get copy of entire map of acquisition frames.
ret = new_settings.getAcquisitionFrames(mofaf);
if (hasError(ret)) { return -1; } // Check for errors

// Set map of acquisition frames to settings.
mofaf[1] = DaoAI::AcquisitionFrame(1, 0, 1);
mofaf[2] = DaoAI::AcquisitionFrame(2, 2, 2);
ret = new_settings.setAcquisitionFrames(mofaf);
if (hasError(ret)) { return -1; } // Check for errors

Capture Assistant

Auto compute acquisition frame settings by analyzing scene given a time buget.

// Capture Assistant
// Analyze scene and generate acquisition frame settings, the total time for all acquisition frames will be less than the time budget.
//             The higher time budget is, the more acquisition frames will be generated.
std::map<int, DaoAI::AcquisitionFrame> ca_mofaf;
ret = cam->captureAssistant(1.0, ca_mofaf);  // Generate a map of acquisition frames with time budget of 1 sec.
if (hasError(ret)) { return -1; }
ret = new_settings.setAcquisitionFrames(ca_mofaf);  // Set the generated acquisition frames to camera settings
if (hasError(ret)) { return -1; }
ret = cam->setSettings(new_settings);  // Apply the camera settings to camera
if (hasError(ret)) { return -1; }
DaoAI::Frame ca_frm;
ret = cam->capture(ca_frm);  // Capture point cloud
if (hasError(ret)) { return -1; }

Filter Settings

Create, read, and modify Filter settings.

// Filter Settings
// Filter settings specify parameters that are used during 3D reconstruction. For a full list of filter settings
//      and their descriptions consult settings.h and the documentation.
// Enable or Disable filter settings.
ret = new_settings.enableFilterSetting(DaoAI::Settings::OutlierThreshold, true); // Enable outlier filter
if (hasError(ret)) { return -1; } // Check for errors
ret = new_settings.enableFilterSetting(DaoAI::Settings::GaussianFilter, false); // Disable gaussian filter
if (hasError(ret)) { return -1; } // Check for errors
ret = new_settings.enableFilterSetting(DaoAI::Settings::FillGaps, true); // Enable Fill Gaps
if (hasError(ret)) { return -1; } // Check for errors

// Check if a filter setting is enabled.
ret = new_settings.checkEnableFilterSetting(DaoAI::Settings::OutlierThreshold, is_enabled); // Check if outlier filter is enabled.
if (hasError(ret)) { return -1; } // Check for errors
if (is_enabled) { std::cout << "Outlier filter is enabled!" << std::endl; }
ret = new_settings.checkEnableFilterSetting(DaoAI::Settings::GaussianFilter, is_enabled); // Check if gaussian filter is enabled.
if (hasError(ret)) { return -1; } // Check for errors
if (is_enabled) { std::cout << "Gaussian filter is enabled!" << std::endl; }
ret = new_settings.checkEnableFilterSetting(DaoAI::Settings::FillGaps, is_enabled); // Enable Fill Gaps
if (hasError(ret)) { return -1; } // Check for errors
if (is_enabled) { std::cout << "Fill gaps is enabled!" << std::endl; }

// Get the current value and valid range of a filter setting.
ret = new_settings.inquireFilterSetting(DaoAI::Settings::OutlierThreshold, dcurr, dmin, dmax);
if (hasError(ret)) { return -1; } // Check for errors
std::cout << "Outlier threshold filter has a current value of " << dcurr << ", with a valid range of " << dmin << " - " << dmax << std::endl;
ret = new_settings.inquireFilterSetting(DaoAI::Settings::OutlierThreshold, dcurr); // Can also get current value without checking range.
if (hasError(ret)) { return -1; } // Check for errors
ret = new_settings.inquireFilterSetting(DaoAI::Settings::GaussianFilter, icurr, imin, imax);
if (hasError(ret)) { return -1; } // Check for errors
std::cout << "Gaussian filter has a current value of " << icurr << ", with a valid range of " << imin << " - " << imax << std::endl;
ret = new_settings.inquireFilterSetting(DaoAI::Settings::GaussianFilter, icurr); // Can also get current value without checking range.
if (hasError(ret)) { return -1; } // Check for errors
ret = new_settings.inquireFilterSetting(DaoAI::Settings::FillGaps, bcurr);
if (hasError(ret)) { return -1; } // Check for errors

// Configure a filter setting.
inewval = 2;
dnewval = 3.4;
bnewval = true;
ret = new_settings.configureFilterSetting(DaoAI::Settings::OutlierThreshold, dnewval);
if (hasError(ret)) { return -1; } // Check for errors
ret = new_settings.configureFilterSetting(DaoAI::Settings::GaussianFilter, inewval);
if (hasError(ret)) { return -1; } // Check for errors
ret = new_settings.configureFilterSetting(DaoAI::Settings::FillXFirst, bnewval);
if (hasError(ret)) { return -1; } // Check for errors

// For numeric filter settings, using a type mismatch getter or setter will work successfully but issue a warning.
ret = new_settings.inquireFilterSetting(DaoAI::Settings::OutlierThreshold, icurr);
if (hasError(ret)) { return -1; } // Expect no error (status = DaoAI::SlcSdkSuccess)
std::cout << ret.details() << std::endl; // Print warning message for using int value to retrieve a double parameter.
dnewval = 1.5;
ret = new_settings.inquireFilterSetting(DaoAI::Settings::GaussianFilter, dnewval);
if (hasError(ret)) { return -1; } // Expect no error (status = DaoAI::SlcSdkSuccess)
std::cout << ret.details() << std::endl; // Print warning message for using double value to set an integer parameter.

System Settings

Create, read, and export System settings.

// System Settings
// System settings are miscellaneous parameters that describe and affect the DaoAI System. For a full list of system
//      settings and their descriptions consult settings.h and the documentation.
//      NOTE: Many of these system settings are read-only, and may not be accurate for current camera system
//            unless getting the updated settings object directly from a camera [DaoAI::Camera.getSettings()].
// Enable or Disable System Setting
ret = new_settings.configureSystemSetting(DaoAI::Settings::ExtraWhitePatternEnable, false);
if (hasError(ret)) { return -1; } // Check for errors
ret = new_settings.configureSystemSetting(DaoAI::Settings::TemperatureRegulationEnable, true);
if (hasError(ret)) { return -1; } // Check for errors

// Check if a system setting is enabled.
ret = new_settings.checkEnableSystemSetting(DaoAI::Settings::ExtraWhitePatternEnable, is_enabled);
if (hasError(ret)) { return -1; } // Check for errors
if (is_enabled) { std::cout << "Extra white pattern is enabled!" << std::endl; }
ret = new_settings.checkEnableSystemSetting(DaoAI::Settings::TemperatureRegulationEnable, is_enabled);
if (hasError(ret)) { return -1; } // Check for errors
if (is_enabled) { std::cout << "Temperature regulation is enabled!" << std::endl; }

// Get the current value of a system setting.
ret = new_settings.inquireSystemSetting(DaoAI::Settings::GPUAvailable, bcurr);
if (hasError(ret)) { return -1; } // Check for errors
if (bcurr) { std::cout << "GPU is Available on your system!" << std::endl; }
ret = new_settings.inquireSystemSetting(DaoAI::Settings::CameraModel, scurr);
if (hasError(ret)) { return -1; } // Check for errors
std::cout << "This camera has model " << scurr << std::endl;

// Save and export settings.
std::string save_settings_path = "../../Examples/example_setting_save.cfg";
ret = new_settings.exportSettings(save_settings_path);
if (hasError(ret)) { return -1; } // Check for errors

Capture

Capture image.

// Camera Captures ================================================================================================
// Declare a DaoAI Frame object to which capture data will be written
DaoAI::Frame frm;
// Capture with default settings (assuming no settings has been set to camera).
ret = cam->capture(frm);
if (hasError(ret)) { return -1; } // Check for errors

// Capture with custom settings
// OPTION 1: Capture with settings. Settings saved by camera for future captures.
ret = cam->capture(new_settings, frm);
if (hasError(ret)) { return -1; } // Check for errors
// OPTION 2: Set settings object to camera to use in capture.
ret = cam->setSettings(new_settings);
if (hasError(ret)) { return -1; } // Check for errors
ret = cam->capture(frm);
if (hasError(ret)) { return -1; } // Check for errors
// OPTION 3: Load settings from file to camera to use in capture.
ret = cam->setSettings("../../Examples/sample_settings.cfg");
if (hasError(ret)) { return -1; } // Check for errors
ret = cam->capture(frm);
if (hasError(ret)) { return -1; } // Check for errors

// Use HDR image as captured frame's color
ret = new_settings.enableFilterSetting(DaoAI::Settings::ShowHDR, true);
if (hasError(ret)) { return -1; }
ret = cam->setSettings(new_settings);
if (hasError(ret)) { return -1; }
ret = cam->capture(frm);
if (hasError(ret)) { return -1; }
// Use the first acquisition frame image as captured frame's color
ret = new_settings.enableFilterSetting(DaoAI::Settings::ShowHDR, false);
if (hasError(ret)) { return -1; }
ret = cam->setSettings(new_settings);
if (hasError(ret)) { return -1; }
ret = cam->capture(frm);
if (hasError(ret)) { return -1; }

// Enable computation using local GPU (for BP-AMR and USB interface 3D cameras only)
ret = cam->enableGPU(true);
if (hasError(ret)) { return -1; }
ret = cam->capture(frm);
if (hasError(ret)) { return -1; }
// Disable computation using local GPU, use CPU instead (for BP-AMR and USB interface 3D cameras only)
ret = cam->enableGPU(false);
if (hasError(ret)) { return -1; }
ret = cam->capture(frm);
if (hasError(ret)) { return -1; }

// Enable temperature regulation
ret = cam->enableTempRegulation(true);
if (hasError(ret)) { return -1; }
// Disable temperature regulation
ret = cam->enableTempRegulation(false);
if (hasError(ret)) { return -1; }

Frames

Save and load image.

// Frames =========================================================================================================
DaoAI::Frame new_frame;
// Create new empty frame
new_frame = DaoAI::Frame();
// Copy constructor
new_frame = DaoAI::Frame(frm);

// Check if frame has data
if (!new_frame.isEmpty()) { std::cout << "Success: Frame contains data from 3D capture!" << std::endl; }

// Save a frame. File extension .dcf is the preferred DaoAI frame format, but saving also supports .pcd and .ply formats.
std::string save_frame_path = "../../Examples/example_frame_save.dcf";
ret = new_frame.save(save_frame_path);
if (hasError(ret)) { return -1; } // Check for errors

// Load a frame from file. Supports .dcf files.
ret = new_frame.load("../../Examples/sample_frame.dcf");
if (hasError(ret)) { return -1; } // Check for errors

// Get point cloud data.
DaoAI::PointCloud pcl;
ret = frm.getPointCloud(pcl);
if (hasError(ret)) { return -1; } // Check for errors

Point Cloud

Create, get and read Point Cloud data.

// Point Cloud ====================================================================================================
// Point cloud contains the coordinate and color information from the 3D Capture Frame.
DaoAI::PointCloud new_pcl;
// Create new point cloud.
new_pcl = DaoAI::PointCloud(); // Empty point cloud.
new_pcl = DaoAI::PointCloud(100, 100); // Specify dimensions of created point cloud.
new_pcl = DaoAI::PointCloud(pcl); // Copy point cloud.
// Clone a point cloud.
new_pcl = pcl.clone();
// Get point cloud structure information.
int size = new_pcl.getSize();
int height = new_pcl.getHeight(); // Number of rows.
int width = new_pcl.getWidth(); // Number of columns.
if (!new_pcl.isEmpty()) { std::cout << "Point cloud contains capture data!" << std::endl; }
// Get point cloud data information.
std::vector<float> x_values = new_pcl.getVecX(); // 2D vector of all the x-coordinates in the point cloud.
std::vector<float> y_values = new_pcl.getVecX(); // 2D vector of all the y-coordinates in the point cloud.
std::vector<float> z_values = new_pcl.getVecX(); // 2D vector of all the z-coordinates in the point cloud.
std::vector<float> confident_values = new_pcl.getVecConfident(); // 2D vector of point cloud confidence values.
std::vector<uint32_t> rgba_values = new_pcl.getVecRgba(); // 2D vector of all the RGBA values in the point cloud. 0xAARRGGBB format.
std::vector<uint8_t> r_values = new_pcl.getVecR(); // 2D vector of all the r-values in the point cloud.
std::vector<uint8_t> g_values = new_pcl.getVecG(); // 2D vector of all the g-values in the point cloud.
std::vector<uint8_t> b_values = new_pcl.getVecB(); // 2D vector of all the b-values in the point cloud.
std::vector<uint8_t> a_values = new_pcl.getVecA(); // 2D vector of all the a-values in the point cloud.
// Get individual point from point cloud.
DaoAI::Point pt;
int idx = rand() % size;
pt = new_pcl(idx); // Get any point using a 1D index between [0, size).
int row = rand() % height; int col = rand() % width;
pt = new_pcl(row, col); // Get any point using a 2D index pair (row, column).
// Get pointer to first point in the point cloud.
DaoAI::Point* first_pt = new_pcl.getDataPtr();

Point

Get and read Point data.

// Point ==========================================================================================================
// Point contains the coordinate and color information of an individual point.
// Get point data.
float x = pt.getX();
float y = pt.getY();
float z = pt.getZ();
float confident = pt.getConfident();
uint8_t r = pt.getR();
uint8_t g = pt.getG();
uint8_t b = pt.getB();
uint8_t a = pt.getA();
uint32_t rgba = pt.getRgba(); // 0xAARRGGBB format (ARGB)
// Set point data.
DaoAI::Point new_point;
new_point.setX(1);
new_point.setY(2);
new_point.setZ(3);
new_point.setConfident(0.4);
new_point.setRgba(0x00FF0000); // Set to red.
new_point.setRgb(0x00, 0xFF, 0x00); // Set to green.
new_point.setRgba(0x00, 0x00, 0xFF, 0x00); // Set to blue.

Clean Up

// Clean Up =======================================================================================================
ret = cam->disConnect();
if (hasError(ret)) { return -1; } // Check for errors
delete cam;

ret = app->stopLogging();
if (hasError(ret)) { return -1; } // Check for errors

std::cout << "End of sample program!" << std::endl;
return 1;