Issues (125)

lib/Model/DlibCnnHogModel/DlibCnnHogModel.php (1 issue)

Labels
Severity
1
<?php
2
/**
3
 * @copyright Copyright (c) 2020-2024, 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 OCA\FaceRecognition\Helper\FaceRect;
27
28
use OCA\FaceRecognition\Model\IModel;
29
30
use OCA\FaceRecognition\Model\DlibCnnModel\DlibCnn5Model;
31
32
class DlibCnnHogModel implements IModel {
33
34
	/*
35
	 * Model files.
36
	 */
37
	const FACE_MODEL_ID = 4;
38
	const FACE_MODEL_NAME = "DlibCnnHog5";
39
	const FACE_MODEL_DESC = "Extends the main model, doing a face validation with the Hog detector";
40
	const FACE_MODEL_DOC = "https://github.com/matiasdelellis/facerecognition/wiki/Models#model-4";
41
42
	/** @var DlibCnn5Model */
43
	private $dlibCnn5Model;
44
45
	/**
46
	 * DlibCnnHogModel __construct.
47
	 *
48
	 * @param DlibCnn5Model $dlibCnn5Model
49
	 */
50 1
	public function __construct(DlibCnn5Model   $dlibCnn5Model)
51
	{
52 1
		$this->dlibCnn5Model    = $dlibCnn5Model;
53
	}
54
55
	public function getId(): int {
56
		return static::FACE_MODEL_ID;
57
	}
58
59
	public function getName(): string {
60
		return static::FACE_MODEL_NAME;
61
	}
62
63
	public function getDescription(): string {
64
		return static::FACE_MODEL_DESC;
65
	}
66
67
	public function getDocumentation(): string {
68
		return static::FACE_MODEL_DOC;
69
	}
70
71
	public function isInstalled(): bool {
72
		if (!$this->dlibCnn5Model->isInstalled())
73
			return false;
74
		return true;
75
	}
76
77
	public function meetDependencies(string &$error_message): bool {
78
		if (!$this->dlibCnn5Model->isInstalled()) {
79
			$error_message = "This Model depend on Model 1 and must install it.";
80
			return false;
81
		}
82
		return true;
83
	}
84
85
	public function getMaximumArea(): int {
86
		return $this->dlibCnn5Model->getMaximumArea();
87
	}
88
89
	public function getPreferredMimeType(): string {
90
		return $this->dlibCnn5Model->getPreferredMimeType();
91
	}
92
93
	/**
94
	 * @return void
95
	 */
96
	public function install() {
97
		// This model reuses models 1 and should not install anything.
98
	}
99
100
	/**
101
	 * @return void
102
	 */
103
	public function open() {
104
		$this->dlibCnn5Model->open();
105
	}
106
107
	public function detectFaces(string $imagePath, bool $compute = true): array {
108
		$detectedFaces = [];
109
110
		$cnnFaces = $this->dlibCnn5Model->detectFaces($imagePath);
111
		if (count($cnnFaces) === 0) {
112
			return $detectedFaces;
113
		}
114
115
		$hogFaces = dlib_face_detection($imagePath);
0 ignored issues
show
The function dlib_face_detection was not found. Maybe you did not declare it correctly or list all dependencies? ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-call  annotation

115
		$hogFaces = /** @scrutinizer ignore-call */ dlib_face_detection($imagePath);
Loading history...
116
117
		foreach ($cnnFaces as $proposedFace) {
118
			$detectedFaces[] = $this->validateFace($proposedFace, $hogFaces);
119
		}
120
121
		return $detectedFaces;
122
	}
123
124
	public function compute(string $imagePath, array $face): array {
125
		return $this->dlibCnn5Model->compute($imagePath, $face);
126
	}
127
128
	private function validateFace($proposedFace, array $validateFaces) {
129
		foreach ($validateFaces as $validateFace) {
130
			$overlapPercent = FaceRect::overlapPercent($proposedFace, $validateFace);
131
			/**
132
			 * The weak link in our default model is the landmark detector that
133
			 * can't align profile or rotate faces correctly.
134
			 *
135
			 * The Hog detector also fails and cannot detect these faces. So, we
136
			 * consider if Hog detector can detect it, to infer when the predictor
137
			 * will give good results.
138
			 *
139
			 * If Hog detects it (Overlap > 35%), we can assume that landmark
140
			 * detector will do it too. In this case, we consider the face valid,
141
			 * and just return it.
142
			 */
143
			if ($overlapPercent >= 0.35) {
144
				return $proposedFace;
145
			}
146
		}
147
148
		/**
149
		 * If Hog don't detect this face, they are probably in profile or rotated.
150
		 * These are bad to compare, so we lower the confidence, to avoid clustering.
151
		 */
152
		$confidence = $proposedFace['detection_confidence'];
153
		$proposedFace['detection_confidence'] = $confidence * 0.6;
154
155
		return $proposedFace;
156
	}
157
158
}
159