File indexing completed on 2024-05-26 04:33:07
0001 /* 0002 * SPDX-FileCopyrightText: 2014 Manuel Riecke <spell1337@gmail.com> 0003 * 0004 * SPDX-License-Identifier: ICS 0005 */ 0006 0007 #include "indexcolorpalette.h" 0008 0009 #include <qmath.h> 0010 0011 #include <KoColorSpaceMaths.h> 0012 #include <KoColorSpaceRegistry.h> 0013 #include <filter/kis_filter_configuration.h> 0014 #include <widgets/kis_multi_integer_filter_widget.h> 0015 0016 float IndexColorPalette::similarity(LabColor c0, LabColor c1) const 0017 { 0018 static const qreal max = KoColorSpaceMathsTraits<quint16>::max; 0019 quint16 diffL = qAbs(c0.L - c1.L); 0020 quint16 diffa = qAbs(c0.a - c1.a); 0021 quint16 diffb = qAbs(c0.b - c1.b); 0022 float valL = diffL/max*similarityFactors.L; 0023 float valA = diffa/max*similarityFactors.a; 0024 float valB = diffb/max*similarityFactors.b; 0025 return 1.f - qSqrt(valL * valL + valA * valA + valB * valB); 0026 } 0027 0028 IndexColorPalette::IndexColorPalette() 0029 { 0030 similarityFactors.L = 1.0f; 0031 similarityFactors.a = 1.0f; 0032 similarityFactors.b = 1.0f; 0033 } 0034 0035 int IndexColorPalette::numColors() const 0036 { 0037 return colors.size(); 0038 } 0039 0040 LabColor IndexColorPalette::getNearestIndex(LabColor clr) const 0041 { 0042 QVector<float> diffs; 0043 diffs.resize(numColors()); 0044 for(int i = 0; i < numColors(); ++i) 0045 diffs[i] = similarity(colors[i], clr); 0046 0047 int primaryColor = -1; 0048 float maxDiff = std::numeric_limits<float>::min(); 0049 for(int i = 0; i < numColors(); ++i) 0050 if(diffs[i] > maxDiff) { 0051 primaryColor = i; 0052 maxDiff = diffs[primaryColor]; 0053 } 0054 0055 KIS_SAFE_ASSERT_RECOVER (primaryColor >= 0) { 0056 LabColor color; 0057 color.L = 0; 0058 color.a = 0; 0059 color.b = 0; 0060 0061 return color; 0062 } 0063 0064 return colors[primaryColor]; 0065 } 0066 0067 QPair<int, int> IndexColorPalette::getNeighbours(int mainClr) const 0068 { 0069 QVector<float> diffs; 0070 diffs.resize(numColors()); 0071 for(int i = 0; i < numColors(); ++i) 0072 diffs[i] = similarity(colors[i], colors[mainClr]); 0073 0074 int darkerColor = 0; 0075 int brighterColor = 0; 0076 for(int i = 0; i < numColors(); ++i) 0077 { 0078 if(i != mainClr) 0079 { 0080 if(colors[i].L < colors[mainClr].L) 0081 { 0082 if(diffs[i] > diffs[darkerColor]) 0083 darkerColor = i; 0084 } 0085 else 0086 { 0087 if(diffs[i] > diffs[brighterColor]) 0088 brighterColor = i; 0089 } 0090 } 0091 } 0092 0093 return qMakePair(darkerColor, brighterColor); 0094 } 0095 0096 void IndexColorPalette::insertShades(LabColor clrA, LabColor clrB, int shades) 0097 { 0098 if(shades == 0) return; 0099 qint16 lumaStep = (clrB.L - clrA.L) / (shades+1); 0100 qint16 astarStep = (clrB.a - clrA.a) / (shades+1); 0101 qint16 bstarStep = (clrB.b - clrA.b) / (shades+1); 0102 for(int i = 0; i < shades; ++i) 0103 { 0104 clrA.L += lumaStep; 0105 clrA.a += astarStep; 0106 clrA.b += bstarStep; 0107 insertColor(clrA); 0108 } 0109 } 0110 0111 void IndexColorPalette::insertShades(KoColor koclrA, KoColor koclrB, int shades) 0112 { 0113 koclrA.convertTo(KoColorSpaceRegistry::instance()->lab16()); 0114 koclrB.convertTo(KoColorSpaceRegistry::instance()->lab16()); 0115 LabColor clrA = *(reinterpret_cast<LabColor*>(koclrA.data())); 0116 LabColor clrB = *(reinterpret_cast<LabColor*>(koclrB.data())); 0117 insertShades(clrA, clrB, shades); 0118 } 0119 0120 void IndexColorPalette::insertShades(QColor qclrA, QColor qclrB, int shades) 0121 { 0122 KoColor koclrA; 0123 koclrA.fromQColor(qclrA); 0124 koclrA.convertTo(KoColorSpaceRegistry::instance()->lab16()); 0125 KoColor koclrB; 0126 koclrB.fromQColor(qclrB); 0127 koclrB.convertTo(KoColorSpaceRegistry::instance()->lab16()); 0128 LabColor clrA = *(reinterpret_cast<LabColor*>(koclrA.data())); 0129 LabColor clrB = *(reinterpret_cast<LabColor*>(koclrB.data())); 0130 insertShades(clrA, clrB, shades); 0131 } 0132 0133 void IndexColorPalette::insertColor(LabColor clr) 0134 { 0135 colors.append(clr); 0136 } 0137 0138 void IndexColorPalette::insertColor(KoColor koclr) 0139 { 0140 koclr.convertTo(KoColorSpaceRegistry::instance()->lab16()); 0141 LabColor clr = *(reinterpret_cast<LabColor*>(koclr.data())); 0142 insertColor(clr); 0143 } 0144 0145 void IndexColorPalette::insertColor(QColor qclr) 0146 { 0147 KoColor koclr; 0148 koclr.fromQColor(qclr); 0149 koclr.convertTo(KoColorSpaceRegistry::instance()->lab16()); 0150 LabColor clr = *(reinterpret_cast<LabColor*>(koclr.data())); 0151 insertColor(clr); 0152 } 0153 0154 namespace 0155 { 0156 struct ColorString 0157 { 0158 int color; 0159 QPair<int, int> neighbours; 0160 float similarity; 0161 }; 0162 } 0163 0164 void IndexColorPalette::mergeMostRedundantColors() 0165 { 0166 QVector<ColorString> colorHood; 0167 colorHood.resize(numColors()); 0168 for(int i = 0; i < numColors(); ++i) 0169 { 0170 colorHood[i].color = i; 0171 colorHood[i].neighbours = getNeighbours(i); 0172 float lSimilarity = 0.05f, rSimilarity = 0.05f; 0173 // There will be exactly 2 colors that have only 1 neighbour, the darkest and the brightest, we don't want to remove those 0174 if(colorHood[i].neighbours.first != -1) 0175 lSimilarity = similarity(colors[colorHood[i].neighbours.first], colors[i]); 0176 if(colorHood[i].neighbours.second != -1) 0177 rSimilarity = similarity(colors[colorHood[i].neighbours.second], colors[i]); 0178 colorHood[i].similarity = (lSimilarity + rSimilarity) / 2; 0179 } 0180 int mostSimilarColor = 0; 0181 for(int i = 0; i < numColors(); ++i) 0182 if(colorHood[i].similarity > colorHood[mostSimilarColor].similarity) 0183 mostSimilarColor = i; 0184 0185 int darkerIndex = colorHood[mostSimilarColor].neighbours.first; 0186 int brighterIndex = colorHood[mostSimilarColor].neighbours.second; 0187 if(darkerIndex != -1 && 0188 brighterIndex != -1) 0189 { 0190 LabColor clrA = colors[darkerIndex]; 0191 LabColor clrB = colors[mostSimilarColor]; 0192 // Remove two, add one = 1 color less 0193 colors.remove(darkerIndex); 0194 colors.remove(mostSimilarColor); 0195 //colors.remove(brighterIndex); 0196 insertShades(clrA, clrB, 1); 0197 //insertShades(clrB, clrC, 1); 0198 } 0199 }