SDK 示例
本章将介绍一些 DaoAI AOI 3D Camera SDK 的常用功能示例代码,以帮助您更好地使用。
前提条件
安装DaoAI AOI 软件
遵循环境配置中的步骤,确保环境正确配置
引入库
在示例中,我们使用了以下几个头文件,其中aoi_ad3dcamera 开头的是用于引入DaoAI AOI 3D Camera SDK的库。
#include <cstdint>
#include <aoi_ad3dcamera/array2d.h>
#include <aoi_ad3dcamera/camera.h>
#include <aoi_ad3dcamera/frame.h>
#include <aoi_ad3dcamera/pointcloud.h>
#include <aoi_ad3dcamera/settings2d.h>
#include <aoi_ad3dcamera/settings3d.h>
#include <exception>
#include <filesystem>
#include <iostream>
#include <opencv2/core/mat.hpp>
#include <opencv2/imgcodecs.hpp>
#include <vector>
连接相机
使用 DaoAI AOI 3D Camera SDK 连接到指定类型相机。
创建相机对象 camera,并尝试连接 DaoAI::CameraMode::AD类型设备。
相机类型CameraMode分为:
AS: 单目相机,支持型号AS470/AS080
AD: 双目相机,支持型号AD470/AD080
AQ: 高精度相机,支持型号AQ060
如果连接失败,会捕获并输出错误信息,并终止程序返回 -1。
以下是代码示例:
std::shared_ptr<DaoAI::Camera> camera = nullptr; try { camera = std::make_shared<DaoAI::Camera>(); auto model = DaoAI::CameraMode::AD; camera->connect(model); std::cout << "Connected to camera " << model << std::endl; // we can check the camera is connected or not if (!camera->connected()) { std::cerr << "Camera is not connected" << std::endl; return -1; } } catch (const std::exception& e) { std::cerr << "Failed to connect camera. Cause: " << e.what() << std::endl; return -1; }
预览
检查相机当前的视野,并调整帧配置以获得理想的图像。
首先,定义了一个 DaoAI::Settings3D::FrameConfig 对象 frame_config,用于设置帧配置参数,其中包括:
曝光补偿(exposure_stop):设置为 -1
亮度(brightness):设置为 3
增益(gain):设置为 0
接着,调用 camera->preview(frame_config) 方法,获取相机在当前配置下的预览图像,并将结果存储在 preview_images 向量中。
然后,通过循环遍历 preview_images 向量,将每个图像保存为 PNG 文件。文件名格式为 "ad_3d_preview_" + std::to_string(i) + ".png",其中 i 表示图像的索引。
以下是代码示例:
try { DaoAI::Settings3D::FrameConfig frame_config(-1, 3.0, 0.0); auto preview_images = camera->preview(frame_config); for (size_t i = 0; i < preview_images.size(); i++) { std::filesystem::path frame_path = std::filesystem::current_path() / ("ad_3d_preview" + std::to_string(i) + ".png"); DaoAISample::saveImage(preview_images[i], frame_path); } } catch (const std::exception& e) { std::cerr << "preview Error: " << e.what() << std::endl; std::cout << "Program execution finished, press any key to exit..." << std::endl; std::cin.get(); return -1; }
2D 拍照
使用相机(或者触发光源)拍照,并调整采集配置以获得理想的图像。
首先,定义了一个 DaoAI::Settings2D 对象 settings_2d,用于设置配置参数,其中包括:
相机触发模式(trigger_mode):设置为 DaoAI::Settings2D::TriggerMode::Software
曝光时间(exposure_time):设置为 std::chrono::milliseconds(600)
增益(gain):设置为 0
接着,调用 camera->capture2D(settings_2d) 方法,获取相机在当前配置下的2D帧数据frame2d,其中包含获取图像数据image()、获取宽高等方法。
然后,通过frame2d.image()获取图像数据,并将图像保存为 PNG 文件。文件名格式为 "ad_2d_image.png"。
以下是代码示例:
try { DaoAI::Settings2D settings_2d(DaoAI::Settings2D::TriggerMode::Software, std::chrono::milliseconds(600), 0); auto frame2d = camera->capture2D(settings_2d); std::filesystem::path frame_path = std::filesystem::current_path() / "ad_2d_image.png"; DaoAISample::saveImage(frame2d.image(), frame_path); } catch (const std::exception& e) { std::cerr << "capture2D Error: " << e.what() << std::endl; std::cout << "Program execution finished, press any key to exit..." << std::endl; std::cin.get(); return -1; }
3D 拍照
使用相机进行3D拍照,请根据需要调整对应过滤器以获得理想的点云。
首先,定义了一个 DaoAI::Settings3D 对象 settings_3d,不同型号相机支持采集帧数不同,设置失败后会抛出异常,以下是一帧参数定义包括:
曝光档(exposure_stop):设置为 -1
亮度(brightness):设置为 3.0
增益(gain):设置为 0.0
设置帧数组到DaoAI::Settings3D对象中 settings_3d.setFrameConfigs(frame_configs); 接着,调用 camera->capture3D(settings_3d) 方法,进行3D采集,采集完成后会返回一个 DaoAI::Frame 对象 frame3d, 可以调用frame3d.getPointCloud()异步获取点云数据。
以下是代码示例:
try { DaoAI::Settings3D settings_3d; DaoAI::Settings3D::FrameConfig frame_config(/*exposure_stop*/-1, /*brightness*/3.0, 0.0); std::vector<DaoAI::Settings3D::FrameConfig> frame_configs; frame_configs.push_back(frame_config); settings_3d.setFrameConfigs(frame_configs); // set filters //settings_3d.setFilter(DaoAI::Settings3D::FillHole(1.0f, 1.0f)); //settings_3d.setFilter(DaoAI::Settings3D::ContrastDistortion(DaoAI::Settings3D::ContrastDistortion::Treatment::Off)); //settings_3d.setFilter(DaoAI::Settings3D::Median(false)); //settings_3d.setFilter(DaoAI::Settings3D::FaceNormal(false)); //settings_3d.setFilter(DaoAI::Settings3D::Smooth(false)); //settings_3d.setFilter(DaoAI::Settings3D::PhaseQuality(false)); //settings_3d.setFilter(DaoAI::Settings3D::Intensity(3.0f)); //settings_3d.setFilter(DaoAI::Settings3D::Outlier(1.0f)); //settings_3d.setFilter(DaoAI::Settings3D::Gaussian(40)); //settings_3d.setFilter(DaoAI::Settings3D::Cluster(5.0f, 2.0f)); auto frame3d = camera->capture3D(settings_3d); DaoAI::PointCloud point_cloud = frame3d.getPointCloud(); std::cout << "Pointcloud dimension -- #points: " << point_cloud.getSize() << ", width: " << point_cloud.getWidth() << ", height: " << point_cloud.getHeight() << std::endl; } catch (const std::exception& e) { std::cerr << "capture3D Error: " << e.what() << std::endl; std::cout << "Program execution finished, press any key to exit..." << std::endl; std::cin.get(); return -1; }
点云保存及加载
点云保存支持PLY、PCD、BGRD格式,且支持PLY、PCD的二进制格式保存。 点云加载暂时只支持BGRD格式,可以通过DaoAI::PointCloud::load方法加载到点云对象。 BGRD格式是一种自定义的二进制格式,它极大地减少了点云数据的存储空间,同时保持了数据的完整性。 以下表格展示了各型号相机支持格式:
型号 |
PLY / binary PLY save |
PCD / binary PCD save |
BGRD save |
BGRD load |
---|---|---|---|---|
AS470 / AS080 |
是 |
是 |
是 |
是 |
AD470 / AD080 |
是 |
是 |
是 |
是 |
AQ060 |
是 |
是 |
否 |
否 |
通过上面获取的frame3d对象参数保存及加载点云,以下是代码示例:
// Save ply text and binary format file void savePly(DaoAI::Frame& frame) { try { auto start = std::chrono::high_resolution_clock::now(); std::string filename = "ad_3d_pointcloud.ply"; std::filesystem::path frame_path = std::filesystem::current_path() / filename; std::cout << "Saving ply " << frame_path.string() << std::endl; frame.save(frame_path, false); auto end = std::chrono::high_resolution_clock::now(); std::cout << "Save ply time: " << std::chrono::duration_cast<std::chrono::milliseconds>(end - start).count() << " ms" << std::endl; filename = "ad_3d_pointcloud-binary.ply"; std::cout << "Saving binary ply" << frame_path.string() << std::endl; start = std::chrono::high_resolution_clock::now(); frame.save(filename); end = std::chrono::high_resolution_clock::now(); std::cout << "Save binary ply time: " << std::chrono::duration_cast<std::chrono::milliseconds>(end - start).count() << " ms" << std::endl; } catch (const std::exception& e) { std::cerr << "Error saving ply: " << e.what() << std::endl; } } // Save pcd text and binary format file void savePcd(DaoAI::Frame& frame) { try { auto start = std::chrono::high_resolution_clock::now(); std::string filename = "ad_3d_pointcloud.pcd"; std::filesystem::path frame_path = std::filesystem::current_path() / filename; std::cout << "Saving pcd " << frame_path.string() << std::endl; frame.save(filename, false); auto end = std::chrono::high_resolution_clock::now(); std::cout << "Save pcd time: " << std::chrono::duration_cast<std::chrono::milliseconds>(end - start).count() << " ms" << std::endl; filename = "ad_3d_pointcloud-binary.pcd"; std::cout << "Saving binary pcd" << filename << std::endl; start = std::chrono::high_resolution_clock::now(); frame.save(filename); end = std::chrono::high_resolution_clock::now(); std::cout << "Save binary pcd time: " << std::chrono::duration_cast<std::chrono::milliseconds>(end - start).count() << " ms" << std::endl; } catch (const std::exception&) { std::cerr << "Error saving pcd" << std::endl; } } // load bgrd format file void loadBgrd(const std::string& filename, const std::string& to_filename_ply) { std::cout << "Loading frame " << filename << std::endl; DaoAI::Frame frame_bgrd; frame_bgrd.load(filename); std::cout << "Frame loaded" << std::endl; try { std::cout << "Saving to ply " << to_filename_ply << std::endl; frame_bgrd.save(to_filename_ply, false); std::cout << "Frame Saving to ply Ok" << std::endl; } catch (const std::exception& e) { std::cerr << "Error saving ply from bgrd: " << e.what() << std::endl; } } // Save bgrd format file and load, then save to ply, for test void saveBgrd(DaoAI::Frame& frame) { try { auto start = std::chrono::high_resolution_clock::now(); std::string filename = "ad_3d_pointcloud.bgrd"; std::filesystem::path frame_path = std::filesystem::current_path() / filename; std::cout << "Saving bgrd " << frame_path.string() << std::endl; frame.save(frame_path, false); auto end = std::chrono::high_resolution_clock::now(); std::cout << "Save bgrd time: " << std::chrono::duration_cast<std::chrono::milliseconds>(end - start).count() << " ms" << std::endl; } catch (const std::exception& e) { std::cerr << "Error saving bgrd: " << e.what() << std::endl; } // load bgrd loadBgrd("ad_3d_pointcloud.bgrd", "ad_3d_pointcloud_bgrd2ply.ply"); }
Settings3D参数
Settings3D类,用于设置3D采集的参数,包括采集帧配置、点云过滤器配置等。 它提供了参数的保存和加载功能,可以通过save和load方法将参数保存到文件或从文件加载。
以下是代码示例:
try { DaoAI::Settings3D settings_3d; settings_3d.save("ad_3d_settings.yaml"); settings_3d.load("ad_3d_settings.yaml"); } catch (const std::exception& e) { std::cerr << "Error saving or loading settings: " << e.what() << std::endl; }
现场校准
我们提供了现场校准功能,可以通过现场校准功能对相机进行标定,以提高测量精度。
它需要使用标定板进行标定,需要已知如下参数:标定板的圆行列数、两个圆的圆心距离。
首先,使用captureInfieldCalibrationData方法采集3-5次标定板数据,并将结果保存到std::vector<DaoAI::TargetResult> target_result_vector中。
然后,使用infieldCalibration方法对采集到的标定板数据进行校准,校准结果返回百分比改进(范围 0 - 1.0),值越大表示校准效果越好。
最后,使用evaluateAccuracy方法评估校准结果,如果校准效果不好,可以重新采集标定板数据,重新进行校准。
以下是代码示例:
// Adjust each parameter as needed. try { std::vector<DaoAI::TargetResult> target_result_vec; // capture infield calibration data for 5 times DaoAI::Settings3D::FrameConfig frame_config_calibration(/*exposure_stop*/-1, /*brightness*/3.0, /*gain*/0.0); int pattern_column = 11; int pattern_row = 9; DaoAI::Size pattern_size(pattern_column, pattern_row); // 11x9 calibration board float center_distance = 2.5f; // Distance between the center of the calibration board circles for (size_t i = 0; i < 5; i++) { auto target_result = camera->captureInfieldCalibrationData(frame_config_calibration, pattern_size); target_result_vec.push_back(target_result); } // save infield calibration data auto percentage_improvement = camera->infieldCalibration(target_result_vec, pattern_size, center_distance); std::cout << "Infield calibration improvement: " << percentage_improvement << "%" << std::endl; // evaluate infield calibration DaoAI::Settings3D settings_3d; DaoAI::Settings3D::FrameConfig frame_config(/*exposure_stop*/-1, /*brightness*/3.0, /*gain*/0.0); std::vector<DaoAI::Settings3D::FrameConfig> frame_configs; frame_configs.push_back(frame_config); settings_3d.setFrameConfigs(frame_configs); // we can set filters here auto start = std::chrono::high_resolution_clock::now(); auto frame3d = camera->capture3D(settings_3d); DaoAI::PointCloud point_cloud = frame3d.getPointCloud(); // capture preview image of the calibration board DaoAI::Settings3D::FrameConfig frame_config_preview(/*exposure_stop*/-1, /*brightness*/3.0, /*gain*/0.0); auto preview_images = camera->preview(frame_config_preview); DaoAI::AccuracyResult accuracy_result = camera->evaluateAccuracy(point_cloud, preview_images.at(0), pattern_size, center_distance); std::cout << "Infield calibration accuracy max error: " << accuracy_result.max_err_perc << "%" << std::endl; std::cout << "Infield calibration accuracy avg error: " << accuracy_result.avg_err_perc << "%" << std::endl; } catch (const std::exception& e) { std::cerr << "Infield Calibration Error: " << e.what() << std::endl; }