【CeleX5事件相机使用系列】Ubuntu下Loop模式的使用(同时获取灰度图与事件)

芯仑的CeleX_MP相机在某一个时刻只能够输出 frame 或 event,而不能像其他DAVIS一样同时输出event和frame。但相机自带loop模式,在该模式下相机的输出将在几种模式下切换。最近写了一下Ubuntu下loop模式的读取,整理记录并做分享。转载请注明出处

Loop模式原理

下图是芯仑给的SDK文档中关于Loop模式的说明。简单总结Loop有三点:

  1. 首先需要 enable Loop模式,通过函数 setSensorLoopMode();
  2. Loop模式将在3种模式下切换,可以设定3种模式;建议设置为:完整图像模式、event图模式、光流模式;
  3. 三种模式都可以分别设置持续时间,涉及到完整图像的,可以设定捕捉图像的数量;涉及事件的,设置持续时间。

在这里插入图片描述

主动式读取(不推荐)

官方提供的参考代码中,给出了两种读取模式。一种是主动式,在while中类似于查询的方式,不断读取不同模式下的数据。核心代码如下:

p->setLoopModeEnabled(true);
p->setSensorLoopMode(CeleX5::Full_Picture_Mode, 1);
p->setSensorLoopMode(CeleX5::Event_Off_Pixel_Timestamp_Mode, 2);
p->setSensorLoopMode(CeleX5::Optical_Flow_Mode, 3);
 
uint8_t* pBuffer1 = new uint8_t[CELEX5_PIXELS_NUMBER];
uint8_t* pBuffer2 = new uint8_t[CELEX5_PIXELS_NUMBER];
uint8_t* pBuffer3 = new uint8_t[CELEX5_PIXELS_NUMBER];

while (true){
    
    
	p->getFullPicBuffer(pBuffer1);
	cv::Mat matFullPic(800, 1280, CV_8UC1, pBuffer1);
	cv::imshow("full", matFullPic);
	
	p->getEventPicBuffer(pBuffer2, CeleX5::EventBinaryPic);
	cv::Mat matEventPic(800, 1280, CV_8UC1, pBuffer2);
	cv::imshow("events", matEventPic);
	waitKey(1);
}

然而我实际测试时发现,这种方式读取会有问题。具体表现为,frame的图像会明显抖动,event的图像会显示前些时刻的数据。例如下图,左侧为灰度图,右侧为event图。第一张显示的正常,但第二张中下一个时刻event的数据显示的是之前某个时刻的图像(灯柱还在左下方时的)。推测这种现象的原因是数据缓存问题。但并没有清除缓存的接口,所以这种方法放弃。

在这里插入图片描述
在这里插入图片描述

回调函数式读取

咨询了芯仑的技术人员,技术人员说要参考GetFrameBufferByCallback这个文件写。同时我也参考了官方在ROS的demo下提供的回调函数式的读取代码。并且在SDK参考文档中找到了相关说明。要点如下:

  1. 继承一个CeleX5DataManager类;
  2. 重载onFrameDataUpdated()函数接收各种图像帧完成的通知。

在这里插入图片描述
核心代码如下:

1. 继承 CeleX5DataManager类

class SensorDataObserver : public CeleX5DataManager{
    
    
public:
	SensorDataObserver(CX5SensorDataServer* pServer){
    
     
		m_pServer = pServer;
		m_pServer->registerData(this, CeleX5DataManager::CeleX_Frame_Data);
	}
    ~SensorDataObserver() {
    
     m_pServer->unregisterData(this, CeleX5DataManager::CeleX_Frame_Data); }
    virtual void onFrameDataUpdated(CeleX5ProcessedData* pSensorData);      //overrides Observer operation
	CX5SensorDataServer* m_pServer;
};

2. 重载onFrameDataUpdated函数

void SensorDataObserver::onFrameDataUpdated(CeleX5ProcessedData* pSensorData){
    
    
	CeleX5::CeleX5Mode sensorMode = pSensorData->getSensorMode();   // 获取当前时刻的模式
	if (CeleX5::Full_Picture_Mode == sensorMode){
    
    			// 完整图像模式,显示图像
        ROS_INFO("In full picture node...");
        time_t time_stamp = 0;
		pCeleX5->getFullPicBuffer(pImageBuffer, time_stamp);
		cv::Mat matFullPic(800, 1280, CV_8UC1, pImageBuffer);
		cv::imshow("full", matFullPic);
	}
	else if (CeleX5::Event_Off_Pixel_Timestamp_Mode == sensorMode){
    
    	// 其他不同模式时,执行不同操作
		...
	}
	else if (CeleX5::Optical_Flow_Mode == sensorMode){
    
    
		...
    }
}

3. 主函数中的配置与初始化

void main(){
    
    	
	pCeleX5->openSensor(CeleX5::CeleX5_MIPI);
	
	// 启动Loop模式,并设置每个模式具体是什么
	pCeleX5->setLoopModeEnabled(true);
	pCeleX5->setSensorLoopMode(CeleX5::Full_Picture_Mode, 1);
	pCeleX5->setSensorLoopMode(CeleX5::Event_In_Pixel_Timestamp_Mode, 2);
	pCeleX5->setSensorLoopMode(CeleX5::Optical_Flow_Mode, 3);
	
	// 每个模式的持续时长。这里的设置为:full frame采集1帧,然后event采集20ms,不采集光流
	pCeleX5->setPictureNumber(1, CeleX5::Full_Picture_Mode);
    pCeleX5->setEventDuration(20);
    pCeleX5->setPictureNumber(0, CeleX5::Optical_Flow_Mode);

	// 启动
	SensorDataObserver* pSensorData = new SensorDataObserver(pCeleX5->getSensorDataServer());
	
	while (true){
    
    
		usleep(1000);
	}
}

其他

完整代码下载:https://download.csdn.net/download/tfb760/15420758
赚个积分吧,感觉自己不容易。(如实在下载困难,可私信。但不保证回复及时)


微信公众号:【事件相机】,交流事件相机的相关科研与应用。欢迎大家关注
请添加图片描述

猜你喜欢

转载自blog.csdn.net/tfb760/article/details/113943504
今日推荐