diff --git a/lib/ClustersBackend/FaceRecognitionBackend.php b/lib/ClustersBackend/FaceRecognitionBackend.php index cbf66914..cafaf18d 100644 --- a/lib/ClustersBackend/FaceRecognitionBackend.php +++ b/lib/ClustersBackend/FaceRecognitionBackend.php @@ -120,18 +120,14 @@ class FaceRecognitionBackend extends Backend 'y' => (float) $row['face_y'] / $row['image_height'], ]; - unset($row['face_x'], $row['face_y'], $row['face_w'], $row['face_h'], $row['image_height'], $row['image_width']); + unset($row['face_x'], $row['face_y'], $row['face_width'], $row['face_height'], $row['image_height'], $row['image_width']); } public function getClustersInternal(int $fileid = 0): array { - if ($fileid) { - throw new \Exception('FaceRecognitionBackend: fileid filter not implemented'); - } - $faces = array_merge( - $this->getFaceRecognitionPersons(), - $this->getFaceRecognitionClusters() + $this->getFaceRecognitionPersons($fileid), + $this->getFaceRecognitionClusters($fileid) ); // Post process @@ -161,7 +157,6 @@ class FaceRecognitionBackend extends Backend 'frf.height', 'm.w as image_width', // Scoring 'm.h as image_height', - 'frf.confidence', 'm.fileid', 'm.datetaken', // Just in case, for postgres )->from('facerecog_faces', 'frf'); @@ -225,7 +220,12 @@ class FaceRecognitionBackend extends Backend return (int) $this->config->getAppValue('facerecognition', 'model', -1); } - private function getFaceRecognitionClusters(bool $show_singles = false, bool $show_hidden = false) + private function minFaceInClusters(): int + { + return (int) $this->config->getAppValue('facerecognition', 'min_faces_in_cluster', 5); + } + + private function getFaceRecognitionClusters(int $fileid = 0) { $query = $this->tq->getBuilder(); @@ -255,13 +255,14 @@ class FaceRecognitionBackend extends Backend $query->addGroupBy('frp.user'); $query->where($query->expr()->isNull('frp.name')); - // By default hides individual faces when they have no name. - if (!$show_singles) { - $query->having($query->expr()->gt($count, $query->expr()->literal(1, \PDO::PARAM_INT))); - } - - // By default it shows the people who were not hidden - if (!$show_hidden) { + // The query change if we want the people in an fileid, or the unnamed clusters + if ($fileid > 0) { + // WHERE these clusters contain fileid if specified + $query->andWhere($query->expr()->eq('fri.file', $query->createNamedParameter($fileid))); + } else { + // WHERE these clusters has a minimum number of faces + $query->having($query->expr()->gte($count, $query->expr()->literal($this->minFaceInClusters(), \PDO::PARAM_INT))); + // WHERE these clusters were not hidden due inconsistencies $query->andWhere($query->expr()->eq('frp.is_visible', $query->expr()->literal(1))); } @@ -276,7 +277,7 @@ class FaceRecognitionBackend extends Backend return $this->tq->executeQueryWithCTEs($query)->fetchAll() ?: []; } - private function getFaceRecognitionPersons() + private function getFaceRecognitionPersons(int $fileid = 0) { $query = $this->tq->getBuilder(); @@ -303,6 +304,12 @@ class FaceRecognitionBackend extends Backend // GROUP by name of face clusters $query->where($query->expr()->isNotNull('frp.name')); + + // WHERE these clusters contain fileid if specified + if ($fileid > 0) { + $query->andWhere($query->expr()->eq('fri.file', $query->createNamedParameter($fileid))); + } + $query->groupBy('frp.user'); $query->addGroupBy('frp.name'); diff --git a/src/components/Metadata.vue b/src/components/Metadata.vue index 69443953..21a0d19e 100644 --- a/src/components/Metadata.vue +++ b/src/components/Metadata.vue @@ -352,7 +352,14 @@ export default defineComponent({ }, people(): IFace[] { - return this.baseInfo?.clusters?.recognize ?? []; + const clusters = this.baseInfo?.clusters; + + // force face-recognition on its own route, or if recognize is disabled + if (this.routeIsFaceRecognition || !this.config.recognize_enabled) { + return clusters?.facerecognition ?? []; + } + + return clusters?.recognize ?? []; }, }, @@ -367,6 +374,7 @@ export default defineComponent({ const clusters = [ this.config.albums_enabled ? 'albums' : null, this.config.recognize_enabled ? 'recognize' : null, + this.config.facerecognition_enabled ? 'facerecognition' : null, ] .filter((c) => c) .join(','); diff --git a/src/mixins/GlobalMixin.ts b/src/mixins/GlobalMixin.ts index fe5a8194..30c4bb42 100644 --- a/src/mixins/GlobalMixin.ts +++ b/src/mixins/GlobalMixin.ts @@ -31,6 +31,9 @@ export default defineComponent({ routeIsRecognizeUnassigned(): boolean { return this.routeIsRecognize && this.$route.params.name === constants.FACE_NULL; }, + routeIsFaceRecognition(): boolean { + return this.$route.name === 'facerecognition'; + }, routeIsArchive(): boolean { return this.$route.name === 'archive'; }, diff --git a/src/types.ts b/src/types.ts index 432f453a..1ac9f1a1 100644 --- a/src/types.ts +++ b/src/types.ts @@ -109,6 +109,7 @@ export interface IImageInfo { clusters?: { albums?: IAlbum[]; recognize?: IFace[]; + facerecognition?: IFace[]; }; } diff --git a/src/vue-globals.d.ts b/src/vue-globals.d.ts index b7d623cf..164fe487 100644 --- a/src/vue-globals.d.ts +++ b/src/vue-globals.d.ts @@ -17,6 +17,7 @@ declare module 'vue' { routeIsPeople: boolean; routeIsRecognize: boolean; routeIsRecognizeUnassigned: boolean; + routeIsFaceRecognition: boolean; routeIsArchive: boolean; routeIsPlaces: boolean; routeIsMap: boolean;