MFC中利用Opencv与C++抓取摄像头进行人脸识别(Mat)

2023-06-28,,

原文:http://blog.csdn.net/mr_curry/article/details/51098311

第一次写博客哈哈,有些小激动,还请各位大神多多包涵~ 
最近的项目需要用到人脸识别,作为一个车辆工程的二年级本科生是崩溃的(一是没有很好的编程基础,只会编一下C与C#;二是…我是车辆工程的啊喂…) 
不过自己还是对计算机视觉这方面还是很感兴趣的,因为做竞赛的缘由,以前多多少少有一点小基础,但要完全做出来还是感觉有些难度。调了一段时间的代码,嘿嘿实现了。这个里面有两点有些“与众不同”(自认为)1.我用Mat代替了IplImage;2.将其用MFC进行表达。(废话少说)接下来贴程序…… 
先说一下我的版本,我是用的VS2013与Opencv2.4.9。首先我们需要在VS中新建一个MFC的框架。

 
 
 
然后点击完成就可以了。接下来我们需要在窗口里面拉几个控件。一个picture control、一个button控件,一个Static Text控件。下面其实是我后来又想做人脸匹配,加了一些功能(好吧我并不会做)。 

修改ID:picture control——–face_picture; 
button——————StartWatch; 
Static Text————-TIME_NEW; 
把我的ID贴出来,方便大家理解。然后就是要为Static Text添加变量,刚开始以为这个和C#的框架差不多,可以直接用什么”label.Text=”,后来才知道先要添加变量,一通乱搞,还翻了书,晕死。 
 
 
 
如图,增添这个我是主要想显示人脸识别的函数运行速度如何,是多少秒。接下来我们双击button控件,进入代码页。 
代码如下:首先是一个你需要引用的头文件:


#include "stdafx.h"
#include "人脸识别与特征匹配.h"
#include "人脸识别与特征匹配Dlg.h"
#include "afxdialogex.h"
#ifdef _DEBUG
#define new DEBUG_NEW
#endif
#include "opencv2/objdetect/objdetect.hpp"
#include "opencv2/highgui/highgui.hpp"
#include "opencv2/imgproc/imgproc.hpp"
#include <iostream>
#include <stdio.h>

1
2
3
4
5
6
7
8
9
10
11
12
13
14
1
2
3
4
5
6
7
8
9
10
11
12
13
14

第二步:

using namespace std;
using namespace cv;

1
2
1
2

然后我们先声明“detectAndDisplay”函数,这里我是用Mat类进行实现,没有用IplImage什么指针的进行实现,一句话,不会管理内存。而后的 haarcascade_frontalface_alt.xml、haarcascade_eye_tree_eyeglasses.xml这两个级联分类器(我也不知道这玩意是不是这么叫的)可以在OpenCV的文件夹里面找到,我是把他们移到了桌面上。

// 用于应用程序“关于”菜单项的 CAboutDlg 对话框
void detectAndDisplay(Mat frame);//声明函数
String face_cascade_name = "C:\\Users\\strstr\\Desktop\\haarcascade_frontalface_alt.xml";//人脸的训练数据
String eyes_cascade_name = "C:\\Users\\strstr\\Desktop\\haarcascade_eye_tree_eyeglasses.xml";//人眼的训练数据
CascadeClassifier face_cascade;
CascadeClassifier eyes_cascade;
string window_name = "人脸识别与检测";
RNG rng(12345);
Mat Allframe;//用于点击button存储照片,同学们可以无视

1
2
3
4
5
6
7
8
9
1
2
3
4
5
6
7
8
9

接下来,我将一路贴代码。有一些是MFC预留的,关键的是button里面的内容和detectAndDisplay函数。

class CAboutDlg : public CDialogEx
{ public:
CAboutDlg(); // 对话框数据
enum { IDD = IDD_ABOUTBOX }; protected:
virtual void DoDataExchange(CDataExchange* pDX); // DDX/DDV 支持 // 实现
protected:
DECLARE_MESSAGE_MAP()
}; CAboutDlg::CAboutDlg() : CDialogEx(CAboutDlg::IDD)
{
} void CAboutDlg::DoDataExchange(CDataExchange* pDX)
{
CDialogEx::DoDataExchange(pDX);
} BEGIN_MESSAGE_MAP(CAboutDlg, CDialogEx)
END_MESSAGE_MAP() // C人脸识别与特征匹配Dlg 对话框 C人脸识别与特征匹配Dlg::C人脸识别与特征匹配Dlg(CWnd* pParent /*=NULL*/)
: CDialogEx(C人脸识别与特征匹配Dlg::IDD, pParent)
, face_time(_T(""))
, face_name(_T(""))
, face_no_name(_T(""))
, face_time_new(0)
{
m_hIcon = AfxGetApp()->LoadIcon(IDR_MAINFRAME);
} void C人脸识别与特征匹配Dlg::DoDataExchange(CDataExchange* pDX)
{
CDialogEx::DoDataExchange(pDX);
DDX_Text(pDX, TIME, face_time);
DDX_Text(pDX, Result, face_name);
DDX_Text(pDX, THEname, face_no_name);
DDX_Text(pDX, TIME_NEW, face_time_new);
} BEGIN_MESSAGE_MAP(C人脸识别与特征匹配Dlg, CDialogEx)
ON_WM_SYSCOMMAND()
ON_WM_PAINT()
ON_WM_QUERYDRAGICON()
ON_BN_CLICKED(StartWatch, &C人脸识别与特征匹配Dlg::OnBnClickedStartwatch)
ON_BN_CLICKED(face_read, &C人脸识别与特征匹配Dlg::OnBnClickedread) ON_BN_CLICKED(face_openvideo, &C人脸识别与特征匹配Dlg::OnBnClickedopenvideo)
ON_BN_CLICKED(Save, &C人脸识别与特征匹配Dlg::OnBnClickedSave)
END_MESSAGE_MAP() // C人脸识别与特征匹配Dlg 消息处理程序 BOOL C人脸识别与特征匹配Dlg::OnInitDialog()
{
CDialogEx::OnInitDialog(); // 将“关于...”菜单项添加到系统菜单中。 // IDM_ABOUTBOX 必须在系统命令范围内。
ASSERT((IDM_ABOUTBOX & 0xFFF0) == IDM_ABOUTBOX);
ASSERT(IDM_ABOUTBOX < 0xF000); CMenu* pSysMenu = GetSystemMenu(FALSE);
if (pSysMenu != NULL)
{
BOOL bNameValid;
CString strAboutMenu;
bNameValid = strAboutMenu.LoadString(IDS_ABOUTBOX);
ASSERT(bNameValid);
if (!strAboutMenu.IsEmpty())
{
pSysMenu->AppendMenu(MF_SEPARATOR);
pSysMenu->AppendMenu(MF_STRING, IDM_ABOUTBOX, strAboutMenu);
}
} // 设置此对话框的图标。 当应用程序主窗口不是对话框时,框架将自动
// 执行此操作
SetIcon(m_hIcon, TRUE); // 设置大图标
SetIcon(m_hIcon, FALSE); // 设置小图标 // TODO: 在此添加额外的初始化代码 return TRUE; // 除非将焦点设置到控件,否则返回 TRUE
} void C人脸识别与特征匹配Dlg::OnSysCommand(UINT nID, LPARAM lParam)
{
if ((nID & 0xFFF0) == IDM_ABOUTBOX)
{
CAboutDlg dlgAbout;
dlgAbout.DoModal();
}
else
{
CDialogEx::OnSysCommand(nID, lParam);
}
} // 如果向对话框添加最小化按钮,则需要下面的代码
// 来绘制该图标。 对于使用文档/视图模型的 MFC 应用程序,
// 这将由框架自动完成。 void C人脸识别与特征匹配Dlg::OnPaint()
{
if (IsIconic())
{
CPaintDC dc(this); // 用于绘制的设备上下文 SendMessage(WM_ICONERASEBKGND, reinterpret_cast<WPARAM>(dc.GetSafeHdc()), 0); // 使图标在工作区矩形中居中
int cxIcon = GetSystemMetrics(SM_CXICON);
int cyIcon = GetSystemMetrics(SM_CYICON);
CRect rect;
GetClientRect(&rect);
int x = (rect.Width() - cxIcon + 1) / 2;
int y = (rect.Height() - cyIcon + 1) / 2; // 绘制图标
dc.DrawIcon(x, y, m_hIcon);
}
else
{
CDialogEx::OnPaint();
}
} //当用户拖动最小化窗口时系统调用此函数取得光标
//显示。
HCURSOR C人脸识别与特征匹配Dlg::OnQueryDragIcon()
{
return static_cast<HCURSOR>(m_hIcon);
}

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151

以下是Button里的代码:

void C人脸识别与特征匹配Dlg::OnBnClickedStartwatch()
{
face_time = "秒";
double t = 0;
double facelook_time = 0;//用于计算函数运行时间
VideoCapture capture(1);//捕获外部摄像头
Mat frame,newframe;//建立两个Mat,一个用来显示视频,另一个给全局里的Allframe
namedWindow("view", WINDOW_AUTOSIZE);
HWND hWnd = (HWND)cvGetWindowHandle("view");
HWND hParent = ::GetParent(hWnd);
::SetParent(hWnd, GetDlgItem(face_picture)->m_hWnd);
::ShowWindow(hParent, SW_HIDE);//隐藏运行程序框,并且把它“画”到MFC上
if (!face_cascade.load(face_cascade_name)){ printf("--(!)Error loading\n");};
if (!eyes_cascade.load(eyes_cascade_name)){ printf("--(!)Error loading\n");};//加载分类器的
if (capture.isOpened())
{
for (;;)//循环以达到视频的效果
{
capture >> frame;
capture >> newframe;
Allframe = newframe;
if (!frame.empty())
{ t = (double)cvGetTickCount();
detectAndDisplay(frame);//识别的函数
t = (double)cvGetTickCount() - t;//用来计算算法执行时间
facelook_time = t / 1000 / ((double)cvGetTickFrequency()*1000.);//检测时间
face_time_new = facelook_time;//输出到static text中
imshow("view", frame);
UpdateData(FALSE);
}
else
{
printf(" --(!) No captured frame -- Break!"); break;
} waitKey(10);
} }
}
void detectAndDisplay(Mat frame)//识别人脸函数
{
std::vector<Rect> faces;
Mat frame_gray;
cvtColor(frame, frame_gray, COLOR_BGR2GRAY);//转换成灰度图像
equalizeHist(frame_gray, frame_gray);//直方图均衡化
//1.1表示每次图像尺寸减小的比例为1.1,2表示每一个目标至少要被检测到3次才算是真的目标(因为周围的像素和不同的窗口大小都可以检测到人脸),CV_HAAR_SCALE_IMAGE表示不是缩放分类器来检测,而是缩放图像,Size(30, 30)为目标的最小最大尺寸
face_cascade.detectMultiScale(frame_gray, faces, 1.1, 2, 0 | CV_HAAR_SCALE_IMAGE, Size(30, 30)); for (size_t i = 0; i < faces.size(); i++)
{
Point center(faces[i].x + faces[i].width / 2, faces[i].y + faces[i].height / 2);
ellipse(frame, center, Size(faces[i].width / 2, faces[i].height / 2), 0, 0, 360, Scalar(255, 0, 255), 2, 8, 0);//画椭圆 Mat faceROI = frame_gray(faces[i]);
std::vector<Rect> eyes; //-- In each face, detect eyes
eyes_cascade.detectMultiScale(faceROI, eyes, 1.1, 2, 0 | CV_HAAR_SCALE_IMAGE, Size(30, 30)); for (size_t j = 0; j < eyes.size(); j++)//检测眼睛
{
Point eye_center(faces[i].x + eyes[j].x + eyes[j].width / 2, faces[i].y + eyes[j].y + eyes[j].height / 2);
int radius = cvRound((eyes[j].width + eyes[j].height)*0.25);
circle(frame, eye_center, radius, Scalar(255, 0, 0), 3, 8, 0);
}
}
}

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70

好了,贴一张运行成功的截图,怕丑到各位,打了些马赛克:

MFC中利用Opencv与C++抓取摄像头进行人脸识别(Mat)的相关教程结束。

《MFC中利用Opencv与C++抓取摄像头进行人脸识别(Mat).doc》

下载本文的Word格式文档,以方便收藏与打印。