opencv人脸识别C++代码
复制代码
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
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904/* * Copyright (c) 2011,2012. Philipp Wagner <bytefish[at]gmx[dot]de>. * Released to public domain under terms of the BSD Simplified license. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: * * Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * Neither the name of the organization nor the names of its contributors * may be used to endorse or promote products derived from this software * without specific prior written permission. * * See <http://www.opensource.org/licenses/bsd-license> */ #include "precomp.hpp" #include <set> namespace cv { using std::set; // Reads a sequence from a FileNode::SEQ with type _Tp into a result vector. template<typename _Tp> inline void readFileNodeList(const FileNode& fn, vector<_Tp>& result) { if (fn.type() == FileNode::SEQ) { for (FileNodeIterator it = fn.begin(); it != fn.end();) { _Tp item; it >> item; result.push_back(item); } } } // Writes the a list of given items to a cv::FileStorage. template<typename _Tp> inline void writeFileNodeList(FileStorage& fs, const string& name, const vector<_Tp>& items) { // typedefs typedef typename vector<_Tp>::const_iterator constVecIterator; // write the elements in item to fs fs << name << "["; for (constVecIterator it = items.begin(); it != items.end(); ++it) { fs << *it; } fs << "]"; } static Mat asRowMatrix(InputArrayOfArrays src, int rtype, double alpha=1, double beta=0) { // make sure the input data is a vector of matrices or vector of vector if(src.kind() != _InputArray::STD_VECTOR_MAT && src.kind() != _InputArray::STD_VECTOR_VECTOR) { string error_message = "The data is expected as InputArray::STD_VECTOR_MAT (a std::vector<Mat>) or _InputArray::STD_VECTOR_VECTOR (a std::vector< vector<...> >)."; CV_Error(CV_StsBadArg, error_message); } // number of samples size_t n = src.total(); // return empty matrix if no matrices given if(n == 0) return Mat(); // dimensionality of (reshaped) samples size_t d = src.getMat(0).total(); // create data matrix Mat data((int)n, (int)d, rtype); // now copy data for(unsigned int i = 0; i < n; i++) { // make sure data can be reshaped, throw exception if not! if(src.getMat(i).total() != d) { string error_message = format("Wrong number of elements in matrix #%d! Expected %d was %d.", i, d, src.getMat(i).total()); CV_Error(CV_StsBadArg, error_message); } // get a hold of the current row Mat xi = data.row(i); // make reshape happy by cloning for non-continuous matrices if(src.getMat(i).isContinuous()) { src.getMat(i).reshape(1, 1).convertTo(xi, rtype, alpha, beta); } else { src.getMat(i).clone().reshape(1, 1).convertTo(xi, rtype, alpha, beta); } } return data; } // Removes duplicate elements in a given vector. template<typename _Tp> inline vector<_Tp> remove_dups(const vector<_Tp>& src) { typedef typename set<_Tp>::const_iterator constSetIterator; typedef typename vector<_Tp>::const_iterator constVecIterator; set<_Tp> set_elems; for (constVecIterator it = src.begin(); it != src.end(); ++it) set_elems.insert(*it); vector<_Tp> elems; for (constSetIterator it = set_elems.begin(); it != set_elems.end(); ++it) elems.push_back(*it); return elems; } // Turk, M., and Pentland, A. "Eigenfaces for recognition.". Journal of // Cognitive Neuroscience 3 (1991), 71–86. //特征脸类 class Eigenfaces : public FaceRecognizer { private: int _num_components;//对应“数学上的事”中所提到的q个主成分 double _threshold; vector<Mat> _projections;//原始向量投影后的坐标 Mat _labels;//每幅图像的标签,用于分类 Mat _eigenvectors;//特征向量 Mat _eigenvalues;//特征值 Mat _mean;//均值 public: using FaceRecognizer::save; using FaceRecognizer::load; // Initializes an empty Eigenfaces model. Eigenfaces(int num_components = 0, double threshold = DBL_MAX) : _num_components(num_components), _threshold(threshold) {} // Initializes and computes an Eigenfaces model with images in src and // corresponding labels in labels. num_components will be kept for // classification. Eigenfaces(InputArrayOfArrays src, InputArray labels, int num_components = 0, double threshold = DBL_MAX) : _num_components(num_components), _threshold(threshold) { train(src, labels); } // Computes an Eigenfaces model with images in src and corresponding labels // in labels. void train(InputArrayOfArrays src, InputArray labels); // Predicts the label of a query image in src. int predict(InputArray src) const; // Predicts the label and confidence for a given sample. void predict(InputArray _src, int &label, double &dist) const; // See FaceRecognizer::load. void load(const FileStorage& fs); // See FaceRecognizer::save. void save(FileStorage& fs) const; AlgorithmInfo* info() const; }; // Belhumeur, P. N., Hespanha, J., and Kriegman, D. "Eigenfaces vs. Fisher- // faces: Recognition using class specific linear projection.". IEEE // Transactions on Pattern Analysis and Machine Intelligence 19, 7 (1997), // 711–720. class Fisherfaces: public FaceRecognizer { private: int _num_components; double _threshold; Mat _eigenvectors; Mat _eigenvalues; Mat _mean; vector<Mat> _projections; Mat _labels; public: using FaceRecognizer::save; using FaceRecognizer::load; // Initializes an empty Fisherfaces model. Fisherfaces(int num_components = 0, double threshold = DBL_MAX) : _num_components(num_components), _threshold(threshold) {} // Initializes and computes a Fisherfaces model with images in src and // corresponding labels in labels. num_components will be kept for // classification. Fisherfaces(InputArrayOfArrays src, InputArray labels, int num_components = 0, double threshold = DBL_MAX) : _num_components(num_components), _threshold(threshold) { train(src, labels); } ~Fisherfaces() {} // Computes a Fisherfaces model with images in src and corresponding labels // in labels. void train(InputArrayOfArrays src, InputArray labels); // Predicts the label of a query image in src. int predict(InputArray src) const; // Predicts the label and confidence for a given sample. void predict(InputArray _src, int &label, double &dist) const; // See FaceRecognizer::load. void load(const FileStorage& fs); // See FaceRecognizer::save. void save(FileStorage& fs) const; AlgorithmInfo* info() const; }; // Face Recognition based on Local Binary Patterns. // // Ahonen T, Hadid A. and Pietikäinen M. "Face description with local binary // patterns: Application to face recognition." IEEE Transactions on Pattern // Analysis and Machine Intelligence, 28(12):2037-2041. // class LBPH : public FaceRecognizer { private: int _grid_x; int _grid_y; int _radius; int _neighbors; double _threshold; vector<Mat> _histograms; Mat _labels; // Computes a LBPH model with images in src and // corresponding labels in labels, possibly preserving // old model data. void train(InputArrayOfArrays src, InputArray labels, bool preserveData); public: using FaceRecognizer::save; using FaceRecognizer::load; // Initializes this LBPH Model. The current implementation is rather fixed // as it uses the Extended Local Binary Patterns per default. // // radius, neighbors are used in the local binary patterns creation. // grid_x, grid_y control the grid size of the spatial histograms. LBPH(int radius_=1, int neighbors_=8, int gridx=8, int gridy=8, double threshold = DBL_MAX) : _grid_x(gridx), _grid_y(gridy), _radius(radius_), _neighbors(neighbors_), _threshold(threshold) {} // Initializes and computes this LBPH Model. The current implementation is // rather fixed as it uses the Extended Local Binary Patterns per default. // // (radius=1), (neighbors=8) are used in the local binary patterns creation. // (grid_x=8), (grid_y=8) controls the grid size of the spatial histograms. LBPH(InputArrayOfArrays src, InputArray labels, int radius_=1, int neighbors_=8, int gridx=8, int gridy=8, double threshold = DBL_MAX) : _grid_x(gridx), _grid_y(gridy), _radius(radius_), _neighbors(neighbors_), _threshold(threshold) { train(src, labels); } ~LBPH() { } // Computes a LBPH model with images in src and // corresponding labels in labels. void train(InputArrayOfArrays src, InputArray labels); // Updates this LBPH model with images in src and // corresponding labels in labels. void update(InputArrayOfArrays src, InputArray labels); // Predicts the label of a query image in src. int predict(InputArray src) const; // Predicts the label and confidence for a given sample. void predict(InputArray _src, int &label, double &dist) const; // See FaceRecognizer::load. void load(const FileStorage& fs); // See FaceRecognizer::save. void save(FileStorage& fs) const; // Getter functions. int neighbors() const { return _neighbors; } int radius() const { return _radius; } int grid_x() const { return _grid_x; } int grid_y() const { return _grid_y; } AlgorithmInfo* info() const; }; //------------------------------------------------------------------------------ // FaceRecognizer //------------------------------------------------------------------------------ void FaceRecognizer::update(InputArrayOfArrays src, InputArray labels ) { if( dynamic_cast<LBPH*>(this) != 0 ) { dynamic_cast<LBPH*>(this)->update( src, labels ); return; } string error_msg = format("This FaceRecognizer (%s) does not support updating, you have to use FaceRecognizer::train to update it.", this->name().c_str()); CV_Error(CV_StsNotImplemented, error_msg); } void FaceRecognizer::save(const string& filename) const { FileStorage fs(filename, FileStorage::WRITE); if (!fs.isOpened()) CV_Error(CV_StsError, "File can't be opened for writing!"); this->save(fs); fs.release(); } void FaceRecognizer::load(const string& filename) { FileStorage fs(filename, FileStorage::READ); if (!fs.isOpened()) CV_Error(CV_StsError, "File can't be opened for writing!"); this->load(fs); fs.release(); } //------------------------------------------------------------------------------ // Eigenfaces特征脸训练函数 //------------------------------------------------------------------------------ void Eigenfaces::train(InputArrayOfArrays _src, InputArray _local_labels) { if(_src.total() == 0) { string error_message = format("Empty training data was given. You'll need more than one sample to learn a model."); CV_Error(CV_StsBadArg, error_message); } else if(_local_labels.getMat().type() != CV_32SC1) { string error_message = format("Labels must be given as integer (CV_32SC1). Expected %d, but was %d.", CV_32SC1, _local_labels.type()); CV_Error(CV_StsBadArg, error_message); } // make sure data has correct size确保输入的图像数据尺寸正确(所有尺寸相同) if(_src.total() > 1) { for(int i = 1; i < static_cast<int>(_src.total()); i++) { if(_src.getMat(i-1).total() != _src.getMat(i).total()) { string error_message = format("In the Eigenfaces method all input samples (training images) must be of equal size! Expected %d pixels, but was %d pixels.", _src.getMat(i-1).total(), _src.getMat(i).total()); CV_Error(CV_StsUnsupportedFormat, error_message); } } } // get labels Mat labels = _local_labels.getMat(); // observations in row Mat data = asRowMatrix(_src, CV_64FC1);//将_src中存放的图像列表中的每幅图像(reshape成1行)作为data的一行 // number of samples int n = data.rows; // assert there are as much samples as labels if(static_cast<int>(labels.total()) != n) { string error_message = format("The number of samples (src) must equal the number of labels (labels)! len(src)=%d, len(labels)=%d.", n, labels.total()); CV_Error(CV_StsBadArg, error_message); } // clear existing model data _labels.release(); _projections.clear(); // clip number of components to be valid if((_num_components <= 0) || (_num_components > n)) _num_components = n; // perform the PCA PCA pca(data, Mat(), CV_PCA_DATA_AS_ROW, _num_components); // copy the PCA results _mean = pca.mean.reshape(1,1); // store the mean vector获取均值向量 _eigenvalues = pca.eigenvalues.clone(); // eigenvalues by row获取特征值 transpose(pca.eigenvectors, _eigenvectors); // eigenvectors by column获取特征向量 // store labels for prediction _labels = labels.clone();//获取分类标签 // save projections for(int sampleIdx = 0; sampleIdx < data.rows; sampleIdx++) { Mat p = subspaceProject(_eigenvectors, _mean, data.row(sampleIdx)); _projections.push_back(p); } } void Eigenfaces::predict(InputArray _src, int &minClass, double &minDist) const { // get data Mat src = _src.getMat(); // make sure the user is passing correct data if(_projections.empty()) { // throw error if no data (or simply return -1?) string error_message = "This Eigenfaces model is not computed yet. Did you call Eigenfaces::train?"; CV_Error(CV_StsError, error_message); } else if(_eigenvectors.rows != static_cast<int>(src.total())) { // check data alignment just for clearer exception messages string error_message = format("Wrong input image size. Reason: Training and Test images must be of equal size! Expected an image with %d elements, but got %d.", _eigenvectors.rows, src.total()); CV_Error(CV_StsBadArg, error_message); } // project into PCA subspace Mat q = subspaceProject(_eigenvectors, _mean, src.reshape(1,1));// 投影到PCA的主成分空间 minDist = DBL_MAX; minClass = -1; //求L2范数也就是欧式距离 for(size_t sampleIdx = 0; sampleIdx < _projections.size(); sampleIdx++) { double dist = norm(_projections[sampleIdx], q, NORM_L2); if((dist < minDist) && (dist < _threshold)) { minDist = dist; minClass = _labels.at<int>((int)sampleIdx); } } } int Eigenfaces::predict(InputArray _src) const { int label; double dummy; predict(_src, label, dummy); return label; } void Eigenfaces::load(const FileStorage& fs) { //read matrices fs["num_components"] >> _num_components; fs["mean"] >> _mean; fs["eigenvalues"] >> _eigenvalues; fs["eigenvectors"] >> _eigenvectors; // read sequences readFileNodeList(fs["projections"], _projections); fs["labels"] >> _labels; } void Eigenfaces::save(FileStorage& fs) const { // write matrices fs << "num_components" << _num_components; fs << "mean" << _mean; fs << "eigenvalues" << _eigenvalues; fs << "eigenvectors" << _eigenvectors; // write sequences writeFileNodeList(fs, "projections", _projections); fs << "labels" << _labels; } //------------------------------------------------------------------------------ // Fisherfaces //------------------------------------------------------------------------------ void Fisherfaces::train(InputArrayOfArrays src, InputArray _lbls) { if(src.total() == 0) { string error_message = format("Empty training data was given. You'll need more than one sample to learn a model."); CV_Error(CV_StsBadArg, error_message); } else if(_lbls.getMat().type() != CV_32SC1) { string error_message = format("Labels must be given as integer (CV_32SC1). Expected %d, but was %d.", CV_32SC1, _lbls.type()); CV_Error(CV_StsBadArg, error_message); } // make sure data has correct size if(src.total() > 1) { for(int i = 1; i < static_cast<int>(src.total()); i++) { if(src.getMat(i-1).total() != src.getMat(i).total()) { string error_message = format("In the Fisherfaces method all input samples (training images) must be of equal size! Expected %d pixels, but was %d pixels.", src.getMat(i-1).total(), src.getMat(i).total()); CV_Error(CV_StsUnsupportedFormat, error_message); } } } // get data Mat labels = _lbls.getMat(); Mat data = asRowMatrix(src, CV_64FC1); // number of samples int N = data.rows; // make sure labels are passed in correct shape if(labels.total() != (size_t) N) { string error_message = format("The number of samples (src) must equal the number of labels (labels)! len(src)=%d, len(labels)=%d.", N, labels.total()); CV_Error(CV_StsBadArg, error_message); } else if(labels.rows != 1 && labels.cols != 1) { string error_message = format("Expected the labels in a matrix with one row or column! Given dimensions are rows=%s, cols=%d.", labels.rows, labels.cols); CV_Error(CV_StsBadArg, error_message); } // clear existing model data _labels.release(); _projections.clear(); // safely copy from cv::Mat to std::vector vector<int> ll; for(unsigned int i = 0; i < labels.total(); i++) { ll.push_back(labels.at<int>(i)); } // get the number of unique classes int C = (int) remove_dups(ll).size(); // clip number of components to be a valid number if((_num_components <= 0) || (_num_components > (C-1))) _num_components = (C-1); // perform a PCA and keep (N-C) components PCA pca(data, Mat(), CV_PCA_DATA_AS_ROW, (N-C)); // project the data and perform a LDA on it LDA lda(pca.project(data),labels, _num_components); // store the total mean vector _mean = pca.mean.reshape(1,1); // store labels _labels = labels.clone(); // store the eigenvalues of the discriminants lda.eigenvalues().convertTo(_eigenvalues, CV_64FC1); // Now calculate the projection matrix as pca.eigenvectors * lda.eigenvectors. // Note: OpenCV stores the eigenvectors by row, so we need to transpose it! gemm(pca.eigenvectors, lda.eigenvectors(), 1.0, Mat(), 0.0, _eigenvectors, GEMM_1_T); // store the projections of the original data for(int sampleIdx = 0; sampleIdx < data.rows; sampleIdx++) { Mat p = subspaceProject(_eigenvectors, _mean, data.row(sampleIdx)); _projections.push_back(p); } } void Fisherfaces::predict(InputArray _src, int &minClass, double &minDist) const { Mat src = _src.getMat(); // check data alignment just for clearer exception messages if(_projections.empty()) { // throw error if no data (or simply return -1?) string error_message = "This Fisherfaces model is not computed yet. Did you call Fisherfaces::train?"; CV_Error(CV_StsBadArg, error_message); } else if(src.total() != (size_t) _eigenvectors.rows) { string error_message = format("Wrong input image size. Reason: Training and Test images must be of equal size! Expected an image with %d elements, but got %d.", _eigenvectors.rows, src.total()); CV_Error(CV_StsBadArg, error_message); } // project into LDA subspace Mat q = subspaceProject(_eigenvectors, _mean, src.reshape(1,1)); // find 1-nearest neighbor minDist = DBL_MAX; minClass = -1; for(size_t sampleIdx = 0; sampleIdx < _projections.size(); sampleIdx++) { double dist = norm(_projections[sampleIdx], q, NORM_L2); if((dist < minDist) && (dist < _threshold)) { minDist = dist; minClass = _labels.at<int>((int)sampleIdx); } } } int Fisherfaces::predict(InputArray _src) const { int label; double dummy; predict(_src, label, dummy); return label; } // See FaceRecognizer::load. void Fisherfaces::load(const FileStorage& fs) { //read matrices fs["num_components"] >> _num_components; fs["mean"] >> _mean; fs["eigenvalues"] >> _eigenvalues; fs["eigenvectors"] >> _eigenvectors; // read sequences readFileNodeList(fs["projections"], _projections); fs["labels"] >> _labels; } // See FaceRecognizer::save. void Fisherfaces::save(FileStorage& fs) const { // write matrices fs << "num_components" << _num_components; fs << "mean" << _mean; fs << "eigenvalues" << _eigenvalues; fs << "eigenvectors" << _eigenvectors; // write sequences writeFileNodeList(fs, "projections", _projections); fs << "labels" << _labels; } //------------------------------------------------------------------------------ // LBPH //------------------------------------------------------------------------------ template <typename _Tp> static void olbp_(InputArray _src, OutputArray _dst) { // get matrices Mat src = _src.getMat(); // allocate memory for result _dst.create(src.rows-2, src.cols-2, CV_8UC1); Mat dst = _dst.getMat(); // zero the result matrix dst.setTo(0); // calculate patterns for(int i=1;i<src.rows-1;i++) { for(int j=1;j<src.cols-1;j++) { _Tp center = src.at<_Tp>(i,j); unsigned char code = 0; code |= (src.at<_Tp>(i-1,j-1) >= center) << 7; code |= (src.at<_Tp>(i-1,j) >= center) << 6; code |= (src.at<_Tp>(i-1,j+1) >= center) << 5; code |= (src.at<_Tp>(i,j+1) >= center) << 4; code |= (src.at<_Tp>(i+1,j+1) >= center) << 3; code |= (src.at<_Tp>(i+1,j) >= center) << 2; code |= (src.at<_Tp>(i+1,j-1) >= center) << 1; code |= (src.at<_Tp>(i,j-1) >= center) << 0; dst.at<unsigned char>(i-1,j-1) = code; } } } //------------------------------------------------------------------------------ // cv::elbp //------------------------------------------------------------------------------ template <typename _Tp> static inline void elbp_(InputArray _src, OutputArray _dst, int radius, int neighbors) { //get matrices Mat src = _src.getMat(); // allocate memory for result _dst.create(src.rows-2*radius, src.cols-2*radius, CV_32SC1); Mat dst = _dst.getMat(); // zero dst.setTo(0); for(int n=0; n<neighbors; n++) { // sample points float x = static_cast<float>(radius * cos(2.0*CV_PI*n/static_cast<float>(neighbors))); float y = static_cast<float>(-radius * sin(2.0*CV_PI*n/static_cast<float>(neighbors))); // relative indices int fx = static_cast<int>(floor(x)); int fy = static_cast<int>(floor(y)); int cx = static_cast<int>(ceil(x)); int cy = static_cast<int>(ceil(y)); // fractional part float ty = y - fy; float tx = x - fx; // set interpolation weights float w1 = (1 - tx) * (1 - ty); float w2 = tx * (1 - ty); float w3 = (1 - tx) * ty; float w4 = tx * ty; // iterate through your data for(int i=radius; i < src.rows-radius;i++) { for(int j=radius;j < src.cols-radius;j++) { // calculate interpolated value float t = static_cast<float>(w1*src.at<_Tp>(i+fy,j+fx) + w2*src.at<_Tp>(i+fy,j+cx) + w3*src.at<_Tp>(i+cy,j+fx) + w4*src.at<_Tp>(i+cy,j+cx)); // floating point precision, so check some machine-dependent epsilon dst.at<int>(i-radius,j-radius) += ((t > src.at<_Tp>(i,j)) || (std::abs(t-src.at<_Tp>(i,j)) < std::numeric_limits<float>::epsilon())) << n; } } } } static void elbp(InputArray src, OutputArray dst, int radius, int neighbors) { int type = src.type(); switch (type) { case CV_8SC1: elbp_<char>(src,dst, radius, neighbors); break; case CV_8UC1: elbp_<unsigned char>(src, dst, radius, neighbors); break; case CV_16SC1: elbp_<short>(src,dst, radius, neighbors); break; case CV_16UC1: elbp_<unsigned short>(src,dst, radius, neighbors); break; case CV_32SC1: elbp_<int>(src,dst, radius, neighbors); break; case CV_32FC1: elbp_<float>(src,dst, radius, neighbors); break; case CV_64FC1: elbp_<double>(src,dst, radius, neighbors); break; default: string error_msg = format("Using Original Local Binary Patterns for feature extraction only works on single-channel images (given %d). Please pass the image data as a grayscale image!", type); CV_Error(CV_StsNotImplemented, error_msg); break; } } static Mat histc_(const Mat& src, int minVal=0, int maxVal=255, bool normed=false) { Mat result; // Establish the number of bins. int histSize = maxVal-minVal+1; // Set the ranges. float range[] = { static_cast<float>(minVal), static_cast<float>(maxVal+1) }; const float* histRange = { range }; // calc histogram calcHist(&src, 1, 0, Mat(), result, 1, &histSize, &histRange, true, false); // normalize if(normed) { result /= (int)src.total(); } return result.reshape(1,1); } static Mat histc(InputArray _src, int minVal, int maxVal, bool normed) { Mat src = _src.getMat(); switch (src.type()) { case CV_8SC1: return histc_(Mat_<float>(src), minVal, maxVal, normed); break; case CV_8UC1: return histc_(src, minVal, maxVal, normed); break; case CV_16SC1: return histc_(Mat_<float>(src), minVal, maxVal, normed); break; case CV_16UC1: return histc_(src, minVal, maxVal, normed); break; case CV_32SC1: return histc_(Mat_<float>(src), minVal, maxVal, normed); break; case CV_32FC1: return histc_(src, minVal, maxVal, normed); break; default: CV_Error(CV_StsUnmatchedFormats, "This type is not implemented yet."); break; } return Mat(); } static Mat spatial_histogram(InputArray _src, int numPatterns, int grid_x, int grid_y, bool /*normed*/) { Mat src = _src.getMat(); // calculate LBP patch size int width = src.cols/grid_x; int height = src.rows/grid_y; // allocate memory for the spatial histogram Mat result = Mat::zeros(grid_x * grid_y, numPatterns, CV_32FC1); // return matrix with zeros if no data was given if(src.empty()) return result.reshape(1,1); // initial result_row int resultRowIdx = 0; // iterate through grid for(int i = 0; i < grid_y; i++) { for(int j = 0; j < grid_x; j++) { Mat src_cell = Mat(src, Range(i*height,(i+1)*height), Range(j*width,(j+1)*width)); Mat cell_hist = histc(src_cell, 0, (numPatterns-1), true); // copy to the result matrix Mat result_row = result.row(resultRowIdx); cell_hist.reshape(1,1).convertTo(result_row, CV_32FC1); // increase row count in result matrix resultRowIdx++; } } // return result as reshaped feature vector return result.reshape(1,1); } //------------------------------------------------------------------------------ // wrapper to cv::elbp (extended local binary patterns) //------------------------------------------------------------------------------ static Mat elbp(InputArray src, int radius, int neighbors) { Mat dst; elbp(src, dst, radius, neighbors); return dst; } void LBPH::load(const FileStorage& fs) { fs["radius"] >> _radius; fs["neighbors"] >> _neighbors; fs["grid_x"] >> _grid_x; fs["grid_y"] >> _grid_y; //read matrices readFileNodeList(fs["histograms"], _histograms); fs["labels"] >> _labels; } // See FaceRecognizer::save. void LBPH::save(FileStorage& fs) const { fs << "radius" << _radius; fs << "neighbors" << _neighbors; fs << "grid_x" << _grid_x; fs << "grid_y" << _grid_y; // write matrices writeFileNodeList(fs, "histograms", _histograms); fs << "labels" << _labels; } void LBPH::train(InputArrayOfArrays _in_src, InputArray _in_labels) { this->train(_in_src, _in_labels, false); } void LBPH::update(InputArrayOfArrays _in_src, InputArray _in_labels) { // got no data, just return if(_in_src.total() == 0) return; this->train(_in_src, _in_labels, true); } void LBPH::train(InputArrayOfArrays _in_src, InputArray _in_labels, bool preserveData) { if(_in_src.kind() != _InputArray::STD_VECTOR_MAT && _in_src.kind() != _InputArray::STD_VECTOR_VECTOR) { string error_message = "The images are expected as InputArray::STD_VECTOR_MAT (a std::vector<Mat>) or _InputArray::STD_VECTOR_VECTOR (a std::vector< vector<...> >)."; CV_Error(CV_StsBadArg, error_message); } if(_in_src.total() == 0) { string error_message = format("Empty training data was given. You'll need more than one sample to learn a model."); CV_Error(CV_StsUnsupportedFormat, error_message); } else if(_in_labels.getMat().type() != CV_32SC1) { string error_message = format("Labels must be given as integer (CV_32SC1). Expected %d, but was %d.", CV_32SC1, _in_labels.type()); CV_Error(CV_StsUnsupportedFormat, error_message); } // get the vector of matrices vector<Mat> src; _in_src.getMatVector(src); // get the label matrix Mat labels = _in_labels.getMat(); // check if data is well- aligned if(labels.total() != src.size()) { string error_message = format("The number of samples (src) must equal the number of labels (labels). Was len(samples)=%d, len(labels)=%d.", src.size(), _labels.total()); CV_Error(CV_StsBadArg, error_message); } // if this model should be trained without preserving old data, delete old model data if(!preserveData) { _labels.release(); _histograms.clear(); } // append labels to _labels matrix for(size_t labelIdx = 0; labelIdx < labels.total(); labelIdx++) { _labels.push_back(labels.at<int>((int)labelIdx)); } // store the spatial histograms of the original data for(size_t sampleIdx = 0; sampleIdx < src.size(); sampleIdx++) { // calculate lbp image Mat lbp_image = elbp(src[sampleIdx], _radius, _neighbors); // get spatial histogram from this lbp image Mat p = spatial_histogram( lbp_image, /* lbp_image */ static_cast<int>(std::pow(2.0, static_cast<double>(_neighbors))), /* number of possible patterns */ _grid_x, /* grid size x */ _grid_y, /* grid size y */ true); // add to templates _histograms.push_back(p); } } void LBPH::predict(InputArray _src, int &minClass, double &minDist) const { if(_histograms.empty()) { // throw error if no data (or simply return -1?) string error_message = "This LBPH model is not computed yet. Did you call the train method?"; CV_Error(CV_StsBadArg, error_message); } Mat src = _src.getMat(); // get the spatial histogram from input image Mat lbp_image = elbp(src, _radius, _neighbors); Mat query = spatial_histogram( lbp_image, /* lbp_image */ static_cast<int>(std::pow(2.0, static_cast<double>(_neighbors))), /* number of possible patterns */ _grid_x, /* grid size x */ _grid_y, /* grid size y */ true /* normed histograms */); // find 1-nearest neighbor minDist = DBL_MAX; minClass = -1; for(size_t sampleIdx = 0; sampleIdx < _histograms.size(); sampleIdx++) { double dist = compareHist(_histograms[sampleIdx], query, CV_COMP_CHISQR); if((dist < minDist) && (dist < _threshold)) { minDist = dist; minClass = _labels.at<int>((int) sampleIdx); } } } int LBPH::predict(InputArray _src) const { int label; double dummy; predict(_src, label, dummy); return label; } Ptr<FaceRecognizer> createEigenFaceRecognizer(int num_components, double threshold) { return new Eigenfaces(num_components, threshold); } Ptr<FaceRecognizer> createFisherFaceRecognizer(int num_components, double threshold) { return new Fisherfaces(num_components, threshold); } Ptr<FaceRecognizer> createLBPHFaceRecognizer(int radius, int neighbors, int grid_x, int grid_y, double threshold) { return new LBPH(radius, neighbors, grid_x, grid_y, threshold); } CV_INIT_ALGORITHM(Eigenfaces, "FaceRecognizer.Eigenfaces", obj.info()->addParam(obj, "ncomponents", obj._num_components); obj.info()->addParam(obj, "threshold", obj._threshold); obj.info()->addParam(obj, "projections", obj._projections, true); obj.info()->addParam(obj, "labels", obj._labels, true); obj.info()->addParam(obj, "eigenvectors", obj._eigenvectors, true); obj.info()->addParam(obj, "eigenvalues", obj._eigenvalues, true); obj.info()->addParam(obj, "mean", obj._mean, true)); CV_INIT_ALGORITHM(Fisherfaces, "FaceRecognizer.Fisherfaces", obj.info()->addParam(obj, "ncomponents", obj._num_components); obj.info()->addParam(obj, "threshold", obj._threshold); obj.info()->addParam(obj, "projections", obj._projections, true); obj.info()->addParam(obj, "labels", obj._labels, true); obj.info()->addParam(obj, "eigenvectors", obj._eigenvectors, true); obj.info()->addParam(obj, "eigenvalues", obj._eigenvalues, true); obj.info()->addParam(obj, "mean", obj._mean, true)); CV_INIT_ALGORITHM(LBPH, "FaceRecognizer.LBPH", obj.info()->addParam(obj, "radius", obj._radius); obj.info()->addParam(obj, "neighbors", obj._neighbors); obj.info()->addParam(obj, "grid_x", obj._grid_x); obj.info()->addParam(obj, "grid_y", obj._grid_y); obj.info()->addParam(obj, "threshold", obj._threshold); obj.info()->addParam(obj, "histograms", obj._histograms, true); obj.info()->addParam(obj, "labels", obj._labels, true)); bool initModule_contrib() { Ptr<Algorithm> efaces = createEigenfaces(), ffaces = createFisherfaces(), lbph = createLBPH(); return efaces->info() != 0 && ffaces->info() != 0 && lbph->info() != 0; } }
http://read.pudn.com/downloads674/sourcecode/graph/opencv/2728222/facerec.cpp__.htm
转载于:https://www.cnblogs.com/mq0036/p/10337718.html
最后
以上就是飞快小海豚最近收集整理的关于opencv人脸识别代码的全部内容,更多相关opencv人脸识别代码内容请搜索靠谱客的其他文章。
本图文内容来源于网友提供,作为学习参考使用,或来自网络收集整理,版权属于原作者所有。
发表评论 取消回复