介绍相机SDK开发及回调操作
随着计算机视觉技术的发展,越来越多的开发者需要使用相机SDK来开发图像处理和目标识别应用。相机SDK提供了一系列接口,方便开发者控制相机、获取图像数据、进行设置等操作。本文将介绍如何进行相机SDK开发,特别是回调操作及其注意事项,并提供相应的代码示例。
1. 相机SDK开发基础
相机SDK通常提供了以下几类功能:
设备管理:枚举、打开和关闭相机设备。
参数设置:设置曝光、增益、分辨率等相机参数。
图像获取:从相机实时获取图像数据。
事件回调:处理相机事件(如图像到达、设备断开)。
2. 回调函数的概念
回调函数是一种通过函数指针间接调用的函数,用于处理特定事件。相机SDK中,回调函数常用于处理图像数据到达、错误发生等事件。
3. 相机SDK开发示例
以下示例基于一个假设的相机SDK库进行演示,展示如何进行设备管理、参数设置和回调操作。
1. 初始化和设备管理
首先,初始化连接相机
void CLaser::OnCameraConnect()
{
if(m_camera_status == CAMERA_PLAY || m_camera_status == CAMERA_STOP)
return;
// TODO: 在此添加命令处理程序代码
BeginWaitCursor();
int status = m_camera.CameraOpen(&m_ImageReadWnd,this);
if (status == 0)
{
//AfxMessageBox("相机连接失败.");
return;
}
m_camera_status = CAMERA_CONNECT;
EndWaitCursor();
LogInfoOut(_T("相机已连接"));
}
我们需要构造相机SDK的成员变量:
InfraredCamera::InfraredCamera(CWnd *pView /*= NULL*/)
{
m_View = NULL;
m_Xfer = NULL;
m_Buffers = NULL;
m_Acq = NULL;
m_AcqDevice = NULL;
m_pDisplayWnd = NULL;
m_pViewWnd = NULL;
m_bIsOpen = false;
m_bGetImage = false;
m_pBuffer = NULL;
m_lasercolor = LASER_GREEN;
m_imageprocess = false;
m_pViewWnd = pView;
}
InfraredCamera::~InfraredCamera(void)
{
if (m_Xfer && *m_Xfer)
{
m_Xfer->Freeze();
m_Xfer->Wait(0);
m_Xfer->Abort();
}
// Destroy view object
if (m_View && *m_View)
m_View->Destroy();
// Destroy transfer object
if (m_Xfer && *m_Xfer)
m_Xfer->Destroy();
// Destroy buffer object
if (m_Buffers && *m_Buffers)
m_Buffers->Destroy();
// Destroy acquisition object
if (m_Acq && *m_Acq)
m_Acq->Destroy();
if (m_AcqDevice && *m_AcqDevice)
m_AcqDevice->Destroy();
// Delete all objects
if (m_View)
delete m_View;
if (m_Xfer)
delete m_Xfer;
if (m_Buffers)
delete m_Buffers;
if (m_Acq)
delete m_Acq;
if (m_AcqDevice)
delete m_AcqDevice;
}
int InfraredCamera::Open()
{
if (!GetOptionsFromQuestions())
return -1;
SapLocation loc(m_serverName_01.c_str(), m_DeviceNumber); //0509 m_serverName
if (SapManager::GetResourceCount(m_serverName_01.c_str(), SapManager::ResourceAcqDevice) > 0)
{
m_AcqDevice = new SapAcqDevice(loc, FALSE);
m_Buffers = new SapBufferWithTrash(2, m_AcqDevice);
//m_Xfer = new SapAcqDeviceToBuf(m_AcqDevice, m_Buffers, XferCallback, this);
// Create acquisition object
if (!m_AcqDevice->Create())
return -1;
}
m_View = new SapView(m_Buffers, m_pDisplayWnd->GetSafeHwnd());
if (m_View && !*m_View && !m_View->Create())
return -1;
m_bIsOpen = true;
return 0;
}
还要定义相机控制函数
int InfraredCamera::Close()
{
if (m_Xfer->Freeze())
return 0;
return -1;
}
// ch:开启抓图 | en:Start Grabbing
int InfraredCamera::StartGrabbing()
{
return 0;
}
// ch:停止抓图 | en:Stop Grabbing
int InfraredCamera::StopGrabbing()
{
return 0;
}
int InfraredCamera::CameraOpen()
{
if (0 == Open())
{
((InfraredCamera()).m_pViewWnd);
RegisterImageCallBack(XferCallback, this);
return 0;
}
return -1;
}
bool InfraredCamera::StartPlay()
{
if (m_Xfer->Grab())
return true;
return false;
}
bool InfraredCamera::StopPlay()
{
if (m_Xfer->Freeze())
return true;
return false;
}
void InfraredCamera::CameraClose()
{
Close();
m_bIsOpen = false;
}
2. 图像获取及回调函数
接下来,我们设置回调函数来处理图像数据到达事件:
void Camera::XferCallback(SapXferCallbackInfo *pInfo)
{
static long preTime = 0;
CString msg;
long curTime = GetTickCount();
long time = curTime - preTime;
preTime = curTime;
msg.Format("取图间隔:%d ms", time); //获取帧之间的时间差
InfraredCamera *pcamera = (InfraredCamera *)pInfo->GetContext(); //开始,从pInfo得到每次的回调内容给到pcamera
SapBuffer *pSapbuff = pcamera->m_View->GetBuffer(); //将从pcamera得到的内容通过GetBuffer给到pSapbuff
int bpp = pSapbuff->GetBytesPerPixel(); //得到图像的多少通道
PUINT8 pData;
pSapbuff->GetAddress((void**)&pData); //获取图像具体内容?
//目标数据
int nBufSize = pSapbuff->GetHeight()*pSapbuff->GetWidth(); //图像内容大小
if (pcamera->m_pBuffer == NULL)
{
pcamera->m_pBuffer = new BYTE[nBufSize];
}
if (pcamera->m_pViewWnd == NULL)
return;
CLaser *pView = (CLaser*)pcamera->m_pViewWnd; //将强转后的pcamera给到pView
try {
memcpy(pcamera->m_pBuffer, pData, nBufSize);
int rows, cols;
rows = pSapbuff->GetHeight();
cols = pSapbuff->GetWidth();
int type = CV_8UC3;
if (bpp == 1)
{
type = CV_8UC1;
}
cv::Mat src_image(rows, cols, CV_8UC1, pData); //得到图像内容
pSapbuff->ReleaseAddress(pData);
pcamera->m_ImageWidth = cols;
pcamera->m_ImageHeigh = rows;
img_view *img_info = new img_view;
img_info->ImageHeigh = rows;
img_info->ImageWidth = cols;
img_info->wndName = NAME_SOURCE_WINDOW;
cv::Mat *displayMat = new cv::Mat(src_image); //图像传给displayMat
pView->PostMessage(WM_SHOW_IMAGE_VIEW, (WPARAM)img_info, (LPARAM)displayMat); //传递消息
long time = GetTickCount();
pcamera->m_small_image.release();
resize(src_image, pcamera->m_small_image, cv::Size(SMALL_IMAGE_COL, SMALL_IMAGE_ROW), 0, 0, cv::INTER_AREA);
cv::INTER_AREA);
pcamera->m_src_image = src_image;
if (pView->m_bStartGrabVideo) {
pView->m_outputVideo << pcamera->m_small_image;
}
src_image.release();
if (pView->m_camera.m_pCamera->m_imageprocess) //判断是否处于m_imageprocess
{
ProcessImageInfo *info = new ProcessImageInfo;
info->src = pcamera->m_small_image.clone();
info->curtime = time;
pView->m_ImgQueue.push(info);
}
else
{
}
pView->m_wndIntervalTime.SendMessage(WM_SETTEXT, 0, (LPARAM)msg.GetBuffer());
}
catch (std::exception ex)
{
return;
}
}
在这个示例中,`XferCallBack函数会在每次图像到达时被调用。我们可以在该函数中处理图像数据,如保存或进行进一步处理。
3. 注意事项
1. 线程安全:回调函数通常在不同的线程中执行,因此需要注意线程安全问题,使用合适的同步机制来保护共享资源。
2. 资源管理:确保在程序结束时正确释放相机资源,避免资源泄漏。
3. 错误处理:在实际开发中,应该添加更多的错误处理代码,确保程序的稳定性和可靠性。
4. 性能优化:对于高帧率相机,确保回调函数执行效率高,避免阻塞回调线程。
4.结论
相机SDK开发是图像处理和目标识别应用的基础,正确使用回调函数和处理相机事件是实现高效稳定程序的关键。