File indexing completed on 2025-03-09 03:54:59

0001 /* ============================================================
0002  *
0003  * This file is a part of digiKam
0004  *
0005  * Date        : 02-02-2012
0006  * Description : Face database interface to train face recognizer.
0007  *
0008  * SPDX-FileCopyrightText: 2012-2013 by Marcel Wiesweg <marcel dot wiesweg at gmx dot de>
0009  * SPDX-FileCopyrightText: 2010-2024 by Gilles Caulier <caulier dot gilles at gmail dot com>
0010  * SPDX-FileCopyrightText:      2019 by Thanh Trung Dinh <dinhthanhtrung1996 at gmail dot com>
0011  * SPDX-FileCopyrightText:      2020 by Nghia Duong <minhnghiaduong997 at gmail dot com>
0012  *
0013  * SPDX-License-Identifier: GPL-2.0-or-later
0014  *
0015  * ============================================================ */
0016 
0017 #include "facedb_p.h"
0018 
0019 namespace Digikam
0020 {
0021 
0022 int FaceDb::insertFaceVector(const cv::Mat& faceEmbedding,
0023                              const int label,
0024                              const QString& context) const
0025 {
0026     QVariantList bindingValues;
0027 
0028     bindingValues << label;
0029     bindingValues << context;
0030     bindingValues << QByteArray::fromRawData((char*)faceEmbedding.ptr<float>(), (sizeof(float) * 128));
0031 
0032     DbEngineSqlQuery query = d->db->execQuery(QLatin1String("INSERT INTO FaceMatrices (identity, `context`, embedding) "
0033                                                             "VALUES (?,?,?);"),
0034                                               bindingValues);
0035 
0036     if (query.lastInsertId().isNull())
0037     {
0038         qCWarning(DIGIKAM_FACEDB_LOG) << "fail to insert face embedding, last query"
0039                                       << query.lastQuery()
0040                                       << "bound values" << query.boundValues()
0041                                       << query.lastError();
0042     }
0043     else
0044     {
0045         qCDebug(DIGIKAM_FACEDB_LOG) << "Commit face mat data "
0046                                     << query.lastInsertId().toInt()
0047                                     << " for identity " << label;
0048     }
0049 
0050     return query.lastInsertId().toInt();
0051 }
0052 
0053 KDTree* FaceDb::reconstructTree() const
0054 {
0055     KDTree* const tree     = new KDTree(128);
0056     DbEngineSqlQuery query = d->db->execQuery(QLatin1String("SELECT id, identity, embedding FROM FaceMatrices;"));
0057 
0058     while (query.next())
0059     {
0060         int nodeId                    = query.value(0).toInt();
0061         int identity                  = query.value(1).toInt();
0062         cv::Mat recordedFaceEmbedding = cv::Mat(1, 128, CV_32F, query.value(2).toByteArray().data()).clone();
0063         KDNode* const newNode         = tree->add(recordedFaceEmbedding, identity);
0064 
0065         if (newNode)
0066         {
0067             newNode->setNodeId(nodeId);
0068         }
0069         else
0070         {
0071             qCWarning(DIGIKAM_FACEDB_LOG) << "Error insert node" << nodeId;
0072         }
0073     }
0074 
0075     return tree;
0076 }
0077 
0078 cv::Ptr<cv::ml::TrainData> FaceDb::trainData() const
0079 {
0080     cv::Mat feature, label;
0081     DbEngineSqlQuery query = d->db->execQuery(QLatin1String("SELECT identity, embedding "
0082                                                             "FROM FaceMatrices;"));
0083 
0084     while (query.next())
0085     {
0086         label.push_back(query.value(0).toInt());
0087         feature.push_back(cv::Mat(1, 128, CV_32F, query.value(1).toByteArray().data()).clone());
0088     }
0089 
0090     return cv::ml::TrainData::create(feature, 0, label);
0091 }
0092 
0093 void FaceDb::clearDNNTraining(const QString& context)
0094 {
0095     if (context.isNull())
0096     {
0097         d->db->execSql(QLatin1String("DELETE FROM FaceMatrices;"));
0098     }
0099     else
0100     {
0101         d->db->execSql(QLatin1String("DELETE FROM FaceMatrices WHERE `context`=?;"),
0102                        context);
0103     }
0104 }
0105 
0106 void FaceDb::clearDNNTraining(const QList<int>& identities, const QString& context)
0107 {
0108     Q_FOREACH (int id, identities)
0109     {
0110         if (context.isNull())
0111         {
0112             d->db->execSql(QLatin1String("DELETE FROM FaceMatrices WHERE identity=?;"),
0113                            id);
0114         }
0115         else
0116         {
0117             d->db->execSql(QLatin1String("DELETE FROM FaceMatrices WHERE identity=? AND `context`=?;"),
0118                            id, context);
0119         }
0120     }
0121 }
0122 
0123 } // namespace Digikam