二次开发,但是找遍了所有的技术文档,都没有找到实现回调取图的完整流程的教程,文档。痛苦不堪,虽然轮询取图在技术文档中实现了,但是还是需要将其与其他很多功能分开。特此,本文将再次简单记录一下实现的过程。
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对话框的静态控件中,实现了高效的图像采集和显示功能。
最后注意,上述一定是在类中实现的,如果没有类的基础,上述可能对你没有什么帮助,当然如果自己实在使用不上上面给出的思路,可以在评论区,评论,博主看到会简答。