File indexing completed on 2025-01-19 03:57:57
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 #include "trainerworker.h" 0017 0018 // Local includes 0019 0020 #include "digikam_debug.h" 0021 0022 namespace Digikam 0023 { 0024 0025 class Q_DECL_HIDDEN MapListTrainingDataProvider : public TrainingDataProvider 0026 { 0027 public: 0028 0029 MapListTrainingDataProvider() 0030 { 0031 } 0032 0033 ~MapListTrainingDataProvider() override 0034 { 0035 qDeleteAll(imagesToTrain); 0036 imagesToTrain.clear(); 0037 } 0038 0039 ImageListProvider* newImages(const Identity& identity) override 0040 { 0041 if (imagesToTrain.contains(identity.id())) 0042 { 0043 QListImageListProvider* const provider = imagesToTrain.value(identity.id()); 0044 0045 if (provider) 0046 { 0047 provider->reset(); 0048 } 0049 0050 return provider; 0051 } 0052 0053 return ∅ 0054 } 0055 0056 ImageListProvider* images(const Identity&) override 0057 { 0058 // Not implemented. Would be needed if we use a backend with a "holistic" approach that needs all images to train. 0059 0060 return ∅ 0061 } 0062 0063 public: 0064 0065 EmptyImageListProvider empty; 0066 QMap<int, QListImageListProvider*> imagesToTrain; 0067 }; 0068 0069 // ---------------------------------------------------------------------------------------- 0070 0071 TrainerWorker::TrainerWorker(FacePipeline::Private* const dd) 0072 : imageRetriever(dd), 0073 d (dd) 0074 { 0075 } 0076 0077 TrainerWorker::~TrainerWorker() 0078 { 0079 wait(); // protect detector 0080 } 0081 0082 /** 0083 * TODO: investigate this method 0084 */ 0085 void TrainerWorker::process(const FacePipelineExtendedPackage::Ptr& package) 0086 { 0087 /* 0088 qCDebug(DIGIKAM_GENERAL_LOG) << "TrainerWorker: processing one package"; 0089 */ 0090 // Get a list of faces with type FaceForTraining (probably type is ConfirmedFace) 0091 0092 QList<FaceTagsIface> toTrain; 0093 QList<int> identities; 0094 QList<Identity> identitySet; 0095 FaceUtils utils; 0096 0097 Q_FOREACH (const FacePipelineFaceTagsIface& face, package->databaseFaces) 0098 { 0099 if (face.roles & FacePipelineFaceTagsIface::ForTraining) 0100 { 0101 FaceTagsIface dbFace = face; 0102 dbFace.setType(FaceTagsIface::FaceForTraining); 0103 toTrain << dbFace; 0104 0105 Identity identity = utils.identityForTag(dbFace.tagId(), recognizer); 0106 0107 identities << identity.id(); 0108 0109 if (!identitySet.contains(identity)) 0110 { 0111 identitySet << identity; 0112 } 0113 } 0114 } 0115 0116 if (!toTrain.isEmpty()) 0117 { 0118 QList<QImage*> images; 0119 0120 if (package->image.isNull()) 0121 { 0122 images = imageRetriever.getThumbnails(package->filePath, toTrain); 0123 } 0124 else 0125 { 0126 images = imageRetriever.getDetails(package->image, toTrain); 0127 } 0128 0129 MapListTrainingDataProvider provider; 0130 0131 // Group images by identity 0132 0133 for (int i = 0 ; i < toTrain.size() ; ++i) 0134 { 0135 QListImageListProvider* const imageList = new QListImageListProvider; 0136 imageList->setImages(QList<QImage*>() << images[i]); 0137 provider.imagesToTrain[identities[i]] = imageList; 0138 } 0139 0140 // NOTE: cropped faces will be deleted by training provider 0141 0142 recognizer.train(identitySet, &provider, QLatin1String("digikam")); 0143 } 0144 0145 utils.removeFaces(toTrain); 0146 package->databaseFaces.replaceRole(FacePipelineFaceTagsIface::ForTraining, FacePipelineFaceTagsIface::Trained); 0147 package->processFlags |= FacePipelinePackage::ProcessedByTrainer; 0148 0149 Q_EMIT processed(package); 0150 } 0151 0152 void TrainerWorker::aboutToDeactivate() 0153 { 0154 imageRetriever.cancel(); 0155 } 0156 0157 } // namespace Digikam 0158 0159 #include "moc_trainerworker.cpp"