1
|
|
|
<?php |
2
|
|
|
/** |
3
|
|
|
* @copyright Copyright (c) 2020, Matias De lellis <[email protected]> |
4
|
|
|
* |
5
|
|
|
* @author Matias De lellis <[email protected]> |
6
|
|
|
* |
7
|
|
|
* @license GNU AGPL version 3 or any later version |
8
|
|
|
* |
9
|
|
|
* This program is free software: you can redistribute it and/or modify |
10
|
|
|
* it under the terms of the GNU Affero General Public License as |
11
|
|
|
* published by the Free Software Foundation, either version 3 of the |
12
|
|
|
* License, or (at your option) any later version. |
13
|
|
|
* |
14
|
|
|
* This program is distributed in the hope that it will be useful, |
15
|
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of |
16
|
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
17
|
|
|
* GNU Affero General Public License for more details. |
18
|
|
|
* |
19
|
|
|
* You should have received a copy of the GNU Affero General Public License |
20
|
|
|
* along with this program. If not, see <http://www.gnu.org/licenses/>. |
21
|
|
|
* |
22
|
|
|
*/ |
23
|
|
|
|
24
|
|
|
namespace OCA\FaceRecognition\Model\DlibCnnHogModel; |
25
|
|
|
|
26
|
|
|
use OCP\IDBConnection; |
27
|
|
|
|
28
|
|
|
use OCA\FaceRecognition\Helper\FaceRect; |
29
|
|
|
|
30
|
|
|
use OCA\FaceRecognition\Model\IModel; |
31
|
|
|
|
32
|
|
|
use OCA\FaceRecognition\Model\DlibCnnModel\DlibCnn5Model; |
33
|
|
|
use OCA\FaceRecognition\Model\DlibHogModel\DlibHogModel; |
34
|
|
|
|
35
|
|
|
class DlibCnnHogModel implements IModel { |
36
|
|
|
|
37
|
|
|
/* |
38
|
|
|
* Model files. |
39
|
|
|
*/ |
40
|
|
|
const FACE_MODEL_ID = 4; |
41
|
|
|
const FACE_MODEL_NAME = "CnnHog5"; |
42
|
|
|
const FACE_MODEL_DESC = "Default Cnn model with Hog validation, and 5 point landmarks preprictor"; |
43
|
|
|
const FACE_MODEL_DOC = ""; |
44
|
|
|
|
45
|
|
|
/** @var IDBConnection */ |
46
|
|
|
private $connection; |
47
|
|
|
|
48
|
|
|
/** @var DlibCnn5Model */ |
49
|
|
|
private $dlibCnn5Model; |
50
|
|
|
|
51
|
|
|
/** @var DlibHogModel */ |
52
|
|
|
private $dlibHogModel; |
53
|
|
|
|
54
|
|
|
/** |
55
|
|
|
* DlibCnnHogModel __construct. |
56
|
|
|
* |
57
|
|
|
* @param IDBConnection $connection |
58
|
|
|
* @param DlibCnn5Model $dlibCnn5Model |
59
|
|
|
* @param DlibHogModel $dlibHogModel |
60
|
|
|
*/ |
61
|
1 |
|
public function __construct(IDBConnection $connection, |
62
|
|
|
DlibCnn5Model $dlibCnn5Model, |
63
|
|
|
DlibHogModel $dlibHogModel) |
64
|
|
|
{ |
65
|
1 |
|
$this->connection = $connection; |
66
|
1 |
|
$this->dlibCnn5Model = $dlibCnn5Model; |
67
|
1 |
|
$this->dlibHogModel = $dlibHogModel; |
68
|
1 |
|
} |
69
|
|
|
|
70
|
|
|
public function getId(): int { |
71
|
|
|
return static::FACE_MODEL_ID; |
72
|
|
|
} |
73
|
|
|
|
74
|
|
|
public function getName(): string { |
75
|
|
|
return static::FACE_MODEL_NAME; |
76
|
|
|
} |
77
|
|
|
|
78
|
|
|
public function getDescription(): string { |
79
|
|
|
return static::FACE_MODEL_DESC; |
80
|
|
|
} |
81
|
|
|
|
82
|
|
|
public function getDocumentation(): string { |
83
|
|
|
return static::FACE_MODEL_DOC; |
84
|
|
|
} |
85
|
|
|
|
86
|
|
|
public function isInstalled(): bool { |
87
|
|
|
if (!$this->dlibCnn5Model->isInstalled()) |
88
|
|
|
return false; |
89
|
|
|
if (!$this->dlibHogModel->isInstalled()) |
90
|
|
|
return false; |
91
|
|
|
return true; |
92
|
|
|
} |
93
|
|
|
|
94
|
|
|
public function meetDependencies(string &$error_message): bool { |
95
|
|
|
if (!$this->dlibCnn5Model->meetDependencies($error_message)) { |
96
|
|
|
$error_message .= " This Model depend on Model 1 and must install it."; |
97
|
|
|
return false; |
98
|
|
|
} |
99
|
|
|
if (!$this->dlibHogModel->meetDependencies($error_message)) { |
100
|
|
|
$error_message .= " This Model depend on Model 3 and must install it."; |
101
|
|
|
return false; |
102
|
|
|
} |
103
|
|
|
return true; |
104
|
|
|
} |
105
|
|
|
|
106
|
|
|
public function getMaximumArea(): int { |
107
|
|
|
return $this->dlibCnn5Model->getMaximumArea(); |
108
|
|
|
} |
109
|
|
|
|
110
|
|
|
public function getPreferredMimeType(): string { |
111
|
|
|
return $this->dlibCnn5Model->getPreferredMimeType(); |
112
|
|
|
} |
113
|
|
|
|
114
|
|
|
public function install() { |
115
|
|
|
if ($this->isInstalled()) { |
116
|
|
|
return; |
117
|
|
|
} |
118
|
|
|
|
119
|
|
|
// Insert on database and enable it |
120
|
|
|
$qb = $this->connection->getQueryBuilder(); |
121
|
|
|
$query = $qb->select($qb->createFunction('COUNT(' . $qb->getColumnName('id') . ')')) |
122
|
|
|
->from('facerecog_models') |
123
|
|
|
->where($qb->expr()->eq('id', $qb->createParameter('id'))) |
124
|
|
|
->setParameter('id', $this->getId()); |
125
|
|
|
$resultStatement = $query->execute(); |
126
|
|
|
$data = $resultStatement->fetch(\PDO::FETCH_NUM); |
127
|
|
|
$resultStatement->closeCursor(); |
128
|
|
|
|
129
|
|
|
if ((int)$data[0] <= 0) { |
130
|
|
|
$query = $this->connection->getQueryBuilder(); |
131
|
|
|
$query->insert('facerecog_models') |
132
|
|
|
->values([ |
133
|
|
|
'id' => $query->createNamedParameter($this->getId()), |
134
|
|
|
'name' => $query->createNamedParameter($this->getName()), |
135
|
|
|
'description' => $query->createNamedParameter($this->getDescription()) |
136
|
|
|
]) |
137
|
|
|
->execute(); |
138
|
|
|
} |
139
|
|
|
} |
140
|
|
|
|
141
|
|
|
public function open() { |
142
|
|
|
return $this->dlibCnn5Model->open(); |
|
|
|
|
143
|
|
|
} |
144
|
|
|
|
145
|
|
|
public function detectFaces(string $imagePath): array { |
146
|
|
|
$detectedFaces = []; |
147
|
|
|
|
148
|
|
|
$cnnFaces = $this->dlibCnn5Model->detectFaces($imagePath); |
149
|
|
|
$hogFaces = $this->dlibHogModel->detectFaces($imagePath); |
150
|
|
|
|
151
|
|
|
foreach ($cnnFaces as $proposedFace) { |
152
|
|
|
$detectedFaces[] = $this->validateFace($proposedFace, $hogFaces); |
153
|
|
|
} |
154
|
|
|
|
155
|
|
|
return $detectedFaces; |
156
|
|
|
} |
157
|
|
|
|
158
|
|
|
public function detectLandmarks(string $imagePath, array $rect): array { |
159
|
|
|
return $this->dlibCnn5Model->detectLandmarks($imagePath, $rect); |
160
|
|
|
} |
161
|
|
|
|
162
|
|
|
public function computeDescriptor(string $imagePath, array $landmarks): array { |
163
|
|
|
return $this->dlibCnn5Model->computeDescriptor($imagePath, $landmarks); |
164
|
|
|
} |
165
|
|
|
|
166
|
|
|
private function validateFace($proposedFace, $validateFaces) { |
167
|
|
|
foreach ($validateFaces as $validateFace) { |
168
|
|
|
$overlayPercent = FaceRect::getOverlayPercent($proposedFace, $validateFace); |
169
|
|
|
/** |
170
|
|
|
* The weak link in our default model is the landmark detector that |
171
|
|
|
* can't align profile faces correctly. |
172
|
|
|
* The Hog detector also fails and cannot detect these faces. |
173
|
|
|
* |
174
|
|
|
* So, if Hog detects it (Overlay > 80%), we know that the landmark |
175
|
|
|
* detector will do it too. |
176
|
|
|
* Just return it. |
177
|
|
|
*/ |
178
|
|
|
if ($overlayPercent > 0.8) { |
179
|
|
|
return $proposedFace; |
180
|
|
|
} |
181
|
|
|
} |
182
|
|
|
|
183
|
|
|
/** |
184
|
|
|
* If Hog don't detect this face, they are probably in profile or rotated. |
185
|
|
|
* These are bad to compare, so we lower the confidence, to avoid clustering. |
186
|
|
|
*/ |
187
|
|
|
$confidence = $proposedFace['detection_confidence']; |
188
|
|
|
$proposedFace['detection_confidence'] = $confidence * 0.9; |
189
|
|
|
|
190
|
|
|
return $proposedFace; |
191
|
|
|
} |
192
|
|
|
|
193
|
|
|
} |
194
|
|
|
|
This check looks for function or method calls that always return null and whose return value is used.
The method
getObject()
can return nothing but null, so it makes no sense to use the return value.The reason is most likely that a function or method is imcomplete or has been reduced for debug purposes.