DALSA相机Sapera Lt二次开发(内触发)

DALSA相机Sapera Lt二次开发之内触发

实验室更换了新的DALSA 2D线阵相机,本次任务是替代就相机的功能,将新相机融入到之前的2D-3D扫描系统中。

相机采集图像、存储图像功能实现

下面会详细介绍实现过程及思路,着急的可以直接跳到代码实现部分

查看Sapera Lt帮助文档(),可得图像捕捉函数 SapTransfer::Snap()
DALSA相机Sapera Lt二次开发(内触发)_第1张图片

从Snap()函数中的Remakes中我们可以得到两点信息:1.Snap()函数一般用于捕捉单帧图像 2.需要在Snap图像之前调用Select()函数,从而控制Snap得到的连续图像按顺序存储在Buffers中,否则图像将只存储到一开始的Buffer中(即一直覆盖之前的图像)

例如在Demos里SeqGrabDemoDlg.cpp的CSeqGrabDemoDlg::OnRecord函数中有如下调用:
m_Xfer->Snap(m_Buffers->GetCount())
其意思是以相机设定的采集频率连续采集X张图片
X=当前设定的采集卡的Buffers个数

讲到Buffers的个数设定,我们不妨先来看看Buffers的生成过程,同样选取SeqGrabDemoDlg.cpp作为例子,有如下代码:(CSeqGrabDemoDlg::OnInitDialog和CSeqGrabDemoDlg::CreateObjects中)
m_Buffers = new SapBufferWithTrash(MAX_BUFFER, m_Acq)
m_Buffers->Create()
第一句的意思是为采集卡对象m_Acq创建一共MAX_BUFFER个Buffers
第二句的意思是生成上句设定的Buffers
至此Buffers生成成功

类似的Acq、Xfer和View可以使用相似的方式生成,这里不再赘述。特别的,给出一种为采集卡配置.ccf参数文件的Acq生成方法,其代码如下:
m_Acq = new SapAcquisition(SapLocation(1, 1), “C:\Program Files\Teledyne DALSA\Sapera\CamFiles\User\Line_Trigger.ccf”);
其中SapLocation(1, 1)为,后一个参数则是.ccf的地址

至此我们实现了Acq、Xfer、Buffers和View的生成和采集一定数量的图像,那我们如何读取采集到的图像呢,查看SDK我们可以找到SapBuffers::Read函数
DALSA相机Sapera Lt二次开发(内触发)_第2张图片
例如如下代码:
m_Buffers->Read(index, 15, 1, pdata)
其意思是读取第index个Buffer中第16个像素的数据(偏移量为15,读取量为1)(读取量应与相机的视野相对应,根据实际需求设定,这里假定读取1个像素),将数据保存到 pdata中
应当注意的是,Snap的索引Index与Read应该相对应,例如当连续采集6张图像时,图像会按照顺序递增的方式存储到0号至5号Buffer,因此读取数据时应当每读取一次数据就让Index加1,其代码实现如下:
m_Xfer->Snap(6);
for(int index = 0; index < 6; index++){
m_Buffers->Read(index, 0, 1, pdata);
}

这里要特别指出存储数据的 pdata大小应该为读取像素个数的4倍,因为Buffer保持像素信息格式为RGBM,当采集彩色图片时仅RGB有值,当采集黑白图片时仅M有值
这里给出 pdata定义代码:
unsigned char *pdata;
pdata = (unsigned char *)malloc(4 * sizeof(unsigned char) * 6);

至此我们实现了Acq、Xfer、Buffers和View的生成和采集并读取一定数量的图像,给出以上功能的完整代码实现:
代码实现部分

	int m_nFramesPerCallback = 1;
	int m_nFramesOnBoard = 4096;
	int m_nFramesLost = 0;
	
	m_Acq = new SapAcquisition(SapLocation(1, 1), "C:\\Program Files\\Teledyne DALSA\\Sapera\\CamFiles\\User\\Line_Trigger.ccf");
	m_Buffers = new SapBuffer(6, m_Acq);
	m_Xfer = new SapAcqToBuf(m_Acq, m_Buffers);
	
	if (m_Acq && !*m_Acq && !m_Acq->Create())
	{
		DestroyObjects();
		return FALSE;
	}
	// Create buffer object
	if (m_Buffers && !*m_Buffers)
	{
		if (!m_Buffers->Create())
		{
			DestroyObjects();
			return FALSE;
		}
		// Clear all buffers
		m_Buffers->Clear();
	}
	if (m_Xfer && !*m_Xfer)
	{
		// Set number of onboard buffers
		m_Xfer->GetPair(0)->SetFramesOnBoard(m_nFramesOnBoard);

		// Set number of frames per callback
		m_Xfer->GetPair(0)->SetFramesPerCallback(m_nFramesPerCallback);

		// If there is a large number of buffers, temporarily boost the command timeout value,
		// since the call to Create may take a long time to complete.
		// As a safe rule of thumb, use 100 milliseconds per buffer.
		int oldCommandTimeout = SapManager::GetCommandTimeout();
		int newCommandTimeout = 100 * m_Buffers->GetCount();

		if (newCommandTimeout < oldCommandTimeout)
			newCommandTimeout = oldCommandTimeout;

		SapManager::SetCommandTimeout(newCommandTimeout);

		// Create transfer object
		if (!m_Xfer->Create())
		{
			DestroyObjects();
			return FALSE;
		}
		m_Xfer->Init(TRUE); // initialize tranfer object and reset source/destination index

							// Retrieve number of frames per callback
							// It may be less than what we have asked for.
		nFramesPerCallback = m_Xfer->GetPair(0)->GetFramesPerCallback();
		if (m_nFramesPerCallback > nFramesPerCallback)
		{
			m_nFramesPerCallback = nFramesPerCallback;
			AfxMessageBox(_T("No memory"));
		}

		// Retrieve number of on-board buffers that has been created.
		// It may be less than what we have asked for.
		m_nFramesOnBoard = m_Xfer->GetPair(0)->GetFramesOnBoard();
	}
	m_Buffers->Clear();
	m_Buffers->ResetIndex();
	m_Buffers->SetIndex(0);
	m_Xfer->Init();
	SapXferFrameRateInfo* pStats = m_Xfer->GetFrameRateStatistics();
	pStats->Reset();
	m_Xfer->Snap(6);//以相机设定的采集频率连续采集6张图片
	for(int index = 0; index < 6; index++){
		m_Buffers->Read(index, 0, 1, pdata);//偏移量和读取量应根据实际需求自行设定
	}

有任何疑问都可以向笔者提问哦

你可能感兴趣的:(笔记)