1 /*
2 * Copyright (c) 2023 Huawei Device Co., Ltd.
3 * Licensed under the Apache License, Version 2.0 (the "License");
4 * you may not use this file except in compliance with the License.
5 * You may obtain a copy of the License at
6 *
7 * http://www.apache.org/licenses/LICENSE-2.0
8 *
9 * Unless required by applicable law or agreed to in writing, software
10 * distributed under the License is distributed on an "AS IS" BASIS,
11 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 * See the License for the specific language governing permissions and
13 * limitations under the License.
14 */
15 #include "render/rs_color_extract.h"
16 #include <cmath>
17 #include <iostream>
18 #include <vector>
19 #include <memory>
20
21 namespace OHOS {
22 namespace Rosen {
23
RSColorExtract(std::shared_ptr<Drawing::Pixmap> pixmap)24 RSColorExtract::RSColorExtract(std::shared_ptr<Drawing::Pixmap> pixmap)
25 {
26 if (pixmap == nullptr) {
27 return ;
28 }
29 pixelmap_ = pixmap;
30 colorValLen_ = static_cast<uint32_t>(pixmap->GetWidth() * pixmap->GetHeight());
31 auto colorVal = new uint32_t[colorValLen_]();
32 std::shared_ptr<uint32_t> colorShared(colorVal, [](uint32_t *ptr) {
33 delete[] ptr;
34 });
35 colorVal_ = std::move(colorShared);
36 for (int i = 0; i < pixmap->GetHeight(); i++) {
37 for (int j = 0; j < pixmap->GetWidth(); j++) {
38 colorVal[i * pixmap->GetWidth() + j] = pixmap->GetColor(j, i);
39 }
40 }
41 GetNFeatureColors(specifiedFeatureColorNum_);
42 }
43
RSColorExtract(std::shared_ptr<Drawing::Pixmap> pixmap,double * coordinates)44 RSColorExtract::RSColorExtract(std::shared_ptr<Drawing::Pixmap> pixmap, double* coordinates)
45 {
46 if (pixmap == nullptr) {
47 return;
48 }
49 pixelmap_ = pixmap;
50 uint32_t left = static_cast<uint32_t>(pixmap->GetWidth() * coordinates[0]); // 0 is index of left
51 uint32_t top = static_cast<uint32_t>(pixmap->GetHeight() * coordinates[1]); // 1 is index of top
52 uint32_t right = static_cast<uint32_t>(pixmap->GetWidth() * coordinates[2]); // 2 is index of right
53 uint32_t bottom = static_cast<uint32_t>(pixmap->GetHeight() * coordinates[3]); // 3 is index of bottom
54 colorValLen_ = (right - left) * (bottom -top);
55 if (colorValLen_ <= 0) {
56 return;
57 }
58 auto colorVal = new uint32_t[colorValLen_]();
59 std::shared_ptr<uint32_t> colorShared(colorVal, [](uint32_t *ptr) {
60 delete[] ptr;
61 });
62 colorVal_ = std::move(colorShared);
63 for (uint32_t i = top; i < bottom; i++) {
64 for (uint32_t j = left; j < right; j++) {
65 colorVal[(i - top) * (right - left) + (j - left)] = pixmap->GetColor(j, i);
66 }
67 }
68 GetNFeatureColors(specifiedFeatureColorNum_);
69 }
70
71 // Return red component of a quantized color
QuantizedRed(uint32_t color)72 uint32_t RSColorExtract::QuantizedRed(uint32_t color)
73 {
74 return (color >> (QUANTIZE_WORD_WIDTH + QUANTIZE_WORD_WIDTH)) & static_cast<uint32_t>(QUANTIZE_WORD_MASK);
75 }
76
77 // Return green component of a quantized color
QuantizedGreen(uint32_t color)78 uint32_t RSColorExtract::QuantizedGreen(uint32_t color)
79 {
80 return (color >> QUANTIZE_WORD_WIDTH) & static_cast<uint32_t>(QUANTIZE_WORD_MASK);
81 }
82
83 // Return blue component of a quantized color
QuantizedBlue(uint32_t color)84 uint32_t RSColorExtract::QuantizedBlue(uint32_t color)
85 {
86 return color & static_cast<uint32_t>(QUANTIZE_WORD_MASK);
87 }
88
ModifyWordWidth(uint8_t color,int inWidth,int outWidth)89 uint32_t RSColorExtract::ModifyWordWidth(uint8_t color, int inWidth, int outWidth)
90 {
91 uint32_t newValue;
92 if (outWidth > inWidth) {
93 newValue = color << (outWidth - inWidth);
94 } else {
95 newValue = color >> (inWidth - outWidth);
96 }
97 return newValue & ((1 << outWidth) - 1);
98 }
99
GetARGB32ColorR(unsigned int color)100 uint8_t RSColorExtract::GetARGB32ColorR(unsigned int color)
101 {
102 return (color >> ARGB_R_SHIFT) & ARGB_MASK;
103 }
GetARGB32ColorG(unsigned int color)104 uint8_t RSColorExtract::GetARGB32ColorG(unsigned int color)
105 {
106 return (color >> ARGB_G_SHIFT) & ARGB_MASK;
107 }
GetARGB32ColorB(unsigned int color)108 uint8_t RSColorExtract::GetARGB32ColorB(unsigned int color)
109 {
110 return (color >> ARGB_B_SHIFT) & ARGB_MASK;
111 }
112
113
QuantizeFromRGB888(uint32_t color)114 uint32_t RSColorExtract::QuantizeFromRGB888(uint32_t color)
115 {
116 uint32_t r = ModifyWordWidth(GetARGB32ColorR(color), 8, QUANTIZE_WORD_WIDTH);
117 uint32_t g = ModifyWordWidth(GetARGB32ColorG(color), 8, QUANTIZE_WORD_WIDTH);
118 uint32_t b = ModifyWordWidth(GetARGB32ColorB(color), 8, QUANTIZE_WORD_WIDTH);
119 return (r << (QUANTIZE_WORD_WIDTH + QUANTIZE_WORD_WIDTH)) | (g << QUANTIZE_WORD_WIDTH) | b;
120 }
121
122
ApproximateToRGB888(uint32_t r,uint32_t g,uint32_t b)123 uint32_t RSColorExtract::ApproximateToRGB888(uint32_t r, uint32_t g, uint32_t b)
124 {
125 uint32_t approximatedRed = ModifyWordWidth(r, QUANTIZE_WORD_WIDTH, 8);
126 uint32_t approximatedGreen = ModifyWordWidth(g, QUANTIZE_WORD_WIDTH, 8);
127 uint32_t approximatedBlue = ModifyWordWidth(b, QUANTIZE_WORD_WIDTH, 8);
128 return (approximatedRed << ARGB_R_SHIFT) | (approximatedGreen << ARGB_G_SHIFT) | (approximatedBlue << ARGB_B_SHIFT);
129 }
130
ApproximateToRGB888(uint32_t color)131 uint32_t RSColorExtract::ApproximateToRGB888(uint32_t color)
132 {
133 return ApproximateToRGB888(QuantizedRed(color), QuantizedGreen(color), QuantizedBlue(color));
134 }
135
136
QuantizePixels(int colorNum)137 std::vector<std::pair<uint32_t, uint32_t>> RSColorExtract::QuantizePixels(int colorNum)
138 {
139 // Create a priority queue which is sorted by volume descending.
140 std::priority_queue<VBox, std::vector<VBox>, std::less<VBox> > q;
141 VBox v(0, distinctColorCount_ - 1, this);
142 q.push(v);
143 SplitBoxes(q, colorNum);
144 return GenerateAverageColors(q);
145 }
146
147
SplitBoxes(std::priority_queue<VBox,std::vector<VBox>,std::less<VBox>> & queue,int maxSize)148 void RSColorExtract::SplitBoxes(std::priority_queue<VBox, std::vector<VBox>, std::less<VBox> > &queue, int maxSize)
149 {
150 while (queue.size() < static_cast<uint32_t>(maxSize)) {
151 VBox vBox = queue.top();
152 queue.pop();
153 if (vBox.CanSplit()) {
154 queue.push(vBox.SplitBox());
155 queue.push(vBox);
156 } else {
157 return;
158 }
159 }
160 return;
161 }
162
cmp(std::pair<uint32_t,uint32_t> & a,std::pair<uint32_t,uint32_t> & b)163 bool RSColorExtract::cmp(std::pair<uint32_t, uint32_t> &a, std::pair<uint32_t, uint32_t> &b)
164 {
165 return a.second > b.second;
166 }
167
GenerateAverageColors(std::priority_queue<VBox,std::vector<VBox>,std::less<VBox>> & queue)168 std::vector<std::pair<uint32_t, uint32_t>> RSColorExtract::GenerateAverageColors(std::priority_queue<VBox,
169 std::vector<VBox>, std::less<VBox> > &queue)
170 {
171 std::vector<std::pair<uint32_t, uint32_t>> featureColors;
172 while (!queue.empty()) {
173 VBox vBox = queue.top();
174 queue.pop();
175 featureColors.push_back(vBox.GetAverageColor());
176 }
177 return featureColors;
178 }
179
SetFeatureColorNum(int N)180 void RSColorExtract::SetFeatureColorNum(int N)
181 {
182 specifiedFeatureColorNum_ = N;
183 GetNFeatureColors(N);
184 return;
185 }
186
Rgb2Gray(uint32_t color)187 uint8_t RSColorExtract::Rgb2Gray(uint32_t color)
188 {
189 uint32_t r = GetARGB32ColorR(color);
190 uint32_t g = GetARGB32ColorG(color);
191 uint32_t b = GetARGB32ColorB(color);
192 return static_cast<uint8_t>(r * RED_GRAY_RATIO + g * GREEN_GRAY_RATIO + b * BLUE_GRAY_RATIO);
193 }
194
CalcGrayMsd() const195 uint32_t RSColorExtract::CalcGrayMsd() const
196 {
197 if (colorValLen_ == 0) {
198 return 0;
199 }
200 uint32_t *colorVal = colorVal_.get();
201 unsigned long long int graySum = 0;
202 unsigned long long int grayVar = 0;
203 for (uint32_t i = 0; i < colorValLen_; i++) {
204 graySum += Rgb2Gray(colorVal[i]);
205 }
206 uint32_t grayAve = graySum / colorValLen_;
207 for (uint32_t i = 0; i < colorValLen_; i++) {
208 grayVar += pow(static_cast<unsigned long long int>(Rgb2Gray(colorVal[i])) - grayAve, 2); // 2 is square
209 }
210 grayVar /= colorValLen_;
211 return static_cast<uint32_t>(grayVar);
212 }
213
NormalizeRgb(uint32_t val)214 float RSColorExtract::NormalizeRgb(uint32_t val)
215 {
216 float res = static_cast<float>(val) / 255;
217 if (res <= 0.03928) { // 0.03928 is used to normalize rgb;
218 res /= 12.92; // 12.92 is used to normalize rgb;
219 } else {
220 res = pow((res + 0.055) / 1.055, 2.4); // 0.055, 1.055, 2.4 is used to normalize rgb;
221 }
222 return res;
223 }
224
CalcRelativeLum(uint32_t color)225 float RSColorExtract::CalcRelativeLum(uint32_t color)
226 {
227 uint32_t r = GetARGB32ColorR(color);
228 uint32_t g = GetARGB32ColorG(color);
229 uint32_t b = GetARGB32ColorB(color);
230 float R = NormalizeRgb(r);
231 float G = NormalizeRgb(g);
232 float B = NormalizeRgb(b);
233 return R * RED_LUMINACE_RATIO + G * GREEN_LUMINACE_RATIO + B * BLUE_LUMINACE_RATIO;
234 }
235
CalcContrastToWhite() const236 float RSColorExtract::CalcContrastToWhite() const
237 {
238 if (colorValLen_ == 0) {
239 return 0.0;
240 }
241 uint32_t *colorVal = colorVal_.get();
242 float lightDegree = 0;
243 float luminanceSum = 0;
244 for (uint32_t i = 0; i < colorValLen_; i++) {
245 luminanceSum += CalcRelativeLum(colorVal[i]);
246 }
247 float luminanceAve = luminanceSum / colorValLen_;
248 // 0.05 is used to ensure denominator is not 0;
249 lightDegree = (1 + 0.05) / (luminanceAve + 0.05);
250 return lightDegree;
251 }
252
GetNFeatureColors(int colorNum)253 void RSColorExtract::GetNFeatureColors(int colorNum)
254 {
255 if (colorValLen_ == 0) {
256 return;
257 }
258 uint32_t *colorVal = colorVal_.get();
259 uint32_t histLen = (1 << (QUANTIZE_WORD_WIDTH * 3)); // 3 means left shift flag
260 auto hist = new uint32_t[histLen]();
261 std::shared_ptr<uint32_t> histShared(hist, [](uint32_t *ptr) {
262 delete[] ptr;
263 });
264 hist_ = move(histShared);
265 for (uint32_t i = 0; i < colorValLen_; i++) {
266 uint32_t quantizedColor = QuantizeFromRGB888(colorVal[i]);
267 hist[quantizedColor]++;
268 }
269
270 for (uint32_t color = 0; color < histLen; color++) {
271 if (hist[color] > 0) {
272 distinctColorCount_++;
273 }
274 }
275
276 // Create an array consisting of only distinct colors
277 auto colors = new uint32_t[distinctColorCount_]();
278 std::shared_ptr<uint32_t> colorsShared(colors, [](uint32_t *ptr) {
279 delete[] ptr;
280 });
281 colors_ = move(colorsShared);
282
283 int distinctColorIndex = 0;
284 for (uint32_t color = 0; color < histLen; color++) {
285 if (hist[color] > 0) {
286 colors[distinctColorIndex++] = color;
287 }
288 }
289
290 if (distinctColorCount_ < colorNum) {
291 //The picture has fewer colors than the maximum requested, just return the colors.
292 for (int i = 0; i < distinctColorCount_; ++i) {
293 std::pair<uint32_t, uint32_t> featureColor = \
294 std::make_pair(ApproximateToRGB888(colors[i]), hist[colors[i]]);
295 featureColors_.push_back(featureColor);
296 }
297 } else {
298 // Use quantization to reduce the number of color.
299 featureColors_ = QuantizePixels(colorNum);
300 }
301 // Sort colors from more to less.
302 sort(featureColors_.begin(), featureColors_.end(), cmp);
303 return;
304 }
305
306 } // namespace Rosen
307 } // namespace OHOS
308