diff --git a/core/libs/facesengine/facedb/facedb.h b/core/libs/facesengine/facedb/facedb.h index dbec985f87..118b44a700 100644 --- a/core/libs/facesengine/facedb/facedb.h +++ b/core/libs/facesengine/facedb/facedb.h @@ -1,129 +1,131 @@ /* ============================================================ * * This file is a part of digiKam * * Date : 02-02-2012 * Description : Face database interface to train identities. * * Copyright (C) 2012-2013 by Marcel Wiesweg * Copyright (C) 2010-2020 by Gilles Caulier * * This program is free software; you can redistribute it * and/or modify it under the terms of the GNU General * Public License as published by the Free Software Foundation; * either version 2, or (at your option) * any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * ============================================================ */ #ifndef DIGIKAM_FACE_DB_H #define DIGIKAM_FACE_DB_H // C++ includes #include // Qt includes #include #include #include #include // Local includes #include "digikam_config.h" #include "identity.h" #include "facedbbackend.h" #include "opencvmatdata.h" namespace Digikam { class LBPHFaceModel; class EigenFaceModel; class FisherFaceModel; class DNNFaceModel; class FaceDb { public: explicit FaceDb(FaceDbBackend* const db); ~FaceDb(); BdEngineBackend::QueryState setSetting(const QString& keyword, const QString& value); QString setting(const QString& keyword) const; /** * Returns true if the integrity of the database is preserved. */ bool integrityCheck(); /** * Shrinks the database. */ void vacuum(); public: // --- Identity management (facedb_identity.cpp) int addIdentity() const; int getNumberOfIdentities() const; void updateIdentity(const Identity& p); void deleteIdentity(int id); void deleteIdentity(const QString& uuid); QList identities() const; QList identityIds() const; public: // --- OpenCV LBPH void updateLBPHFaceModel(LBPHFaceModel& model); LBPHFaceModel lbphFaceModel() const; void clearLBPHTraining(const QString& context = QString()); void clearLBPHTraining(const QList& identities, const QString& context = QString()); public: // --- OpenCV EIGEN void updateEIGENFaceModel(EigenFaceModel& model, const std::vector& images_rgb); EigenFaceModel eigenFaceModel() const; void clearEIGENTraining(const QString& context = QString()); void clearEIGENTraining(const QList& identities, const QString& context = QString()); public: // --- OpenCV FISHER FisherFaceModel fisherFaceModel() const; public: // --- OpenCV DNN void updateDNNFaceModel(DNNFaceModel& model); DNNFaceModel dnnFaceModel(bool debug) const; + void clearDNNTraining(const QString& context = QString()); + void clearDNNTraining(const QList& identities, const QString& context = QString()); private: // Hidden copy constructor and assignment operator. FaceDb(const FaceDb&); FaceDb& operator=(const FaceDb&); class Private; Private* const d; }; } // namespace Digikam #endif // DIGIKAM_FACE_DB_H diff --git a/core/libs/facesengine/facedb/facedb_dnn.cpp b/core/libs/facesengine/facedb/facedb_dnn.cpp index 7f9563a07a..206e5c4fb4 100644 --- a/core/libs/facesengine/facedb/facedb_dnn.cpp +++ b/core/libs/facesengine/facedb/facedb_dnn.cpp @@ -1,166 +1,196 @@ /* ============================================================ * * This file is a part of digiKam * * Date : 02-02-2012 * Description : Face database interface to train identities. * * Copyright (C) 2012-2013 by Marcel Wiesweg * Copyright (C) 2010-2020 by Gilles Caulier * Copyright (C) 2019 by Thanh Trung Dinh * * This program is free software; you can redistribute it * and/or modify it under the terms of the GNU General * Public License as published by the Free Software Foundation; * either version 2, or (at your option) * any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * ============================================================ */ #include "facedb_p.h" namespace Digikam { void FaceDb::updateDNNFaceModel(DNNFaceModel& model) { QList metadataList = model.vecMetadata(); for (size_t i = 0 ; i < (size_t)metadataList.size() ; ++i) { const DNNFaceVecMetadata& metadata = metadataList[i]; if (metadata.storageStatus == DNNFaceVecMetadata::Created) { std::vector vecdata = model.vecData(i); if (vecdata.size() > 2) { qCDebug(DIGIKAM_FACEDB_LOG) << "vecdata: " << vecdata[vecdata.size()-2] << vecdata[vecdata.size()-1]; } QByteArray vec_byte(vecdata.size() * sizeof(float), 0); float* const fp = reinterpret_cast(vec_byte.data()); for (size_t k = 0 ; k < vecdata.size() ; ++k) { *(fp + k) = vecdata[k]; } QByteArray compressed_vecdata = qCompress(vec_byte); if (compressed_vecdata.isEmpty()) { qCWarning(DIGIKAM_FACEDB_LOG) << "Cannot compress face mat data to commit in database for identity " << metadata.identity; } else { QVariantList histogramValues; QVariant insertedId; histogramValues << metadata.identity << metadata.context << compressed_vecdata; QVariantList values; d->db->execSql(QLatin1String("SELECT id FROM FaceMatrices " "WHERE identity=? AND `context`=?;"), metadata.identity, metadata.context, &values); if (values.count() > 20) { for (int j = 0 ; j < values.count() - 20 ; ++j) { qCDebug(DIGIKAM_FACEDB_LOG) << "Delete face mat data " << values.at(j).toInt() << " for identity " << metadata.identity; d->db->execSql(QLatin1String("DELETE FROM FaceMatrices " "WHERE id=? AND identity=? AND `context`=?;"), values.at(j).toInt(), metadata.identity, metadata.context); } } d->db->execSql(QLatin1String("INSERT INTO FaceMatrices (identity, `context`, vecdata) " "VALUES (?,?,?);"), histogramValues, nullptr, &insertedId); model.setWrittenToDatabase(i, insertedId.toInt()); qCDebug(DIGIKAM_FACEDB_LOG) << "Commit compressed face mat data " << insertedId << " for identity " << metadata.identity << " with size " << compressed_vecdata.size(); } } } } DNNFaceModel FaceDb::dnnFaceModel(bool debug) const { if(debug) { return DNNFaceModel(); } qCDebug(DIGIKAM_FACEDB_LOG) << "Loading DNN model"; DbEngineSqlQuery query = d->db->execQuery(QLatin1String("SELECT id, identity, `context`, vecdata " "FROM FaceMatrices;")); DNNFaceModel model = DNNFaceModel(); QList> mats; QList matMetadata; while (query.next()) { DNNFaceVecMetadata metadata; std::vector vecdata; metadata.databaseId = query.value(0).toInt(); metadata.identity = query.value(1).toInt(); metadata.context = query.value(2).toString(); metadata.storageStatus = DNNFaceVecMetadata::InDatabase; QByteArray cData = query.value(3).toByteArray(); if (!cData.isEmpty()) { QByteArray new_vec = qUncompress(cData); if (new_vec.isEmpty()) { qCWarning(DIGIKAM_FACEDB_LOG) << "Cannot uncompress face mat data to checkout from database for identity " << metadata.identity; } else { qCDebug(DIGIKAM_FACEDB_LOG) << "Checkout face mat data " << metadata.databaseId << " for identity " << metadata.identity << " with size " << cData.size(); float* const it = reinterpret_cast(new_vec.data()); for (size_t i = 0 ; i < new_vec.size() / sizeof(float) ; ++i) { vecdata.push_back(*(it+i)); } mats << vecdata; matMetadata << metadata; } } else { qCWarning(DIGIKAM_FACEDB_LOG) << "Face mat data to checkout from database are empty for identity " << metadata.identity; } } model.setMats(mats, matMetadata); return model; } +void FaceDb::clearDNNTraining(const QString& context) +{ + if (context.isNull()) + { + d->db->execSql(QLatin1String("DELETE FROM FaceMatrices;")); + } + else + { + d->db->execSql(QLatin1String("DELETE FROM FaceMatrices WHERE `context`=?;"), + context); + } +} + +void FaceDb::clearDNNTraining(const QList& identities, const QString& context) +{ + foreach (int id, identities) + { + if (context.isNull()) + { + d->db->execSql(QLatin1String("DELETE FROM FaceMatrices WHERE identity=?;"), + id); + } + else + { + d->db->execSql(QLatin1String("DELETE FROM FaceMatrices WHERE identity=? AND `context`=?;"), + id, context); + } + } +} + } // namespace Digikam diff --git a/core/libs/facesengine/facedb/facedb_eigen.cpp b/core/libs/facesengine/facedb/facedb_eigen.cpp index fd8668949e..2801af23c5 100644 --- a/core/libs/facesengine/facedb/facedb_eigen.cpp +++ b/core/libs/facesengine/facedb/facedb_eigen.cpp @@ -1,198 +1,201 @@ /* ============================================================ * * This file is a part of digiKam * * Date : 02-02-2012 * Description : Face database interface to train identities. * * Copyright (C) 2012-2013 by Marcel Wiesweg * Copyright (C) 2010-2020 by Gilles Caulier * Copyright (C) 2019 by Thanh Trung Dinh * * This program is free software; you can redistribute it * and/or modify it under the terms of the GNU General * Public License as published by the Free Software Foundation; * either version 2, or (at your option) * any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * ============================================================ */ #include "facedb_p.h" namespace Digikam { void FaceDb::updateEIGENFaceModel(EigenFaceModel& model, const std::vector& images_rgb) { QList metadataList = model.matMetadata(); for (size_t i = 0, j = 0 ; i < (size_t)metadataList.size() ; ++i) { const EigenFaceMatMetadata& metadata = metadataList[i]; if (metadata.storageStatus == EigenFaceMatMetadata::Created) { OpenCVMatData data = model.matData(i); cv::Mat mat_rgb; if (j >= images_rgb.size()) { qCWarning(DIGIKAM_FACEDB_LOG) << "updateEIGENFaceModel: the size of images_rgb is wrong"; } else { mat_rgb = images_rgb[j++]; } if (data.data.isEmpty()) { qCWarning(DIGIKAM_FACEDB_LOG) << "Eigenface data to commit in database are empty for Identity " << metadata.identity; } else { QByteArray compressed = qCompress(data.data); std::vector vecdata; /** FIXME !!! Why the Eigen face use DNN code here ??? * Otherwise, how does it comput vecdata ??? * Buggy codes from GSoC 2017 */ // this->getFaceVector(mat_rgb, vecdata); QByteArray vec_byte(vecdata.size() * sizeof(float), 0); float* const fp = reinterpret_cast(vec_byte.data()); for (size_t k = 0 ; k < vecdata.size() ; ++k) { *(fp + k) = vecdata[k]; } QByteArray compressed_vecdata = qCompress(vec_byte); if (compressed.isEmpty()) { qCWarning(DIGIKAM_FACEDB_LOG) << "Cannot compress mat data to commit in database for Identity " << metadata.identity; } else if (compressed_vecdata.isEmpty()) { qCWarning(DIGIKAM_FACEDB_LOG) << "Cannot compress face vec data to commit in database for Identity " << metadata.identity; } else { QVariantList histogramValues; QVariant insertedId; histogramValues << metadata.identity << metadata.context << data.type << data.rows << data.cols << compressed << compressed_vecdata; d->db->execSql(QLatin1String("INSERT INTO FaceMatrices (identity, `context`, `type`, `rows`, `cols`, `data`, vecdata) " "VALUES (?,?,?,?,?,?,?);"), histogramValues, nullptr, &insertedId); model.setWrittenToDatabase(i, insertedId.toInt()); qCDebug(DIGIKAM_FACEDB_LOG) << "Commit compressed matData " << insertedId << " for identity " << metadata.identity << " with size " << compressed.size(); } } } } } EigenFaceModel FaceDb::eigenFaceModel() const { qCDebug(DIGIKAM_FACEDB_LOG) << "Loading EIGEN model"; DbEngineSqlQuery query = d->db->execQuery(QLatin1String("SELECT id, identity, `context`, `type`, `rows`, `cols`, `data`, vecdata " "FROM FaceMatrices;")); EigenFaceModel model = EigenFaceModel(); QList mats; QList matMetadata; while (query.next()) { EigenFaceMatMetadata metadata; OpenCVMatData data; metadata.databaseId = query.value(0).toInt(); metadata.identity = query.value(1).toInt(); metadata.context = query.value(2).toString(); metadata.storageStatus = EigenFaceMatMetadata::InDatabase; // cv::Mat data.type = query.value(3).toInt(); data.rows = query.value(4).toInt(); data.cols = query.value(5).toInt(); QByteArray cData = query.value(6).toByteArray(); if (!cData.isEmpty()) { data.data = qUncompress(cData); if (data.data.isEmpty()) { qCWarning(DIGIKAM_FACEDB_LOG) << "Cannot uncompress mat data to checkout from database for Identity " << metadata.identity; } else { qCDebug(DIGIKAM_FACEDB_LOG) << "Checkout compressed histogram " << metadata.databaseId << " for identity " << metadata.identity << " with size " << cData.size(); mats << data; matMetadata << metadata; } } else { qCWarning(DIGIKAM_FACEDB_LOG) << "Mat data to checkout from database are empty for Identity " << metadata.identity; } } model.setMats(mats, matMetadata); return model; } void FaceDb::clearEIGENTraining(const QString& context) { if (context.isNull()) { d->db->execSql(QLatin1String("DELETE FROM FaceMatrices;")); } else { - d->db->execSql(QLatin1String("DELETE FROM FaceMatrices WHERE `context`=?;"), context); + d->db->execSql(QLatin1String("DELETE FROM FaceMatrices WHERE `context`=?;"), + context); } } void FaceDb::clearEIGENTraining(const QList& identities, const QString& context) { foreach (int id, identities) { if (context.isNull()) { - d->db->execSql(QLatin1String("DELETE FROM FaceMatrices WHERE identity=?;"), id); + d->db->execSql(QLatin1String("DELETE FROM FaceMatrices WHERE identity=?;"), + id); } else { - d->db->execSql(QLatin1String("DELETE FROM FaceMatrices WHERE identity=? AND `context`=?;"), id, context); + d->db->execSql(QLatin1String("DELETE FROM FaceMatrices WHERE identity=? AND `context`=?;"), + id, context); } } } } // namespace Digikam diff --git a/core/libs/facesengine/facedb/facedb_lbph.cpp b/core/libs/facesengine/facedb/facedb_lbph.cpp index 6c984ab03d..06b68007fd 100644 --- a/core/libs/facesengine/facedb/facedb_lbph.cpp +++ b/core/libs/facesengine/facedb/facedb_lbph.cpp @@ -1,241 +1,244 @@ /* ============================================================ * * This file is a part of digiKam * * Date : 02-02-2012 * Description : Face database interface to train identities. * * Copyright (C) 2012-2013 by Marcel Wiesweg * Copyright (C) 2010-2020 by Gilles Caulier * Copyright (C) 2019 by Thanh Trung Dinh * * This program is free software; you can redistribute it * and/or modify it under the terms of the GNU General * Public License as published by the Free Software Foundation; * either version 2, or (at your option) * any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * ============================================================ */ #include "facedb_p.h" namespace Digikam { namespace { enum { LBPHStorageVersion = 1 }; } void FaceDb::updateLBPHFaceModel(LBPHFaceModel& model) { QVariantList values; values << LBPHStorageVersion << model.radius() << model.neighbors() << model.gridX() << model.gridY(); if (model.databaseId) { values << model.databaseId; d->db->execSql(QLatin1String("UPDATE OpenCVLBPHRecognizer SET version=?, radius=?, neighbors=?, grid_x=?, grid_y=? WHERE id=?;"), values); } else { QVariant insertedId; d->db->execSql(QLatin1String("INSERT INTO OpenCVLBPHRecognizer (version, radius, neighbors, grid_x, grid_y) VALUES (?,?,?,?,?);"), values, nullptr, &insertedId); model.databaseId = insertedId.toInt(); } QList metadataList = model.histogramMetadata(); for (int i = 0 ; i < metadataList.size() ; ++i) { const LBPHistogramMetadata& metadata = metadataList[i]; if (metadata.storageStatus == LBPHistogramMetadata::Created) { OpenCVMatData data = model.histogramData(i); if (data.data.isEmpty()) { qCWarning(DIGIKAM_FACEDB_LOG) << "Histogram data to commit in database are empty for Identity " << metadata.identity; } else { QByteArray compressed = qCompress(data.data); if (compressed.isEmpty()) { qCWarning(DIGIKAM_FACEDB_LOG) << "Cannot compress histogram data to commit in database for Identity " << metadata.identity; } else { QVariantList histogramValues; QVariant insertedId; histogramValues << model.databaseId << metadata.identity << metadata.context << data.type << data.rows << data.cols << compressed; values.clear(); d->db->execSql(QLatin1String("SELECT id FROM OpenCVLBPHistograms " "WHERE recognizerid=? AND identity=? AND `type`=?;"), model.databaseId, metadata.identity, data.type, &values); if (values.count() > 20) { for (int j = 0 ; j < values.count() - 20 ; ++j) { qCDebug(DIGIKAM_FACEDB_LOG) << "Delete compressed histogram " << values.at(j).toInt() << " for identity " << metadata.identity; d->db->execSql(QLatin1String("DELETE FROM OpenCVLBPHistograms " "WHERE id=? AND recognizerid=? AND identity=? AND `type`=?;"), values.at(j).toInt(), model.databaseId, metadata.identity, data.type); } } d->db->execSql(QLatin1String("INSERT INTO OpenCVLBPHistograms (recognizerid, identity, `context`, `type`, `rows`, `cols`, `data`) " "VALUES (?,?,?,?,?,?,?);"), histogramValues, nullptr, &insertedId); model.setWrittenToDatabase(i, insertedId.toInt()); qCDebug(DIGIKAM_FACEDB_LOG) << "Commit compressed histogram " << insertedId.toInt() << " for identity " << metadata.identity << " with size " << compressed.size(); } } } } } LBPHFaceModel FaceDb::lbphFaceModel() const { QVariantList values; qCDebug(DIGIKAM_FACEDB_LOG) << "Loading LBPH model"; d->db->execSql(QLatin1String("SELECT id, version, radius, neighbors, grid_x, grid_y FROM OpenCVLBPHRecognizer;"), &values); for (QList::const_iterator it = values.constBegin() ; it != values.constEnd() ; ) { LBPHFaceModel model; model.databaseId = it->toInt(); ++it; qCDebug(DIGIKAM_FACEDB_LOG) << "Found model id" << model.databaseId; int version = it->toInt(); ++it; if (version > LBPHStorageVersion) { qCDebug(DIGIKAM_FACEDB_LOG) << "Unsupported LBPH storage version" << version; it += 4; continue; } model.setRadius(it->toInt()); ++it; model.setNeighbors(it->toInt()); ++it; model.setGridX(it->toInt()); ++it; model.setGridY(it->toInt()); ++it; DbEngineSqlQuery query = d->db->execQuery(QLatin1String("SELECT id, identity, `context`, `type`, `rows`, `cols`, `data` " "FROM OpenCVLBPHistograms WHERE recognizerid=?;"), model.databaseId); QList histograms; QList histogramMetadata; while (query.next()) { LBPHistogramMetadata metadata; OpenCVMatData data; metadata.databaseId = query.value(0).toInt(); metadata.identity = query.value(1).toInt(); metadata.context = query.value(2).toString(); metadata.storageStatus = LBPHistogramMetadata::InDatabase; // cv::Mat data.type = query.value(3).toInt(); data.rows = query.value(4).toInt(); data.cols = query.value(5).toInt(); QByteArray cData = query.value(6).toByteArray(); if (!cData.isEmpty()) { data.data = qUncompress(cData); if (data.data.isEmpty()) { qCWarning(DIGIKAM_FACEDB_LOG) << "Cannot uncompress histogram data to checkout from database for Identity " << metadata.identity; } else { qCDebug(DIGIKAM_FACEDB_LOG) << "Checkout compressed histogram " << metadata.databaseId << " for identity " << metadata.identity << " with size " << cData.size(); histograms << data; histogramMetadata << metadata; } } else { qCWarning(DIGIKAM_FACEDB_LOG) << "Histogram data to checkout from database are empty for Identity " << metadata.identity; } } model.setHistograms(histograms, histogramMetadata); return model; } return LBPHFaceModel(); } void FaceDb::clearLBPHTraining(const QString& context) { if (context.isNull()) { d->db->execSql(QLatin1String("DELETE FROM OpenCVLBPHistograms;")); d->db->execSql(QLatin1String("DELETE FROM OpenCVLBPHRecognizer;")); } else { - d->db->execSql(QLatin1String("DELETE FROM OpenCVLBPHistograms WHERE `context`=?;"), context); + d->db->execSql(QLatin1String("DELETE FROM OpenCVLBPHistograms WHERE `context`=?;"), + context); } } void FaceDb::clearLBPHTraining(const QList& identities, const QString& context) { foreach (int id, identities) { if (context.isNull()) { - d->db->execSql(QLatin1String("DELETE FROM OpenCVLBPHistograms WHERE identity=?;"), id); + d->db->execSql(QLatin1String("DELETE FROM OpenCVLBPHistograms WHERE identity=?;"), + id); } else { - d->db->execSql(QLatin1String("DELETE FROM OpenCVLBPHistograms WHERE identity=? AND `context`=?;"), id, context); + d->db->execSql(QLatin1String("DELETE FROM OpenCVLBPHistograms WHERE identity=? AND `context`=?;"), + id, context); } } } } // namespace Digikam diff --git a/core/libs/facesengine/recognition/recognitiondatabase_recognize.cpp b/core/libs/facesengine/recognition/recognitiondatabase_recognize.cpp index 55b754f197..90b4754fc2 100644 --- a/core/libs/facesengine/recognition/recognitiondatabase_recognize.cpp +++ b/core/libs/facesengine/recognition/recognitiondatabase_recognize.cpp @@ -1,207 +1,216 @@ /* ============================================================ * * This file is a part of digiKam * * Date : 2010-06-16 * Description : The recognition database wrapper * * Copyright (C) 2010 by Marcel Wiesweg * Copyright (C) 2010 by Aditya Bhatt * Copyright (C) 2010-2020 by Gilles Caulier * Copyright (C) 2019 by Thanh Trung Dinh * * This program is free software; you can redistribute it * and/or modify it under the terms of the GNU General * Public License as published by the Free Software Foundation; * either version 2, or (at your option) * any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * ============================================================ */ #include "recognitiondatabase_p.h" namespace Digikam { void RecognitionDatabase::Private::clear(OpenCVLBPHFaceRecognizer* const, const QList& idsToClear, const QString& trainingContext) { // force later reload delete opencvlbph; opencvlbph = nullptr; if (idsToClear.isEmpty()) { FaceDbAccess().db()->clearLBPHTraining(trainingContext); } else { FaceDbAccess().db()->clearLBPHTraining(idsToClear, trainingContext); } } void RecognitionDatabase::Private::clear(OpenCVEIGENFaceRecognizer* const, const QList& idsToClear, const QString& trainingContext) { // force later reload delete opencveigen; opencveigen = nullptr; if (idsToClear.isEmpty()) { FaceDbAccess().db()->clearEIGENTraining(trainingContext); } else { FaceDbAccess().db()->clearEIGENTraining(idsToClear, trainingContext); } } void RecognitionDatabase::Private::clear(OpenCVFISHERFaceRecognizer* const, const QList&, const QString&) { // force later reload delete opencvfisher; opencvfisher = nullptr; } void RecognitionDatabase::Private::clear(OpenCVDNNFaceRecognizer* const, - const QList&, - const QString&) + const QList& idsToClear, + const QString& trainingContext) { // force later reload delete opencvdnn; opencvdnn = nullptr; + + if (idsToClear.isEmpty()) + { + FaceDbAccess().db()->clearDNNTraining(trainingContext); + } + else + { + FaceDbAccess().db()->clearDNNTraining(idsToClear, trainingContext); + } } // ------------------------------------------------------------------------------ int RecognitionDatabase::recommendedImageSize(const QSize& availableSize) const { // hardcoded for now, change when we know better. Q_UNUSED(availableSize) return 256; } Identity RecognitionDatabase::recognizeFace(const QImage& image) { QList result = recognizeFaces(QList() << image); if (result.isEmpty()) { return Identity(); } return result.first(); } QList RecognitionDatabase::recognizeFaces(const QList& images) { QListImageListProvider provider(images); return recognizeFaces(&provider); } void RecognitionDatabase::activeFaceRecognizer(RecognizeAlgorithm algorithmType) { if (algorithmType == RecognizeAlgorithm::EigenFace || algorithmType == RecognizeAlgorithm::FisherFace) { d->recognizeAlgorithm = RecognizeAlgorithm::LBP; } else { d->recognizeAlgorithm = algorithmType; } } void RecognitionDatabase::createDNNDebug() { d->createDNNDebug(); } QList RecognitionDatabase::recognizeFaces(ImageListProvider* const images) { if (!d || !d->dbAvailable) { return QList(); } QMutexLocker lock(&d->mutex); QList result; for ( ; !images->atEnd() ; images->proceed()) { int id = -1; try { if (d->recognizeAlgorithm == RecognizeAlgorithm::LBP) { id = d->lbph()->recognize(d->preprocessingChain(images->image())); } else if (d->recognizeAlgorithm == RecognizeAlgorithm::EigenFace) { id = d->eigen()->recognize(d->preprocessingChain(images->image())); } else if (d->recognizeAlgorithm == RecognizeAlgorithm::FisherFace) { id = d->fisher()->recognize(d->preprocessingChain(images->image())); } else if (d->recognizeAlgorithm == RecognizeAlgorithm::DNN) { id = d->dnn()->recognize(d->preprocessingChainRGB(images->image())); } else { qCCritical(DIGIKAM_FACESENGINE_LOG) << "No obvious recognize algorithm"; } } catch (cv::Exception& e) { qCCritical(DIGIKAM_FACESENGINE_LOG) << "cv::Exception:" << e.what(); } catch (...) { qCCritical(DIGIKAM_FACESENGINE_LOG) << "Default exception from OpenCV"; } if (id == -1) { result << Identity(); } else { result << d->identityCache.value(id); } } return result; } void RecognitionDatabase::clusterFaces(const QList& images, std::vector& clusteredIndices, QStringList dataset, int nbOfClusters) const { std::vector preprocessedImages; foreach (const QImage& image, images) { preprocessedImages.push_back(d->preprocessingChainRGB(image)); } d->dnn()->cluster(preprocessedImages, clusteredIndices, dataset, nbOfClusters); } } // namespace Digikam