OpenCVMFC图片视频摄像头输入响应详细图解
Posted GraceSkyer
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了OpenCVMFC图片视频摄像头输入响应详细图解相关的知识,希望对你有一定的参考价值。
记住新建项目后,要配置OpenCV环境!参考链接http://blog.csdn.net/zy122121cs/article/details/49180541
做工程搭建框架什么的,基本的要熟练啊。
其中借鉴了ww老师的代码~
新建项目,命名:
点确定,然后,我习惯用基于对话框的:然后点击完成。
从工具箱拖几个控件出来: Combo Box组合框属性设置:
给图片随便命名个ID,再选择类型Frame:
如右图所示,框架就搭好了:
在Test01Dlg.h头文件中添加如下:
//包含Opencv库函数
#include <iostream>
#include <vector>
#include <io.h>
#include <direct.h>
#include <stdio.h>
#include <afxwin.h>
#include "opencv2/imgproc/imgproc.hpp"//图像处理函数基本模块,包括图像滤波、图像几何变换、色彩空间转换等
#include "opencv2/highgui/highgui.hpp"//视频捕捉,图像视频读取解码,图形交互
#include "afxwin.h"
using namespace std;
using namespace cv;
继续在这里加以下代码,定义枚举类型和私有变量:
private: //定义枚举类型 typedef enum {ememVIDEO_IN, emPICTURES_IN,emCAMERA_IN } READ_METHOD;//读入方式,图像0,分为相机1,视频2读入 typedef enum {emVIEWBEF, emVIEWAFT } SHOW_WINDOW;//读入窗口,0为第一个窗口,2为第二个窗口 //全局私有变量 VideoCapture cap_VidCam;//获取相机输入或者本地视频 cv::Mat m_frmBef;//原图像 int inputType;//选择的数据输入方式 int nImageWidth;//记录或设置的图像宽度 int nImageHeight;//记录或设置的图像高度 CString workDir;//图像初始默认文件夹
初始化部分BOOL CTest01Dlg::OnInitDialog():
1 BOOL CTest01Dlg::OnInitDialog() 2 { 3 CDialogEx::OnInitDialog(); 4 5 // 将“关于...”菜单项添加到系统菜单中。 6 7 // IDM_ABOUTBOX 必须在系统命令范围内。 8 ASSERT((IDM_ABOUTBOX & 0xFFF0) == IDM_ABOUTBOX); 9 ASSERT(IDM_ABOUTBOX < 0xF000); 10 11 CMenu* pSysMenu = GetSystemMenu(FALSE); 12 if (pSysMenu != NULL) 13 { 14 BOOL bNameValid; 15 CString strAboutMenu; 16 bNameValid = strAboutMenu.LoadString(IDS_ABOUTBOX); 17 ASSERT(bNameValid); 18 if (!strAboutMenu.IsEmpty()) 19 { 20 pSysMenu->AppendMenu(MF_SEPARATOR); 21 pSysMenu->AppendMenu(MF_STRING, IDM_ABOUTBOX, strAboutMenu); 22 } 23 } 24 25 // 设置此对话框的图标。当应用程序主窗口不是对话框时,框架将自动 26 // 执行此操作 27 SetIcon(m_hIcon, TRUE); // 设置大图标 28 SetIcon(m_hIcon, FALSE); // 设置小图标 29 30 // TODO: 在此添加额外的初始化代码 31 32 //初始化视频数据读入方法 33 com_InputStyle.SetCurSel(1); 34 inputType=emPICTURES_IN; 35 36 //将OpenCV中的窗口显示在MFC中 37 namedWindow("emVIEWBEF", WINDOW_AUTOSIZE); 38 HWND hWnd = (HWND) cvGetWindowHandle("emVIEWBEF"); 39 HWND hParent = ::GetParent(hWnd); 40 ::SetParent(hWnd, GetDlgItem(IDC_FRMBEF)->m_hWnd); 41 ::ShowWindow(hParent, SW_HIDE); 42 43 UpdateData( FALSE );//更新界面控件 44 45 //将OpenCV中的窗口显示在MFC中 46 workDir = F_InitWorkDir();//判断Imgs及SaveFrame文件夹是否存在,不存在创建(ww) 47 48 //初始化图像显示控件的图像 49 CRect rect; 50 GetDlgItem(IDC_FRMBEF) ->GetClientRect( &rect ); 51 m_frmBef = Mat::zeros(rect.Height(), rect.Width(), CV_8UC3); 52 53 return TRUE; // 除非将焦点设置到控件,否则返回 TRUE 54 }
void CTest01Dlg::OnPaint()部分:
1 void CTest01Dlg::OnPaint() 2 { 3 if (IsIconic()) 4 { 5 CPaintDC dc(this); // 用于绘制的设备上下文 6 7 SendMessage(WM_ICONERASEBKGND, reinterpret_cast<WPARAM>(dc.GetSafeHdc()), 0); 8 9 // 使图标在工作区矩形中居中 10 int cxIcon = GetSystemMetrics(SM_CXICON); 11 int cyIcon = GetSystemMetrics(SM_CYICON); 12 CRect rect; 13 GetClientRect(&rect); 14 int x = (rect.Width() - cxIcon + 1) / 2; 15 int y = (rect.Height() - cyIcon + 1) / 2; 16 17 // 绘制图标 18 dc.DrawIcon(x, y, m_hIcon); 19 } 20 else 21 { 22 CDialogEx::OnPaint(); 23 24 CDialog::UpdateWindow(); // 更新windows窗口,如果无这步调用,图片显示还会出现问题 25 if (!m_frmBef.empty()) 26 { 27 F_ShowImage(emVIEWBEF,m_frmBef); // 重绘图片函数 28 } 29 } 30 }
单击combo box组合框右键,给图像输入方式下拉框关联变量:
然后,给变量命个名:
单击组合框右键,选择“添加事件处理程序”
给函数命名:
然后编辑该函数,加一行代码:
类似的给“选择”按钮添加函数,代码如下:
1 // 根据选择不同,分别做摄像头输入,视频输入,本地图像组输入背景建模处理 2 void CTest01Dlg::OnBnChoosePicture() 3 { 4 // TODO: 在此添加控件通知处理程序代码 5 if (inputType==emPICTURES_IN)//(1)如选择图像输入 6 { 7 StopCam();//停止相机工作 8 string frmPath; 9 frmPath = DoSelectFiles( 10 _T("*.bmp"), 11 OFN_ENABLESIZING |OFN_EXPLORER | OFN_ALLOWMULTISELECT | OFN_HIDEREADONLY, 12 _T("image files (*.bmp; *.png; *.jpg) |*.bmp; *.png; *.jpg; *.jpeg| All Files (*.*) |*.*||"), 13 _T("选择图像序列"), 14 workDir+"\\Imgs"); 15 m_frmBef=cv::imread(frmPath);//读取图像 16 F_ShowImage(emVIEWBEF,m_frmBef); 17 } 18 else if(inputType==emCAMERA_IN)//(2)如选择视频输入 19 { 20 //摄像头输入,设置摄像头显示分辨率 21 nImageWidth = 640; 22 nImageHeight = 480; 23 //打开第一个摄像头 24 if ( !cap_VidCam.open(0) ) 25 { 26 AfxMessageBox(_T("打开摄像头失败!")); 27 return; 28 } 29 cap_VidCam.set(CV_CAP_PROP_FRAME_WIDTH, nImageWidth); //cv设置视频流的帧宽度(只对摄像头有效) 30 cap_VidCam.set(CV_CAP_PROP_FRAME_HEIGHT, nImageHeight);//cv设置视频流的帧高度(只对摄像头有效) 31 // 启动摄像头后显示实时画面 32 SetTimer(1, 10, NULL); // 10ms 定时显示 33 while(1) { 34 cap_VidCam >> m_frmBef; 35 if(m_frmBef.empty()) break; 36 F_ShowImage(emVIEWBEF,m_frmBef); 37 if(waitKey(20)>0)break; 38 } 39 cap_VidCam.release(); 40 } 41 else//(3)如选择视频输入 42 { 43 CStringA videoFiles;//存储文件的名字 44 StopCam();//停止相机工作 45 videoFiles = DoSelectFiles( 46 _T("*.avi"), 47 OFN_ENABLESIZING |OFN_EXPLORER | OFN_ALLOWMULTISELECT | OFN_HIDEREADONLY, 48 _T("video files (*.avi) |*.avi| All Files (*.*) |*.*||"), 49 _T("选择视频文件"), 50 workDir+"\\Videos"); 51 cap_VidCam.open(LPCSTR(videoFiles));//打开文件 52 SetTimer(1, 10, NULL); // 10ms 定时显示 53 while(1) { 54 cap_VidCam >> m_frmBef; 55 if(m_frmBef.empty()) break; 56 F_ShowImage(emVIEWBEF,m_frmBef); 57 if(waitKey(20)>0)break; 58 } 59 cap_VidCam.release(); 60 } 61 }
继续在下面添加 关闭摄像头部分 代码:
1 //关闭摄像头 2 void CTest01Dlg::StopCam() 3 { 4 if (cap_VidCam.isOpened()) 5 { 6 KillTimer(1);//该函数移除先前用SetTimer设置的定时器,在定时器使用完毕后移除定时器时使用 7 // 对图像数据清零 8 m_frmBef = Scalar(0); 9 cap_VidCam.release();//释放VideoCapture对象 10 } 11 }
打开文件对话框相关代码:
1 //弹出打开文件对话框,选择单个文件,并可以限制文件类型 2 CStringA CTest01Dlg::DoSelectFiles( 3 LPCTSTR lpszDefExt, 4 DWORD dwFlags, 5 LPCTSTR lpszFilter, 6 LPCSTR lpstrTitle, 7 LPCSTR lpstrInitialDir ) 8 { 9 CStringA selectedFile; 10 POSITION filePosition; 11 12 CFileDialog dlg( TRUE, lpszDefExt, NULL, dwFlags, lpszFilter, NULL ); 13 dlg.m_ofn.lpstrFile[0] = NULL; 14 dlg.m_ofn.lpstrTitle = lpstrTitle; 15 dlg.m_ofn.lpstrInitialDir = lpstrInitialDir; 16 17 if( dlg.DoModal() == IDOK ) 18 { 19 selectedFile = dlg.GetPathName(); 20 } 21 return selectedFile; 22 } 23 //初始化(创建)程序运行所需的文件夹 24 CString CTest01Dlg::F_InitWorkDir() 25 { 26 CStringA strPath; 27 TCHAR path[_MAX_PATH]; 28 TCHAR drive[_MAX_DRIVE]; 29 TCHAR dir[_MAX_DIR]; 30 TCHAR fname[_MAX_FNAME]; 31 TCHAR ext[_MAX_EXT]; 32 ::GetModuleFileName(AfxGetApp()->m_hInstance, path, _MAX_PATH); 33 _tsplitpath(path, drive, dir, fname, ext); 34 35 strPath.Empty(); 36 strPath += CString(drive); 37 strPath += CString(dir); 38 39 string saveDir = strPath; 40 saveDir += "/Imgs"; 41 F_CheckDir(saveDir, true); 42 saveDir = strPath; 43 saveDir += "/Videos"; 44 F_CheckDir(saveDir, true); 45 saveDir = strPath; 46 saveDir += "/SaveFrame"; 47 F_CheckDir(saveDir, true); 48 49 return CString(strPath); 50 } 51 //检查文件夹是否存在 52 bool CTest01Dlg::F_CheckDir(const string dir, bool creatDir /* = false */) 53 { 54 bool RetVal = false; 55 56 string fileName = dir; 57 fileName += "\\\\*"; 58 59 _finddata_t FileInfo; 60 long Handle = _findfirst(fileName.c_str(), &FileInfo); 61 62 if (Handle == -1L) 63 { 64 if (creatDir) 65 { 66 if(_mkdir(dir.c_str())==0) 67 { 68 RetVal = true; 69 } 70 } 71 } 72 else 73 { 74 RetVal = true; 75 _findclose(Handle); 76 } 77 return RetVal; 78 }
显示图像部分 代码:
1 //显示图像,将要绘制的图像 src 复制到 des,然后绘制到控件号为 ID 的 Picture 控件 2 void CTest01Dlg::F_ShowImage(int type,Mat& src) 3 { 4 cv::Mat m_dst; 5 CRect rect; 6 GetDlgItem(IDC_FRMBEF)->GetClientRect(&rect); 7 cv::Rect dst(rect.left,rect.top,rect.right,rect.bottom); 8 cv::resize(src,m_dst,cv::Size(rect.Width(),rect.Height())); 9 if (type==emVIEWBEF) 10 { 11 imshow("emVIEWBEF", m_dst); 12 } 13 }
然后别忘了给“保存图片”按钮 添加响应函数:
1 void CTest01Dlg::OnBnClickedSaveImage() 2 { 3 //定义可以保存的图像类型后缀名 4 CString csBMP="BMP Files(*.BMP)|*.BMP|"; 5 CString csJPG="JPG Files(*.JPG)|*.JPG|"; 6 CString csTIF="TIF Files(*.TIF)|*.TIF|"; 7 CString csPNG="PNG Files(*.PNG)|*.PNG|"; 8 CString csDIB="DIB Files(*.DIB)|*.DIB|"; 9 CString csPBM="PBM Files(*.PBM)|*.PBM|"; 10 CString csPGM="PGM Files(*.PGM)|*.PGM|"; 11 CString csPPM="PPM Files(*.PPM)|*.PPM|"; 12 CString csSR ="SR Files(*.SR) |*.SR|"; 13 CString csRAS="RAS Files(*.RAS)|*.RAS||"; 14 15 CString csFilter=csBMP+csJPG+csTIF+csPNG+csDIB 16 +csPBM+csPGM+csPPM+csSR+csRAS; 17 18 CString name[]={"","bmp","jpg","tif","png","dib", 19 "pbm","pgm","ppm","sr", "ras",""}; 20 21 CString strFileName; 22 CString strExtension; 23 24 CString defaultDir = workDir+"\\SaveFrame"; //默认打开的文件路径 25 CString fileName = "new.bmp"; //默认保存的文件名 26 27 CFileDialog openFileDlg(false,".bmp", fileName, OFN_HIDEREADONLY|OFN_OVERWRITEPROMPT, csFilter, NULL); 28 openFileDlg.m_ofn.lpstrInitialDir=defaultDir;//初始化路径 29 // 文件存盘对话框 30 if (openFileDlg.DoModal()==IDOK ) // 输入了文件名 31 { 32 strFileName = openFileDlg.m_ofn.lpstrFile; 33 if (openFileDlg.m_ofn.nFileExtension == 0) // 无文件后缀 34 { 35 strExtension = name[openFileDlg.m_ofn.nFilterIndex]; 36 strFileName = strFileName + \'.\' + strExtension; 37 // 加文件后缀 38 } 39 40 string s(strFileName.GetBuffer()); 41 imwrite(s,m_frmBef); // 当前画面存盘 42 } 43 }
给“关闭”按钮添加响应函数:
1 void CTest01Dlg::OnBnClickedOk() 2 { 3 // TODO: 在此添加控件通知处理程序代码 4 StopCam();//停止相机工作 5 CDialogEx::OnOK(); 6 }
注:以上代码均加在Test01Dlg.cpp中(Test01换成你自己命名的项目名)
然后这个简单的框架就搭好啦! ^-^
以上是关于OpenCVMFC图片视频摄像头输入响应详细图解的主要内容,如果未能解决你的问题,请参考以下文章
Python+OpenCV4:读写输入和输出的简单实践(图片视频摄像头)
OpenCV+visual studio 2019 实现对avi视频或摄像头 laplace边缘检测。从AVI文件( bsd.avi)中得到视频流,对视频流进行Laplace边缘检测,并输出结果。(代