mfc | mfc集成opencv,实现监控、拍照、录像、录像播放(保姆级教程)

1. 开发环境

编辑器:Visual Studio2022
OpenCV版本:4.5.4

2. MFC项目搭建

mfc | mfc集成opencv,实现监控、拍照、录像、录像播放(保姆级教程)_第1张图片
mfc | mfc集成opencv,实现监控、拍照、录像、录像播放(保姆级教程)_第2张图片
mfc | mfc集成opencv,实现监控、拍照、录像、录像播放(保姆级教程)_第3张图片
mfc | mfc集成opencv,实现监控、拍照、录像、录像播放(保姆级教程)_第4张图片
点击完成后,项目创建完成。界面如下:
mfc | mfc集成opencv,实现监控、拍照、录像、录像播放(保姆级教程)_第5张图片
点击"本地Windows调试器",即可运行,运行结果如下:
mfc | mfc集成opencv,实现监控、拍照、录像、录像播放(保姆级教程)_第6张图片

3. 集成OPENCV

3.1 opencv安装

下载地址:https://opencv.org/releases/
安装:无脑下一步(记住opencv的安装路径)

3.2 opencv目录

安装完成后,opencv目录下有build和sources两个文件夹,build是我们需要使用的,build文件夹内容见下图
mfc | mfc集成opencv,实现监控、拍照、录像、录像播放(保姆级教程)_第7张图片

3.3 opencv文件拷贝到项目中

右击项目,选择"在文件资源管理器中打开文件夹"
mfc | mfc集成opencv,实现监控、拍照、录像、录像播放(保姆级教程)_第8张图片
将opencv/build/include目录复制到项目的目录下
将opencv/build/x64/vc15/lib目录复制到项目的目录下
复制完后的目录如下:
mfc | mfc集成opencv,实现监控、拍照、录像、录像播放(保姆级教程)_第9张图片
回到项目,点击重新生成,打开生成exe所在的目录
mfc | mfc集成opencv,实现监控、拍照、录像、录像播放(保姆级教程)_第10张图片
将opencv\build\x64\vc15\bin目录下的opencv_videoio_ffmpeg454_64.dll,opencv_world454d.dll文件都拷贝到exe所在目录。
拷贝好的项目目录如下:
mfc | mfc集成opencv,实现监控、拍照、录像、录像播放(保姆级教程)_第11张图片

3.4 opencv配置

配置项目的页面:右击项目->属性->左侧的三个目录
mfc | mfc集成opencv,实现监控、拍照、录像、录像播放(保姆级教程)_第12张图片

库目录:
mfc | mfc集成opencv,实现监控、拍照、录像、录像播放(保姆级教程)_第13张图片
mfc | mfc集成opencv,实现监控、拍照、录像、录像播放(保姆级教程)_第14张图片
选择刚才拷贝的lib文件,确定
mfc | mfc集成opencv,实现监控、拍照、录像、录像播放(保姆级教程)_第15张图片
回到上一层,点击应用。

头文件:同理添加头文件。
mfc | mfc集成opencv,实现监控、拍照、录像、录像播放(保姆级教程)_第16张图片
链接器:在链接器中添加opencv_world454d.lib(直接粘贴即可)
mfc | mfc集成opencv,实现监控、拍照、录像、录像播放(保姆级教程)_第17张图片
点击应用确定。至此Opencv开发环境配置完成。

3.5 测试OpenCV

回到项目主界面,双击确定,进入代码
mfc | mfc集成opencv,实现监控、拍照、录像、录像播放(保姆级教程)_第18张图片
编辑确定按钮的代码,代码内容如下

void CopencvDemoDlg::OnBnClickedOk()
{
	//1.从摄像头读入视频
	VideoCapture cap(0);
	//2.循环显示每一帧
	while (1)
	{
		Mat cam;
		cap >> cam;//获取当前帧图像
		imshow("相机", cam);//显示当前帧图像
		waitKey(30);//延时30秒
	}
}

拉到项目最上方,添加头文件

#include 
#include

using namespace std;
using namespace cv;

mfc | mfc集成opencv,实现监控、拍照、录像、录像播放(保姆级教程)_第19张图片
至此项目编码完成,启动项目,点击确定,界面如下:
mfc | mfc集成opencv,实现监控、拍照、录像、录像播放(保姆级教程)_第20张图片

3.6 OPENCV视频嵌入到弹框中

3.6.1 控件添加(Picture Control)

从左侧的工具栏中选择Picture Control,拖动到窗口中,调整大小,移动到合适位置,效果如下图
mfc | mfc集成opencv,实现监控、拍照、录像、录像播放(保姆级教程)_第21张图片

3.6.2 控件ID修改

右击控件属性,修改ID为"IDC_PIC"
mfc | mfc集成opencv,实现监控、拍照、录像、录像播放(保姆级教程)_第22张图片

3.6.3 控件绑定变量

右击控件,添加变量
mfc | mfc集成opencv,实现监控、拍照、录像、录像播放(保姆级教程)_第23张图片

3.6.4 控件绑定点击事件

点击完成后,双击页面的确定,重新编写代码,代码如下

void CopencvDemoDlg::OnBnClickedOk()
{
	//将opencv的窗体嵌入到页面中
	cv::namedWindow("picView", cv::WINDOW_AUTOSIZE);
	HWND hWnd = (HWND)cvGetWindowHandle("picView");
	HWND hParent = ::GetParent(hWnd);
	::SetParent(hWnd, GetDlgItem(IDC_PIC)->m_hWnd);
	::ShowWindow(hParent, SW_HIDE);

	//1.从摄像头读入视频
	VideoCapture cap(0);
	//2.循环显示每一帧
	while (1)
	{
		Mat cam;
		cap >> cam;//获取当前帧图像
		imshow("picView", cam);//显示当前帧图像
		waitKey(30);//延时30秒
	}
}

启动项目, 效果如下:
mfc | mfc集成opencv,实现监控、拍照、录像、录像播放(保姆级教程)_第24张图片

3.6.5 Button控件显示的文字修改

右击按钮属性,修改描述文字,ID
mfc | mfc集成opencv,实现监控、拍照、录像、录像播放(保姆级教程)_第25张图片

3.7 界面设计

3.7.1 放大对话框区域

将鼠标移动至对话框右下角,左击(不松开)鼠标,往右下角拖动,放大窗口,放大后的效果如下图
mfc | mfc集成opencv,实现监控、拍照、录像、录像播放(保姆级教程)_第26张图片

3.7.2 添加Button控件

左击(不松开)工具箱的Button控件,拖动到右侧的对话框后,松开鼠标左键
mfc | mfc集成opencv,实现监控、拍照、录像、录像播放(保姆级教程)_第27张图片
同理再添加4个按钮,效果如图
mfc | mfc集成opencv,实现监控、拍照、录像、录像播放(保姆级教程)_第28张图片

3.7.3 按钮显示内容修改

参照3.6.5 章节,修改按钮的显示名称。

名称 显示文字 变量
按钮1 关闭监控
按钮2 录像
按钮3 录像结束
按钮4 播放视频
按钮5 打开照片所在目录

修改完毕后,拖动控件,重新布局,效果如下
mfc | mfc集成opencv,实现监控、拍照、录像、录像播放(保姆级教程)_第29张图片

4 监控、拍照、录像功能实现

4.2 添加全局静态变量

打开项目对话框的头文件(opencvDemoDlg.h),在头文件中定义静态变量mfc | mfc集成opencv,实现监控、拍照、录像、录像播放(保姆级教程)_第30张图片

	static bool closeFlag;//关闭监控标志
	static bool takePhotoFlag;//拍照标志
	static bool recordFlag;//录像标志

打开项目对话框的cpp文件(opencvDemoDlg.cpp),在cpp文件中声明变量。
下图中的folderPath为全局变量,closeFlag、takePhotoFlag 、recordFlag三个变量为静态变量(静态变量的定义为类名::变量名)
mfc | mfc集成opencv,实现监控、拍照、录像、录像播放(保姆级教程)_第31张图片

//关闭监控标志
bool CopencvDemoDlg::closeFlag = false;
//拍照标志
bool CopencvDemoDlg::takePhotoFlag = false;
//录像标志
bool CopencvDemoDlg::recordFlag = false;
//图片、视频默认存储位置
CString folerPath = L"c:/record/";

4.2 关闭监控功能实现

回到资源视图,打开主对话框,双击关闭监控按钮,添加如下代码

void CopencvDemoDlg::OnBnClickedButton1()
{
	// closeFlag置为true,关闭实时监控
	CopencvDemoDlg::closeFlag = true;
}

同理,双击实时监控,添加如下代码

//当用户点机实时监控,将closeFlag置为false
CopencvDemoDlg::closeFlag = false;

//此处代码省略

//如果CloseFlag为true,跳出循环,结束监控
if (CopencvDemoDlg::closeFlag) break;

mfc | mfc集成opencv,实现监控、拍照、录像、录像播放(保姆级教程)_第32张图片
至此已经实现监控、关闭监控功能,至此点击运行项目,测试开启和关闭功能。

4.3 开启关闭BUG修复

尝试发现,当第一次关闭再打开后,只有摄像头再亮,视频不显示。原因是我们创建的picView窗体已被销毁。解决方案只需要确保我们每次打开的窗体名称不同即可,此时可以使用时间来命名窗口。

void CopencvDemoDlg::OnBnClickedOk()
{
	//获取当前时间日期  
	CTime m_time;
	m_time = CTime::GetCurrentTime();
	//通过格式化日期,构建View名称
	CString viewTime = m_time.Format(_T("%Y%m%d%H%M%Sview"));
	//将CString转换为string类型
	string viewTitleString = CT2A(viewTime.GetBuffer());
	//将string类型转为char*
	char* viewName = (char*)viewTitleString.data();

	//当用户点机实时监控,将closeFlag置为false
	CopencvDemoDlg::closeFlag = false;

	//将opencv的窗体嵌入到页面中
	cv::namedWindow(viewName, cv::WINDOW_AUTOSIZE);
	HWND hWnd = (HWND)cvGetWindowHandle(viewName);
	HWND hParent = ::GetParent(hWnd);
	::SetParent(hWnd, GetDlgItem(IDC_PIC)->m_hWnd);
	::ShowWindow(hParent, SW_HIDE);

	//1.从摄像头读入视频
	VideoCapture cap(0);
	//2.循环显示每一帧
	while (1)
	{
		Mat cam;
		cap >> cam;//获取当前帧图像
		imshow(viewName, cam);//显示当前帧图像

		//如果CloseFlag为true,跳出循环,结束监控
		if (CopencvDemoDlg::closeFlag) break;
		
		waitKey(30);//延时30秒
	}
}

mfc | mfc集成opencv,实现监控、拍照、录像、录像播放(保姆级教程)_第33张图片
至此开启监控、关闭监控功能开发完成。

4.4 拍照

回到资源视图,打开主对话框,双击拍照按钮,添加如下代码

void CopencvDemoDlg::OnBnClickedPhoto()
{
	// TODO: 在此添加控件通知处理程序代码
	takePhotoFlag = true;
}

双击实时监控按钮,添加如下代码
mfc | mfc集成opencv,实现监控、拍照、录像、录像播放(保姆级教程)_第34张图片

	//拍照
		if (takePhotoFlag)
		{
			//拍照状态重置
			takePhotoFlag = false;
			//生成并转换照片名称
			m_time = CTime::GetCurrentTime();             
			CString m_strDateTime = folerPath + m_time.Format(_T("%Y%m%d%H%M%S.jpg"));  
			string name = CT2A(m_strDateTime.GetBuffer());
			//将Mat数据写入文件
			bool res = imwrite(name, cam);	
		}

拍照功能至此完成,运行项目,点击实时监控后,点击拍照即可实现拍照。拍摄的照片可在C:\record目录下查看。

4.5 打开照片所在位置

回到资源视图,打开主对话框,双击打开照片所在位置按钮,添加如下代码

CreateDirectory(folerPath, NULL);
ShellExecute(NULL, NULL, folerPath, NULL, NULL, SW_SHOW);

4.6 录像

回到资源视图,打开主对话框,双击录像按钮,添加如下代码

//开启摄像头
	VideoCapture capture(0);
	// 获取视频参数
	int width = capture.get(CAP_PROP_FRAME_WIDTH);
	int height = capture.get(CAP_PROP_FRAME_HEIGHT);
	int count = capture.get(CAP_PROP_FRAME_COUNT);
	double fps = capture.get(CAP_PROP_FPS);

	//生成录制文件名
	CTime m_time;
	m_time = CTime::GetCurrentTime();
	CString videoNameCString = folerPath + m_time.Format(_T("%Y%m%d%H%M%S.avi")); //格式化日期时间
	string videoName = CT2A(videoNameCString.GetBuffer());

	//实例化VideoWriter对象
	VideoWriter writer(videoName, VideoWriter::fourcc('D', 'I', 'V', 'X'), 30, Size(width, height), true);

	//生成实时监控名
	Mat frame;
	CString viewNameCString = folerPath + m_time.Format(_T("%Y%m%d%H%M%SView"));
	string viewNameString = CT2A(viewNameCString.GetBuffer());
	//opencv嵌入到mfc中
	char* viewName = (char*)viewNameString.data();
	cv::namedWindow(viewName, cv::WINDOW_AUTOSIZE);
	HWND hWnd = (HWND)cvGetWindowHandle(viewName);
	HWND hParent = ::GetParent(hWnd);
	::SetParent(hWnd, GetDlgItem(IDC_PIC)->m_hWnd);
	::ShowWindow(hParent, SW_HIDE);

	//循环播放并录制
	while (true) {
		//读帧数据,显示数据
		capture.read(frame);
		flip(frame, frame, 1);
		if (frame.empty()) break;
		imshow(viewName, frame);
		//帧写入视频文件
		writer.write(frame);
		waitKey(30);
		if (recordFlag) break;
	}

	//重置录制状态
	recordFlag = false;
	//释放写视频对象
	writer.release();

4.7 结束录像

回到资源视图,打开主对话框,双击录像结束按钮,添加如下代码

recordFlag = true;

录像功能至此结束,运行项目,点击录像,等待一段时间,点击结束录像,录像完成。

4.8 播放视频

回到资源视图,打开主对话框,双击播放视频按钮,添加如下代码

	// 公共对话框结构。   
	OPENFILENAME ofn;
	// 保存获取文件名称的缓冲区。
	TCHAR szFile[MAX_PATH];
	// 初始化选择文件对话框。   
	ZeroMemory(&ofn, sizeof(OPENFILENAME));
	ofn.lStructSize = sizeof(OPENFILENAME);
	ofn.hwndOwner = NULL;
	ofn.lpstrFile = szFile;
	ofn.lpstrFile[0] = '\0';
	ofn.nMaxFile = sizeof(szFile);
	ofn.lpstrFilter = L"All(*.*)\0*.*\0Text(*.txt)\0*.AVI\0\0";
	ofn.nFilterIndex = 1;
	ofn.lpstrFileTitle = NULL;
	ofn.nMaxFileTitle = 0;
	ofn.lpstrInitialDir = NULL;
	ofn.Flags = OFN_PATHMUSTEXIST | OFN_FILEMUSTEXIST;
	//ofn.lpTemplateName =  MAKEINTRESOURCE(ID_TEMP_DIALOG);  
	// 显示打开选择文件对话框。   

	if (GetOpenFileName(&ofn))
	{
		//显示选择的文件。   
		OutputDebugString(szFile);
		playAVI(szFile);
	}

在函数外,添加PlayAVI的实现

void CopencvDemoDlg::playAVI(CString cfileName)
{
	CTime m_time;
	m_time = CTime::GetCurrentTime();             //获取当前时间日期  
	CString viewTime = m_time.Format(_T("%Y%m%d%H%M%Sview"));
	string viewNameString = CT2A(viewTime.GetBuffer());

	char* viewName = (char*)viewNameString.data();
	cv::namedWindow(viewName, cv::WINDOW_AUTOSIZE);
	HWND hWnd = (HWND)cvGetWindowHandle(viewName);
	HWND hParent = ::GetParent(hWnd);
	::SetParent(hWnd, GetDlgItem(IDC_PIC)->m_hWnd);
	::ShowWindow(hParent, SW_HIDE);

	string fileName = CT2A(cfileName.GetBuffer());
	VideoCapture capture(fileName);

	while (true) {
		Mat frame;
		Mat edge;
		capture >> frame;

		if (frame.empty())
			break;

		cvtColor(frame, edge, COLOR_BGR2GRAY);

		imshow(viewName, frame);

		//等待50ms,如果从键盘输入的是q、Q、或者是Esc键,则退出
		int key = waitKey(50);
		if (key == 'q' || key == 'Q' || key == 27)
			break;
	}
}

打开项目的头文件(opencvDemoDlg.h),添加PlayAVI的声明

void playAVI(CString cfileName);//播放avi视频

mfc | mfc集成opencv,实现监控、拍照、录像、录像播放(保姆级教程)_第35张图片
至此监控、拍照、录像、录像播放功能完成。

你可能感兴趣的:(C++,c++)