实验室更换了新的DALSA 2D线阵相机,本次任务是替代就相机的功能,将新相机融入到之前的2D-3D扫描系统中。
下面会详细介绍实现过程及思路,着急的可以直接跳到代码实现部分
查看Sapera Lt帮助文档(),可得图像捕捉函数 SapTransfer::Snap()
从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函数
例如如下代码:
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);//偏移量和读取量应根据实际需求自行设定
}
有任何疑问都可以向笔者提问哦