File indexing completed on 2025-01-19 03:53:34
0001 /* ============================================================ 0002 * 0003 * This file is a part of digiKam project 0004 * https://www.digikam.org 0005 * 0006 * Date : 2003-01-17 0007 * Description : Haar Database interface 0008 * 0009 * SPDX-FileCopyrightText: 2016-2018 by Mario Frank <mario dot frank at uni minus potsdam dot de> 0010 * SPDX-FileCopyrightText: 2003 by Ricardo Niederberger Cabral <nieder at mail dot ru> 0011 * SPDX-FileCopyrightText: 2009-2024 by Gilles Caulier <caulier dot gilles at gmail dot com> 0012 * SPDX-FileCopyrightText: 2009-2013 by Marcel Wiesweg <marcel dot wiesweg at gmx dot de> 0013 * SPDX-FileCopyrightText: 2009-2011 by Andi Clemens <andi dot clemens at gmail dot com> 0014 * 0015 * SPDX-License-Identifier: GPL-2.0-or-later 0016 * 0017 * ============================================================ */ 0018 0019 #include "haariface_p.h" 0020 0021 namespace Digikam 0022 { 0023 0024 void DatabaseBlob::read(const QByteArray& array, Haar::SignatureData& data) 0025 { 0026 QDataStream stream(array); 0027 0028 // check version 0029 0030 qint32 version; 0031 stream >> version; 0032 0033 if (version != Version) 0034 { 0035 qCDebug(DIGIKAM_DATABASE_LOG) << "Unsupported binary version of Haar Blob in database"; 0036 return; 0037 } 0038 0039 stream.setVersion(QDataStream::Qt_4_3); 0040 0041 // read averages 0042 0043 for (int i = 0 ; i < 3 ; ++i) 0044 { 0045 stream >> data.avg[i]; 0046 } 0047 0048 // read coefficients 0049 0050 for (int i = 0 ; i < 3 ; ++i) 0051 { 0052 for (int j = 0 ; j < Haar::NumberOfCoefficients ; ++j) 0053 { 0054 stream >> data.sig[i][j]; 0055 } 0056 } 0057 } 0058 0059 QByteArray DatabaseBlob::write(Haar::SignatureData& data) 0060 { 0061 QByteArray array; 0062 array.reserve(sizeof(qint32) + 3*sizeof(double) + 3*sizeof(qint32)*Haar::NumberOfCoefficients); 0063 QDataStream stream(&array, QIODevice::WriteOnly); 0064 stream.setVersion(QDataStream::Qt_4_3); 0065 0066 // write version 0067 0068 stream << (qint32)Version; 0069 0070 // write averages 0071 0072 for (int i = 0 ; i < 3 ; ++i) 0073 { 0074 stream << data.avg[i]; 0075 } 0076 0077 // write coefficients 0078 0079 for (int i = 0 ; i < 3 ; ++i) 0080 { 0081 for (int j = 0 ; j < Haar::NumberOfCoefficients ; ++j) 0082 { 0083 stream << data.sig[i][j]; 0084 } 0085 } 0086 0087 return array; 0088 } 0089 0090 // ----------------------------------------------------------------------------------------------------- 0091 0092 const QString HaarIface::Private::signatureQuery = QString::fromUtf8("SELECT imageid, matrix FROM ImageHaarMatrix;"); 0093 const Haar::WeightBin HaarIface::Private::weightBin; 0094 0095 HaarIface::Private::Private() 0096 : m_data(new Haar::ImageData) 0097 { 0098 } 0099 0100 HaarIface::Private::~Private() 0101 { 0102 } 0103 0104 void HaarIface::Private::rebuildSignatureCache(const QSet<qlonglong>& imageIds) 0105 { 0106 m_signatureCache.reset(new SignatureCache); 0107 m_albumCache.reset(new AlbumCache); 0108 0109 // Variables for data read from DB 0110 0111 DatabaseBlob blob; 0112 qlonglong imageid; 0113 int albumid; 0114 Haar::SignatureData targetSig; 0115 0116 // reference for easier access 0117 0118 SignatureCache& sigCache = *m_signatureCache; 0119 AlbumCache& albCache = *m_albumCache; 0120 0121 DbEngineSqlQuery query = SimilarityDbAccess().backend()->prepareQuery(signatureQuery); 0122 0123 if (!SimilarityDbAccess().backend()->exec(query)) 0124 { 0125 return; 0126 } 0127 0128 QHash<qlonglong, QPair<int, int> > itemAlbumHash = CoreDbAccess().db()->getAllItemsWithAlbum(); 0129 0130 // Remove all ids from the fully created itemAlbumHash that are not needed for the duplicates search. 0131 // This is usually faster then starting a query for every single id in imageIds. 0132 0133 if (!imageIds.isEmpty()) 0134 { 0135 for (auto it = itemAlbumHash.begin() ; it != itemAlbumHash.end() ; ) 0136 { 0137 if (!imageIds.contains(it.key())) 0138 { 0139 it = itemAlbumHash.erase(it); 0140 } 0141 else 0142 { 0143 ++it; 0144 } 0145 } 0146 } 0147 0148 const bool filterByAlbumRoots = !m_albumRootsToSearch.isEmpty(); 0149 0150 while (query.next()) 0151 { 0152 imageid = query.value(0).toLongLong(); 0153 0154 if (itemAlbumHash.contains(imageid)) 0155 { 0156 // Pair storage of <albumroootid, albumid> 0157 0158 const QPair<int, int>& albumPair = itemAlbumHash.value(imageid); 0159 0160 if (filterByAlbumRoots) 0161 { 0162 if (!m_albumRootsToSearch.contains(albumPair.first)) 0163 { 0164 continue; 0165 } 0166 } 0167 0168 blob.read(query.value(1).toByteArray(), targetSig); 0169 albumid = albumPair.second; 0170 sigCache[imageid] = targetSig; 0171 albCache[imageid] = albumid; 0172 } 0173 } 0174 } 0175 0176 bool HaarIface::Private::hasSignatureCache() const 0177 { 0178 return !(m_signatureCache.isNull() || m_signatureCache->isEmpty()); 0179 } 0180 0181 bool HaarIface::Private::retrieveSignatureFromCache(qlonglong imageId, Haar::SignatureData& data) 0182 { 0183 if (!hasSignatureCache()) 0184 { 0185 return false; 0186 } 0187 0188 if (m_signatureCache->contains(imageId)) 0189 { 0190 data = m_signatureCache.data()->value(imageId); 0191 0192 return true; 0193 } 0194 0195 return false; 0196 } 0197 0198 void HaarIface::Private::setImageDataFromImage(const QImage& image) 0199 { 0200 m_data->fillPixelData(image); 0201 } 0202 0203 void HaarIface::Private::setImageDataFromImage(const DImg& image) 0204 { 0205 m_data->fillPixelData(image); 0206 } 0207 0208 SignatureCache* HaarIface::Private::signatureCache() const 0209 { 0210 return m_signatureCache.data(); 0211 } 0212 0213 AlbumCache* HaarIface::Private::albumCache() const 0214 { 0215 return m_albumCache.data(); 0216 } 0217 0218 Haar::ImageData* HaarIface::Private::imageData() const 0219 { 0220 return m_data.data(); 0221 } 0222 0223 void HaarIface::Private::setAlbumRootsToSearch(const QSet<int>& albumRootIds) 0224 { 0225 m_albumRootsToSearch = albumRootIds; 0226 } 0227 0228 const QSet<int>& HaarIface::Private::albumRootsToSearch() const 0229 { 0230 return m_albumRootsToSearch; 0231 } 0232 0233 } // namespace Digikam