File indexing completed on 2024-05-12 15:58:27
0001 /* 0002 * This file is part of the KDE project 0003 * 0004 * SPDX-FileCopyrightText: 2005 Cyrille Berger <cberger@cberger.net> 0005 * 0006 * SPDX-License-Identifier: GPL-2.0-or-later 0007 */ 0008 0009 #include "kis_math_toolbox.h" 0010 0011 #include <KoConfig.h> 0012 0013 #ifdef HAVE_OPENEXR 0014 #include <half.h> 0015 #endif 0016 0017 #include <QVector> 0018 #include <QGlobalStatic> 0019 0020 #include <KoColorSpaceMaths.h> 0021 0022 #include <kis_debug.h> 0023 #include "kis_iterator_ng.h" 0024 0025 #include "math.h" 0026 0027 template<typename T> 0028 inline double toDouble(const quint8* data, int channelpos) 0029 { 0030 return (double)(*((T*)(data + channelpos))); 0031 } 0032 0033 template<typename T> 0034 void fromDouble(quint8* data, int channelpos, double v) 0035 { 0036 *((T*)(data + channelpos)) = (T)qRound(v); 0037 } 0038 0039 template<typename T> 0040 void fromDoubleF(quint8* data, int channelpos, double v) 0041 { 0042 *((T*)(data + channelpos)) = (T)v; 0043 } 0044 0045 template<typename T> 0046 void fromDoubleCheckNull(quint8* data, int channelpos, double v, bool *isNull) 0047 { 0048 T value = qRound(v); 0049 *((T*)(data + channelpos)) = value; 0050 *isNull = value == T(0); 0051 } 0052 0053 template<typename T> 0054 void fromDoubleCheckNullF(quint8* data, int channelpos, double v, bool *isNull) 0055 { 0056 T value = v; 0057 *((T*)(data + channelpos)) = (T)v; 0058 *isNull = value < std::numeric_limits<T>::epsilon(); 0059 } 0060 0061 0062 void KisMathToolbox::transformToFR(KisPaintDeviceSP src, KisFloatRepresentation* fr, const QRect& rect) 0063 { 0064 qint32 depth = src->colorSpace()->colorChannelCount(); 0065 QList<KoChannelInfo *> cis = src->colorSpace()->channels(); 0066 // remove non-color channels 0067 for (qint32 c = 0; c < cis.count(); ++c) { 0068 if (cis[c]->channelType() != KoChannelInfo::COLOR) 0069 cis.removeAt(c--); 0070 } 0071 QVector<PtrToDouble> f(depth); 0072 if (!getToDoubleChannelPtr(cis, f)) 0073 return; 0074 0075 KisHLineConstIteratorSP srcIt = src->createHLineIteratorNG(rect.x(), rect.y(), rect.width()); 0076 0077 for (int i = rect.y(); i < rect.height(); i++) { 0078 float *dstIt = fr->coeffs + (i - rect.y()) * fr->size * fr->depth; 0079 do { 0080 const quint8* v1 = srcIt->oldRawData(); 0081 for (int k = 0; k < depth; k++) { 0082 *dstIt = f[k](v1, cis[k]->pos()); 0083 ++dstIt; 0084 } 0085 } while (srcIt->nextPixel()); 0086 srcIt->nextRow(); 0087 } 0088 } 0089 0090 bool KisMathToolbox::getToDoubleChannelPtr(QList<KoChannelInfo *> cis, QVector<PtrToDouble>& f) 0091 { 0092 qint32 channels = cis.count(); 0093 0094 for (qint32 k = 0; k < channels; k++) { 0095 switch (cis[k]->channelValueType()) { 0096 case KoChannelInfo::UINT8: 0097 f[k] = toDouble<quint8>; 0098 break; 0099 case KoChannelInfo::UINT16: 0100 f[k] = toDouble<quint16>; 0101 break; 0102 #ifdef HAVE_OPENEXR 0103 case KoChannelInfo::FLOAT16: 0104 f[k] = toDouble<half>; 0105 break; 0106 #endif 0107 case KoChannelInfo::FLOAT32: 0108 f[k] = toDouble<float>; 0109 break; 0110 case KoChannelInfo::INT8: 0111 f[k] = toDouble<qint8>; 0112 break; 0113 case KoChannelInfo::INT16: 0114 f[k] = toDouble<qint16>; 0115 break; 0116 default: 0117 warnKrita << "Unsupported value type in KisMathToolbox"; 0118 return false; 0119 } 0120 } 0121 0122 return true; 0123 } 0124 0125 void KisMathToolbox::transformFromFR(KisPaintDeviceSP dst, KisFloatRepresentation* fr, const QRect& rect) 0126 { 0127 qint32 depth = dst->colorSpace()->colorChannelCount(); 0128 QList<KoChannelInfo *> cis = dst->colorSpace()->channels(); 0129 // remove non-color channels 0130 for (qint32 c = 0; c < cis.count(); ++c) { 0131 if (cis[c]->channelType() != KoChannelInfo::COLOR) 0132 cis.removeAt(c--); 0133 } 0134 0135 QVector<PtrFromDouble> f(depth); 0136 if (!getFromDoubleChannelPtr(cis, f)) 0137 return; 0138 0139 KisHLineIteratorSP dstIt = dst->createHLineIteratorNG(rect.x(), rect.y(), rect.width()); 0140 for (int i = rect.y(); i < rect.height(); i++) { 0141 float *srcIt = fr->coeffs + (i - rect.y()) * fr->size * fr->depth; 0142 do { 0143 quint8* v1 = dstIt->rawData(); 0144 for (int k = 0; k < depth; k++) { 0145 f[k](v1, cis[k]->pos(), *srcIt); 0146 ++srcIt; 0147 } 0148 } while(dstIt->nextPixel()); 0149 dstIt->nextRow(); 0150 } 0151 } 0152 0153 bool KisMathToolbox::getFromDoubleChannelPtr(QList<KoChannelInfo *> cis, QVector<PtrFromDouble>& f) 0154 { 0155 qint32 channels = cis.count(); 0156 0157 for (qint32 k = 0; k < channels; k++) { 0158 switch (cis[k]->channelValueType()) { 0159 case KoChannelInfo::UINT8: 0160 f[k] = fromDouble<quint8>; 0161 break; 0162 case KoChannelInfo::UINT16: 0163 f[k] = fromDouble<quint16>; 0164 break; 0165 #ifdef HAVE_OPENEXR 0166 case KoChannelInfo::FLOAT16: 0167 f[k] = fromDoubleF<half>; 0168 break; 0169 #endif 0170 case KoChannelInfo::FLOAT32: 0171 f[k] = fromDoubleF<float>; 0172 break; 0173 case KoChannelInfo::INT8: 0174 f[k] = fromDouble<qint8>; 0175 break; 0176 case KoChannelInfo::INT16: 0177 f[k] = fromDouble<qint16>; 0178 break; 0179 default: 0180 warnKrita << "Unsupported value type in KisMathToolbox"; 0181 return false; 0182 } 0183 } 0184 0185 return true; 0186 } 0187 0188 bool KisMathToolbox::getFromDoubleCheckNullChannelPtr(QList<KoChannelInfo *> cis, QVector<PtrFromDoubleCheckNull>& f) 0189 { 0190 qint32 channels = cis.count(); 0191 0192 for (qint32 k = 0; k < channels; k++) { 0193 switch (cis[k]->channelValueType()) { 0194 case KoChannelInfo::UINT8: 0195 f[k] = fromDoubleCheckNull<quint8>; 0196 break; 0197 case KoChannelInfo::UINT16: 0198 f[k] = fromDoubleCheckNull<quint16>; 0199 break; 0200 #ifdef HAVE_OPENEXR 0201 case KoChannelInfo::FLOAT16: 0202 f[k] = fromDoubleCheckNullF<half>; 0203 break; 0204 #endif 0205 case KoChannelInfo::FLOAT32: 0206 f[k] = fromDoubleCheckNullF<float>; 0207 break; 0208 case KoChannelInfo::INT8: 0209 f[k] = fromDoubleCheckNull<qint8>; 0210 break; 0211 case KoChannelInfo::INT16: 0212 f[k] = fromDoubleCheckNull<qint16>; 0213 break; 0214 default: 0215 warnKrita << "Unsupported value type in KisMathToolbox"; 0216 return false; 0217 } 0218 } 0219 0220 return true; 0221 } 0222 0223 double KisMathToolbox::minChannelValue(KoChannelInfo *c) 0224 { 0225 switch (c->channelValueType()) 0226 { 0227 case KoChannelInfo::UINT8 : return KoColorSpaceMathsTraits<quint8>::min; 0228 case KoChannelInfo::UINT16 : return KoColorSpaceMathsTraits<quint16>::min; 0229 case KoChannelInfo::UINT32 : return KoColorSpaceMathsTraits<quint32>::min; 0230 #ifdef HAVE_OPENEXR 0231 case KoChannelInfo::FLOAT16 : return KoColorSpaceMathsTraits<half>::min; 0232 #endif 0233 case KoChannelInfo::FLOAT32 : return KoColorSpaceMathsTraits<float>::min; 0234 case KoChannelInfo::FLOAT64 : return KoColorSpaceMathsTraits<double>::min; 0235 case KoChannelInfo::INT8 : return 127; 0236 case KoChannelInfo::INT16 : return KoColorSpaceMathsTraits<qint16>::min; 0237 default: return 0; 0238 } 0239 } 0240 0241 double KisMathToolbox::maxChannelValue(KoChannelInfo *c) 0242 { 0243 switch (c->channelValueType()) 0244 { 0245 case KoChannelInfo::UINT8 : return KoColorSpaceMathsTraits<quint8>::max; 0246 case KoChannelInfo::UINT16 : return KoColorSpaceMathsTraits<quint16>::max; 0247 case KoChannelInfo::UINT32 : return KoColorSpaceMathsTraits<quint32>::max; 0248 #ifdef HAVE_OPENEXR 0249 case KoChannelInfo::FLOAT16 : return KoColorSpaceMathsTraits<half>::max; 0250 #endif 0251 case KoChannelInfo::FLOAT32 : return KoColorSpaceMathsTraits<float>::max; 0252 case KoChannelInfo::FLOAT64 : return KoColorSpaceMathsTraits<double>::max; 0253 case KoChannelInfo::INT8 : return -128; 0254 case KoChannelInfo::INT16 : return KoColorSpaceMathsTraits<qint16>::max; 0255 default: return 0; 0256 } 0257 } 0258 0259 void KisMathToolbox::wavetrans(KisMathToolbox::KisWavelet* wav, KisMathToolbox::KisWavelet* buff, uint halfsize) 0260 { 0261 uint l = (2 * halfsize) * wav->depth * sizeof(float); 0262 for (uint i = 0; i < halfsize; i++) { 0263 float * itLL = buff->coeffs + i * buff->size * buff->depth; 0264 float * itHL = buff->coeffs + (i * buff->size + halfsize) * buff->depth; 0265 float * itLH = buff->coeffs + (halfsize + i) * buff->size * buff->depth; 0266 float * itHH = buff->coeffs + ((halfsize + i) * buff->size + halfsize) * buff->depth; 0267 float * itS11 = wav->coeffs + 2 * i * wav->size * wav->depth; 0268 float * itS12 = wav->coeffs + (2 * i * wav->size + 1) * wav->depth; 0269 float * itS21 = wav->coeffs + (2 * i + 1) * wav->size * wav->depth; 0270 float * itS22 = wav->coeffs + ((2 * i + 1) * wav->size + 1) * wav->depth; 0271 for (uint j = 0; j < halfsize; j++) { 0272 for (uint k = 0; k < wav->depth; k++) { 0273 *(itLL++) = (*itS11 + *itS12 + *itS21 + *itS22) * M_SQRT1_2; 0274 *(itHL++) = (*itS11 - *itS12 + *itS21 - *itS22) * M_SQRT1_2; 0275 *(itLH++) = (*itS11 + *itS12 - *itS21 - *itS22) * M_SQRT1_2; 0276 *(itHH++) = (*(itS11++) - *(itS12++) - *(itS21++) + *(itS22++)) * M_SQRT1_2; 0277 } 0278 itS11 += wav->depth; itS12 += wav->depth; 0279 itS21 += wav->depth; itS22 += wav->depth; 0280 } 0281 } 0282 for (uint i = 0; i < halfsize; i++) { 0283 uint p = i * wav->size * wav->depth; 0284 memcpy(wav->coeffs + p, buff->coeffs + p, l); 0285 p = (i + halfsize) * wav->size * wav->depth; 0286 memcpy(wav->coeffs + p, buff->coeffs + p, l); 0287 } 0288 if (halfsize != 1) { 0289 wavetrans(wav, buff, halfsize / 2); 0290 } 0291 } 0292 0293 void KisMathToolbox::waveuntrans(KisMathToolbox::KisWavelet* wav, KisMathToolbox::KisWavelet* buff, uint halfsize) 0294 { 0295 uint l = (2 * halfsize) * wav->depth * sizeof(float); 0296 for (uint i = 0; i < halfsize; i++) { 0297 float * itLL = wav->coeffs + i * buff->size * buff->depth; 0298 float * itHL = wav->coeffs + (i * buff->size + halfsize) * buff->depth; 0299 float * itLH = wav->coeffs + (halfsize + i) * buff->size * buff->depth; 0300 float * itHH = wav->coeffs + ((halfsize + i) * buff->size + halfsize) * buff->depth; 0301 float * itS11 = buff->coeffs + 2 * i * wav->size * wav->depth; 0302 float * itS12 = buff->coeffs + (2 * i * wav->size + 1) * wav->depth; 0303 float * itS21 = buff->coeffs + (2 * i + 1) * wav->size * wav->depth; 0304 float * itS22 = buff->coeffs + ((2 * i + 1) * wav->size + 1) * wav->depth; 0305 for (uint j = 0; j < halfsize; j++) { 0306 for (uint k = 0; k < wav->depth; k++) { 0307 *(itS11++) = (*itLL + *itHL + *itLH + *itHH) * 0.25 * M_SQRT2; 0308 *(itS12++) = (*itLL - *itHL + *itLH - *itHH) * 0.25 * M_SQRT2; 0309 *(itS21++) = (*itLL + *itHL - *itLH - *itHH) * 0.25 * M_SQRT2; 0310 *(itS22++) = (*(itLL++) - *(itHL++) - *(itLH++) + *(itHH++)) * 0.25 * M_SQRT2; 0311 } 0312 itS11 += wav->depth; itS12 += wav->depth; 0313 itS21 += wav->depth; itS22 += wav->depth; 0314 } 0315 } 0316 for (uint i = 0; i < halfsize; i++) { 0317 uint p = i * wav->size * wav->depth; 0318 memcpy(wav->coeffs + p, buff->coeffs + p, l); 0319 p = (i + halfsize) * wav->size * wav->depth; 0320 memcpy(wav->coeffs + p, buff->coeffs + p, l); 0321 } 0322 0323 if (halfsize != wav->size / 2) { 0324 waveuntrans(wav, buff, halfsize*2); 0325 } 0326 } 0327 0328 KisMathToolbox::KisWavelet* KisMathToolbox::fastWaveletTransformation(KisPaintDeviceSP src, const QRect& rect, KisWavelet* buff) 0329 { 0330 if (buff == 0) { 0331 buff = initWavelet(src, rect); 0332 } 0333 KisWavelet* wav = initWavelet(src, rect); 0334 transformToFR(src, wav, rect); 0335 wavetrans(wav, buff, wav->size / 2); 0336 0337 return wav; 0338 } 0339 0340 void KisMathToolbox::fastWaveletUntransformation(KisPaintDeviceSP dst, const QRect& rect, KisWavelet* wav, KisWavelet* buff) 0341 { 0342 if (buff == 0) { 0343 buff = initWavelet(dst, rect); 0344 } 0345 0346 waveuntrans(wav, buff, 1); 0347 transformFromFR(dst, wav, rect); 0348 }