Skip to content

Commit d3c8ff5

Browse files
committed
quantize: add StbLoadImage using stb_image.h
1 parent b23b7b5 commit d3c8ff5

File tree

5 files changed

+127
-87
lines changed

5 files changed

+127
-87
lines changed

.gitignore

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,6 @@ build
22
patch
33
dist
44
*.egg*
5-
materialyoucolor/quantize/*.cc
6-
materialyoucolor/quantize/*.h
5+
materialyoucolor/quantize
76
__pycache__
87
*.pyc

materialyoucolor/__init__.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1 +1 @@
1-
__version__ = "2.0.8"
1+
__version__ = "2.0.9"

quantizer_cpp.patch

Lines changed: 105 additions & 81 deletions
Original file line numberDiff line numberDiff line change
@@ -1,84 +1,3 @@
1-
diff '--color=auto' -uNr patch/celebi.cc materialyoucolor/quantize/celebi.cc
2-
--- patch/celebi.cc 2024-01-13 11:47:16.897315093 +0530
3-
+++ materialyoucolor/quantize/celebi.cc 2023-12-29 11:13:04.097468166 +0530
4-
@@ -14,47 +14,53 @@
5-
* limitations under the License.
6-
*/
7-
8-
-#include "cpp/quantize/celebi.h"
9-
+#include "celebi.h"
10-
11-
#include <cstddef>
12-
+#include <cstdint>
13-
#include <cstdio>
14-
#include <cstdlib>
15-
+#include <iostream>
16-
#include <vector>
17-
18-
-#include "cpp/quantize/wsmeans.h"
19-
-#include "cpp/quantize/wu.h"
20-
-#include "cpp/utils/utils.h"
21-
-
22-
-namespace material_color_utilities {
23-
-
24-
-QuantizerResult QuantizeCelebi(const std::vector<Argb>& pixels,
25-
- uint16_t max_colors) {
26-
- if (max_colors == 0 || pixels.empty()) {
27-
- return QuantizerResult();
28-
- }
29-
-
30-
+#include "wsmeans.h"
31-
+#include "wu.h"
32-
+#include "utils.h"
33-
+#include "pybind11/pybind11.h"
34-
+#include "pybind11/stl.h"
35-
+
36-
+namespace python = pybind11;
37-
+
38-
+// std::map<Argb, uint32_t>
39-
+std::map<uint32_t, uint32_t> QuantizeCelebi(const python::list& pixels,
40-
+ int max_colors) {
41-
if (max_colors > 256) {
42-
max_colors = 256;
43-
}
44-
45-
int pixel_count = pixels.size();
46-
47-
- std::vector<Argb> opaque_pixels;
48-
+ std::vector<material_color_utilities::Argb> opaque_pixels;
49-
opaque_pixels.reserve(pixel_count);
50-
for (int i = 0; i < pixel_count; i++) {
51-
- int pixel = pixels[i];
52-
- if (!IsOpaque(pixel)) {
53-
- continue;
54-
- }
55-
+ python::list rgba_ = python::cast<python::list>(pixels[i]);
56-
+ uint32_t pixel = (python::cast<uint32_t>(rgba_[0]) << 16) |
57-
+ (python::cast<uint32_t>(rgba_[1]) << 8) |
58-
+ python::cast<uint32_t>(rgba_[2]);
59-
opaque_pixels.push_back(pixel);
60-
}
61-
62-
- std::vector<Argb> wu_result = QuantizeWu(opaque_pixels, max_colors);
63-
-
64-
- QuantizerResult result =
65-
- QuantizeWsmeans(opaque_pixels, wu_result, max_colors);
66-
+ std::vector<material_color_utilities::Argb> wu_result = material_color_utilities::QuantizeWu(opaque_pixels, max_colors);
67-
68-
- return result;
69-
+ material_color_utilities::QuantizerResult result =
70-
+ material_color_utilities::QuantizeWsmeans(opaque_pixels, wu_result, max_colors);
71-
+
72-
+ return result.color_to_count;
73-
}
74-
75-
-} // namespace material_color_utilities
76-
+
77-
+
78-
+PYBIND11_MODULE(celebi, m) {
79-
+ m.doc() = "QuantizeCelebi from cpp";
80-
+ m.def("QuantizeCelebi", &QuantizeCelebi, "Get dominant colors");
81-
+}
821
diff '--color=auto' -uNr patch/celebi.h materialyoucolor/quantize/celebi.h
832
--- patch/celebi.h 2024-01-13 11:47:16.477314056 +0530
843
+++ materialyoucolor/quantize/celebi.h 2023-12-29 11:08:43.363374804 +0530
@@ -252,3 +171,108 @@ diff '--color=auto' -uNr patch/wu.h materialyoucolor/quantize/wu.h
252171

253172
namespace material_color_utilities {
254173

174+
--- patch/celebi.cc 2024-03-25 23:22:50.123427023 +0530
175+
+++ materialyoucolor/quantize/celebi.cc 2024-03-25 23:20:03.277959473 +0530
176+
@@ -14,47 +14,78 @@
177+
* limitations under the License.
178+
*/
179+
180+
-#include "cpp/quantize/celebi.h"
181+
+#include "celebi.h"
182+
183+
#include <cstddef>
184+
+#include <cstdint>
185+
#include <cstdio>
186+
#include <cstdlib>
187+
+#include <iostream>
188+
#include <vector>
189+
190+
-#include "cpp/quantize/wsmeans.h"
191+
-#include "cpp/quantize/wu.h"
192+
-#include "cpp/utils/utils.h"
193+
-
194+
-namespace material_color_utilities {
195+
-
196+
-QuantizerResult QuantizeCelebi(const std::vector<Argb>& pixels,
197+
- uint16_t max_colors) {
198+
- if (max_colors == 0 || pixels.empty()) {
199+
- return QuantizerResult();
200+
- }
201+
-
202+
+#include "wsmeans.h"
203+
+#include "wu.h"
204+
+#include "utils.h"
205+
+#include "pybind11/pybind11.h"
206+
+#include "pybind11/stl.h"
207+
+#define STB_IMAGE_IMPLEMENTATION
208+
+#include "stb_image.h"
209+
+
210+
+namespace python = pybind11;
211+
+
212+
+// std::map<Argb, uint32_t>
213+
+std::map<uint32_t, uint32_t> QuantizeCelebi(const std::vector<std::vector<int>>& pixels,
214+
+ int max_colors) {
215+
if (max_colors > 256) {
216+
max_colors = 256;
217+
}
218+
-
219+
int pixel_count = pixels.size();
220+
221+
- std::vector<Argb> opaque_pixels;
222+
+ std::vector<material_color_utilities::Argb> opaque_pixels;
223+
opaque_pixels.reserve(pixel_count);
224+
for (int i = 0; i < pixel_count; i++) {
225+
- int pixel = pixels[i];
226+
- if (!IsOpaque(pixel)) {
227+
- continue;
228+
- }
229+
+ uint32_t pixel = (pixels[i][0] << 16) |
230+
+ (pixels[i][1] << 8) |
231+
+ (pixels[i][2]);
232+
+ //if (pixels[i].size() > 3 && pixels[i][3] == 255)
233+
opaque_pixels.push_back(pixel);
234+
}
235+
236+
- std::vector<Argb> wu_result = QuantizeWu(opaque_pixels, max_colors);
237+
+ std::vector<material_color_utilities::Argb> wu_result = material_color_utilities::QuantizeWu(
238+
+ opaque_pixels, max_colors);
239+
240+
- QuantizerResult result =
241+
- QuantizeWsmeans(opaque_pixels, wu_result, max_colors);
242+
+ material_color_utilities::QuantizerResult result =
243+
+ material_color_utilities::QuantizeWsmeans(opaque_pixels, wu_result, max_colors);
244+
+
245+
+ return result.color_to_count;
246+
+}
247+
+
248+
249+
- return result;
250+
+std::vector<std::vector<int>> StbLoadImage(const char* image_path) {
251+
+ int width, height, channels;
252+
+ std::vector<std::vector<int>> pixel_array = {};
253+
+ // Load the actual image
254+
+ unsigned char* pixel_result = stbi_load(image_path, &width, &height, &channels, 4);
255+
+ if (!pixel_result) {return pixel_array;}
256+
+
257+
+ pixel_array.reserve(width * height);
258+
+ unsigned char* pixel_position;
259+
+
260+
+ for (int y = 0; y < height; ++y) {
261+
+ for (int x = 0; x < width; ++x) {
262+
+ pixel_position = pixel_result + (x + y * width) * 4;
263+
+ std::vector<int> current_color = {
264+
+ pixel_position[0], pixel_position[1], pixel_position[2]};
265+
+ if (channels > 3) {current_color.push_back(pixel_position[3]);}
266+
+ pixel_array.push_back(current_color);
267+
+ }
268+
+ }
269+
+ stbi_image_free(pixel_result);
270+
+ return pixel_array;
271+
}
272+
273+
-} // namespace material_color_utilities
274+
+PYBIND11_MODULE(celebi, m) {
275+
+ m.doc() = "Functions from cpp backend";
276+
+ m.def("QuantizeCelebi", &QuantizeCelebi, "Get dominant colors");
277+
+ m.def("StbLoadImage", &StbLoadImage, "Get pixel array");
278+
+}

setup.py

Lines changed: 14 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -614,6 +614,13 @@ def download_files(base_url, folder, file_map):
614614
"stl/filesystem.h",
615615
}
616616

617+
# For stb_image backend
618+
STB_IMAGE_COMMIT = "ae721c50eaf761660b4f90cc590453cdb0c2acd0"
619+
STB_IMAGE_URL = (
620+
"https://raw.githubusercontent.com/nothings"
621+
"/stb/{}/".format(STB_IMAGE_COMMIT)
622+
)
623+
617624
if PURE_PYTHON:
618625
print(
619626
"\nWarning: Skipping build of extension : `QuantizeCelebi`"
@@ -624,6 +631,13 @@ def download_files(base_url, folder, file_map):
624631
should_apply = download_files(MCU_URL, MCU_FOLDER, MCU_FILES)
625632
download_files(PYBIND_URL, PYBIND_FOLDER, PYBIND_FILES)
626633
download_files(PYBIND_URL, PYBIND_FOLDER, PYBIND_EXTRA_FILES)
634+
download_files(STB_IMAGE_URL, MCU_FOLDER, ["stb_image.h"])
635+
636+
# write __init__.py
637+
with open(os.path.join(MCU_FOLDER, "__init__.py"), "w") as file:
638+
file.write("from .celebi import QuantizeCelebi, StbLoadImage")
639+
file.close()
640+
627641
if should_apply:
628642
print("[Info]: Applying patch: ", PATCH_FILE)
629643
os.system(
@@ -639,7 +653,6 @@ def download_files(base_url, folder, file_map):
639653
author="Ansh Dadwal",
640654
author_email="[email protected]",
641655
packages=find_packages(),
642-
install_requires=["pillow"],
643656
long_description=long_description,
644657
long_description_content_type="text/markdown",
645658
exclude=["README.md", "*.pyc", "example.py"],

tests/test_all.py

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@
55
from timeit import default_timer
66
import sys
77
from materialyoucolor.utils.color_utils import rgba_from_argb
8-
from materialyoucolor.quantize import QuantizeCelebi
8+
from materialyoucolor.quantize import QuantizeCelebi, StbLoadImage
99
from materialyoucolor.score.score import Score
1010
from materialyoucolor.hct import Hct
1111
from materialyoucolor.dynamiccolor.material_dynamic_colors import MaterialDynamicColors
@@ -47,7 +47,11 @@
4747
image_data = image.getdata()
4848
pixel_array = [image_data[_] for _ in range(0, pixel_len, int(sys.argv[2]))]
4949
end = default_timer()
50-
print("File open took : ", end - start, "secs")
50+
print("File open took [pillow]: ", end - start, "secs")
51+
start = default_timer()
52+
pixel_array = StbLoadImage(FILENAME)
53+
end = default_timer()
54+
print("File open took [stb_image]: ", end - start, "secs")
5155

5256
start = default_timer()
5357
colors = QuantizeCelebi(pixel_array, MAX_COLOR)

0 commit comments

Comments
 (0)