OpenCV实现人脸检测

2025-05-27 0 64

前段日子,写了个人脸检测的小程序,可以检测标记图片、视频、摄像头中的人脸。效果还行吧,用的是opencv提供人脸库。至于具体的人脸检测原理,找资料去啃吧。

环境:VS2013+OPENCV2.4.10+Win8.1

OpenCV实现人脸检测

一、基于对话框的MFC

首先,新建一个基于对话框的MFC应用程序,命名为myFaceDetect(取消“安全开发周期(SDL)检查”勾选,我自己习惯取消这个)。

OpenCV实现人脸检测

放置Button,设置Button的ID和Caption。
图片按钮——ID:IDC_FACEDETECT
视频按钮——ID:IDC_FACEV
摄像头按钮——ID:IDC_FACEC

二、添加消息响应函数

为图片按钮、视频按钮、摄像头按钮,在类向导中添加消息响应函数。
在图片按钮上右键,选择类向导。在CMyFaceDetectDlg类(对话框类)下选中BN_CLICKED消息,点击添加处理程序。其余两个按钮,按同样操作,添加消息响应函数。
完成上述操作后,获得对应三个按钮的消息响应函数。

OpenCV实现人脸检测
OpenCV实现人脸检测

?

1

2

3
void CMyFaceDetectDlg::OnClickedFacedetect()//图片按钮

void CMyFaceDetectDlg::OnClickedFacev()//视频按钮

void CMyFaceDetectDlg::OnClickedFacec()//摄像头按钮

三、人脸检测实现

首先,将OpenCV2.4.10+VS2013环境的配置完成,这个网上有许多教程。这是我以前写的一篇配置教程:Visual Studio 2013+OpenCV2.4.10环境搭建教程

对话框类的头文件:MyFaceDetectDlg.h

?

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
// MyFaceDetectDlg.h : 头文件

//

#pragma once

#include <opencv2/objdetect/objdetect.hpp>

#include <opencv2\\highgui\\highgui.hpp>

#include <opencv2\\ml\\ml.hpp>

#include <opencv.hpp>

#include "afxwin.h"

using namespace cv;

// CMyFaceDetectDlg 对话框

class CMyFaceDetectDlg : public CDialogEx

{

// 构造

public:

CMyFaceDetectDlg(CWnd* pParent = NULL); // 标准构造函数

// 对话框数据

enum { IDD = IDD_MYFACEDETECT_DIALOG };

protected:

virtual void DoDataExchange(CDataExchange* pDX); // DDX/DDV 支持

// 实现

protected:

HICON m_hIcon;

HICON m_catIcon;//程序的小猫图标。如果想用默认的图片,可以将其注释掉。

// 生成的消息映射函数

virtual BOOL OnInitDialog();

afx_msg void OnPaint();

afx_msg HCURSOR OnQueryDragIcon();

DECLARE_MESSAGE_MAP()

public:

afx_msg void OnClickedFacedetect();

public:

CascadeClassifier cascade;//级联分类器

Mat image;//图片

double scale;//缩小比例。缩小图片可以加快检测速度,当然加快检测速度还有其他的方法。

public:

void detectAndDraw(Mat& img, CascadeClassifier& cascade, double scale);//添加的实现人脸检测的函数,核心函数

CButton m_btn;//为了美化按钮添加对象,可以注释掉。

afx_msg void OnClickedFacev();

afx_msg void OnClickedFacec();

afx_msg void OnBnClickedCancel();

};

对话框类的实现:MyFaceDetectDlg.cpp

?

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

152

153

154

155

156

157

158

159

160

161

162

163

164

165

166

167

168

169

170

171

172

173

174

175

176

177

178

179

180

181

182

183

184

185

186

187

188

189

190

191

192

193

194

195

196

197

198

199

200

201

202

203

204

205

206

207

208

209

210

211

212

213

214

215

216

217

218

219

220

221

222

223

224

225

226

227

228

229

230

231

232

233

234

235

236

237

238

239

240

241

242

243

244

245

246

247

248

249

250

251

252

253

254

255
// MyFaceDetectDlg.cpp : 实现文件

//

#include "stdafx.h"

#include "MyFaceDetect.h"

#include "MyFaceDetectDlg.h"

#include "afxdialogex.h"

#include <string>

#ifdef _DEBUG

#define new DEBUG_NEW

#endif

// CMyFaceDetectDlg 对话框

CMyFaceDetectDlg::CMyFaceDetectDlg(CWnd* pParent /*=NULL*/)

: CDialogEx(CMyFaceDetectDlg::IDD, pParent)

{

m_hIcon = AfxGetApp()->LoadIcon(IDR_MAINFRAME);

m_catIcon = AfxGetApp()->LoadIcon(IDI_ICON4);//加载自己的图标(小猫~)

scale = 1.3;

}

void CMyFaceDetectDlg::DoDataExchange(CDataExchange* pDX)

{

CDialogEx::DoDataExchange(pDX);

DDX_Control(pDX, IDC_FACEDETECT, m_btn);

}

BEGIN_MESSAGE_MAP(CMyFaceDetectDlg, CDialogEx)

ON_WM_PAINT()

ON_WM_QUERYDRAGICON()

ON_BN_CLICKED(IDC_FACEDETECT, &CMyFaceDetectDlg::OnClickedFacedetect)

ON_BN_CLICKED(IDC_FACEV, &CMyFaceDetectDlg::OnClickedFacev)

ON_BN_CLICKED(IDC_FACEC, &CMyFaceDetectDlg::OnClickedFacec)

ON_BN_CLICKED(IDCANCEL, &CMyFaceDetectDlg::OnBnClickedCancel)

END_MESSAGE_MAP()

// CMyFaceDetectDlg 消息处理程序

BOOL CMyFaceDetectDlg::OnInitDialog()

{

CDialogEx::OnInitDialog();

// 设置此对话框的图标。 当应用程序主窗口不是对话框时,框架将自动

// 执行此操作

//若不需要自己设置图标,可以将后面所有m_catIcon改成m_hIcon

SetIcon(m_catIcon, TRUE); // 设置大图标。

SetIcon(m_catIcon, FALSE); // 设置小图标

//按钮加载图片背景

//HBITMAP hbmp1 = ::LoadBitmap(AfxGetInstanceHandle(), MAKEINTRESOURCE(IDB_BITMAP2));

//m_btn.SetBitmap(hbmp1);

// TODO: 在此添加额外的初始化代码

return TRUE; // 除非将焦点设置到控件,否则返回 TRUE

}

// 如果向对话框添加最小化按钮,则需要下面的代码

// 来绘制该图标。 对于使用文档/视图模型的 MFC 应用程序,

// 这将由框架自动完成。

void CMyFaceDetectDlg::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_catIcon);

}

else

{

/*改变对话框背景****若需要默认背景,可以删除*/

CPaintDC dc(this);

CRect rect;

GetClientRect(&rect);

CDC dcBmp;

dcBmp.CreateCompatibleDC(&dc);

CBitmap bmpBackGround;

bmpBackGround.LoadBitmap(IDB_BITMAP4);

BITMAP m_bitmap;

bmpBackGround.GetBitmap(&m_bitmap);

CBitmap *pbmpOld = dcBmp.SelectObject(&bmpBackGround);

dc.StretchBlt(0, 0, rect.Width(), rect.Height(), &dcBmp, 0, 0, m_bitmap.bmWidth, m_bitmap.bmHeight, SRCCOPY);

/*********************************/

CDialogEx::OnPaint();

}

}

//当用户拖动最小化窗口时系统调用此函数取得光标

//显示。

HCURSOR CMyFaceDetectDlg::OnQueryDragIcon()

{

return static_cast<HCURSOR>(m_catIcon);

}

void CMyFaceDetectDlg::OnClickedFacedetect()

{

// TODO: 在此添加控件通知处理程序代码

CString filename;

//打开对话框

CFileDialog OpenDlg(TRUE, NULL, NULL, OFN_HIDEREADONLY | OFN_OVERWRITEPROMPT | OFN_NOCHANGEDIR,

_T("图片 (*.jpg)|*.jpg|(*.*) |*.*|"), NULL);

if (OpenDlg.DoModal() != IDOK)

{

return;

}

filename = OpenDlg.GetPathName();//获得文件路径

/*CString转换*string*/

USES_CONVERSION;

std::string tempName(W2A(filename));

image = imread(tempName);//读取图片

const String cascade_name = "./haarcascade_frontalface_alt2.xml";//加载人脸库

if (!cascade.load(cascade_name))

{

MessageBox(_T("ERROR:Could not load cascade!"));

return;

}

if (!image.data)

{

MessageBox(_T("ERROR:Could not load image!"));

return;

}

namedWindow("人脸检测", CV_WINDOW_AUTOSIZE);

detectAndDraw(image, cascade, scale);//调用人脸检测函数

imshow("人脸检测", image);

return;

}

void CMyFaceDetectDlg::detectAndDraw(Mat& img, CascadeClassifier& cascade, double scale)

{

/*程序核心函数,检测标记人脸*/

int i = 0;

vector<Rect>faces;//定义一个容器,保存检测结果

const static Scalar colors[] = {

CV_RGB(0, 0, 255),

CV_RGB(0, 128, 255),

CV_RGB(0, 255, 255),

CV_RGB(0, 255, 0),

CV_RGB(255, 128, 0),

CV_RGB(255, 255, 0),

CV_RGB(255, 0, 0),

CV_RGB(255, 0, 255)

};

Mat gray, smallImage(cvRound(img.rows / scale), cvRound(img.cols / scale), CV_8UC1);//用cvRound取整

cvtColor(img, gray, CV_BGR2GRAY);//转化灰度图

resize(gray, smallImage, smallImage.size(), 0, 0, INTER_LINEAR);//图片尺度调整

equalizeHist(smallImage, smallImage);//直方图均衡

cascade.detectMultiScale(smallImage, faces);//核心,检测人脸

for (vector<Rect>::const_iterator r = faces.begin(); r != faces.end(); r++, i++)

{

//利用迭代器,标记出人脸位置。

Point center;

Scalar color = colors[i % 8];

int radius;

/*计算出原图像中的圆心和半径。公式很简单,自己写一下,就可以理解了*/

center.x = cvRound((r->x + r->width*0.5)*scale);

center.y = cvRound((r->y + r->height*0.5)*scale);

radius = cvRound((r->width + r->height)*0.25*scale);

/****************/

circle(img, center, radius, color, 3);

}

}

void CMyFaceDetectDlg::OnClickedFacev()

{

// TODO: 在此添加控件通知处理程序代码

//检测视频帧中的人脸

CString filename;

CFileDialog OpenDlg(TRUE, NULL, NULL, OFN_HIDEREADONLY | OFN_OVERWRITEPROMPT | OFN_NOCHANGEDIR,

_T("视频(*.avi)|*.avi|(*.*)|*.*|"), NULL);

if (OpenDlg.DoModal() != IDOK)

{

return;

}

/*CString转换*string*/

filename = OpenDlg.GetPathName();

USES_CONVERSION;

std::string tempName(W2A(filename));

const String cascade_name = "./haarcascade_frontalface_alt2.xml";

if (!cascade.load(cascade_name))

{

MessageBox(_T("ERROR:Could not load cascade!"));

return;

}

VideoCapture capture(tempName);//打开视频

if (!capture.isOpened())

{

MessageBox(_T("ERROR:Could not load Video!"));

return;

}

double rate = capture.get(CV_CAP_PROP_FPS);

bool stop(false);

int delay = 1000 / rate;

while (!stop)

{

if (!capture.read(image))//读取视频帧

break;

detectAndDraw(image, cascade, scale);

imshow("人脸检测", image);

if (waitKey(delay) >= 0)

stop = true;

}

capture.release();

return;

}

void CMyFaceDetectDlg::OnClickedFacec()

{

// TODO: 在此添加控件通知处理程序代码

//检测摄像头中的人脸数据

const String cascade_name = "./haarcascade_frontalface_alt2.xml";

if (!cascade.load(cascade_name))

{

MessageBox(_T("ERROR:Could not load cascade!"));

return;

}

VideoCapture capture(0);//打开摄像头

if (!capture.isOpened())

{

MessageBox(_T("ERROR:Could not load capture!"));

return;

}

//double rate = capture.get(CV_CAP_PROP_FPS);

//bool stop(false);

//int delay = 1000 / rate;

int k=0;

while (1)

{

if (!capture.read(image))

break;

detectAndDraw(image, cascade, scale);

imshow("人脸检测", image);

k=waitkey(10);

if (k=27)//ESC键

break;

}

capture.release();

return;

}

void CMyFaceDetectDlg::OnBnClickedCancel()

{

// TODO: 在此添加控件通知处理程序代码

CDialogEx::OnCancel();

}

三 运行程序

视频和图片都有测试,一般只要是正脸、清晰的都能检测图片。另外,需要将haarcascade_frontalface_alt2.xml文件复制到程序目录下。
OpenCV实现人脸检测

将文件在目录opencv\\sources\\data\\haarcascades下。

OpenCV实现人脸检测

OpenCV实现人脸检测

以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持快网idc。

收藏 (0) 打赏

感谢您的支持,我会继续努力的!

打开微信/支付宝扫一扫,即可进行扫码打赏哦,分享从这里开始,精彩与您同在
点赞 (0)

声明:本站所有文章,如无特殊说明或标注,均为本站原创发布。任何个人或组织,在未征得本站同意时,禁止复制、盗用、采集、发布本站内容到任何网站、书籍等各类媒体平台。如若本站内容侵犯了原著者的合法权益,可联系我们进行处理。

快网idc优惠网 建站教程 OpenCV实现人脸检测 https://www.kuaiidc.com/72979.html

相关文章

发表评论
暂无评论