MFC,C++,海康SDK,回调,轮询
二次开发,但是找遍了所有的技术文档,都没有找到实现回调取图的完整流程的教程,文档。痛苦不堪,虽然轮询取图在技术文档中实现了,但是还是需要将其与其他很多功能分开。特此,本文将再次简单记录一下实现的过程。
1.一定要使用面向对象的方式。
创建一个相机类和一个主框架类,这里直接在其技术文件中可以找到复制粘贴即可。
然后现在讲述回调实现的源码。轮询技术文档提供,不赘述.
1. 修改对话框类头文件
首先在CImage_GrabDlg.h
中添加必要的成员变量和函数声明:
// Image_GrabDlg.h
class CImage_GrabDlg : public CDialogEx
{// ... 其他已有代码protected:// 用于显示图像的静态控件句柄HWND m_hwndDisplay;// 图像数据相关unsigned char* m_pSaveImageBuf;unsigned int m_nSaveImageBufSize;CRITICAL_SECTION m_hSaveImageMux;MV_FRAME_OUT_INFO_EX m_stImageInfo;// 回调函数声明static void __stdcall ImageCallBackEx(unsigned char* pData, MV_FRAME_OUT_INFO_EX* pFrameInfo, void* pUser);void OnImageCallBack(unsigned char* pData, MV_FRAME_OUT_INFO_EX* pFrameInfo);// 初始化函数void DisplayWindowInitial();// ... 其他已有成员
};
2. 修改对话框类实现文件
2.1 初始化部分
// Image_GrabDlg.cpp
CImage_GrabDlg::CImage_GrabDlg(CWnd* pParent /*=NULL*/): CDialogEx(IDD_IMAGE_GRAB_DIALOG, pParent), m_pcMyCamera(NULL), m_nDeviceCombo(0), m_bOpenDevice(FALSE), m_bStartGrabbing(FALSE), m_hGrabThread(NULL), m_bThreadState(FALSE), m_nTriggerMode(MV_TRIGGER_MODE_OFF), m_pSaveImageBuf(NULL), m_nSaveImageBufSize(0)
{m_hIcon = AfxGetApp()->LoadIcon(IDR_MAINFRAME);memset(&m_stImageInfo, 0, sizeof(MV_FRAME_OUT_INFO_EX));InitializeCriticalSection(&m_hSaveImageMux);
}CImage_GrabDlg::~CImage_GrabDlg()
{DeleteCriticalSection(&m_hSaveImageMux);if (m_pSaveImageBuf){free(m_pSaveImageBuf);m_pSaveImageBuf = NULL;}
}
2.2 回调函数实现
// 静态回调函数
void __stdcall CImage_GrabDlg::ImageCallBackEx(unsigned char* pData, MV_FRAME_OUT_INFO_EX* pFrameInfo, void* pUser)
{if (!pData || !pFrameInfo || !pUser){return;}CImage_GrabDlg* pThis = (CImage_GrabDlg*)pUser;pThis->OnImageCallBack(pData, pFrameInfo);
}// 实际处理回调的成员函数
void CImage_GrabDlg::OnImageCallBack(unsigned char* pData, MV_FRAME_OUT_INFO_EX* pFrameInfo)
{// 保存图像数据EnterCriticalSection(&m_hSaveImageMux);if (NULL == m_pSaveImageBuf || pFrameInfo->nFrameLen > m_nSaveImageBufSize){if (m_pSaveImageBuf){free(m_pSaveImageBuf);m_pSaveImageBuf = NULL;}m_pSaveImageBuf = (unsigned char*)malloc(pFrameInfo->nFrameLen);if (m_pSaveImageBuf == NULL){LeaveCriticalSection(&m_hSaveImageMux);return;}m_nSaveImageBufSize = pFrameInfo->nFrameLen;}memcpy(m_pSaveImageBuf, pData, pFrameInfo->nFrameLen);memcpy(&m_stImageInfo, pFrameInfo, sizeof(MV_FRAME_OUT_INFO_EX));LeaveCriticalSection(&m_hSaveImageMux);// 在UI线程中更新显示if (m_hwndDisplay){MV_CC_IMAGE stImageData = {0};stImageData.nWidth = pFrameInfo->nWidth;stImageData.nHeight = pFrameInfo->nHeight;stImageData.enPixelType = pFrameInfo->enPixelType;stImageData.nImageLen = pFrameInfo->nFrameLen;stImageData.pImageBuf = pData;m_pcMyCamera->DisplayOneFrame(m_hwndDisplay, &stImageData);}
}
2.3 开始采集按钮实现
void CImage_GrabDlg::OnBnClickedButton4()
{if (FALSE == m_bOpenDevice || TRUE == m_bStartGrabbing || NULL == m_pcMyCamera){return;}// 注册回调函数int nRet = MV_CC_RegisterImageCallBackEx(m_pcMyCamera->outinterface(), CImage_GrabDlg::ImageCallBackEx, this);if (MV_OK != nRet){ShowErrorMsg(TEXT("Register image callback fail"), nRet);return;}// 设置采集模式为连续采集nRet = m_pcMyCamera->SetNetTransMode(MV_TRIGGER_MODE_OFF);if (MV_OK != nRet){ShowErrorMsg(TEXT("Set trigger mode fail"), nRet);return;}// 开始采集nRet = m_pcMyCamera->StartGrabbing();if (MV_OK != nRet){ShowErrorMsg(TEXT("Start grabbing fail"), nRet);return;}m_bStartGrabbing = TRUE;
}
2.4 停止采集按钮实现
void CImage_GrabDlg::OnBnClickedButton6()
{if (FALSE == m_bOpenDevice || FALSE == m_bStartGrabbing || NULL == m_pcMyCamera){return;}// 停止采集int nRet = m_pcMyCamera->StopGrabbing();if (MV_OK != nRet){ShowErrorMsg(TEXT("Stop grabbing fail"), nRet);return;}// 注销回调函数nRet = MV_CC_RegisterImageCallBackEx(m_pcMyCamera->outinterface(), NULL, NULL);if (MV_OK != nRet){ShowErrorMsg(TEXT("Unregister image callback fail"), nRet);}m_bStartGrabbing = FALSE;
}
3. 显示窗口初始化
void CImage_GrabDlg::DisplayWindowInitial()
{CWnd *pWnd = GetDlgItem(IDC_DISPLAY_STATIC);if (pWnd){m_hwndDisplay = pWnd->GetSafeHwnd();// 设置静态控件样式为SS_BITMAP,用于显示图像pWnd->ModifyStyle(0, SS_BITMAP);// 初始化显示黑色背景CRect rect;pWnd->GetClientRect(&rect);CDC *pDC = pWnd->GetDC();CBitmap bitmap;bitmap.CreateCompatibleBitmap(pDC, rect.Width(), rect.Height());pWnd->SetBitmap((HBITMAP)bitmap.Detach());pWnd->ReleaseDC(pDC);}
}
4. 资源文件修改
在对话框资源中添加一个静态文本控件,ID设置为IDC_DISPLAY_STATIC
,用于显示图像。调整其大小以适应图像显示需求。
5. 使用说明
点击"查找设备"按钮枚举可用相机设备
选择设备后点击"打开设备"按钮连接相机
点击"开始采集"按钮开始接收图像并在静态控件中显示
点击"停止采集"按钮停止图像采集
点击"关闭设备"按钮断开相机连接
注意事项
图像显示使用了静态控件的SS_BITMAP样式,确保控件足够大以显示完整图像
使用了临界区保护图像数据,确保多线程安全
回调函数中直接调用显示函数,确保图像实时显示
需要处理图像格式转换,如果相机输出的像素格式与显示要求不符
这个方案利用了海康威视相机SDK的回调机制,在回调函数中获取图像数据并显示在MFC对话框的静态控件中,实现了高效的图像采集和显示功能。
最后注意,上述一定是在类中实现的,如果没有类的基础,上述可能对你没有什么帮助,当然如果自己实在使用不上上面给出的思路,可以在评论区,评论,博主看到会简答。