Passed
Push — master ( 7063d6...9e7aeb )
by Matias
04:08
created

DlibCnnModel   A

Complexity

Total Complexity 22

Size/Duplication

Total Lines 174
Duplicated Lines 0 %

Test Coverage

Coverage 56.52%

Importance

Changes 0
Metric Value
eloc 76
c 0
b 0
f 0
dl 0
loc 174
ccs 39
cts 69
cp 0.5652
rs 10
wmc 22

13 Methods

Rating   Name   Duplication   Size   Complexity  
A open() 0 4 1
A install() 0 20 2
A meetDependencies() 0 15 4
A __construct() 0 9 1
A detectFaces() 0 14 3
A getDescription() 0 2 1
A getName() 0 2 1
A isInstalled() 0 8 4
A getMaximumArea() 0 3 1
A getPreferredMimeType() 0 2 1
A getId() 0 2 1
A compute() 0 8 1
A getDocumentation() 0 2 1
1
<?php
2
/**
3
 * @copyright Copyright (c) 2021-2023, Matias De lellis <[email protected]>
4
 * @copyright Copyright (c) 2018, Branko Kokanovic <[email protected]>
5
 *
6
 * @author Branko Kokanovic <[email protected]>
7
 *
8
 * @license GNU AGPL version 3 or any later version
9
 *
10
 * This program is free software: you can redistribute it and/or modify
11
 * it under the terms of the GNU Affero General Public License as
12
 * published by the Free Software Foundation, either version 3 of the
13
 * License, or (at your option) any later version.
14
 *
15
 * This program is distributed in the hope that it will be useful,
16
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
17
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
18
 * GNU Affero General Public License for more details.
19
 *
20
 * You should have received a copy of the GNU Affero General Public License
21
 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
22
 *
23
 */
24
25
namespace OCA\FaceRecognition\Model\DlibCnnModel;
26
27
use OCA\FaceRecognition\Service\CompressionService;
28
use OCA\FaceRecognition\Service\DownloadService;
29
use OCA\FaceRecognition\Service\ModelService;
30
use OCA\FaceRecognition\Service\SettingsService;
31
32
use OCA\FaceRecognition\Model\IModel;
33
34
class DlibCnnModel implements IModel {
35
36
	/*
37
	 * Model files.
38
	 */
39
	const FACE_MODEL_ID = -1;
40
	const FACE_MODEL_NAME = "";
41
	const FACE_MODEL_DESC = "";
42
	const FACE_MODEL_DOC = "";
43
44
	/** Relationship between image size and memory consumed */
45
	const MEMORY_AREA_RELATIONSHIP = -1;
46
	const MINIMUM_MEMORY_REQUIREMENTS = -1;
47
48
	const FACE_MODEL_BZ2_URLS = array();
49
	const FACE_MODEL_FILES = array();
50
51
	const I_MODEL_DETECTOR = 0;
52
	const I_MODEL_PREDICTOR = 1;
53
	const I_MODEL_RESNET = 2;
54
55
	const PREFERRED_MIMETYPE = 'image/png';
56
57
	/** @var \CnnFaceDetection */
0 ignored issues
show
Bug introduced by
The type CnnFaceDetection was not found. Maybe you did not declare it correctly or list all dependencies?

The issue could also be caused by a filter entry in the build configuration. If the path has been excluded in your configuration, e.g. excluded_paths: ["lib/*"], you can move it to the dependency path list as follows:

filter:
    dependency_paths: ["lib/*"]

For further information see https://scrutinizer-ci.com/docs/tools/php/php-scrutinizer/#list-dependency-paths

Loading history...
58
	private $cfd;
59
60
	/** @var \FaceLandmarkDetection */
0 ignored issues
show
Bug introduced by
The type FaceLandmarkDetection was not found. Maybe you did not declare it correctly or list all dependencies?

The issue could also be caused by a filter entry in the build configuration. If the path has been excluded in your configuration, e.g. excluded_paths: ["lib/*"], you can move it to the dependency path list as follows:

filter:
    dependency_paths: ["lib/*"]

For further information see https://scrutinizer-ci.com/docs/tools/php/php-scrutinizer/#list-dependency-paths

Loading history...
61
	private $fld;
62
63
	/** @var \FaceRecognition */
0 ignored issues
show
Bug introduced by
The type FaceRecognition was not found. Maybe you did not declare it correctly or list all dependencies?

The issue could also be caused by a filter entry in the build configuration. If the path has been excluded in your configuration, e.g. excluded_paths: ["lib/*"], you can move it to the dependency path list as follows:

filter:
    dependency_paths: ["lib/*"]

For further information see https://scrutinizer-ci.com/docs/tools/php/php-scrutinizer/#list-dependency-paths

Loading history...
64
	private $fr;
65
66
	/** @var CompressionService */
67
	private $compressionService;
68
69
	/** @var DownloadService */
70
	private $downloadService;
71
72
	/** @var ModelService */
73
	private $modelService;
74
75
	/** @var SettingsService */
76
	private $settingsService;
77
78
79
	/**
80
	 * DlibCnnModel __construct.
81
	 *
82
	 * @param CompressionService $compressionService
83
	 * @param DownloadService $downloadService
84
	 * @param ModelService $modelService
85
	 * @param SettingsService $settingsService
86
	 */
87 1
	public function __construct(CompressionService $compressionService,
88
	                            DownloadService $downloadService,
89
	                            ModelService    $modelService,
90
	                            SettingsService $settingsService)
91
	{
92 1
		$this->compressionService = $compressionService;
93 1
		$this->downloadService    = $downloadService;
94 1
		$this->modelService     = $modelService;
95 1
		$this->settingsService  = $settingsService;
96
	}
97
98 4
	public function getId(): int {
99 4
		return static::FACE_MODEL_ID;
100
	}
101
102
	public function getName(): string {
103
		return static::FACE_MODEL_NAME;
104
	}
105
106
	public function getDescription(): string {
107
		return static::FACE_MODEL_DESC;
108
	}
109
110
	public function getDocumentation(): string {
111
		return static::FACE_MODEL_DOC;
112
	}
113
114 4
	public function isInstalled(): bool {
115 4
		if (!$this->modelService->modelFileExists($this->getId(), static::FACE_MODEL_FILES[self::I_MODEL_DETECTOR]))
116 1
			return false;
117 3
		if (!$this->modelService->modelFileExists($this->getId(), static::FACE_MODEL_FILES[self::I_MODEL_PREDICTOR]))
118
			return false;
119 3
		if (!$this->modelService->modelFileExists($this->getId(), static::FACE_MODEL_FILES[self::I_MODEL_RESNET]))
120
			return false;
121 3
		return true;
122
	}
123
124
	public function meetDependencies(string &$error_message): bool {
125
		if (!extension_loaded('pdlib')) {
126
			$error_message = "The PDlib PHP extension is not loaded";
127
			return false;
128
		}
129
		$availableMemory = $this->settingsService->getAssignedMemory();
130
		if ($availableMemory < 0) {
131
			$error_message = "Seems that you still have to configure the assigned memory for image processing.";
132
			return false;
133
		}
134
		if ($availableMemory < static::MINIMUM_MEMORY_REQUIREMENTS) {
135
			$error_message = "Your system does not meet the minimum memory requirements.";
136
			return false;
137
		}
138
		return true;
139
	}
140
141
	public function getMaximumArea(): int {
142
		$assignedMemory = $this->settingsService->getAssignedMemory();
143
		return intval($assignedMemory/static::MEMORY_AREA_RELATIONSHIP);
144
	}
145
146 4
	public function getPreferredMimeType(): string {
147 4
		return static::PREFERRED_MIMETYPE;
148
	}
149
150
	/**
151
	 * @return void
152
	 */
153 4
	public function install() {
154 4
		if ($this->isInstalled()) {
155 3
			return;
156
		}
157
158
		// Create main folder where install models.
159 1
		$this->modelService->prepareModelFolder($this->getId());
160
161
		/* Download and install models */
162 1
		$detectorModelBz2 = $this->downloadService->downloadFile(static::FACE_MODEL_BZ2_URLS[self::I_MODEL_DETECTOR]);
163 1
		$this->compressionService->bunzip2($detectorModelBz2, $this->modelService->getFileModelPath($this->getId(), static::FACE_MODEL_FILES[self::I_MODEL_DETECTOR]));
164
165 1
		$predictorModelBz2 = $this->downloadService->downloadFile(static::FACE_MODEL_BZ2_URLS[self::I_MODEL_PREDICTOR]);
166 1
		$this->compressionService->bunzip2($predictorModelBz2, $this->modelService->getFileModelPath($this->getId(), static::FACE_MODEL_FILES[self::I_MODEL_PREDICTOR]));
167
168 1
		$resnetModelBz2 = $this->downloadService->downloadFile(static::FACE_MODEL_BZ2_URLS[self::I_MODEL_RESNET]);
169 1
		$this->compressionService->bunzip2($resnetModelBz2, $this->modelService->getFileModelPath($this->getId(), static::FACE_MODEL_FILES[self::I_MODEL_RESNET]));
170
171
		/* Clean temporary files */
172 1
		$this->downloadService->clean();
173
	}
174
175
	/**
176
	 * @return void
177
	 */
178 4
	public function open() {
179 4
		$this->cfd = new \CnnFaceDetection($this->modelService->getFileModelPath($this->getId(), static::FACE_MODEL_FILES[self::I_MODEL_DETECTOR]));
180 4
		$this->fld = new \FaceLandmarkDetection($this->modelService->getFileModelPath($this->getId(), static::FACE_MODEL_FILES[self::I_MODEL_PREDICTOR]));
181 4
		$this->fr = new \FaceRecognition($this->modelService->getFileModelPath($this->getId(), static::FACE_MODEL_FILES[self::I_MODEL_RESNET]));
182
	}
183
184 2
	public function detectFaces(string $imagePath, bool $compute = true): array {
185 2
		$faces_detected = $this->cfd->detect($imagePath, 0);
186
187 2
		if (!$compute)
188
			return $faces_detected;
189
190 2
		foreach ($faces_detected as &$face) {
191 1
			$landmarks = $this->fld->detect($imagePath, $face);
192 1
			$descriptor = $this->fr->computeDescriptor($imagePath, $landmarks);
193
194 1
			$face['landmarks'] = $landmarks['parts'];
195 1
			$face['descriptor'] = $descriptor;
196
		}
197 2
		return $faces_detected;
198
	}
199
200
	public function compute(string $imagePath, array $face): array {
201
		$landmarks = $this->fld->detect($imagePath, $face);
202
		$descriptor = $this->fr->computeDescriptor($imagePath, $landmarks);
203
204
		$face['landmarks'] = $landmarks['parts'];
205
		$face['descriptor'] = $descriptor;
206
207
		return $face;
208
	}
209
210
}
211