Krita Source Code Documentation
Loading...
Searching...
No Matches
kis_common_colors_recalculation_runner.cpp
Go to the documentation of this file.
1/*
2 * SPDX-License-Identifier: GPL-3.0-or-later
3 */
4
6
7#include <cmath>
8
9#include <QImage>
10
11#include "KoColor.h"
13
14#include "kis_common_colors.h"
15
17
18class Color
19{
20public:
21 Color(QRgb rgb) : r(qRed(rgb)), g(qGreen(rgb)), b(qBlue(rgb)) {}
22 unsigned char r;
23 unsigned char g;
24 unsigned char b;
25 inline unsigned char operator[](ColorAxis i) const
26 {
27 if(i==RedAxis) return r;
28 if(i==GreenAxis) return g;
29 return b;
30 }
31};
32
33class VBox
34{
36public:
38 {
39 QList<Color> colorList;
40 for(int i=0; i<rgbList.size(); i++) {
41 colorList.append(Color(rgbList.at(i)));
42 }
43 m_colors = colorList;
44 }
45
46 VBox(QList<Color> colorList) : m_colors(colorList) {}
47
48 int population() const { return m_colors.size(); }
49
51 {
52 ColorAxis axis = biggestAxis();
53 Q_ASSERT(axisSize(axis)>=3);
54
55 unsigned char divpos = divPos(axis);
56 QList<Color> newVBoxColors;
57 for(int i=m_colors.size()-1; i>=0; i--) {
58 Color c = m_colors.at(i);
59 if(c[axis]>divpos) {
60 m_colors.removeAt(i);
61 newVBoxColors.append(c);
62 }
63 }
64
65 return VBox(newVBoxColors);
66 }
67
68 QRgb mean() const
69 {
70 int r=0;
71 int g=0;
72 int b=0;
73 for(int i=0;i<m_colors.size(); i++) {
74 r+=(int) m_colors.at(i)[RedAxis];
75 g+=(int) m_colors.at(i)[GreenAxis];
76 b+=(int) m_colors.at(i)[BlueAxis];
77 }
78 int size = m_colors.size();
79 Q_ASSERT(size>0);
80
81 return qRgb(r/size, g/size, b/size);
82 }
83
84 unsigned char axisSize(ColorAxis axis) const
85 {
86 unsigned char valMin = 255;
87 unsigned char valMax = 0;
88 for(int i=0; i<m_colors.size(); i++) {
89 if(m_colors.at(i)[axis]>valMax)
90 valMax=m_colors.at(i)[axis];
91 if(m_colors.at(i)[axis]<valMin)
92 valMin=m_colors.at(i)[axis];
93 }
94 return valMax-valMin;
95 }
96
98 {
99 unsigned char sR = axisSize(RedAxis);
100 unsigned char sG = axisSize(GreenAxis);
101 unsigned char sB = axisSize(BlueAxis);
102 if(sR>sG && sR>sB) return RedAxis;
103 if(sG>sR && sG>sB) return GreenAxis;
104 return BlueAxis;
105 }
106
107private:
108// unsigned char divPos(ColorAxis axis) const
109// {
110// QList<unsigned char> values;
111// for(int i=0;i<m_colors.size(); i++) {
112// values.append(m_colors.at(i)[axis]);
113// }
114// std::sort(values.begin(), values.end());
115// return values.at(values.size()*4/5);
116// }
117 unsigned char divPos(ColorAxis axis) const
118 {
119 short min=m_colors.at(0)[axis];
120 short max=m_colors.at(0)[axis];
121 for(int i=0;i<m_colors.size(); i++) {
122 if(min>m_colors.at(i)[axis]) min=m_colors.at(i)[axis];
123 if(max<m_colors.at(i)[axis]) max=m_colors.at(i)[axis];
124 }
125
126 return (min+max)/2;
127 }
128};
129
134
136{
137 QList<QRgb> colors = getColors();
138
139 VBox startBox(colors);
140 QList<VBox> boxes;
141 boxes.append(startBox);
142
143 while (boxes.size()<m_numColors*3/5 && colors.size()>m_numColors*3/5) {
144 int biggestBox=-1;
145 int biggestBoxPopulation=-1;
146
147 for(int i=0; i<boxes.size(); i++) {
148 if(boxes.at(i).population()>biggestBoxPopulation &&
149 boxes.at(i).axisSize(boxes.at(i).biggestAxis())>=3) {
150 biggestBox=i;
151 biggestBoxPopulation=boxes.at(i).population();
152 }
153 }
154
155 if(biggestBox==-1 || boxes[biggestBox].population()<=3)
156 break;
157 VBox newBox = boxes[biggestBox].divide();
158 boxes.append(newBox);
159 }
160
161
162 while (boxes.size()<m_numColors && colors.size()>m_numColors) {
163 int biggestBox=-1;
164 int biggestBoxAxisSize=-1;
165
166 for(int i=0; i<boxes.size(); i++) {
167 if(boxes.at(i).axisSize(boxes.at(i).biggestAxis())>biggestBoxAxisSize &&
168 boxes.at(i).axisSize(boxes.at(i).biggestAxis())>=3) {
169 biggestBox=i;
170 biggestBoxAxisSize=boxes.at(i).axisSize(boxes.at(i).biggestAxis());
171 }
172 }
173
174 if(biggestBox==-1 || boxes[biggestBox].population()<=3)
175 break;
176 VBox newBox = boxes[biggestBox].divide();
177 boxes.append(newBox);
178 }
179
180 const KoColorSpace* colorSpace = KoColorSpaceRegistry::instance()->rgb8();
181 QList<KoColor> colorList;
182 for(int i=0; i<boxes.size(); i++) {
183 if(boxes.at(i).population()>=1) {
184 colorList.append(KoColor(QColor(boxes.at(i).mean()), colorSpace));
185 }
186 }
187
188 return colorList;
189}
190
192{
193 int width = m_imageData.width();
194 int height = m_imageData.height();
195
196 QImage tmpImage;
197 int pixelCount = height*width;
198 if(pixelCount> (1<<16)) {
199 qreal factor = sqrt((1<<16)/(qreal) pixelCount);
200 tmpImage = m_imageData.scaledToWidth(width*factor);
201 }
202 else {
203 tmpImage = m_imageData;
204 }
205 width=tmpImage.width();
206 height=tmpImage.height();
207
208 QSet<QRgb> colorList;
209
210 for (int i=0; i<width; i++) {
211 for (int j=0; j<height; j++) {
212 colorList.insert(tmpImage.pixel(i, j)|qRgba(0,0,0,255));
213 }
214 }
215 return QList<QRgb>(colorList.begin(), colorList.end());
216}
unsigned char operator[](ColorAxis i) const
void setColors(QList< KoColor > colors)
VBox(QList< QRgb > rgbList)
VBox(QList< Color > colorList)
unsigned char divPos(ColorAxis axis) const
unsigned char axisSize(ColorAxis axis) const
unsigned int QRgb
static KoColorSpaceRegistry * instance()
const KoColorSpace * rgb8(const QString &profileName=QString())