MFC中有两类线程,分别称之为工作者线程和用户界面线程。二者的主要区别在于工作者线程没有消息循环,而用户界面线程有自己的消息队列和消息循环。
工作者线程没有消息机制,通常用来执行后台计算和维护任务,如冗长的计算过程,打印机的后台打印等。
用户界面线程一般用于处理独立于其他线程执行之外的用户输入,响应用户及系统所产生的事件和消息等。
一、建立工程。
1、建立一个基于对话框的工程VideoProcess,在对话框中加入一个按钮IDC_CAMERA,标题为“打开摄像头” 。
右击工程并选中“New Class…”为工程添加基类为CWinThread派生线程类CCamera。
给工程添加新对话框IDD_CAMERA_DLG,标题为“摄像头视频”。 为对话框IDD_CAMERA_DLG创建一个基于CDialog的类CCameraDlg。
2、在主对话框中添加按钮,并双击后,添加消息响应函数(启动用户界面线程),还要加上CCamera类的头文件。
void CVideoProcessDlg::OnBnClickedCameraDlg() { // TODO: 在此添加控件通知处理程序代码 CWinThread *pThread=AfxBeginThread(RUNTIME_CLASS(CCamera)); }
3、并在CCamera类中添加protected变量CCameraDlg m_dlg,并添加头文件。
#include "CameraDlg.h" // CCamera class CCamera : public CWinThread { DECLARE_DYNCREATE(CCamera) protected: CCamera(); // 动态创建所使用的受保护的构造函数 virtual ~CCamera(); CCameraDlg m_dlg; //tfygg public: virtual BOOL InitInstance(); virtual int ExitInstance(); protected: DECLARE_MESSAGE_MAP() };
分别重载InitInstance()函数和ExitInstance()函数:
BOOL CCamera::InitInstance() { // TODO: 在此执行任意逐线程初始化 m_dlg.Create(IDD_CAMERA_DLG); m_dlg.ShowWindow(SW_SHOW); m_pMainWnd=&m_dlg; return TRUE; } int CCamera::ExitInstance() { // TODO: 在此执行任意逐线程清理 m_dlg.DestroyWindow(); return CWinThread::ExitInstance(); }
至此,基本工程环境建立完毕。编译运行后,点击主对话框的按钮,就会弹出Camera对话框。
二、OpenCV静态编译环境搭建
1、搭建OpenCV基本环境。
(1)配置好头文件目录
(2)配置好静态库目录。选择staticlib目录
(3)添加“附加依赖库”:
IlmImfd.lib
libjasperd.lib
libjpegd.lib
libpngd.lib
libtiffd.lib
zlibd.lib
opencv_calib3d249d.lib
opencv_contrib249d.lib
opencv_core249d.lib
opencv_features2d249d.lib
opencv_flann249d.lib
opencv_gpu249d.lib
opencv_highgui249d.lib
opencv_imgproc249d.lib
opencv_legacy249d.lib
opencv_ml249d.lib
opencv_nonfree249d.lib
opencv_objdetect249d.lib
opencv_ocl249d.lib
opencv_photo249d.lib
opencv_stitching249d.lib
opencv_superres249d.lib
opencv_ts249d.lib
opencv_video249d.lib
opencv_ocl249.lib
opencv_videostab249d.lib
opencv_photo249.lib
opencv_stitching249.lib
opencv_superres249.lib
opencv_videostab249.lib
opencv_calib3d249.lib
opencv_contrib249.lib
opencv_core249.lib
opencv_features2d249.lib
opencv_flann249.lib
opencv_gpu249.lib
opencv_highgui249.lib
opencv_imgproc249.lib
opencv_legacy249.lib
opencv_ml249.lib
vfw32.lib
comctl32.lib
其中第一个库很重要。 最后两个库不是opencv的,但也要添加。
(4)编译测试。
2、添加CvvImage类。点击打开链接
3、添加videoProcessor类。
三、播放视频
1、在IDD_CAMERA_DLG对话框中添加Picture控件,用于显示视频。
2、在CameraDlg.h文件中添加一个线程参数结构:
struct threadInfo { CRect rect;// 矩形类 HDC hdc; // 获取设备上下文句柄 CDC *pDC; };
线程函数的声明:
UINT ThreadFunc(LPVOID lpParam);
注意,二者应在类CCameraDlg的外部。
3、在类CCameraDlg内部添加protected型变量: CWinThread* pThread;
4、在CameraDlg.cpp文件中进行如下操作:
(1)定义公共变量: threadInfo Info;
(2)添加OnInitDialog方法。并加入以下代码
BOOL CCameraDlg::OnInitDialog() { CDialog::OnInitDialog(); // TODO: 在此添加额外的初始化 UpdateData(TRUE); Info.pDC = GetDlgItem(IDC_VIDEO)->GetDC();//根据ID获得窗口指针再获取与该窗口关联的上下文指针 Info.hdc= Info.pDC->GetSafeHdc(); // 获取设备上下文句柄 GetDlgItem(IDC_VIDEO)->GetClientRect(&Info.rect); //获取box1客户区 pThread=AfxBeginThread(ThreadFunc,&Info); return TRUE; // return TRUE unless you set the focus to a control // 异常: OCX 属性页应返回 FALSE }
(3)添加线程处理函数。
UINT ThreadFunc(LPVOID lpParam) { threadInfo* pInfo=(threadInfo*)lpParam; CRect rect = pInfo->rect;// 矩形类 HDC hdc = pInfo->hdc; // 获取设备上下文句柄 VideoProcessor processor; processor.setInput(0); processor.displayInputParam("input", hdc, &rect); processor.run(); return 0; }
4、测试。
四、运动检测
1、添加线程类CBgFg。
2、添加对话框,并添加该对话框的类。
3、重载线程类的InitInstance()函数和ExitInstance()。
4、测试。如下图:
五、暂停/恢复视频线程
主要是使用SuspendThread()和ResumeThread()
1、添加按钮
2、在按钮的代码里添加:
挂起pThread->SuspendThread();
恢复 pThread->ResumeThread();
注意遇到的问题:
1、Error 1 error LNK2038: mismatch detected for '_ITERATOR_DEBUG_LEVEL': value '0' doesn't match value '2' in bvpmeasure.obj
这个 value ‘0’、value '2' 还是容易解决,一般就是用Release模式去链接了一个Debug编译出的lib,或者用Debug模式链接了Release编译的lib。调整相应的lib版本即可。
2、1>LIBCMT.lib(invarg.obj) : error LNK2005: ___pInvalidArgHandler 已经在 LIBCMTD.lib(invarg.obj) 中定义
1>LINK : warning LNK4098: 默认库“LIBCMT”与其他库的使用冲突;请使用 /NODEFAULTLIB:library
解决办法:链接器->输入->忽略特定默认库: libcmt.lib