File indexing completed on 2025-03-09 03:55:01
0001 /* ============================================================ 0002 * 0003 * This file is a part of digiKam 0004 * 0005 * Date : 2010-06-16 0006 * Description : Identity management of recognition wrapper 0007 * 0008 * SPDX-FileCopyrightText: 2010 by Marcel Wiesweg <marcel dot wiesweg at gmx dot de> 0009 * SPDX-FileCopyrightText: 2010 by Aditya Bhatt <adityabhatt1991 at gmail dot com> 0010 * SPDX-FileCopyrightText: 2010-2024 by Gilles Caulier <caulier dot gilles at gmail dot com> 0011 * SPDX-FileCopyrightText: 2019 by Thanh Trung Dinh <dinhthanhtrung1996 at gmail dot com> 0012 * SPDX-FileCopyrightText: 2020 by Nghia Duong <minhnghiaduong997 at gmail dot com> 0013 * 0014 * SPDX-License-Identifier: GPL-2.0-or-later 0015 * 0016 * ============================================================ */ 0017 0018 #include "facialrecognition_wrapper_p.h" 0019 0020 namespace Digikam 0021 { 0022 /** 0023 * NOTE: Takes care that there may be multiple values of attribute in identity's attributes 0024 */ 0025 bool FacialRecognitionWrapper::Private::identityContains(const Identity& identity, 0026 const QString& attribute, 0027 const QString& value) 0028 { 0029 const QMultiMap<QString, QString> map = identity.attributesMap(); 0030 QMultiMap<QString, QString>::const_iterator it = map.constFind(attribute); 0031 0032 for ( ; (it != map.constEnd()) && (it.key() == attribute) ; ++it) 0033 { 0034 if (it.value() == value) 0035 { 0036 return true; 0037 } 0038 } 0039 0040 return false; 0041 } 0042 0043 Identity FacialRecognitionWrapper::Private::findByAttribute(const QString& attribute, 0044 const QString& value) const 0045 { 0046 Q_FOREACH (const Identity& identity, identityCache) 0047 { 0048 if (identityContains(identity, attribute, value)) 0049 { // cppcheck-suppress useStlAlgorithm 0050 return identity; 0051 } 0052 } 0053 0054 return Identity(); 0055 } 0056 0057 /** 0058 * NOTE: Takes care that there may be multiple values of attribute in valueMap 0059 */ 0060 Identity FacialRecognitionWrapper::Private::findByAttributes(const QString& attribute, 0061 const QMultiMap<QString, QString>& valueMap) const 0062 { 0063 QMultiMap<QString, QString>::const_iterator it = valueMap.find(attribute); 0064 0065 for ( ; (it != valueMap.end()) && (it.key() == attribute) ; ++it) 0066 { 0067 Q_FOREACH (const Identity& identity, identityCache) 0068 { 0069 if (identityContains(identity, attribute, it.value())) 0070 { // cppcheck-suppress useStlAlgorithm 0071 return identity; 0072 } 0073 } 0074 } 0075 0076 return Identity(); 0077 } 0078 0079 // ----------------------------------------------------------------------- 0080 0081 QList<Identity> FacialRecognitionWrapper::allIdentities() const 0082 { 0083 if (!d || !d->dbAvailable) 0084 { 0085 return QList<Identity>(); 0086 } 0087 0088 QMutexLocker lock(&d->mutex); 0089 0090 return (d->identityCache.values()); 0091 } 0092 0093 Identity FacialRecognitionWrapper::identity(int id) const 0094 { 0095 if (!d || !d->dbAvailable) 0096 { 0097 return Identity(); 0098 } 0099 0100 QMutexLocker lock(&d->mutex); 0101 0102 return (d->identityCache.value(id)); 0103 } 0104 0105 Identity FacialRecognitionWrapper::findIdentity(const QString& attribute, const QString& value) const 0106 { 0107 if (!d || !d->dbAvailable || attribute.isEmpty()) 0108 { 0109 return Identity(); 0110 } 0111 0112 QMutexLocker lock(&d->mutex); 0113 0114 return (d->findByAttribute(attribute, value)); 0115 } 0116 0117 Identity FacialRecognitionWrapper::findIdentity(const QMultiMap<QString, QString>& attributes) const 0118 { 0119 if (!d || !d->dbAvailable || attributes.isEmpty()) 0120 { 0121 return Identity(); 0122 } 0123 0124 QMutexLocker lock(&d->mutex); 0125 0126 Identity match; 0127 0128 // First and foremost, UUID 0129 0130 QString uuid = attributes.value(QLatin1String("uuid")); 0131 match = d->findByAttribute(QLatin1String("uuid"), uuid); 0132 0133 if (!match.isNull()) 0134 { 0135 return match; 0136 } 0137 0138 // A negative UUID match, with a given UUID, precludes any further search 0139 0140 if (!uuid.isNull()) 0141 { 0142 return Identity(); 0143 } 0144 0145 // full name 0146 0147 match = d->findByAttributes(QLatin1String("fullName"), attributes); 0148 0149 if (!match.isNull()) 0150 { 0151 return match; 0152 } 0153 0154 // name 0155 0156 match = d->findByAttributes(QLatin1String("name"), attributes); 0157 0158 if (!match.isNull()) 0159 { 0160 return match; 0161 } 0162 0163 QMultiMap<QString, QString>::const_iterator it; 0164 0165 for (it = attributes.begin() ; it != attributes.end() ; ++it) 0166 { 0167 if ( 0168 (it.key() == QLatin1String("uuid")) || 0169 (it.key() == QLatin1String("fullName")) || 0170 (it.key() == QLatin1String("name")) 0171 ) 0172 { 0173 continue; 0174 } 0175 0176 match = d->findByAttribute(it.key(), it.value()); 0177 0178 if (!match.isNull()) 0179 { 0180 return match; 0181 } 0182 } 0183 0184 return Identity(); 0185 } 0186 0187 Identity FacialRecognitionWrapper::addIdentity(const QMultiMap<QString, QString>& attributes) 0188 { 0189 if (!d || !d->dbAvailable) 0190 { 0191 return Identity(); 0192 } 0193 0194 QMutexLocker lock(&d->mutex); 0195 0196 if (attributes.contains(QLatin1String("uuid"))) 0197 { 0198 Identity matchByUuid = findIdentity(QLatin1String("uuid"), attributes.value(QLatin1String("uuid"))); 0199 0200 if (!matchByUuid.isNull()) 0201 { 0202 // This situation is not well defined. 0203 0204 qCDebug(DIGIKAM_FACESENGINE_LOG) << "Called addIdentity with a given UUID, and there is such a UUID already in the database." 0205 << "The existing identity is returned without adjusting properties!"; 0206 0207 return matchByUuid; 0208 } 0209 } 0210 0211 Identity identity; 0212 { 0213 FaceDbOperationGroup group; 0214 int id = FaceDbAccess().db()->addIdentity(); 0215 identity.setId(id); 0216 identity.setAttributesMap(attributes); 0217 identity.setAttribute(QLatin1String("uuid"), QUuid::createUuid().toString()); 0218 FaceDbAccess().db()->updateIdentity(identity); 0219 } 0220 0221 d->identityCache[identity.id()] = identity; 0222 0223 return identity; 0224 } 0225 0226 Identity FacialRecognitionWrapper::addIdentityDebug(const QMultiMap<QString, QString>& attributes) 0227 { 0228 Identity identity; 0229 { 0230 identity.setId(attributes.value(QLatin1String("name")).toInt()); 0231 identity.setAttributesMap(attributes); 0232 identity.setAttribute(QLatin1String("uuid"), QUuid::createUuid().toString()); 0233 } 0234 0235 d->identityCache[identity.id()] = identity; 0236 0237 return identity; 0238 } 0239 0240 void FacialRecognitionWrapper::addIdentityAttributes(int id, const QMultiMap<QString, QString>& attributes) 0241 { 0242 if (!d || !d->dbAvailable) 0243 { 0244 return; 0245 } 0246 0247 QMutexLocker lock(&d->mutex); 0248 0249 QHash<int, Identity>::iterator it = d->identityCache.find(id); 0250 0251 if (it != d->identityCache.end()) 0252 { 0253 QMultiMap<QString, QString> map = it->attributesMap(); 0254 map.unite(attributes); 0255 it->setAttributesMap(map); 0256 FaceDbAccess().db()->updateIdentity(*it); 0257 } 0258 } 0259 0260 void FacialRecognitionWrapper::addIdentityAttribute(int id, const QString& attribute, const QString& value) 0261 { 0262 if (!d || !d->dbAvailable) 0263 { 0264 return; 0265 } 0266 0267 QMutexLocker lock(&d->mutex); 0268 QHash<int, Identity>::iterator it = d->identityCache.find(id); 0269 0270 if (it != d->identityCache.end()) 0271 { 0272 QMultiMap<QString, QString> map = it->attributesMap(); 0273 map.insert(attribute, value); 0274 it->setAttributesMap(map); 0275 FaceDbAccess().db()->updateIdentity(*it); 0276 } 0277 } 0278 0279 void FacialRecognitionWrapper::setIdentityAttributes(int id, const QMultiMap<QString, QString>& attributes) 0280 { 0281 if (!d || !d->dbAvailable) 0282 { 0283 return; 0284 } 0285 0286 QMutexLocker lock(&d->mutex); 0287 QHash<int, Identity>::iterator it = d->identityCache.find(id); 0288 0289 if (it != d->identityCache.end()) 0290 { 0291 it->setAttributesMap(attributes); 0292 FaceDbAccess().db()->updateIdentity(*it); 0293 } 0294 } 0295 0296 void FacialRecognitionWrapper::deleteIdentity(const Identity& identityToBeDeleted) 0297 { 0298 if (!d || !d->dbAvailable || identityToBeDeleted.isNull()) 0299 { 0300 return; 0301 } 0302 0303 QMutexLocker lock(&d->mutex); 0304 0305 FaceDbAccess().db()->deleteIdentity(identityToBeDeleted.id()); 0306 d->identityCache.remove(identityToBeDeleted.id()); 0307 } 0308 0309 void FacialRecognitionWrapper::deleteIdentities(QList<Identity> identitiesToBeDeleted) 0310 { 0311 QList<Identity>::iterator identity = identitiesToBeDeleted.begin(); 0312 0313 while (identity != identitiesToBeDeleted.end()) 0314 { 0315 deleteIdentity(*identity); 0316 0317 identity = identitiesToBeDeleted.erase(identity); 0318 } 0319 } 0320 0321 } // namespace Digikam