forked from galeone/face-miner
-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathfaceclassifier.cpp
121 lines (105 loc) · 4.18 KB
/
faceclassifier.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
/*
Face Miner: data mining applied to face detection
Copyright (C) 2016 Paolo Galeone <nessuno@nerdz.eu>
This Source Code Form is subject to the terms of the Mozilla Public
License, v. 2.0. If a copy of the MPL was not distributed with this
file, You can obtain one at http://mozilla.org/MPL/2.0/.
Exhibit B is not attached; this software is compatible with the
licenses expressed under Section 1.12 of the MPL v2.
*/
#include "faceclassifier.h"
FaceClassifier::FaceClassifier(VarianceClassifier* vc,
FeatureClassifier* fc,
SVMClassifier* svmc,
cv::Size size) {
_vc = vc;
_fc = fc;
_sc = svmc;
_windowSize = size;
_scaleFactor = 1.25;
_step = 2;
}
// Returns true if contains some faces. Hilight with a rectangle the face on the
// image.
std::vector<cv::Rect> FaceClassifier::classify(const cv::Mat& image) {
std::vector<cv::Rect> allCandidates;
cv::Mat1b gray = Preprocessor::gray(image);
// pyramid downsampling
// from smaller to bigger.
// avoid to search where a face in a lower scale is found < image, scale
// factor >
std::vector<std::pair<cv::Mat1b, float>> pyramid;
for (float factor = 1;; factor *= _scaleFactor) {
// Size of the image scaled down (from bigger to smaller)
cv::Size sz(image.cols / factor, image.rows / factor);
// Difference between sized of the scaled image and the original detection
// window
cv::Size sz1(sz.width - _windowSize.width, sz.height - _windowSize.height);
// if the actual scaled image is smaller than the origina detection window,
// break
if (sz1.width < 0 || sz1.height < 0) {
break;
}
cv::Mat1b level;
cv::resize(gray, level, sz, 0, 0, cv::INTER_NEAREST);
pyramid.push_back(std::pair<cv::Mat1b, float>(level, factor));
}
// from smaller to bigger
for (auto rit = pyramid.rbegin(); rit != pyramid.rend(); rit++) {
cv::Mat1b level = (*rit).first;
float factor = (*rit).second;
_slidingSearch(level, factor, allCandidates);
}
return allCandidates;
}
// allCandidates contains the previous positions, scaled to the original
// dimension of image of the found face
// thus we can exploit this thing to skip a big section of the level = the
// intersection of the candidates
// scaled by factor (thus is compatible with level) with level
void FaceClassifier::_slidingSearch(cv::Mat1b& level,
float factor,
std::vector<cv::Rect>& allCandidates) {
cv::Size winSize(std::ceil(_windowSize.width * factor),
std::ceil(_windowSize.height * factor));
std::vector<cv::Rect> toSkip;
for (const cv::Rect& r : allCandidates) {
toSkip.push_back(cv::Rect(r.x / factor, r.y / factor, r.width / factor,
r.height / factor));
}
for (auto y = 0; y < level.rows - _windowSize.height; y += _step) {
for (auto x = 0; x < level.cols - _windowSize.width; x += _step) {
cv::Rect roi_rect(x, y, _windowSize.width, _windowSize.height);
// if roi_rect intersect a toSkip element, lets continue
auto exists =
std::find_if(toSkip.begin(), toSkip.end(), [&](const cv::Rect& skip) {
cv::Rect intersection(skip & roi_rect);
if (intersection.area() > 0) {
x += intersection.width + _step;
return true;
}
return false;
});
if (exists != toSkip.end()) { // intersection exists, we can skip
continue;
}
cv::Mat1b roi = level(roi_rect);
if (_vc->classify(roi)) { // variance
// std::cout << "V";
if (_fc->classify(roi)) { // features (shape)
// std::cout << "F";
if (_sc->classify(roi)) { // svm to refine
// std::cout << "S";
cv::Rect destPos(std::floor(x * factor), std::floor(y * factor),
winSize.width + 1, winSize.height + 1);
allCandidates.push_back(destPos);
// add current roi to toSkip vector
toSkip.push_back(roi_rect);
x += _windowSize.height;
}
}
// std::cout << std::endl;
}
}
}
}