基于openCV实现人脸检测

2025-05-27 0 44

openCV的人脸识别主要通过Haar分类器实现,当然,这是在已有训练数据的基础上。openCV安装在 opencv/opencv/sources/data/haarcascades_cuda(或haarcascades)中存在预先训练好的物体检测器(xml格式),包括正脸、侧脸、眼睛、微笑、上半身、下半身、全身等。

openCV的的Haar分类器是一个监督分类器,首先对图像进行直方图均衡化并归一化到同样大小,然后标记里面是否包含要监测的物体。它首先由Paul Viola和Michael Jones设计,称为Viola Jones检测器。Viola Jones分类器在级联的每个节点中使用AdaBoost来学习一个高检测率低拒绝率的多层树分类器。它使用了以下一些新的特征:

1. 使用类Haar输入特征:对矩形图像区域的和或者差进行阈值化。
2. 积分图像技术加速了矩形区域的45°旋转的值的计算,用来加速类Haar输入特征的计算。
3. 使用统计boosting来创建两类问题(人脸和非人脸)的分类器节点(高通过率,低拒绝率)
4. 把弱分类器节点组成筛选式级联。即,第一组分类器最优,能通过包含物体的图像区域,同时允许一些不包含物体通过的图像通过;第二组分

类器次优分类器,也是有较低的拒绝率;以此类推。也就是说,对于每个boosting分类器,只要有人脸都能检测到,同时拒绝一小部分非人脸,并将其传给下一个分类器,是为低拒绝率。以此类推,最后一个分类器将几乎所有的非人脸都拒绝掉,只剩下人脸区域。只要图像区域通过了整个级联,则认为里面有物体。

此技术虽然适用于人脸检测,但不限于人脸检测,还可用于其他物体的检测,如汽车、飞机等的正面、侧面、后面检测。在检测时,先导入训练好的参数文件,其中haarcascade_frontalface_alt2.xml对正面脸的识别效果较好haarcascade_profileface.xml对侧脸的检测效果较好。当然,如果要达到更高的分类精度,可以收集更多的数据进行训练,这是后话。

以下代码基本实现了正脸、眼睛、微笑、侧脸的识别,若要添加其他功能,可以自行调整。

?

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

256

257

258

259

260

261

262

263

264

265

266

267

268

269

270

271

272

273

274

275

276

277

278

279

280

281

282

283

284

285

286

287

288

289

290

291

292

293

294

295

296

297

298

299

300

301

302

303

304

305

306

307

308

309

310

311

312

313

314

315

316

317

318

319

320

321

322

323

324

325

326

327

328

329

330

331

332

333

334

335

336

337

338

339

340

341

342

343

344

345

346

347

348

349

350

351

352

353

354

355

356

357

358

359

360

361

362

363

364

365

366

367

368

369

370

371

372

373

374

375

376

377

378

379

380

381

382

383

384

385

386

387

388

389

390

391

392

393

394

395

396

397

398

399

400

401

402

403

404

405

406

407

408

409

410

411

412

413

414

415

416

417

418

419

420

421

422

423
// faceDetector.h

// This is just the face, eye, smile, profile detector from OpenCV's samples/c directory

//

/* *************** License:**************************

Jul. 18, 2016

Author: Liuph

Right to use this code in any way you want without warranty, support or any guarantee of it working.

OTHER OPENCV SITES:

* The source code is on sourceforge at:

http://sourceforge.net/projects/opencvlibrary/

* The OpenCV wiki page (As of Oct 1, 2008 this is down for changing over servers, but should come back):

http://opencvlibrary.sourceforge.net/

* An active user group is at:

http://tech.groups.yahoo.com/group/OpenCV/

* The minutes of weekly OpenCV development meetings are at:

http://pr.willowgarage.com/wiki/OpenCV

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

#include "cv.h"

#include "highgui.h"

#include <stdio.h>

#include <stdlib.h>

#include <string.h>

#include <assert.h>

#include <math.h>

#include <float.h>

#include <limits.h>

#include <time.h>

#include <ctype.h>

#include <iostream>

using namespace std;

static CvMemStorage* storage = 0;

static CvHaarClassifierCascade* cascade = 0;

static CvHaarClassifierCascade* nested_cascade = 0;

static CvHaarClassifierCascade* smile_cascade = 0;

static CvHaarClassifierCascade* profile = 0;

int use_nested_cascade = 0;

void detect_and_draw( IplImage* image );

/* The path that stores the trained parameter files.

After openCv is installed, the file path is

"opencv/opencv/sources/data/haarcascades_cuda" or "opencv/opencv/sources/data/haarcascades" */

const char* cascade_name =

"../faceDetect/haarcascade_frontalface_alt2.xml";

const char* nested_cascade_name =

"../faceDetect/haarcascade_eye_tree_eyeglasses.xml";

const char* smile_cascade_name =

"../faceDetect/haarcascade_smile.xml";

const char* profile_name =

"../faceDetect/haarcascade_profileface.xml";

double scale = 1;

int faceDetector(const char* imageName, int nNested, int nSmile, int nProfile)

{

CvCapture* capture = 0;

IplImage *frame, *frame_copy = 0;

IplImage *image = 0;

const char* scale_opt = "--scale=";

int scale_opt_len = (int)strlen(scale_opt);

const char* cascade_opt = "--cascade=";

int cascade_opt_len = (int)strlen(cascade_opt);

const char* nested_cascade_opt = "--nested-cascade";

int nested_cascade_opt_len = (int)strlen(nested_cascade_opt);

const char* smile_cascade_opt = "--smile-cascade";

int smile_cascade_opt_len = (int)strlen(smile_cascade_opt);

const char* profile_opt = "--profile";

int profile_opt_len = (int)strlen(profile_opt);

int i;

const char* input_name = 0;

int opt_num = 7;

char** opts = new char*[7];

opts[0] = "compile_opencv.exe";

opts[1] = "--scale=1";

opts[2] = "--cascade=1";

if (nNested == 1)

opts[3] = "--nested-cascade=1";

else

opts[3] = "--nested-cascade=0";

if (nSmile == 1)

opts[4] = "--smile-cascade=1";

else

opts[4] = "--smile-cascade=0";

if (nProfile == 1)

opts[5] = "--profile=1";

else

opts[5] = "--profile=0";

opts[6] = (char*)imageName;

for( i = 1; i < opt_num; i++ )

{

if( strncmp( opts[i], cascade_opt, cascade_opt_len) == 0)

{

cout<<"cascade: "<<cascade_name<<endl;

}

else if( strncmp( opts[i], nested_cascade_opt, nested_cascade_opt_len ) == 0)

{

if( opts[i][nested_cascade_opt_len + 1] == '1')

{

cout<<"nested: "<<nested_cascade_name<<endl;

nested_cascade = (CvHaarClassifierCascade*)cvLoad( nested_cascade_name, 0, 0, 0 );

}

if( !nested_cascade )

fprintf( stderr, "WARNING: Could not load classifier cascade for nested objects\\n" );

}

else if( strncmp( opts[i], scale_opt, scale_opt_len ) == 0 )

{

cout<< "scale: "<< scale<<endl;

if( !sscanf( opts[i] + scale_opt_len, "%lf", &scale ) || scale < 1 )

scale = 1;

}

else if (strncmp( opts[i], smile_cascade_opt, smile_cascade_opt_len ) == 0)

{

if( opts[i][smile_cascade_opt_len + 1] == '1')

{

cout<<"smile: "<<smile_cascade_name<<endl;

smile_cascade = (CvHaarClassifierCascade*)cvLoad( smile_cascade_name, 0, 0, 0 );

}

if( !smile_cascade )

fprintf( stderr, "WARNING: Could not load classifier cascade for smile objects\\n" );

}

else if (strncmp( opts[i], profile_opt, profile_opt_len ) == 0)

{

if( opts[i][profile_opt_len + 1] == '1')

{

cout<<"profile: "<<profile_name<<endl;

profile = (CvHaarClassifierCascade*)cvLoad( profile_name, 0, 0, 0 );

}

if( !profile )

fprintf( stderr, "WARNING: Could not load classifier cascade for profile objects\\n" );

}

else if( opts[i][0] == '-' )

{

fprintf( stderr, "WARNING: Unknown option %s\\n", opts[i] );

}

else

{

input_name = imageName;

printf("input_name: %s\\n", imageName);

}

}

cascade = (CvHaarClassifierCascade*)cvLoad( cascade_name, 0, 0, 0 );

if( !cascade )

{

fprintf( stderr, "ERROR: Could not load classifier cascade\\n" );

fprintf( stderr,

"Usage: facedetect [--cascade=\\"<cascade_path>\\"]\\n"

" [--nested-cascade[=\\"nested_cascade_path\\"]]\\n"

" [--scale[=<image scale>\\n"

" [filename|camera_index]\\n" );

return -1;

}

storage = cvCreateMemStorage(0);

if( !input_name || (isdigit(input_name[0]) && input_name[1] == '\\0') )

capture = cvCaptureFromCAM( !input_name ? 0 : input_name[0] - '0' );

else if( input_name )

{

image = cvLoadImage( input_name, 1 );

if( !image )

capture = cvCaptureFromAVI( input_name );

}

else

image = cvLoadImage( "../lena.jpg", 1 );

cvNamedWindow( "result", 1 );

if( capture )

{

for(;;)

{

if( !cvGrabFrame( capture ))

break;

frame = cvRetrieveFrame( capture );

if( !frame )

break;

if( !frame_copy )

frame_copy = cvCreateImage( cvSize(frame->width,frame->height),

IPL_DEPTH_8U, frame->nChannels );

if( frame->origin == IPL_ORIGIN_TL )

cvCopy( frame, frame_copy, 0 );

else

cvFlip( frame, frame_copy, 0 );

detect_and_draw( frame_copy );

if( cvWaitKey( 10 ) >= 0 )

goto _cleanup_;

}

cvWaitKey(0);

_cleanup_:

cvReleaseImage( &frame_copy );

cvReleaseCapture( &capture );

}

else

{

if( image )

{

detect_and_draw( image );

cvWaitKey(0);

cvReleaseImage( &image );

}

else if( input_name )

{

/* assume it is a text file containing the

list of the image filenames to be processed - one per line */

FILE* f = fopen( input_name, "rt" );

if( f )

{

char buf[1000+1];

while( fgets( buf, 1000, f ) )

{

int len = (int)strlen(buf), c;

while( len > 0 && isspace(buf[len-1]) )

len--;

buf[len] = '\\0';

printf( "file %s\\n", buf );

image = cvLoadImage( buf, 1 );

if( image )

{

detect_and_draw( image );

c = cvWaitKey(0);

if( c == 27 || c == 'q' || c == 'Q' )

break;

cvReleaseImage( &image );

}

}

fclose(f);

}

}

}

cvDestroyWindow("result");

return 0;

}

void detect_and_draw( IplImage* img )

{

static CvScalar colors[] =

{

{{0,0,255}},

{{0,128,255}},

{{0,255,255}},

{{0,255,0}},

{{255,128,0}},

{{255,255,0}},

{{255,0,0}},

{{255,0,255}}

};

IplImage *gray, *small_img;

int i, j;

gray = cvCreateImage( cvSize(img->width,img->height), 8, 1 );

small_img = cvCreateImage( cvSize( cvRound (img->width/scale),

cvRound (img->height/scale)), 8, 1 );

cvCvtColor( img, gray, CV_BGR2GRAY );

cvResize( gray, small_img, CV_INTER_LINEAR );

cvEqualizeHist( small_img, small_img );

cvClearMemStorage( storage );

if( cascade )

{

double t = (double)cvGetTickCount();

CvSeq* faces = cvHaarDetectObjects( small_img, cascade, storage,

1.1, 2, 0

//|CV_HAAR_FIND_BIGGEST_OBJECT

//|CV_HAAR_DO_ROUGH_SEARCH

|CV_HAAR_DO_CANNY_PRUNING

//|CV_HAAR_SCALE_IMAGE

,

cvSize(30, 30) );

t = (double)cvGetTickCount() - t;

printf( "faces detection time = %gms\\n", t/((double)cvGetTickFrequency()*1000.) );

for( i = 0; i < (faces ? faces->total : 0); i++ )

{

CvRect* r = (CvRect*)cvGetSeqElem( faces, i );

CvMat small_img_roi;

CvSeq* nested_objects;

CvSeq* smile_objects;

CvPoint center;

CvScalar 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);

cvCircle( img, center, radius, color, 3, 8, 0 );

//eye

if( nested_cascade != 0)

{

cvGetSubRect( small_img, &small_img_roi, *r );

nested_objects = cvHaarDetectObjects( &small_img_roi, nested_cascade, storage,

1.1, 2, 0

//|CV_HAAR_FIND_BIGGEST_OBJECT

//|CV_HAAR_DO_ROUGH_SEARCH

//|CV_HAAR_DO_CANNY_PRUNING

//|CV_HAAR_SCALE_IMAGE

,

cvSize(0, 0) );

for( j = 0; j < (nested_objects ? nested_objects->total : 0); j++ )

{

CvRect* nr = (CvRect*)cvGetSeqElem( nested_objects, j );

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

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

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

cvCircle( img, center, radius, color, 3, 8, 0 );

}

}

//smile

if (smile_cascade != 0)

{

cvGetSubRect( small_img, &small_img_roi, *r );

smile_objects = cvHaarDetectObjects( &small_img_roi, smile_cascade, storage,

1.1, 2, 0

//|CV_HAAR_FIND_BIGGEST_OBJECT

//|CV_HAAR_DO_ROUGH_SEARCH

//|CV_HAAR_DO_CANNY_PRUNING

//|CV_HAAR_SCALE_IMAGE

,

cvSize(0, 0) );

for( j = 0; j < (smile_objects ? smile_objects->total : 0); j++ )

{

CvRect* nr = (CvRect*)cvGetSeqElem( smile_objects, j );

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

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

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

cvCircle( img, center, radius, color, 3, 8, 0 );

}

}

}

}

if( profile )

{

double t = (double)cvGetTickCount();

CvSeq* faces = cvHaarDetectObjects( small_img, profile, storage,

1.1, 2, 0

//|CV_HAAR_FIND_BIGGEST_OBJECT

//|CV_HAAR_DO_ROUGH_SEARCH

|CV_HAAR_DO_CANNY_PRUNING

//|CV_HAAR_SCALE_IMAGE

,

cvSize(30, 30) );

t = (double)cvGetTickCount() - t;

printf( "profile faces detection time = %gms\\n", t/((double)cvGetTickFrequency()*1000.) );

for( i = 0; i < (faces ? faces->total : 0); i++ )

{

CvRect* r = (CvRect*)cvGetSeqElem( faces, i );

CvMat small_img_roi;

CvSeq* nested_objects;

CvSeq* smile_objects;

CvPoint center;

CvScalar color = colors[(7-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);

cvCircle( img, center, radius, color, 3, 8, 0 );

//eye

if( nested_cascade != 0)

{

cvGetSubRect( small_img, &small_img_roi, *r );

nested_objects = cvHaarDetectObjects( &small_img_roi, nested_cascade, storage,

1.1, 2, 0

//|CV_HAAR_FIND_BIGGEST_OBJECT

//|CV_HAAR_DO_ROUGH_SEARCH

//|CV_HAAR_DO_CANNY_PRUNING

//|CV_HAAR_SCALE_IMAGE

,

cvSize(0, 0) );

for( j = 0; j < (nested_objects ? nested_objects->total : 0); j++ )

{

CvRect* nr = (CvRect*)cvGetSeqElem( nested_objects, j );

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

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

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

cvCircle( img, center, radius, color, 3, 8, 0 );

}

}

//smile

if (smile_cascade != 0)

{

cvGetSubRect( small_img, &small_img_roi, *r );

smile_objects = cvHaarDetectObjects( &small_img_roi, smile_cascade, storage,

1.1, 2, 0

//|CV_HAAR_FIND_BIGGEST_OBJECT

//|CV_HAAR_DO_ROUGH_SEARCH

//|CV_HAAR_DO_CANNY_PRUNING

//|CV_HAAR_SCALE_IMAGE

,

cvSize(0, 0) );

for( j = 0; j < (smile_objects ? smile_objects->total : 0); j++ )

{

CvRect* nr = (CvRect*)cvGetSeqElem( smile_objects, j );

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

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

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

cvCircle( img, center, radius, color, 3, 8, 0 );

}

}

}

}

cvShowImage( "result", img );

cvReleaseImage( &gray );

cvReleaseImage( &small_img );

}

?

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
//main.cpp

//openCV配置

//附加包含目录: include, include/opencv, include/opencv2

//附加库目录: lib

//附加依赖项: debug:--> opencv_calib3d243d.lib;...;

// release:--> opencv_calib3d243.lib;...;

#include<string>

#include <opencv2\\opencv.hpp>

#include "CV2_compile.h"

#include "CV_compile.h"

#include "face_detector.h"

using namespace cv;

using namespace std;

int main(int argc, char** argv)

{

const char* imagename = "../lena.jpg";

faceDetector(imagename,1,0,0);

return 0;

}

调整主函数中faceDetect(const char* imageName, int nNested, int nSmile, int nProfile)函数中的参数,分别表示图像文件名,是否检测眼睛,是否检测微笑,是否检测侧脸。以检测正脸、眼睛为例:

基于openCV实现人脸检测

再来看一张合影。

基于openCV实现人脸检测

========华丽丽的分割线==========

如果对分类器的参数不满意,或者说想识别其他的物体例如车、人、飞机、苹果等等等等,只需要选择适当的样本训练,获取该物体的各个方面的参数,训练过程可以通过openCV的haartraining实现(参考haartraining参考文档,opencv/apps/traincascade),主要包括个步骤:

1. 收集打算学习的物体数据集(如正面人脸图,侧面汽车图等, 1000~10000个正样本为宜),把它们存储在一个或多个目录下面。
2. 使用createsamples来建立正样本的向量输出文件,通过这个文件可以重复训练过程,使用同一个向量输出文件尝试各种参数。
3. 获取负样本,即不包含该物体的图像。
4. 训练。命令行实现。

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

收藏 (0) 打赏

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

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

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

快网idc优惠网 建站教程 基于openCV实现人脸检测 https://www.kuaiidc.com/73321.html

相关文章

发表评论
暂无评论