File indexing completed on 2025-03-09 03:55:01
0001 /* ============================================================ 0002 * 0003 * This file is a part of digiKam 0004 * 0005 * Date : 2020-05-22 0006 * Description : Wrapper of face recognition using OpenFace 0007 * 0008 * SPDX-FileCopyrightText: 2019 by Thanh Trung Dinh <dinhthanhtrung1996 at gmail dot com> 0009 * SPDX-FileCopyrightText: 2020-2024 by Gilles Caulier <caulier dot gilles at gmail dot com> 0010 * SPDX-FileCopyrightText: 2020 by Nghia Duong <minhnghiaduong997 at gmail dot com> 0011 * 0012 * SPDX-License-Identifier: GPL-2.0-or-later 0013 * 0014 * ============================================================ */ 0015 0016 #include "opencvdnnfacerecognizer_p.h" 0017 0018 namespace Digikam 0019 { 0020 0021 OpenCVDNNFaceRecognizer::OpenCVDNNFaceRecognizer(Classifier method) 0022 : d(new Private(method)) 0023 { 0024 } 0025 0026 OpenCVDNNFaceRecognizer::~OpenCVDNNFaceRecognizer() 0027 { 0028 delete d; 0029 } 0030 0031 void OpenCVDNNFaceRecognizer::setNbNeighBors(int k) 0032 { 0033 d->kNeighbors = k; 0034 } 0035 0036 void OpenCVDNNFaceRecognizer::setThreshold(float threshold) 0037 { 0038 d->threshold = threshold; 0039 } 0040 0041 cv::Mat OpenCVDNNFaceRecognizer::prepareForRecognition(QImage& inputImage) 0042 { 0043 cv::Mat cvImage; // = cv::Mat(image.height(), image.width(), CV_8UC3); 0044 cv::Mat cvImageWrapper; 0045 0046 if (inputImage.format() != QImage::Format_ARGB32_Premultiplied) 0047 { 0048 inputImage = inputImage.convertToFormat(QImage::Format_ARGB32_Premultiplied); 0049 } 0050 0051 cvImageWrapper = cv::Mat(inputImage.height(), inputImage.width(), CV_8UC4, inputImage.scanLine(0), inputImage.bytesPerLine()); 0052 cv::cvtColor(cvImageWrapper, cvImage, CV_RGBA2RGB); 0053 0054 /* 0055 resize(cvImage, cvImage, Size(256, 256), (0, 0), (0, 0), cv::INTER_LINEAR); 0056 equalizeHist(cvImage, cvImage); 0057 */ 0058 return cvImage; 0059 } 0060 0061 cv::Mat OpenCVDNNFaceRecognizer::prepareForRecognition(const cv::Mat& cvInputImage) 0062 { 0063 int TargetInputSize = 256; 0064 0065 cv::Mat cvOutputImage; 0066 0067 cv::resize(cvInputImage, cvOutputImage, cv::Size(TargetInputSize, TargetInputSize)); 0068 0069 return cvOutputImage; 0070 } 0071 0072 0073 void OpenCVDNNFaceRecognizer::train(const QList<QImage*>& images, 0074 const int label, 0075 const QString& context) 0076 { 0077 cv::parallel_for_(cv::Range(0, images.size()), Private::ParallelTrainer(d, images, label, context)); 0078 0079 d->newDataAdded = true; 0080 } 0081 0082 int OpenCVDNNFaceRecognizer::recognize(QImage* inputImage) 0083 { 0084 int id = -1; 0085 0086 cv::Mat faceEmbedding = d->extractors[0]->getFaceEmbedding(prepareForRecognition(*inputImage)); 0087 0088 switch (d->method) 0089 { 0090 case SVM: 0091 { 0092 id = d->predictSVM(faceEmbedding); 0093 break; 0094 } 0095 0096 case OpenCV_KNN: 0097 { 0098 id = d->predictKNN(faceEmbedding); 0099 break; 0100 } 0101 0102 case Tree: 0103 { 0104 id = d->predictKDTree(faceEmbedding); 0105 break; 0106 } 0107 0108 case DB: 0109 { 0110 id = d->predictDb(faceEmbedding); 0111 break; 0112 } 0113 0114 default: 0115 { 0116 qCWarning(DIGIKAM_FACEDB_LOG) << "Not recognized classifying method"; 0117 } 0118 } 0119 0120 return id; 0121 } 0122 0123 QVector<int> OpenCVDNNFaceRecognizer::recognize(const QList<QImage*>& inputImages) 0124 { 0125 QVector<int> ids; 0126 0127 cv::parallel_for_(cv::Range(0, inputImages.size()), Private::ParallelRecognizer(d, inputImages, ids)); 0128 0129 return ids; 0130 } 0131 0132 0133 void OpenCVDNNFaceRecognizer::clearTraining(const QList<int>& idsToClear, const QString& trainingContext) 0134 { 0135 if (idsToClear.isEmpty()) 0136 { 0137 FaceDbAccess().db()->clearDNNTraining(trainingContext); 0138 } 0139 else 0140 { 0141 FaceDbAccess().db()->clearDNNTraining(idsToClear, trainingContext); 0142 } 0143 /* 0144 FaceDbAccess().db()->clearTreeDb(); 0145 */ 0146 } 0147 0148 bool OpenCVDNNFaceRecognizer::registerTrainingData(const cv::Mat& preprocessedImage, int label) 0149 { 0150 cv::Mat faceEmbedding = d->extractors[0]->getFaceEmbedding(preprocessedImage); 0151 0152 if (d->method == Tree) 0153 { 0154 KDNode* const newNode = d->tree->add(faceEmbedding, label); 0155 0156 if (!newNode) 0157 { 0158 qCWarning(DIGIKAM_FACEDB_LOG) << "Error insert new node"; 0159 0160 return false; 0161 } 0162 } 0163 0164 return true; 0165 } 0166 0167 int OpenCVDNNFaceRecognizer::verifyTestData(const cv::Mat& preprocessedImage) 0168 { 0169 int id = -1; 0170 0171 if (d->method == Tree) 0172 { 0173 id = d->predictKDTree(d->extractors[0]->getFaceEmbedding(preprocessedImage)); 0174 } 0175 0176 return id; 0177 } 0178 0179 } // namespace Digikam