File indexing completed on 2025-01-19 03:57:56

0001 /* ============================================================
0002  *
0003  * This file is a part of digiKam project
0004  * https://www.digikam.org
0005  *
0006  * Date        : 2010-09-03
0007  * Description : Integrated, multithread face detection / recognition
0008  *
0009  * SPDX-FileCopyrightText: 2010-2011 by Marcel Wiesweg <marcel dot wiesweg at gmx dot de>
0010  * SPDX-FileCopyrightText: 2012-2024 by Gilles Caulier <caulier dot gilles at gmail dot com>
0011  *
0012  * SPDX-License-Identifier: GPL-2.0-or-later
0013  *
0014  * ============================================================ */
0015 
0016 #ifndef DIGIKAM_FACE_PIPELINE_H
0017 #define DIGIKAM_FACE_PIPELINE_H
0018 
0019 // Local includes
0020 
0021 #include "facepipelinepackage.h"
0022 
0023 namespace Digikam
0024 {
0025 
0026 class FacePipeline : public QObject
0027 {
0028     Q_OBJECT
0029 
0030 public:
0031 
0032     enum FilterMode
0033     {
0034         /// Will read any given image
0035         ScanAll,
0036 
0037         /// Will skip any image that is already marked as scanned
0038         SkipAlreadyScanned,
0039 
0040         /// Will read unconfirmed faces for recognition
0041         ReadUnconfirmedFaces,
0042 
0043         /// Will read faces marked for training
0044         ReadFacesForTraining,
0045 
0046         /// Will read faces which are confirmed
0047         ReadConfirmedFaces
0048     };
0049 
0050     enum WriteMode
0051     {
0052         /// Write results. Merge with existing entries.
0053         NormalWrite,
0054 
0055         /// Add new results. Previous all results will be cleared.
0056         OverwriteAllFaces,
0057 
0058         /// Add new results. Previous unconfirmed results will be cleared.
0059         OverwriteUnconfirmed
0060 
0061     };
0062 
0063 public:
0064 
0065     explicit FacePipeline();
0066     ~FacePipeline() override;
0067 
0068     /**
0069      * You can plug these four different steps in the working pipeline.
0070      * 1) Call any of the four plug...() methods. See below for supported combinations.
0071      * 2) Call construct() to set up the pipeline.
0072      *
0073      * - Database filter: Prepares database records and/or filters out items.
0074      *                    See FilterMode for specification.
0075      * - Preview loader:  If no preview loader is plugged, you must provide
0076      *                    a DImg for face detection and recognition
0077      * - Face Detector:   If no recognizer is plugged, all detected face are marked
0078      *                    as the unknown person
0079      * - Face Recognizer: If no detector is plugged, only already scanned faces
0080      *                    marked as unknown will be processed.
0081      *                    They are implicitly read from the database.
0082      * - DatabaseWriter:  Writes the detection and recognition results to the database.
0083      *                    The trainer works on a completely different storage
0084      *                    and is not affected by the database writer.
0085      * - DatabaseEditor:  Can confirm or reject faces
0086      *
0087      * PlugParallel: You can call this instead of the simple plugging method.
0088      * Depending on the number of processor cores of the machine and the memory cost,
0089      * more than one element may be plugged and process parallelly for this part of the pipeline.
0090      *
0091      * Supported combinations:
0092      *  (Database Filter ->) (Preview Loader ->) Detector -> Recognizer (-> DatabaseWriter)
0093      *  (Database Filter ->) (Preview Loader ->) Detector               (-> DatabaseWriter)
0094      *  (Database Filter ->) (Preview Loader ->) Recognizer             (-> DatabaseWriter)
0095      *  DatabaseEditor
0096      *  Trainer
0097      *  DatabaseEditor -> Trainer
0098      */
0099     void plugDatabaseFilter(FilterMode mode);
0100     void plugRerecognizingDatabaseFilter();
0101     void plugRetrainingDatabaseFilter();
0102     void plugFacePreviewLoader();
0103     void plugFaceDetector();
0104     void plugParallelFaceDetectors();
0105     void plugFaceRecognizer();
0106     void plugDatabaseWriter(WriteMode mode);
0107     void plugDatabaseEditor();
0108     void plugTrainer();
0109     void plugDetectionBenchmarker();
0110     void plugRecognitionBenchmarker();
0111     void construct();
0112 
0113     /**
0114      * Cancels all processing
0115      */
0116     void cancel();
0117 
0118     /**
0119      * Cancels and waits for the pipeline to finish
0120      */
0121     void shutDown();
0122 
0123     bool hasFinished()           const;
0124     QString benchmarkResult()    const;
0125 
0126     /**
0127      * Set the priority of the threads used by this pipeline.
0128      * The default setting is QThread::LowPriority.
0129      */
0130     void setPriority(QThread::Priority priority);
0131     QThread::Priority priority() const;
0132 
0133 public Q_SLOTS:
0134 
0135     /**
0136      * Processes the given image info. If a filter is installed,
0137      * returns false if the info is skipped, or true if it is processed.
0138      * If no preview loader is plugged, you must provide a DImg for detection or recognition.
0139      * Any of the signals below will only be emitted if true is returned.
0140      */
0141     bool process(const ItemInfo& info);
0142     bool process(const ItemInfo& info, const DImg& image);
0143 
0144     /**
0145      * Confirm the face. Pass the original face, and additionally tag id or region
0146      * if they changed. Returns the confirmed face entry immediately purely for convenience,
0147      * it is not yet in the database (connect to signal processed() to react when the processing finished).
0148      * If a trainer is plugged, the face will be trained.
0149      */
0150     FaceTagsIface confirm(const ItemInfo& info,
0151                           const FaceTagsIface& face,
0152                           int assignedTagId = 0,
0153                           const TagRegion& assignedRegion = TagRegion());
0154     FaceTagsIface confirm(const ItemInfo& info,
0155                           const FaceTagsIface& face,
0156                           const DImg& image,
0157                           int assignedTagId = 0,
0158                           const TagRegion& assignedRegion = TagRegion());
0159     /**
0160      * Train the given faces.
0161      */
0162     void train(const ItemInfo& info,
0163                const QList<FaceTagsIface>& faces);
0164     void train(const ItemInfo& info,
0165                const QList<FaceTagsIface>& faces,
0166                const DImg& image);
0167 
0168     /**
0169      * Remove the given face.
0170      */
0171     void remove(const ItemInfo& info,
0172                 const FaceTagsIface& face);
0173 
0174     /**
0175      * Add an entry manually.
0176      */
0177     FaceTagsIface addManually(const ItemInfo& info,
0178                               const DImg& image,
0179                               const TagRegion& assignedRegion);
0180 
0181     /**
0182      * Change the given face's region to newRegion.
0183      * Does not care for training atm.
0184      */
0185     FaceTagsIface editRegion(const ItemInfo& info,
0186                              const DImg& image,
0187                              const FaceTagsIface& databaseFace,
0188                              const TagRegion& newRegion);
0189 
0190     /**
0191      * Changes the given face's tagId to newTagId.
0192      * Used to Reject Facial Recognition suggestions, since
0193      * the tag needs to be converted from Unconfirmed to Unknown.
0194      */
0195     FaceTagsIface editTag(const ItemInfo& info,
0196                           const FaceTagsIface& databaseFace,
0197                           int newTagId);
0198 
0199     /**
0200      * Batch processing. If a filter is installed, the skipped() signal
0201      * will inform about skipped infos. Filtering is done in a thread, returns immediately.
0202      * Some of the signals below will be emitted in any case.
0203      */
0204     void process(const QList<ItemInfo>& infos);
0205 
0206     void setAccuracyAndModel(double accuracy, bool yolo);
0207 
0208 Q_SIGNALS:
0209 
0210     /// Emitted when processing is scheduled.
0211     void scheduled();
0212 
0213     /// Emitted when processing has started
0214     void started(const QString& message);
0215 
0216     /// Emitted when one package begins processing
0217     void processing(const FacePipelinePackage& package);
0218 
0219     /// Emitted when one package has finished processing
0220     void processed(const FacePipelinePackage& package);
0221     void progressValueChanged(float progress);
0222 
0223     /// Emitted when the last package has finished processing
0224     void finished();
0225 
0226     /// Emitted when one or several packages were skipped, usually because they have already been scanned.
0227     void skipped(const QList<ItemInfo>& skippedInfos);
0228 
0229 public:
0230 
0231     class Private;
0232 
0233 private:
0234 
0235     // Disable
0236     explicit FacePipeline(QObject*)              = delete;
0237     FacePipeline(const FacePipeline&)            = delete;
0238     FacePipeline& operator=(const FacePipeline&) = delete;
0239 
0240 private:
0241 
0242     Private* const d;
0243     friend class Private;
0244 };
0245 
0246 } // namespace Digikam
0247 
0248 #endif // DIGIKAM_FACE_PIPELINE_H