1、硬件原因
(1)硬件主要涉及网线和网卡的选择,Dalsa相机最好选择千兆网线和千兆网卡。若一台PC需要连接多个相机,最好添加对应个数的网卡;
(2)网卡配置:对应网卡需要进行配置,配置方法如下所示:
①打开“网络连接”,选择对应网卡,右键选择“属性”;
②选择“配置”
③选择“高级”,配置“巨帧数据包”,选择最大(9014字节);“速度和双工”,选择最大(1.0 Gbps全双工)。
至此,和硬件相关的配置已经结束,如果能解决图像丢帧的问题,即可忽略第二步。若还没有解决,可能还与软件(代码)有关,代码主要在于抓图方式和取图方式。
2、软件原因
本人使用的是官方MFC-SDK,需要实现的功能为:当收到触发信号时,获取相机当前帧图像,并对该图像进行图像处理操作。最开始使用的方法为,开启软件后,持续获取流数据,即调用Grab()函数开始抓图,当收到触发信号时,直接从缓冲区(m_Buffers)中取数据转换为Mat图像,然后进行后续处理,结果发现,此方法会存在丢帧的情况。
后通过查看相机文档及相关资料得知,当相机得到一帧完整数据时,会自动调用回调函数(XferCallback),回调函数结束时,说明获取了一张完整的图像,故选用单张抓图Snap()+回调函数内获取图像的方式,最终解决了图像丢帧的问题。
主要代码部分展示:
头文件主要变量及函数定义:
CImageExWnd m_ImageWnd;
SapAcqDevice *m_AcqDevice;
SapBuffer *m_Buffers;
SapTransfer *m_Xfer;
SapView *m_View;
static void XferCallback(SapXferCallbackInfo *pInfo);
初始化OnInitDialog()函数部分代码:
//OnInitDialog()函数中
//Select acquisition server from dialog
//Only the servers that support "AcqDevice" resource are listed
CAcqConfigDlg dlg(this, CAcqConfigDlg::ServerAcqDevice);
if (dlg.DoModal() != IDOK)
{
MessageBox(_T("未发现或选中相机"), _T("错误"), MB_ICONHAND);
EndDialog(TRUE);
return FALSE;
}
// Define objects(important!)
m_AcqDevice = new SapAcqDevice(dlg.GetLocation(), dlg.GetConfigFile());
m_Buffers = new SapBufferWithTrash(1, m_AcqDevice); //1个垃圾缓冲区,如果获取多帧图像,为防止丢帧最好设置至少2个以上的缓冲区,因为此处使用单张抓图,所以1个缓冲区即可。
m_Xfer = new SapAcqDeviceToBuf(m_AcqDevice, m_Buffers, XferCallback, this);
m_View = new SapView(m_Buffers);
//// Attach sapview to image viewer
m_ImageWnd.AttachSapView(m_View);
// Create all objects
if (!CreateObjects()) { EndDialog(TRUE); return FALSE; }
m_ImageWnd.AttachEventHandler(this);
m_ImageWnd.CenterImage();
m_ImageWnd.Reset();
回调XferCallback()函数:
void CGigeCameraDemoDlg::XferCallback(SapXferCallbackInfo *pInfo)
{
CGigeCameraDemoDlg *pDlg = (CGigeCameraDemoDlg *)pInfo->GetContext();
int staticCount = 0;
BYTE pData;
void* pDataAddr = &pData;
pDlg->m_Buffers->GetAddress(staticCount, &pDataAddr);
int width = pDlg->m_Buffers->GetWidth();
int height = pDlg->m_Buffers->GetHeight();
Mat img = Mat::zeros(cv::Size(width, height), CV_8U);
memcpy(img.data, pDataAddr, width*height);
img.copyTo(global_source_image); //global_source_image为全局Mat
callback_flag = true; //自定义全局变量
}
某函数中抓取图像:
//m_Xfer->Snap()即为单张抓图,此处选用单张抓图
//m_Xfer->Grab()即为获取视频流,持续抓图
if (m_Xfer->Snap())
{
UpdateMenu(); //更新按钮状态
}
//当callback_flag为true时,可以使用图像
while(callback_flag == true)
{
//使用global_source_image进行一系列图像操作
//操作结束退出循环,并将callback_flag置为false.
}