File indexing completed on 2025-03-09 03:52:49
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 2d transform 0008 * Wavelet algorithms, metric and query ideas based on the paper 0009 * "Fast Multiresolution Image Querying" 0010 * by Charles E. Jacobs, Adam Finkelstein and David H. Salesin. 0011 * https://grail.cs.washington.edu/wp-content/uploads/2015/08/jacobs-1995.pdf 0012 * 0013 * SPDX-FileCopyrightText: 2003 by Ricardo Niederberger Cabral <nieder at mail dot ru> 0014 * SPDX-FileCopyrightText: 2008-2024 by Gilles Caulier <caulier dot gilles at gmail dot com> 0015 * SPDX-FileCopyrightText: 2008-2013 by Marcel Wiesweg <marcel dot wiesweg at gmx dot de> 0016 * 0017 * SPDX-License-Identifier: GPL-2.0-or-later 0018 * 0019 * ============================================================ */ 0020 0021 #ifndef DIGIKAM_HAAR_H 0022 #define DIGIKAM_HAAR_H 0023 0024 // C++ includes 0025 0026 #include <cstring> 0027 0028 // Qt includes 0029 0030 #include <QtGlobal> 0031 0032 class QImage; 0033 0034 namespace Digikam 0035 { 0036 0037 class DImg; 0038 0039 namespace Haar 0040 { 0041 0042 /** 0043 * Weights for the Haar coefficients. Straight from the referenced paper 0044 * "Fast Multiresolution Image Querying" 0045 * by Charles E. Jacobs, Adam Finkelstein and David H. Salesin. 0046 * https://www.cs.washington.edu/homes/salesin/abstracts.html 0047 */ 0048 static const float s_haar_weights[2][6][3] = 0049 { 0050 // For scanned picture (sketch=0): 0051 // Y I Q idx total occurs 0052 0053 { { 5.00F, 19.21F, 34.37F }, // 0 58.58 1 (`DC' component) 0054 { 0.83F, 1.26F, 0.36F }, // 1 2.45 3 0055 { 1.01F, 0.44F, 0.45F }, // 2 1.90 5 0056 { 0.52F, 0.53F, 0.14F }, // 3 1.19 7 0057 { 0.47F, 0.28F, 0.18F }, // 4 0.93 9 0058 { 0.30F, 0.14F, 0.27F } 0059 }, // 5 0.71 16384-25=16359 0060 0061 // For handdrawn/painted sketch (sketch=1): 0062 // Y I Q 0063 0064 { { 4.04F, 15.14F, 22.62F }, 0065 { 0.78F, 0.92F, 0.40F }, 0066 { 0.46F, 0.53F, 0.63F }, 0067 { 0.42F, 0.26F, 0.25F }, 0068 { 0.41F, 0.14F, 0.15F }, 0069 { 0.32F, 0.07F, 0.38F } 0070 } 0071 }; 0072 0073 /** 0074 * Number of pixels on one side of image; required to be a power of 2. 0075 */ 0076 enum { NumberOfPixels = 128 }; 0077 0078 /** 0079 * Total pixels in a square image. 0080 */ 0081 enum { NumberOfPixelsSquared = NumberOfPixels * NumberOfPixels }; 0082 0083 /** 0084 * Number of Haar coefficients we retain as signature for an image. 0085 */ 0086 enum { NumberOfCoefficients = 40 }; 0087 0088 typedef double Unit; 0089 0090 /** 0091 * Keep this definition constant at qint32 (guaranteed binary size!) 0092 */ 0093 typedef qint32 Idx; 0094 0095 // --------------------------------------------------------------------------------- 0096 0097 class ImageData 0098 { 0099 public: 0100 0101 Unit data1[NumberOfPixelsSquared] = { 0.0 }; 0102 Unit data2[NumberOfPixelsSquared] = { 0.0 }; 0103 Unit data3[NumberOfPixelsSquared] = { 0.0 }; 0104 0105 void fillPixelData(const QImage& image); 0106 void fillPixelData(const DImg& image); 0107 }; 0108 0109 // --------------------------------------------------------------------------------- 0110 0111 class SignatureData 0112 { 0113 public: 0114 0115 /** 0116 * Y/I/Q positions with largest magnitude 0117 */ 0118 Haar::Idx sig[3][Haar::NumberOfCoefficients] = { { 0 } }; 0119 0120 /** 0121 * YIQ for position [0,0] 0122 */ 0123 double avg[3] = { 0.0 }; 0124 }; 0125 0126 // --------------------------------------------------------------------------------- 0127 0128 /** 0129 * This class provides very fast lookup if a certain pixel 0130 * is set (positive or negative) in the loaded coefficient set. 0131 */ 0132 class SignatureMap 0133 { 0134 public: 0135 0136 SignatureMap() 0137 { 0138 m_indexList = new MapIndexType[2 * Haar::NumberOfPixelsSquared]; 0139 } 0140 0141 ~SignatureMap() 0142 { 0143 delete[] m_indexList; 0144 } 0145 0146 /// Load a set of coefficients 0147 0148 void fill(const Haar::Idx* const coefs) 0149 { 0150 // For maximum performance, we use a flat array. 0151 // First 16k for negative values, second 16k for positive values. 0152 // All values or false, only 2*40 are true. 0153 0154 memset(m_indexList, 0, sizeof(MapIndexType[2 * Haar::NumberOfPixelsSquared])); 0155 int x = 0; 0156 0157 for (int i = 0 ; i < Haar::NumberOfCoefficients ; ++i) 0158 { 0159 x = coefs[i] + Haar::NumberOfPixelsSquared; 0160 m_indexList[x] = true; 0161 } 0162 } 0163 0164 /// Query if the given index is set. 0165 /// Index must be in the range -16383..16383. 0166 0167 bool operator[](Haar::Idx index) const 0168 { 0169 return m_indexList[index + Haar::NumberOfPixelsSquared]; 0170 } 0171 0172 private: 0173 0174 // To prevent cppcheck warnings. 0175 0176 explicit SignatureMap(const SignatureMap& other) 0177 { 0178 m_indexList = new MapIndexType[2 * Haar::NumberOfPixelsSquared]; 0179 memcpy(m_indexList, other.m_indexList, sizeof(MapIndexType[2 * Haar::NumberOfPixelsSquared])); 0180 } 0181 0182 public: 0183 0184 typedef bool MapIndexType; 0185 MapIndexType* m_indexList = nullptr; 0186 0187 private: 0188 0189 SignatureMap& operator=(const SignatureMap&); // Disable 0190 }; 0191 0192 // --------------------------------------------------------------------------------- 0193 0194 class WeightBin 0195 { 0196 public: 0197 0198 explicit WeightBin(); 0199 0200 unsigned char bin(int index) const 0201 { 0202 return m_bin[index]; 0203 } 0204 0205 unsigned char binAbs(int index) const 0206 { 0207 return ( 0208 (index > 0) ? m_bin[index] 0209 : m_bin[-index] 0210 ); 0211 } 0212 0213 public: 0214 0215 /** 0216 * Fixed weight mask for pixel positions (i,j). 0217 * Each entry x = i*NUM_PIXELS + j, gets value max(i,j) saturated at 5. 0218 * To be treated as a constant. 0219 */ 0220 unsigned char m_bin[16384] = { 0 }; 0221 }; 0222 0223 // --------------------------------------------------------------------------------- 0224 0225 class Weights 0226 { 0227 public: 0228 0229 enum SketchType 0230 { 0231 ScannedSketch = 0, 0232 PaintedSketch = 1 0233 }; 0234 0235 public: 0236 0237 explicit Weights(SketchType type = ScannedSketch) 0238 : m_type(type) 0239 { 0240 } 0241 0242 float weight(int weight, int channel) const 0243 { 0244 return (s_haar_weights[(int)m_type][weight][channel]); 0245 } 0246 0247 float weightForAverage(int channel) const 0248 { 0249 return (s_haar_weights[(int)m_type][0][channel]); 0250 } 0251 0252 private: 0253 0254 SketchType m_type; 0255 }; 0256 0257 // --------------------------------------------------------------------------------- 0258 0259 class Calculator 0260 { 0261 0262 public: 0263 0264 explicit Calculator(); 0265 ~Calculator(); 0266 0267 int calcHaar(ImageData* const imageData, SignatureData* const sigData); 0268 0269 void transform(ImageData* const data); 0270 0271 private: 0272 0273 void haar2D(Unit a[]); 0274 inline void getmLargests(Unit* const cdata, Idx* const sig); 0275 }; 0276 0277 } // namespace Haar 0278 0279 } // namespace Digikam 0280 0281 #endif // DIGIKAM_HAAR_H