API使用说明
Algo SDK 是一款专为evs device 设计的软件开发工具包,提供了算法的功能和简便的操作方式,帮助开发者轻松集成各项功能。
环境配置
请确保您的开发环境中已安装以下必备组件:
- 操作系统: windows 10 64 位
- 编译器: 适用于您的操作系统的 C/C++ 编译器
- 依赖库: 确保安装了必要的库,OpenCV,我们会提供SDK对于的OpenCV版本,自行配置环境变量即可。
- 开发工具: 如 IDE(Visual Studio 2019等)
建议: 开发路径使用全英文
Algo模块说明
Algo库主要分为三个模块:
OpticalFlow
- 功能: 该API是基于EVS的光流实现。
HandDetector
- 功能: 该API是基于EVS的手形检测器实现。
HumanDetector
- 功能: 该API是基于EVS的人形检测器实现。
Algo目录说明
- bin目录: 包含所有核心库及依赖库
- docs目录: 包含接口说明文档
- include目录: 包含接口头文件
- lib目录: 包含所有开发库的lib文件
- models目录: 包含训练模型数据
- samples_cpp目录: 包含操作设备的简单样例,运行样例需要 OpenCV 环境
注意: 编译样例后运需要把models目录、bin目录下动态库,拷贝到.exe可执行文件同一目录。
1.OpticalFlow
该API是基于EVS的光流实现。
Of函数
Of函数是光流类的初始化构造函数,参数释义如下:
Of(
uint16_t width,
uint16_t height,
uint8_t scale,
uint8_t search_radius,
uint8_t block_dimension);
- width:EVS图像的宽。
- height:EVS图像的高。
- scale:EVS降采样倍数。
- search_radius:表示的是光流搜索半径大小,通常建议为4。
- block_dimension:表示的是光流计算相关特征所用的图像大小,通常建议为21,越大越准确但效率降低。
run函数
run函数是运行光流算法的核心函数,参数释义如下:
int run(
const cv::Mat& in_img,
cv::Mat& out_img,
uint8_t stack_nums = 1);
- in_img:表示用来计算光流的EVS输入图像。通常0表示没有事件,1和2分别表示正负事件。
- out_img:表示计算出的光流图像,用CV_8SC2类型来表示。每个像素的两个通道的值分别表示x,y的光流大小,符号表示方向
- stack_nums:EVS叠帧的数量,默认为1,表示不叠帧,通常事件稀疏需要叠帧。
showOf函数
showOf函数是将run函数得到的光流图像用HVS空间箭头可视化出来,参数释义如下:
int showOf(
cv::Mat& of_result,
cv::Mat& of_mask,
uint8_t ratio = 2,
uint8_t step = 2);
- of_result:表示run函数计算出的光流图像。
- of_mask:表示将of_result可视化后的光流的结果。
- ratio:表示将可视化的光流箭头同比放大多少倍。
- step:表示将可视化的光流箭头稀疏采样多少倍。
用例
// 使用光流算法
#include <AlpOpticalFlow/Of.h>
#include <iostream>
#include <iomanip>
#include <sstream>
#include <chrono>
#include <thread>
#include <ctime>
#include <regex>
#include <filesystem>
#include <fstream>
namespace fs = std::filesystem;
using namespace ALP;
/**
* @brief 用于存储和管理程序运行时所需的各种变量
*
* 该结构体包含处理 EVS 数据帧所需的成员变量,以及相关的线程和锁。
*/
struct SampleVar
{
// 保护 EVS 数据帧列表的互斥锁
std::mutex evs_mutex_;
// 标记是否关闭数据处理
bool is_close_ = false;
// 播放 EVS 数据的线程
std::unique_ptr<std::thread > evs_thread_;
// 是否开启 EVS 数据存储
bool is_evs_show_ = false;
// evs 图像的宽度
int evs_width_ = 768;
// evs 图像的高度
int evs_height_ = 608;
std::string evs_image_dir_ = "C:/Users/SMTPC-0430/Desktop/Pic/EVS_RAW";//D:/TestData/Human/20250115161806780/evs_raw
// 创建光流类
std::shared_ptr<Of> optical_flow_ = nullptr;
};
std::shared_ptr<SampleVar> var_ = std::make_shared<SampleVar>();
/*
* @brief readRawImage 采用二进制方式读取 .raw 文件,并将其转换为 cv::Mat,以 8-bit 灰度格式解析数据。
*
* 直接使用 cv::imread 读取 .raw 文件会失败,因为它不是标准图片格式。
*
*/
cv::Mat readRawImage(const std::string& filename, int width, int height)
{
std::ifstream file(filename, std::ios::binary);
if (!file) {
std::cerr << "ERROR: Cannot open file: " << filename << std::endl;
return cv::Mat();
}
cv::Mat image(height, width, CV_8UC1); // 8-bit 单通道灰度图
image *= 100;
file.read(reinterpret_cast<char*>(image.data), width * height);
if (file.gcount() != width * height) {
std::cerr << "WARNING: File size mismatch: " << filename << std::endl;
return cv::Mat();
}
return image;
}
/**
* @brief 显示 EVS 图像界面(本地文件版本)
*
* 该函数创建一个新的线程来处理和显示本地存储的EVS图像文件。
* 图像文件将按文件系统顺序循环读取,并计算/显示光流信息。
*/
void displayEVS()
{
var_->evs_thread_ = std::make_unique<std::thread>([&]()
{
var_->is_evs_show_ = true;
std::vector<std::string> image_files;
for (const auto& entry : fs::directory_iterator(var_->evs_image_dir_)) {
if (entry.path().extension() == ".raw") {
image_files.push_back(entry.path().string());
}
}
if (image_files.empty()) {
std::cerr << "ERROR: No image files found in " << var_->evs_image_dir_ << std::endl;
var_->is_evs_show_ = false;
return;
}
std::sort(image_files.begin(), image_files.end()); // 确保按顺序处理
size_t frame_index = 0;
const int frame_delay = 30;
while (!var_->is_close_) {
cv::Mat tem = readRawImage(image_files[frame_index], var_->evs_width_, var_->evs_height_);
if (tem.empty()) {
frame_index = (frame_index + 1) % image_files.size();
continue;
}
cv::Mat out;
if (!var_->optical_flow_->run(tem, out, 10)) {
cv::Mat of_mask;
var_->optical_flow_->showOf(out, of_mask, 10, 3);
cv::namedWindow("of", cv::WINDOW_FREERATIO);
cv::imshow("of", of_mask);
cv::waitKey(1);
}
frame_index = (frame_index + 1) % image_files.size();
std::this_thread::sleep_for(std::chrono::milliseconds(frame_delay));
}
var_->is_evs_show_ = false;
});
}
/**
* @brief 关闭设备
*
* 该函数用于关闭 Eiger 设备,停止所有数据流,并释放相关资源。
*/
void closeDevice()
{
// 等待 EVS 显示线程结束
if (var_->evs_thread_)
{
var_->evs_thread_->join();
var_->evs_thread_ = nullptr;
}
}
int main(int argc, char* argv[])
{
// 创建光流类
var_->optical_flow_ = std::make_shared<Of>(var_->evs_width_, var_->evs_height_, 6, 4, 31);
displayEVS();
closeDevice();
return 0;
}
效果
2.HandDetector
HandDetector函数
此函数用来构造具有初始手检测器类型的HandDetector对象,参数释义如下:
HandDetector(HandDetectorType type);
- type: aps or evs Currently only supports HumanDetectorType::evs
detect函数
输入图像进行检测,然后从方框和地标中获取结果,参数释义如下:
int detect ( const cv::Mat & image,
std::vector< cv::Rect > & boxes,
std::vector< std::vector< cv::Point2f > > & landmarks ) ;
- image:输入图像
- boxes:表示检测到的手部框结果
- landmarks:表示手的关键点
init函数
初始化函数,参数释义如下:
int init(const std::string& device="cpu");
- cpu" or "cuda", defalut is "cpu"
用例
#pragma execution_character_set("utf-8")
/**********************************************
* 此样例为播放保存的evs raw数据 *
***********************************************/
//手势检测
#include <ALPML/HandDetector/hand_detector.h>
#include <iostream>
#include <iomanip>
#include <sstream>
#include <chrono>
#include <thread>
#include <ctime>
#include <regex>
#include <filesystem>
#include <fstream>
namespace fs = std::filesystem;
using namespace ALP;
/**
* @brief 用于存储和管理程序运行时所需的各种变量
*
* 该结构体包含处理 APS 和 EVS 数据帧所需的成员变量,以及相关的线程和锁。
*/
struct SampleVar
{
// 保护 EVS 数据帧列表的互斥锁
std::mutex evs_mutex_;
// 标记是否关闭数据处理
bool is_close_ = false;
// 播放 EVS 数据的线程
std::unique_ptr<std::thread > evs_thread_;
// 是否开启 EVS 数据存储
bool is_evs_show_ = false;
// evs 图像的宽度
int evs_width_ = 768;
// evs 图像的高度
int evs_height_ = 608;
// WriterFile类的智能指针
const int play_evs_ = 2;
// 创建手势检测
std::shared_ptr<HandDetector> detector_ = nullptr;
std::string evs_image_dir_ = "C:/Users/SMTPC-0430/Desktop/Pic/EVS_RAW";
};
std::shared_ptr<SampleVar> var_ = std::make_shared<SampleVar>();
/*
* @brief readRawImage 采用二进制方式读取 .raw 文件,并将其转换为 cv::Mat,以 8-bit 灰度格式解析数据。
*
* 直接使用 cv::imread 读取 .raw 文件会失败,因为它不是标准图片格式。
*
*/
cv::Mat readRawImage(const std::string& filename, int width, int height)
{
std::ifstream file(filename, std::ios::binary);
if (!file) {
std::cerr << "ERROR: Cannot open file: " << filename << std::endl;
return cv::Mat();
}
cv::Mat image(height, width, CV_8UC1); // 8-bit 单通道灰度图
image *= 100;
file.read(reinterpret_cast<char*>(image.data), width * height);
if (file.gcount() != width * height) {
std::cerr << "WARNING: File size mismatch: " << filename << std::endl;
return cv::Mat();
}
return image;
}
/**
* @brief 显示 EVS 图像界面
*
* 该函数创建一个新的线程来处理和显示 EVS 数据帧。
* 在这个线程中,会从 `var_->evs_frames_` 列表中获取最新的 EVS 数据帧,
* 并将其转换为 OpenCV 的 Mat 对象进行显示。
*/
void displayEVS()
{
// 创建一个新的线程来处理 EVS 数据帧的显示
var_->evs_thread_ = std::make_unique<std::thread>([&]()
{
// 开始存储EVS数据
var_->is_evs_show_ = true;
std::vector<std::string> image_files;
for (const auto& entry : fs::directory_iterator(var_->evs_image_dir_)) {
if (entry.path().extension() == ".raw") {
image_files.push_back(entry.path().string());
}
}
if (image_files.empty()) {
std::cerr << "ERROR: No image files found in " << var_->evs_image_dir_ << std::endl;
var_->is_evs_show_ = false;
return;
}
std::sort(image_files.begin(), image_files.end()); // 确保按顺序处理
size_t frame_index = 0;
const int frame_delay = 15;
// 主循环,持续处理 EVS 数据直到关闭标志被设置
while (!var_->is_close_)
{
// 获取互斥锁以保护 EVS 数据帧列表
std::unique_lock<std::mutex> locker(var_->evs_mutex_);
const cv::Mat tem = readRawImage(image_files[frame_index], var_->evs_width_, var_->evs_height_);
if (tem.empty()) {
frame_index = (frame_index + 1) % image_files.size();
continue;
}
if (var_->detector_) {
std::vector<cv::Rect> box;
std::vector<std::vector<cv::Point2f>> landmarks;
cv::Mat image = tem;
var_->detector_->detect(image, box, landmarks);
cv::cvtColor(image, image, cv::COLOR_GRAY2BGR);
image *= 100;
for (size_t i = 0; i < box.size(); i++) {
cv::rectangle(image, box[i], cv::Scalar(0, 0, 255), 2);
}
for (auto& landmark : landmarks) {
for (auto& point : landmark) {
cv::circle(image, point, 2, cv::Scalar(0, 0, 255), 2);
}
}
cv::imshow("image", image);
cv::waitKey(25);
}
frame_index = (frame_index + 1) % image_files.size();
}
// 停止存储EVS数据
var_->is_evs_show_ = false;
});
}
/**
* @brief 关闭设备
*
* 该函数用于关闭 Eiger 设备,停止所有数据流,并释放相关资源。
*/
void closeDevice()
{
// 等待 EVS 显示线程结束
if (var_->evs_thread_)
{
var_->evs_thread_->join();
var_->evs_thread_ = nullptr;
}
}
int main(int argc, char* argv[])
{
// 创建手势检测
var_->detector_ = std::make_shared<HandDetector>(HandDetectorType::evs);
var_->detector_->init("cpu");
// 启动显示 EVS 图像的线程
displayEVS();
closeDevice();
return 0;
}
效果
3.HumanDetector
HumanDetector函数
此函数用来构造具有初始手检测器类型的HumanDetector对象,参数释义如下:
HumanDetector(HumanDetectorType type);
- type: aps or evs Currently only supports HumanDetectorType::evs
detect函数
输入要检测的图像,然后从框中获取结果,参数释义如下:
int detect(const cv::Mat& image, std::vector<cv::Rect>& boxes);
- image:输入图像
- boxes:输出检测框
init函数
初始化函数,参数释义如下:
int init ( const std::string & device = "cpu" )
- device type:"cpu" or "cuda", defalut is "cpu"
用例
#pragma execution_character_set("utf-8")
/**********************************************
* 此样例为播放保存的evs raw数据 *
***********************************************/
// 人形检测
#include <AlpML/HumanDetector/human_detector.h>
#include <iostream>
#include <iomanip>
#include <sstream>
#include <chrono>
#include <thread>
#include <ctime>
#include <regex>
#include <filesystem>
#include <fstream>
namespace fs = std::filesystem;
using namespace ALP;
/**
* @brief 用于存储和管理程序运行时所需的各种变量
*
* 该结构体包含处理 APS 和 EVS 数据帧所需的成员变量,以及相关的线程和锁。
*/
struct SampleVar
{
// 保护 EVS 数据帧列表的互斥锁
std::mutex evs_mutex_;
// 标记是否关闭数据处理
bool is_close_ = false;
// 播放 EVS 数据的线程
std::unique_ptr<std::thread > evs_thread_;
// 是否开启 EVS 数据存储
bool is_evs_show_ = false;
// evs 图像的宽度
int evs_width_ = 768;
// evs 图像的高度
int evs_height_ = 608;
const int play_evs_ = 2;
std::string evs_image_dir_ = "C:/Users/SMTPC-0430/Desktop/Pic/human/EVS_RAW";//D:/TestData/Human/20250115161806780/evs_raw C:/Users/SMTPC-0430/Desktop/Pic/human/EVS_RAW
// 创建人形检测类
std::shared_ptr<ALP::HumanDetector> detector_ = nullptr;
};
std::shared_ptr<SampleVar> var_ = std::make_shared<SampleVar>();
/*
* @brief readRawImage 采用二进制方式读取 .raw 文件,并将其转换为 cv::Mat,以 8-bit 灰度格式解析数据。
*
* 直接使用 cv::imread 读取 .raw 文件会失败,因为它不是标准图片格式。
*
*/
cv::Mat readRawImage(const std::string& filename, int width, int height)
{
std::ifstream file(filename, std::ios::binary);
if (!file) {
std::cerr << "ERROR: Cannot open file: " << filename << std::endl;
return cv::Mat();
}
cv::Mat image(height, width, CV_8UC1); // 8-bit 单通道灰度图
image *= 100;
file.read(reinterpret_cast<char*>(image.data), width * height);
if (file.gcount() != width * height) {
std::cerr << "WARNING: File size mismatch: " << filename << std::endl;
return cv::Mat();
}
return image;
}
/**
* @brief 显示 EVS 图像界面
*
* 该函数创建一个新的线程来处理和显示 EVS 数据帧。
* 在这个线程中,会从 `var_->evs_frames_` 列表中获取最新的 EVS 数据帧,
* 并将其转换为 OpenCV 的 Mat 对象进行显示。
*/
void displayEVS()
{
// 创建一个新的线程来处理 EVS 数据帧的显示
var_->evs_thread_ = std::make_unique<std::thread>([&]()
{
// 开始存储EVS数据
var_->is_evs_show_ = true;
var_->is_evs_show_ = true;
std::vector<std::string> image_files;
for (const auto& entry : fs::directory_iterator(var_->evs_image_dir_)) {
if (entry.path().extension() == ".raw") {
image_files.push_back(entry.path().string());
}
}
if (image_files.empty()) {
std::cerr << "ERROR: No image files found in " << var_->evs_image_dir_ << std::endl;
var_->is_evs_show_ = false;
return;
}
std::sort(image_files.begin(), image_files.end()); // 确保按顺序处理
size_t frame_index = 0;
const int frame_delay = 15;
// 主循环,持续处理 EVS 数据直到关闭标志被设置
while (!var_->is_close_)
{
// 获取互斥锁以保护 EVS 数据帧列表
std::unique_lock<std::mutex> locker(var_->evs_mutex_);
const cv::Mat tem = readRawImage(image_files[frame_index], var_->evs_width_, var_->evs_height_);
if (tem.empty()) {
frame_index = (frame_index + 1) % image_files.size();
continue;
}
if (var_->detector_)
{
std::vector<cv::Rect> box;
cv::Mat image = tem;
var_->detector_->detect(image, box);
cv::cvtColor(image, image, cv::COLOR_GRAY2BGR);
image *= 100;
for (size_t i = 0; i < box.size(); i++)
{
cv::rectangle(image, box[i], cv::Scalar(0, 0, 255), 2);
}
cv::imshow("image", image);
cv::waitKey(25);
}
frame_index = (frame_index + 1) % image_files.size();
}
// 停止存储EVS数据
var_->is_evs_show_ = false;
});
}
/**
* @brief 关闭设备
*
* 该函数用于关闭 Eiger 设备,停止所有数据流,并释放相关资源。
*/
void closeDevice()
{
// 等待 EVS 显示线程结束
if (var_->evs_thread_)
{
var_->evs_thread_->join();
var_->evs_thread_ = nullptr;
}
}
int main(int argc, char* argv[])
{
// 创建手势检测
var_->detector_ = std::make_shared<HumanDetector>(HumanDetectorType::evs);
var_->detector_->init("cpu");
// 启动显示 EVS 图像的线程
displayEVS();
closeDevice();
return 0;
}