SDK 示例

采集教程

本教程介绍了如何使用DaoAI SDK来采集点云和二维图像。

前提条件

  • 安装DaoAI相机工作室软件

帮助函数

// 用于检查返回的SlcSdkError对象的错误信息的辅助工具。
bool hasError(DaoAI::SlcSdkError error_info) {
    if (error_info.status() == DaoAI::SlcSdkSuccess) { // 状态代码SlcSdkSuccess表示没有发现错误。
        return false;
    }
    else {
        // 请查阅文档或头文件error.h了解不同错误状态代码的含义。
        // 大多数错误会有一个详细的描述,有助于调试。参见SlcSdkError.details()。
        //     注意:即使状态码是SlcSdkSuccess,细节部分仍然可能包括警告。
        std::cout << "ERROR " << error_info.status() << ": " << error_info.details() << std::endl;
        return true;
    }
}

设置

// 设置 ==========================================================================================================
// 声明一个错误返回对象,以检查整个应用程序的错误。
DaoAI::SlcSdkError ret;

// 创建一个新的DaoAI应用程序实例。
DaoAI::Application* app = new DaoAI::Application();

// 指定用于记录的目录。日志包含详细的错误和进程信息。
std::string logging_directory = "../../Logs/";
ret = app->startLogging(logging_directory);
if (hasError(ret)) { return -1; } // Check for errors

// 如果使用远程相机,请指定远程IP地址。
std::string remote_ip = "192.168.1.2";

// 声明相机地图,该地图将用于获取所有连接的DaoAI相机。
std::map<std::string, DaoAI::Camera*> cameras;

//  从应用程序中获取相机。这一步必须在尝试连接任何相机之前完成。
ret = app->getCameras(cameras, remote_ip);
if (hasError(ret)) { return -1; } // Check for errors

if (cameras.size() == 0) {
   return -1; // 必须检测到至少有一台相机。
}
std::cout << cameras.size() << " cameras detected." << std::endl;
for (std::pair<std::string, DaoAI::Camera*> pair : cameras) {
   std::cout << "      " << pair.first << std::endl; // 打印检测到的相机的序列号。
}

// 声明指向DaoAI相机对象的指针。
DaoAI::Camera* cam;

连接相机

连接相机有3个选项。

// 连接相机 =========================================================================================
// 必须先连接一个DaoAI相机,然后才能使用它进行采集。
// 选项 1:连接到第一个检测到的DaoAI相机。
ret = app->connectCamera(cam);
if (hasError(ret)) { return -1; } // Check for errors
ret = cam->disConnect();
if (hasError(ret)) { return -1; } // Check for errors

// 选项 2:通过序列号连接到特定的相机。
std::string serial_num = cameras.begin()->first; // 从地图上的第一台相机上获取序列号。
// 方法 A
ret = app->connectCamera(serial_num, cam);
if (hasError(ret)) { return -1; } // Check for errors
ret = app->disconnectCamera(serial_num); //  也可以通过序列号断开摄像头。
if (hasError(ret)) { return -1; } // Check for errors
// 方法 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

// 选项 3:连接在相机地图中发现的任何相机。
if (cameras.size() > 0) {
   cam = cameras.begin()->second;
}
ret = cam->connect();
if (hasError(ret)) { return -1; } // Check for errors

相机动作

获取序列号、相机固有参数和相机设置信息。

// 相机动作 =================================================================================================
// 有些相机操作需要相机,请务必查看文档和错误信息。
// 检查相机是否已连接。
if (!cam->isConnected()) {
   return -1;
}

// 获取此相机的序列号。
serial_num = cam->getSerialNumber();
std::cout << "Serial number of connected camera is " << serial_num << std::endl;

// 获取相机内参。
std::vector<float> intrinsic_params;
ret = cam->getIntrinsicParam(intrinsic_params);
if (hasError(ret)) { return -1; } // Check for errors

// 获取此相机当前的使用设置。
DaoAI::Settings settings = cam->getSettings();

相机设置

创建相机设置并从相机设置文件中加载。

// 相机设置 ================================================================================================
// DaoAI Settings 可以与相机一起使用,在拍摄和重建过程中调整参数。
DaoAI::Settings new_settings;
int icurr, imin, imax; // 用这些来查询整数设置。
double dcurr, dmin, dmax; // 用这些来查询双精度浮点型设置。
bool bcurr; // 用这个来查询布尔值设置。
std::string scurr; // 用这个来查询字符串的设置。
bool is_enabled; // 用这个来检查一个设置是否被启用。
int inewval; // 用这个来为一个设置设置一个新的整数值。
double dnewval; // 用这个来为一个设置设置一个新的双精度浮点型值。
bool bnewval; // 用这个来为一个设置设置一个新的布尔值。
// 创建新的空相机设置。
new_settings = DaoAI::Settings();
// 从文件中加载现有的相机设置。
std::string path_to_settings = "../../Examples/sample_settings.cfg";
new_settings = DaoAI::Settings(path_to_settings);
// Clone 设置
new_settings = DaoAI::Settings(settings);

采集帧

配置采集帧参数。

// 采集帧
// 采集帧指定在图像采集过程中使用的参数。一个设置对象最多可以支持10个。
// 每个采集框都有三个可修改的参数: 亮度、增益和曝光档。
// 详情请参见文档。
DaoAI::AcquisitionFrame af;

// 创建默认的 AcquisitionFrame
af = DaoAI::AcquisitionFrame();

// 用初始值创建 AcquisitionFrame
int brightness = 3;
double gain = 2.0;
int exposure_stop = -1;
af = DaoAI::AcquisitionFrame(brightness, gain, exposure_stop);

// 查看任何 AcquisitionFrame 参数的当前值和可接受范围。
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

// 将任何AcquisitionFrame参数配置为一个自定义值。
ret = af.configureSetting(DaoAI::AcquisitionFrame::ExposureStop, 2);
if (hasError(ret)) { return -1; } // Check for errors

// 双精度浮点参数也可以用双精度浮点值进行检索和修改。
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

// 使用不正确的类型来配置或查询一个参数会成功,但会返回一个警告。
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.

// 在设置中添加采集帧。
int index; // Index of added acquisition frame.
ret = new_settings.addAcquisitionFrame(af, index);
if (hasError(ret)) { return -1; } // Check for errors

// 获取采集帧。
DaoAI::AcquisitionFrame returned_af;
ret = new_settings.getAcquisitionFrame(returned_af, 1);
if (hasError(ret)) { return -1; } // Check for errors

// 删除索引值的采集帧。
ret = new_settings.deleteAcquisitionFrame(index);
if (hasError(ret)) { return -1; } // Check for errors

// 不获取索引添加采集帧。
ret = new_settings.addAcquisitionFrame(af);
if (hasError(ret)) { return -1; } // Check for errors

// 修改并替换索引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;
// 获取整个采集帧地图的副本。
ret = new_settings.getAcquisitionFrames(mofaf);
if (hasError(ret)) { return -1; } // Check for errors

// 将采集帧的地图设置为设置。
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

采集助手

通过分析给定时间段的场景,自动计算采集帧设置。

// 采集助手
// 分析场景并生成采集帧设置,所有采集帧的总时间将小于时间预算。
// 时间预算越高,生成的采集帧就越多。
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; }

过滤器设置

创建、读取和修改过滤器设置。

// 滤镜设置
// 滤镜设置指定在三维重建过程中使用的参数。关于过滤器设置的完整列表
// 和它们的描述,请查阅settings.h和文档。
// 启用或禁用过滤器设置。
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

// 检查是否启用了过滤器设置。
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; }

// 获取一个过滤器设置的当前值和有效范围。
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

// 配置一个过滤器设置。
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

// 对于数字过滤器的设置,使用类型不匹配的getter或setter会成功,但会发出警告。
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.

系统设置

创建、读取和导出系统设置。

// 系统设置
// 系统设置是描述和影响DaoAI系统的各种参数。关于系统设置的完整列表,
// 请参考settings.h和文档中的描述。
// 注意:这些系统设置中有许多是只读的,对于当前的摄像机系统来说可能并不准确。
// 除非直接从摄像机中获取更新的设置对象[DaoAI::Camera.getSettings()]。
// 启用或停用系统设置
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

// 检查一个系统设置是否被启用。
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; }

// 获取一个系统设置的当前值。
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;

// 保存和导出设置。
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

采集

采集图像.

// 相机采集  ================================================================================================
// 声明一个DaoAI帧对象,采集的数据将被写入其中
DaoAI::Frame frm;
// 用默认设置进行拍摄(假设没有对相机进行设置)。
ret = cam->capture(frm);
if (hasError(ret)) { return -1; } // Check for errors

// 使用自定义设置进行采集
// 方案1:使用设置进行拍摄。相机保存的设置用于今后的采集。
ret = cam->capture(new_settings, frm);
if (hasError(ret)) { return -1; } // Check for errors
// 方案2:将设置对象设定为相机,以便在采集时使用。
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
// 方案3:将设置从文件加载到相机,以便在采集中使用。
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

// 使用HDR图像作为拍摄画面的颜色
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; }
// 使用第一个采集帧的图像作为采集帧的颜色
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; }

// 启用使用本地GPU进行计算(仅适用于BP-AMR和USB接口的3D相机)。
ret = cam->enableGPU(true);
if (hasError(ret)) { return -1; }
ret = cam->capture(frm);
if (hasError(ret)) { return -1; }
// 禁止使用本地GPU进行计算,使用CPU代替(仅适用于BP-AMR和USB接口的3D相机)。
ret = cam->enableGPU(false);
if (hasError(ret)) { return -1; }
ret = cam->capture(frm);
if (hasError(ret)) { return -1; }

// 启用温度调节功能
ret = cam->enableTempRegulation(true);
if (hasError(ret)) { return -1; }
// 禁用温度调节功能
ret = cam->enableTempRegulation(false);
if (hasError(ret)) { return -1; }

保存和加载图像。

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

// 检查帧是否有数据
if (!new_frame.isEmpty()) { std::cout << "Success: Frame contains data from 3D capture!" << std::endl; }

// 保存一个框架。文件扩展名.dcf是首选的DaoAI框架格式,但保存也支持.pcd和.ply格式。
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

// 从文件中加载一个框架。支持.dcf文件。
ret = new_frame.load("../../Examples/sample_frame.dcf");
if (hasError(ret)) { return -1; } // Check for errors

// 获取点云数据。
DaoAI::PointCloud pcl;
ret = frm.getPointCloud(pcl);
if (hasError(ret)) { return -1; } // Check for errors

点云

创建、获取和读取点云数据。

// 点云 ====================================================================================================
// 点云包含来自3D采集帧的坐标和颜色信息。
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();
// 获取点云结构信息。
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; }
// 获取点云数据信息。
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();

获取和读取点的数据。

// 点 ==========================================================================================================
// 点包含单个点的坐标和颜色信息。
// 获取点的数据。
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)
// 设定点数据。
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.

清理

// 清理 =======================================================================================================
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;