├── .gitignore
├── requirements.txt
├── ui
├── merging_colours.ui
├── progress_bar.ui
├── number_display.py
├── progress_bar.py
├── pixel_perfect.ui
├── ui_funcs.py
├── pixel_perfect.py
├── main.ui
└── main_gui.py
├── README.md
├── scrapper.py
├── main.py
└── res
└── colours.json
/.gitignore:
--------------------------------------------------------------------------------
1 | # Local files (pycache, logs, etc.)
2 | examples/
3 | __pycache__/
4 | **/__pycache__/
5 |
6 | *.log
7 |
8 | # Virtual Env
9 | .Python
10 | [Bb]in
11 | [Ii]nclude
12 | [Ll]ib
13 | [Ll]ib64
14 | [Ll]ocal
15 | [Ss]cripts
16 | share
17 | pyvenv.cfg
18 | .venv
19 | pip-selfcheck.json
--------------------------------------------------------------------------------
/requirements.txt:
--------------------------------------------------------------------------------
1 | cycler==0.10.0
2 | decorator==4.4.1
3 | imageio==2.6.1
4 | kiwisolver==1.1.0
5 | matplotlib==3.1.1
6 | networkx==2.4
7 | numpy==1.17.4
8 | opencv-python==4.1.1.26
9 | Pillow==8.1.1
10 | pyparsing==2.4.5
11 | PyQt5==5.13.2
12 | PyQt5-sip==12.7.0
13 | python-dateutil==2.8.1
14 | PyWavelets==1.1.1
15 | scikit-image==0.16.2
16 | scipy==1.3.2
17 | six==1.13.0
18 |
--------------------------------------------------------------------------------
/ui/merging_colours.ui:
--------------------------------------------------------------------------------
1 |
2 |
3 | Dialog
4 |
5 |
6 |
7 | 0
8 | 0
9 | 245
10 | 32
11 |
12 |
13 |
14 | Dialog
15 |
16 |
17 |
18 |
19 | 10
20 | 10
21 | 161
22 | 16
23 |
24 |
25 |
26 | Number of colours merged:
27 |
28 |
29 |
30 |
31 |
32 | 170
33 | 10
34 | 55
35 | 16
36 |
37 |
38 |
39 |
40 |
41 |
42 |
43 |
44 |
45 |
46 |
--------------------------------------------------------------------------------
/ui/progress_bar.ui:
--------------------------------------------------------------------------------
1 |
2 |
3 | Dialog
4 |
5 |
6 |
7 | 0
8 | 0
9 | 400
10 | 70
11 |
12 |
13 |
14 | Dialog
15 |
16 |
17 |
18 |
19 | 137
20 | 10
21 | 251
22 | 23
23 |
24 |
25 |
26 | 0
27 |
28 |
29 | true
30 |
31 |
32 |
33 |
34 |
35 | 10
36 | 10
37 | 111
38 | 16
39 |
40 |
41 |
42 | Reducing colours...
43 |
44 |
45 |
46 |
47 |
48 | 10
49 | 40
50 | 93
51 | 28
52 |
53 |
54 |
55 | Cancel
56 |
57 |
58 |
59 |
60 |
61 |
62 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # reduce-colours
2 |
3 | This algorithm allows you to reduce the number of colours inside an original image to a desired number of colours (*n*).
4 |
5 | ## Fast tutorial:
6 |
7 | 1. `pip install -r requirements.txt`
8 | 2. `py ui/main_gui.py`
9 |
10 | ## Slower tutorial:
11 | * First, download [Python 3.7](https://www.python.org/downloads/)
12 | * Do this OR the next step:
13 | * Download [GIT for Windows](https://gitforwindows.org/) (if you're using Windows)
14 | * Open a command prompt where you want to put the program's files (`SHIFT + right click` > "open command prompt here")
15 | * Write `git clone https://github.com/Coul33t/reduce-colours.git`: this will copy the content of this repository to your machine
16 | * Do this OR the previous step:
17 | * Download the ZIP file (green icon in the top right corner of this repository)
18 | * Extract it where you want to put the program's files
19 | * Open a command prompt in the folder (`SHIFT + Right click` on the folder, then > "open command prompt here")
20 | * Write `pip install -r requirements.txt` in the command prompt (this will install all the required libraries for the program to run corectly)
21 | * Write `py ui/main_gui.py` (this will launch the program)
22 |
23 | ### Libraries used:
24 | * Skimage (Scikit image)
25 | * OpenCV (unusued right now)
26 | * PIL
27 | * Numpy
28 | * Libtcod (unused right now)
29 |
30 | ### TODO:
31 | * Args parser (input image and *n*)
32 | * Allow to specify regions to exclude for the colour reduction
33 | * Initial and final colours display in terminal with libtcod
34 |
--------------------------------------------------------------------------------
/ui/number_display.py:
--------------------------------------------------------------------------------
1 | # -*- coding: utf-8 -*-
2 |
3 | # Form implementation generated from reading ui file 'merging_colours.ui'
4 | #
5 | # Created by: PyQt5 UI code generator 5.11.3
6 | #
7 | # WARNING! All changes made in this file will be lost!
8 |
9 | from PyQt5 import QtCore, QtWidgets
10 |
11 | class Ui_Dialog(object):
12 | def setupUi(self, Dialog):
13 | Dialog.setObjectName("Dialog")
14 | Dialog.resize(245, 32)
15 | self.label_number = QtWidgets.QLabel(Dialog)
16 | self.label_number.setGeometry(QtCore.QRect(10, 10, 161, 16))
17 | self.label_number.setObjectName("label_number")
18 | self.label_number_value = QtWidgets.QLabel(Dialog)
19 | self.label_number_value.setGeometry(QtCore.QRect(170, 10, 55, 16))
20 | self.label_number_value.setText("")
21 | self.label_number_value.setObjectName("label_number_value")
22 |
23 | self.retranslateUi(Dialog)
24 | QtCore.QMetaObject.connectSlotsByName(Dialog)
25 |
26 | def retranslateUi(self, Dialog):
27 | _translate = QtCore.QCoreApplication.translate
28 | Dialog.setWindowTitle(_translate("Dialog", "Dialog"))
29 | self.label_number.setText(_translate("Dialog", "Number of colours merged:"))
30 |
31 | class NumberDisplay(QtWidgets.QDialog, Ui_Dialog):
32 | def __init__(self, name=None, parent=None):
33 | super(NumberDisplay, self).__init__(parent)
34 | self.setupUi(self)
35 | self.show()
36 |
37 | if name is not None:
38 | self.set_title(name)
39 |
40 | def set_value(self, val):
41 | self.label_number_value.setText(str(val))
42 |
43 | def set_title(self, desc):
44 | self.setWindowTitle(desc)
45 |
--------------------------------------------------------------------------------
/ui/progress_bar.py:
--------------------------------------------------------------------------------
1 | # -*- coding: utf-8 -*-
2 |
3 | # Form implementation generated from reading ui file 'progress_bar.ui'
4 | #
5 | # Created by: PyQt5 UI code generator 5.11.3
6 | #
7 | # WARNING! All changes made in this file will be lost!
8 |
9 | from PyQt5 import QtCore, QtWidgets
10 |
11 | class Ui_Dialog(object):
12 | def setupUi(self, Dialog):
13 | Dialog.setObjectName("Dialog")
14 | Dialog.resize(400, 70)
15 | self.progressBar = QtWidgets.QProgressBar(Dialog)
16 | self.progressBar.setGeometry(QtCore.QRect(137, 10, 251, 23))
17 | self.progressBar.setProperty("value", 24)
18 | self.progressBar.setObjectName("progressBar")
19 | self.label = QtWidgets.QLabel(Dialog)
20 | self.label.setGeometry(QtCore.QRect(10, 10, 111, 16))
21 | self.label.setObjectName("label")
22 | self.pushButton = QtWidgets.QPushButton(Dialog)
23 | self.pushButton.setGeometry(QtCore.QRect(10, 40, 93, 28))
24 | self.pushButton.setObjectName("pushButton")
25 |
26 | self.retranslateUi(Dialog)
27 | QtCore.QMetaObject.connectSlotsByName(Dialog)
28 |
29 | def retranslateUi(self, Dialog):
30 | _translate = QtCore.QCoreApplication.translate
31 | Dialog.setWindowTitle(_translate("Dialog", "Dialog"))
32 | self.label.setText(_translate("Dialog", "Reducing colours..."))
33 | self.pushButton.setText(_translate("Dialog", "Cancel"))
34 |
35 | class ProgressBar(QtWidgets.QDialog, Ui_Dialog):
36 | def __init__(self, name=None, parent=None):
37 | super(ProgressBar, self).__init__(parent)
38 | self.setupUi(self)
39 | self.show()
40 |
41 | if name is not None:
42 | self.set_title(name)
43 |
44 | def set_value(self, val):
45 | self.progressBar.setProperty("value", val)
46 |
47 | def set_title(self, desc):
48 | self.setWindowTitle(desc)
49 |
--------------------------------------------------------------------------------
/scrapper.py:
--------------------------------------------------------------------------------
1 | from bs4 import BeautifulSoup as BS
2 | from selenium.webdriver import Firefox
3 | from selenium.webdriver.firefox.options import Options
4 | import json
5 |
6 | # This file isn't meant to be run every time, I just did it once and that's it.
7 | # The result is located in the "colours.json" file.
8 |
9 | class RGB2DMC:
10 | def __init__(self, rgb_value, hex_value, dmc_name, floss_number):
11 | self.rgb_value = rgb_value
12 | self.hex_value = hex_value
13 | self.dmc_name = dmc_name
14 | self.floss_number = floss_number
15 |
16 |
17 |
18 | firefox_options = Options()
19 | firefox_options.add_argument('--headless')
20 |
21 | driver = Firefox(options=firefox_options)
22 |
23 | driver.get('https://threadcolors.com/')
24 | html = driver.page_source
25 | soup = BS(html, 'html.parser')
26 |
27 | table_lines = soup.find_all('tr')
28 |
29 | colours = []
30 | colour_dict = {'Floss': None, 'DMC Name': None, 'RGB': None, 'Hex': None}
31 | keys_order = []
32 | rgb_keys = ['R', 'G', 'B']
33 |
34 | for i, row in enumerate(table_lines):
35 | if i == 0:
36 | for column in row.find_all('th'):
37 | to_string = ''.join(column.contents).replace(u'\xa0', u'')
38 | keys_order.append(to_string)
39 | if to_string != '' and to_string not in rgb_keys:
40 | colour_dict[to_string] = []
41 |
42 | else:
43 | new_colour = colour_dict.copy()
44 | values = [x.get_text() for x in row.find_all('td')]
45 | rgb_values = [0, 0, 0]
46 | for j, val in enumerate(values):
47 | if j != 0:
48 | if keys_order[j] in rgb_keys:
49 | if keys_order[j] == 'R':
50 | rgb_values[0] = int(val)
51 | elif keys_order[j] == 'G':
52 | rgb_values[1] = int(val)
53 | elif keys_order[j] == 'B':
54 | rgb_values[2] = int(val)
55 | else:
56 | new_colour[keys_order[j]] = val
57 | new_colour['RGB'] = rgb_values
58 | colours.append(new_colour)
59 |
60 |
61 | with open('colours.json', 'w') as json_output:
62 | json.dump(colours, json_output)
63 |
--------------------------------------------------------------------------------
/ui/pixel_perfect.ui:
--------------------------------------------------------------------------------
1 |
2 |
3 | Dialog
4 |
5 |
6 |
7 | 0
8 | 0
9 | 574
10 | 417
11 |
12 |
13 |
14 | Dialog
15 |
16 |
17 |
18 |
19 | 10
20 | 10
21 | 361
22 | 361
23 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
31 |
32 | 380
33 | 220
34 | 81
35 | 28
36 |
37 |
38 |
39 | Go
40 |
41 |
42 |
43 |
44 |
45 | 380
46 | 280
47 | 81
48 | 28
49 |
50 |
51 |
52 | Validate
53 |
54 |
55 |
56 |
57 |
58 | 480
59 | 280
60 | 81
61 | 28
62 |
63 |
64 |
65 | Cancel
66 |
67 |
68 |
69 |
70 |
71 | 482
72 | 220
73 | 81
74 | 28
75 |
76 |
77 |
78 | Reset
79 |
80 |
81 |
82 |
83 |
84 | 380
85 | 130
86 | 181
87 | 80
88 |
89 |
90 |
91 | Pixelisation type
92 |
93 |
94 |
95 |
96 | 10
97 | 20
98 | 151
99 | 20
100 |
101 |
102 |
103 | Most common colour
104 |
105 |
106 | true
107 |
108 |
109 |
110 |
111 |
112 | 10
113 | 50
114 | 141
115 | 20
116 |
117 |
118 |
119 | Colours' average
120 |
121 |
122 |
123 |
124 |
125 |
126 | 380
127 | 10
128 | 181
129 | 111
130 |
131 |
132 |
133 | Pixels
134 |
135 |
136 |
137 |
138 | 10
139 | 20
140 | 55
141 | 16
142 |
143 |
144 |
145 | Pixel size:
146 |
147 |
148 |
149 |
150 |
151 | 110
152 | 20
153 | 61
154 | 22
155 |
156 |
157 |
158 | 1
159 |
160 |
161 | 999999
162 |
163 |
164 |
165 |
166 |
167 | 10
168 | 50
169 | 101
170 | 16
171 |
172 |
173 |
174 | Offset pixel grid:
175 |
176 |
177 |
178 |
179 |
180 | 110
181 | 50
182 | 61
183 | 22
184 |
185 |
186 |
187 |
188 |
189 |
190 | 10
191 | 80
192 | 91
193 | 20
194 |
195 |
196 |
197 | Display grid
198 |
199 |
200 |
201 |
202 |
203 |
204 |
205 |
--------------------------------------------------------------------------------
/main.py:
--------------------------------------------------------------------------------
1 | import cv2
2 | from PIL import Image, ImageCms
3 | from skimage import color
4 | import numpy as np
5 | from math import floor, sqrt
6 | # Display the initial and final in a console
7 | import tcod as libtcod
8 | import argparse
9 |
10 |
11 | def compute_similarity_matrix(colours):
12 | colour_without_occurences = colours
13 | # If the occurence are in the colours array
14 | if len(colours[0]) == 2:
15 | colour_without_occurences = [x[1] for x in colours]
16 |
17 | similarity_matrix = np.zeros((len(colour_without_occurences), len(colour_without_occurences)))
18 |
19 | for i, current_colour in enumerate(colour_without_occurences):
20 | for j, colour_to_compare in enumerate(colour_without_occurences):
21 | similarity_matrix[i, j] = sum(abs(np.asarray(current_colour) - np.asarray(colour_to_compare)))
22 |
23 | similarity_matrix = 1 - (similarity_matrix / 255)
24 |
25 | return similarity_matrix
26 |
27 | def merge_most_similar(similarity_matrix, colours_lab, replaced_colours, replacement:'bright'):
28 | # TODO:
29 | # get most similar
30 | # merge (take the most lumineuse one)
31 | # add to dict the replaced colour
32 | # ex: green replaced by blue, blue replaced by violet -> green replaced by violet too
33 |
34 | # TODO:
35 | # Maybe actually replace everything in the original image and redo the whole process?
36 |
37 | # Get the most similar colours
38 | similarity_matrix[similarity_matrix == 1] = -1
39 | max_idx = np.unravel_index(similarity_matrix.argmax(), similarity_matrix.shape)
40 |
41 | c1_idx = max_idx[0]
42 | c2_idx = max_idx[1]
43 | c1 = colours_lab[c1_idx]
44 | c2 = colours_lab[c2_idx]
45 |
46 | # Compare their luminances : we keep the brightest one
47 | # TODO: try with lowest and merge
48 | if replacement == 'bright':
49 | # c1 is brigther than c2
50 | brigther_colour = c1
51 | darker_colour = c2
52 | brigther_idx = c1_idx
53 | darker_idx = c2_idx
54 | # If not, switch them
55 | if c1[1][0] < c2[1][0]:
56 | brigther_colour = c2
57 | darker_colour = c1
58 | brigther_idx = c2_idx
59 | darker_idx = c1_idx
60 |
61 | brigther_colour = ','.join([str(x) for x in brigther_colour[1]])
62 | darker_colour = ','.join([str(x) for x in darker_colour[1]])
63 |
64 | # Add the colours to the replacement array
65 | replaced_colours[darker_colour] = brigther_colour
66 |
67 |
68 | colours_lab[brigther_idx][0] += colours_lab[darker_idx][0]
69 | del colours_lab[darker_idx]
70 |
71 |
72 | return colours_lab, replaced_colours
73 |
74 | def replace_colours(img_lab_data, colours_lab, replaced_colours):
75 | final_img = img_lab_data.copy()
76 | breakpoint()
77 | for i in range(final_img.shape[0]):
78 | for j in range(final_img.shape[1]):
79 | final_img[i, j] = replaced_colours[colour_to_str(final_img[i, j])]
80 | breakpoint()
81 |
82 | return final_img
83 |
84 | def colour_to_str(colour):
85 | return ','.join([str(x) for x in colour])
86 |
87 | def merge_colours(img_rgb, final_colour_number, all_colours_rgb):
88 | final_colours = []
89 |
90 | for i in range(final_colour_number):
91 | idx = [x[0] for x in all_colours_rgb].index(max([x[0] for x in all_colours_rgb]))
92 | final_colours.append(all_colours_rgb[idx][1])
93 | all_colours_rgb[idx][0] = -1
94 |
95 | final_img = img_rgb.copy()
96 |
97 | #TODO: check if the RGB2LAB conversion MUST occurs at the very last
98 | # or if the problems I had were because of code problem uh
99 |
100 | for i in range(final_img.shape[0]):
101 | for j in range(final_img.shape[1]):
102 | c1 = color.rgb2lab([[final_img[i, j]]])[0][0]
103 | c2 = [color.rgb2lab([[x]])[0][0] for x in final_colours]
104 | distances = [dst(c1, x) for x in c2]
105 | final_img[i, j] = final_colours[distances.index(min(distances))]
106 |
107 | return final_img
108 |
109 | def dst(c1, c2):
110 | return sqrt(pow(c2[0] - c1[0], 2) + pow(c2[1] - c1[1], 2) + pow(c2[2] - c1[2], 2))
111 |
112 | # return : file to convert, number of color
113 | def parser():
114 | parser = argparse.ArgumentParser(description="Reduce the color number of a given file.")
115 | parser.add_argument("filename", metavar="filename", type=str,nargs=1, help="the path of the image")
116 | parser.add_argument("final_color_number", metavar="N", type=int, nargs='?', default=4, help="the final number of colors")
117 | args = parser.parse_args()
118 | return args.filename[0], args.final_color_number
119 |
120 | def main():
121 | filename, final_colour_number = parser()
122 |
123 | # img = cv2.imread('tortank.png')
124 | img = Image.open(filename).convert('RGB')
125 |
126 | # sRGB instead of RGB ([0, 1] instead of [0, 255])
127 | img_rgb_data = np.asarray(img) / 255
128 |
129 | # Get all the colours in the image
130 | all_colours_rgb = img.getcolors()
131 |
132 | # Convert tuples into lists
133 | all_colours_rgb = [[x[0], np.asarray(x[1]) / 255] for x in all_colours_rgb]
134 |
135 | # NEW METHOD:
136 | # take the 4 most represented colours
137 | # compute closeness to each colour, assign the closest one
138 | final_img = merge_colours(img_rgb_data, final_colour_number, all_colours_rgb)
139 |
140 | # MUST specify that the datatype should be uint8 (float in the array),
141 | # or else it displays a weird image
142 | final_img = np.asarray(final_img * 255, 'uint8')
143 |
144 | final_img = Image.fromarray(final_img, mode='RGB')
145 | final_img.show()
146 | final_img.save('dracaufeu_reduced.png')
147 |
148 | # OLD METHOD
149 |
150 | # # k: original value
151 | # # v: replacement
152 | # replaced_colours = {}
153 | # for elem in colours_lab:
154 | # replaced_colours[colour_to_str(elem[1])] = None
155 |
156 | # while len(colours_lab) > final_colour_number:
157 | # # Compute the similarity matrix between colours
158 | # similarity_matrix = compute_similarity_matrix(colours_lab)
159 | # # Merge two colours
160 | # colours_lab, replaced_colours = merge_most_similar(similarity_matrix, colours_lab, replaced_colours, 'bright')
161 |
162 | # final_img = replace_colours(img_lab_data, colours_lab, replaced_colours)
163 |
164 | if __name__ == '__main__':
165 | main()
--------------------------------------------------------------------------------
/ui/ui_funcs.py:
--------------------------------------------------------------------------------
1 | from skimage import color
2 | import numpy as np
3 | from math import floor, sqrt
4 | from progress_bar import ProgressBar
5 | from number_display import NumberDisplay
6 | from PyQt5.QtWidgets import QApplication
7 | from PyQt5 import QtGui
8 | import cv2
9 |
10 | #TODO: replace skimage rgb2lab by OpenCV RGB2Lab (way faster)
11 | def resize_image(img, max_size):
12 | size = list(np.asarray(img).shape[:2])
13 |
14 | resized = False
15 |
16 | #TODO: sure about this?
17 | if size[0] > max_size[0] or size[1] > max_size[1]:
18 | ratio = min(max_size[1] / size[1], max_size[0] / size[0])
19 | new_size = [0, 0]
20 | new_size[1] = int(size[0] * ratio)
21 | new_size[0] = int(size[1] * ratio)
22 | resized = True
23 |
24 | elif size[0] < max_size[0] or size[1] < max_size[1]:
25 | ratio = min(max_size[1] / size[1], max_size[0] / size[0])
26 | new_size = [0, 0]
27 | new_size[1] = int(size[0] * ratio)
28 | new_size[0] = int(size[1] * ratio)
29 | resized = True
30 |
31 | if resized:
32 | return img.resize(new_size)
33 |
34 | return img
35 |
36 | def get_number_of_colours(img):
37 | return len(img.getcolors(img.size[0] * img.size[1]))
38 |
39 | def get_colours(img, final_colour_number):
40 | # Get all the colours in the image
41 | all_colours_rgb = img.getcolors(img.size[0] * img.size[1])
42 |
43 | if final_colour_number > len(all_colours_rgb):
44 | final_colour_number = len(all_colours_rgb)
45 |
46 | # Convert tuples into lists
47 | all_colours_rgb = [[x[0], np.asarray(x[1])] for x in all_colours_rgb]
48 |
49 | final_colours = []
50 |
51 | for _ in range(final_colour_number):
52 | idx = [x[0] for x in all_colours_rgb].index(max([x[0] for x in all_colours_rgb]))
53 | final_colours.append(all_colours_rgb[idx][1])
54 | all_colours_rgb[idx][0] = -1
55 |
56 | return final_colours
57 |
58 | def reduce_colours(img_rgb, final_colours):
59 |
60 | if not isinstance(img_rgb, np.ndarray):
61 | img_rgb = np.asarray(img_rgb) / 255
62 |
63 | final_img = img_rgb.copy()
64 |
65 | # TODO: check if the RGB2LAB conversion MUST occurs at the very last
66 | # or if the problems I had were because of code problem uh
67 |
68 | pb = ProgressBar('Reducing colours')
69 |
70 | for i in range(final_img.shape[0]):
71 | for j in range(final_img.shape[1]):
72 | c1 = color.rgb2lab([[final_img[i, j]]])[0][0]
73 | c2 = [color.rgb2lab([[x]])[0][0] for x in final_colours]
74 | distances = [dst(c1, x) for x in c2]
75 | final_img[i, j] = final_colours[distances.index(min(distances))]
76 |
77 | pb.set_value(floor((((i * final_img.shape[1]) + j) / (final_img.shape[0] * final_img.shape[1])) * 100))
78 | QApplication.processEvents()
79 |
80 | pb.close()
81 |
82 | return final_img
83 |
84 | def dst(c1, c2, colour_space='lab'):
85 | if colour_space == 'lab':
86 | return sqrt(pow(c2[0] - c1[0], 2) + pow(c2[1] - c1[1], 2) + pow(c2[2] - c1[2], 2))
87 | elif colour_space == 'rgb':
88 | #https://www.compuphase.com/cmetric.htm
89 | return sqrt(2 * pow(c2[0] - c1[0], 2) + 4 * pow(c2[1] - c1[1], 2) + 3 * pow(c2[2] - c1[2], 2))
90 |
91 | def get_similarity_matrix(listView_colours):
92 | list_size = listView_colours.rowCount()
93 | similarity_matrix = np.zeros((list_size, list_size)) - 1
94 |
95 | for i in range(list_size):
96 | for j in range(list_size):
97 | if i != j:
98 | c1 = np.asarray(listView_colours.item(i).background().color().getRgb()[:-1]) / 255
99 | c2 = np.asarray(listView_colours.item(j).background().color().getRgb()[:-1]) / 255
100 | similarity_matrix[i, j] = dst(color.rgb2lab([[c1]])[0][0], color.rgb2lab([[c2]])[0][0])
101 |
102 | return similarity_matrix
103 |
104 | def merge_colours(listView_colours, threshold):
105 | similarity_matrix = get_similarity_matrix(listView_colours)
106 |
107 | all_to_merge = np.where(np.logical_and(similarity_matrix > 0, similarity_matrix < threshold))
108 |
109 | number_display_window = NumberDisplay('Merging colours')
110 | counter = 0
111 |
112 | while len(all_to_merge[0]) > 0:
113 | # Get the first one to merge
114 | to_merge = (all_to_merge[0][0], all_to_merge[1][0])
115 |
116 | # Get colour as RGB values in range [0;1]
117 | c1 = np.asarray(listView_colours.item(to_merge[0]).background().color().getRgb()[:-1]) / 255
118 | c2 = np.asarray(listView_colours.item(to_merge[1]).background().color().getRgb()[:-1]) / 255
119 |
120 | # Get colour as LAB
121 | c1 = color.rgb2lab([[c1]])[0][0]
122 | c2 = color.rgb2lab([[c2]])[0][0]
123 |
124 | # Is this a godd way to merge colours?
125 | new_colour_lab = (c1 + c2) / 2.0
126 |
127 | nc = color.lab2rgb([[new_colour_lab]])[0][0] * 255
128 | nc = QtGui.QColor(int(nc[0]), int(nc[1]), int(nc[2]))
129 |
130 | listView_colours.item(to_merge[0]).setBackground(QtGui.QColor(nc))
131 | listView_colours.removeRow(to_merge[1])
132 |
133 | counter += 1
134 | number_display_window.set_value(counter)
135 | QApplication.processEvents()
136 |
137 | similarity_matrix = get_similarity_matrix(listView_colours)
138 | all_to_merge = np.where(np.logical_and(similarity_matrix > 0, similarity_matrix < threshold))
139 |
140 | number_display_window.close()
141 |
142 | def convert_rgb_to_numpy_array(colours_list):
143 | for colour in colours_list:
144 | colour['RGB'] = np.asarray(colour['RGB']) / 255
145 |
146 | def add_Lab(colours_list):
147 | for colour in colours_list:
148 | rgb_colour = np.array(colour['RGB'], dtype=np.float32)
149 | colour_to_lab = cv2.cvtColor(np.asarray([[rgb_colour]]), cv2.COLOR_RGB2Lab)[0][0]
150 | colour['Lab'] = colour_to_lab
151 |
152 | def get_closest_colour(rgb_colour, colour_corres_list, colour_space='lab'):
153 | closest = [99999, None, None]
154 |
155 | if colour_space == 'lab':
156 |
157 | lab_colour = cv2.cvtColor(np.asarray([[rgb_colour]], dtype='float32') / 255, cv2.COLOR_RGB2Lab)[0][0]
158 |
159 | for colour_in_list in colour_corres_list:
160 | distance = dst(lab_colour, colour_in_list['Lab'])
161 | if distance < closest[0]:
162 | closest[0] = distance
163 | closest[1] = colour_in_list
164 |
165 | elif colour_space == 'rgb':
166 |
167 | for colour_in_list in colour_corres_list:
168 | distance = dst(rgb_colour, np.asarray((colour_in_list['RGB'] * 255), dtype='uint8'))
169 | if distance < closest[0]:
170 | closest[0] = distance
171 | closest[1] = colour_in_list
172 |
173 | closest[2] = luminance(np.asarray(closest[1]['RGB']))
174 | return closest
175 |
176 | def to_dmc_colours(colours_list, colour_corres_list, colour_space='lab'):
177 | new_colours = []
178 |
179 | for colour in colours_list:
180 | dmc_colour = get_closest_colour(colour, colour_corres_list, colour_space)
181 | if dmc_colour not in new_colours:
182 | new_colours.append(dmc_colour[1]['RGB'] * 255)
183 |
184 | return new_colours
185 |
186 | def luminance(colour):
187 | """
188 | Compute the luminance of a colour, and return the adequate colour
189 | to write on the initial one (black or white).
190 | """
191 | if (0.299 * colour[0] + 0.587 * colour[1] + 0.114 * colour[2]) > 0.5:
192 | return np.array([0, 0, 0])
193 |
194 | return np.array([1, 1, 1])
195 |
--------------------------------------------------------------------------------
/ui/pixel_perfect.py:
--------------------------------------------------------------------------------
1 | # -*- coding: utf-8 -*-
2 |
3 | # Form implementation generated from reading ui file 'ui\pixel_perfect.ui'
4 | #
5 | # Created by: PyQt5 UI code generator 5.11.3
6 | #
7 | # WARNING! All changes made in this file will be lost!
8 |
9 | from PyQt5 import QtCore, QtGui, QtWidgets
10 |
11 | from math import floor
12 | from skimage import color
13 | import numpy as np
14 | from PIL import Image, ImageQt
15 | from ui_funcs import resize_image
16 | from cv2 import cvtColor, COLOR_RGB2Lab, COLOR_Lab2RGB
17 |
18 | class Ui_Dialog(object):
19 | def setupUi(self, Dialog):
20 | Dialog.setObjectName("Dialog")
21 | Dialog.resize(574, 417)
22 | self.label_img = QtWidgets.QLabel(Dialog)
23 | self.label_img.setGeometry(QtCore.QRect(10, 10, 361, 361))
24 | self.label_img.setText("")
25 | self.label_img.setObjectName("label_img")
26 | self.pushButton_go = QtWidgets.QPushButton(Dialog)
27 | self.pushButton_go.setGeometry(QtCore.QRect(380, 220, 81, 28))
28 | self.pushButton_go.setObjectName("pushButton_go")
29 | self.pushButton_validate = QtWidgets.QPushButton(Dialog)
30 | self.pushButton_validate.setGeometry(QtCore.QRect(380, 280, 81, 28))
31 | self.pushButton_validate.setObjectName("pushButton_validate")
32 | self.pushButton_cancel = QtWidgets.QPushButton(Dialog)
33 | self.pushButton_cancel.setGeometry(QtCore.QRect(480, 280, 81, 28))
34 | self.pushButton_cancel.setObjectName("pushButton_cancel")
35 | self.pushButton_reset = QtWidgets.QPushButton(Dialog)
36 | self.pushButton_reset.setGeometry(QtCore.QRect(482, 220, 81, 28))
37 | self.pushButton_reset.setObjectName("pushButton_reset")
38 | self.groupBox_pixelisation_type = QtWidgets.QGroupBox(Dialog)
39 | self.groupBox_pixelisation_type.setGeometry(QtCore.QRect(380, 130, 181, 80))
40 | self.groupBox_pixelisation_type.setObjectName("groupBox_pixelisation_type")
41 | self.radioButton_common_colour = QtWidgets.QRadioButton(self.groupBox_pixelisation_type)
42 | self.radioButton_common_colour.setGeometry(QtCore.QRect(10, 20, 151, 20))
43 | self.radioButton_common_colour.setObjectName("radioButton_common_colour")
44 | self.radioButton_colours_average = QtWidgets.QRadioButton(self.groupBox_pixelisation_type)
45 | self.radioButton_colours_average.setGeometry(QtCore.QRect(10, 50, 141, 20))
46 | self.radioButton_colours_average.setObjectName("radioButton_colours_average")
47 | self.groupBox_pixels = QtWidgets.QGroupBox(Dialog)
48 | self.groupBox_pixels.setGeometry(QtCore.QRect(380, 10, 181, 111))
49 | self.groupBox_pixels.setObjectName("groupBox_pixels")
50 | self.label_pixel_size = QtWidgets.QLabel(self.groupBox_pixels)
51 | self.label_pixel_size.setGeometry(QtCore.QRect(10, 20, 55, 16))
52 | self.label_pixel_size.setObjectName("label_pixel_size")
53 | self.spinBox_pixel_size = QtWidgets.QSpinBox(self.groupBox_pixels)
54 | self.spinBox_pixel_size.setGeometry(QtCore.QRect(110, 20, 61, 22))
55 | self.spinBox_pixel_size.setMinimum(1)
56 | self.spinBox_pixel_size.setMaximum(999999)
57 | self.spinBox_pixel_size.setObjectName("spinBox_pixel_size")
58 | self.label_offset_pixel_grid = QtWidgets.QLabel(self.groupBox_pixels)
59 | self.label_offset_pixel_grid.setGeometry(QtCore.QRect(10, 50, 101, 16))
60 | self.label_offset_pixel_grid.setObjectName("label_offset_pixel_grid")
61 | self.spinBox_offset_pixel_grid = QtWidgets.QSpinBox(self.groupBox_pixels)
62 | self.spinBox_offset_pixel_grid.setGeometry(QtCore.QRect(110, 50, 61, 22))
63 | self.spinBox_offset_pixel_grid.setObjectName("spinBox_offset_pixel_grid")
64 | self.checkBox_display_grid = QtWidgets.QCheckBox(self.groupBox_pixels)
65 | self.checkBox_display_grid.setGeometry(QtCore.QRect(10, 80, 91, 20))
66 | self.checkBox_display_grid.setObjectName("checkBox_display_grid")
67 |
68 | self.retranslateUi(Dialog)
69 | QtCore.QMetaObject.connectSlotsByName(Dialog)
70 |
71 | def retranslateUi(self, Dialog):
72 | _translate = QtCore.QCoreApplication.translate
73 | Dialog.setWindowTitle(_translate("Dialog", "Dialog"))
74 | self.pushButton_go.setText(_translate("Dialog", "Go"))
75 | self.pushButton_validate.setText(_translate("Dialog", "Validate"))
76 | self.pushButton_cancel.setText(_translate("Dialog", "Cancel"))
77 | self.pushButton_reset.setText(_translate("Dialog", "Reset"))
78 | self.groupBox_pixelisation_type.setTitle(_translate("Dialog", "Pixelisation type"))
79 | self.radioButton_common_colour.setText(_translate("Dialog", "Most common colour"))
80 | self.radioButton_colours_average.setText(_translate("Dialog", "Colours\' average"))
81 | self.groupBox_pixels.setTitle(_translate("Dialog", "Pixels"))
82 | self.label_pixel_size.setText(_translate("Dialog", "Pixel size:"))
83 | self.label_offset_pixel_grid.setText(_translate("Dialog", "Offset pixel grid:"))
84 | self.checkBox_display_grid.setText(_translate("Dialog", "Display grid"))
85 |
86 | class PixelPerfect(QtWidgets.QDialog, Ui_Dialog):
87 | def __init__(self, original_image=None, name=None, parent=None):
88 | super(PixelPerfect, self).__init__(parent)
89 | self.setupUi(self)
90 | self.show()
91 | self.original_image = original_image
92 |
93 | self.label_size = (self.label_img.size().height(), self.label_img.size().width())
94 |
95 | self.resized_original_image = original_image.copy()
96 | self.resized_original_image = resize_image(self.resized_original_image, self.label_size)
97 | self.qimage_resized_original = None
98 | self.pixel_perfected_image = None
99 | self.resized_pixel_perfected_image = None
100 | self.qimage_resized_pixel_perfected = None
101 |
102 | self.displayed_image = None
103 |
104 | self.grid_overlay = None
105 |
106 | self.link_components()
107 |
108 | self.display_original_image()
109 |
110 |
111 | def link_components(self):
112 | self.pushButton_cancel.clicked.connect(self.close_window)
113 | self.pushButton_validate.clicked.connect(self.return_image)
114 | self.pushButton_reset.clicked.connect(self.display_original_image)
115 | self.pushButton_go.clicked.connect(self.pixelate_image)
116 |
117 | def close_window(self):
118 | self.close()
119 |
120 | def reset_pixel_perfected_image(self):
121 | self.pixel_perfected_image = self.original_image.copy()
122 |
123 | def display_original_image(self):
124 | self.qimage_resized_original = ImageQt.ImageQt(self.resized_original_image)
125 | self.displayed_image = QtGui.QPixmap.fromImage(self.qimage_resized_original)
126 | self.label_img.setPixmap(self.displayed_image)
127 |
128 | def create_pixel_grid(self):
129 | grid_size = self.spinBox_pixel_size.value()
130 |
131 | self.grid_overlay = None
132 | self.grid_overlay = np.zeros((self.label_size[0], self.label_size[1], 4), dtype='uint8')
133 |
134 | for i in range(floor(self.label_size[0] / grid_size)):
135 | for j in range(floor(self.label_size[1] / grid_size)):
136 |
137 | colour = np.array([200, 200, 200, 127]).astype('uint8')
138 | if i % 2 == 0 and j % 2 == 0:
139 | colour = np.array([175, 175, 175, 127]).astype('uint8')
140 |
141 | for x in range(i * grid_size, (i * grid_size) + grid_size + 1):
142 | for y in range(j * grid_size, (j * grid_size) + grid_size + 1):
143 | self.grid_overlay[x, y] = colour
144 |
145 | print(self.grid_overlay)
146 | self.grid_overlay = Image.fromarray(self.grid_overlay, mode='RGBA')
147 | self.grid_overlay = ImageQt.ImageQt(self.grid_overlay)
148 | self.grid_overlay = QtGui.QPixmap.fromImage(self.grid_overlay)
149 |
150 |
151 |
152 | def pixelate_image(self):
153 | grid_offset = int(self.spinBox_offset_pixel_grid.value())
154 |
155 | pixel_size = int(self.spinBox_pixel_size.value())
156 | x_size = floor((self.original_image.size[0] - grid_offset) / pixel_size)
157 | y_size = floor((self.original_image.size[1] - grid_offset) / pixel_size)
158 |
159 |
160 | self.reset_pixel_perfected_image()
161 | img_as_array = np.array(self.pixel_perfected_image)
162 |
163 | for y in range(y_size):
164 | for x in range(x_size):
165 | sub_image = self.pixel_perfected_image.crop((x * pixel_size + grid_offset,
166 | y * pixel_size + grid_offset,
167 | (x * pixel_size) + pixel_size + grid_offset,
168 | (y * pixel_size) + pixel_size + grid_offset))
169 |
170 | colours = sub_image.getcolors(sub_image.size[0] * sub_image.size[1])
171 |
172 | # Pink debugging default colour
173 | final_colour = (255, 0, 255)
174 | if self.radioButton_common_colour.isChecked():
175 | final_colour = max(colours, key=lambda x: x[0])[1]
176 |
177 | elif self.radioButton_colours_average.isChecked():
178 | for i, colour in enumerate(colours):
179 | colours[i] = cvtColor(np.asarray([[colour[1]]], dtype='float32') / 255, COLOR_RGB2Lab)
180 |
181 | final_colour = sum(colours) / len(colours)
182 | final_colour = cvtColor(final_colour, COLOR_Lab2RGB) * 255
183 |
184 | img_as_array[y * pixel_size + grid_offset: (y * pixel_size) + pixel_size + grid_offset,
185 | x * pixel_size + grid_offset: (x * pixel_size) + pixel_size + grid_offset] = final_colour
186 |
187 |
188 | self.pixel_perfected_image = Image.fromarray(img_as_array, mode='RGB')
189 | self.resized_pixel_perfected_image = resize_image(self.pixel_perfected_image, self.label_size)
190 | self.qimage_resized_pixel_perfected = ImageQt.ImageQt(self.resized_pixel_perfected_image)
191 | self.displayed_image = QtGui.QPixmap.fromImage(self.qimage_resized_pixel_perfected)
192 | self.label_img.setPixmap(self.displayed_image)
193 |
194 | def return_image(self):
195 | self.close_window()
196 |
197 |
--------------------------------------------------------------------------------
/ui/main.ui:
--------------------------------------------------------------------------------
1 |
2 |
3 | MainWindow
4 |
5 |
6 |
7 | 0
8 | 0
9 | 881
10 | 609
11 |
12 |
13 |
14 | MainWindow
15 |
16 |
17 |
18 |
19 |
20 | 10
21 | 10
22 | 93
23 | 28
24 |
25 |
26 |
27 | Import
28 |
29 |
30 |
31 |
32 |
33 | 120
34 | 15
35 | 241
36 | 21
37 |
38 |
39 |
40 |
41 |
42 |
43 |
44 |
45 |
46 | 10
47 | 90
48 | 361
49 | 361
50 |
51 |
52 |
53 |
54 |
55 |
56 | Qt::AlignLeading|Qt::AlignLeft|Qt::AlignTop
57 |
58 |
59 |
60 |
61 |
62 | 550
63 | 30
64 | 42
65 | 22
66 |
67 |
68 |
69 |
70 |
71 |
72 | 390
73 | 30
74 | 141
75 | 20
76 |
77 |
78 |
79 | Final number of colours:
80 |
81 |
82 |
83 |
84 |
85 | 600
86 | 30
87 | 51
88 | 28
89 |
90 |
91 |
92 | Ok
93 |
94 |
95 |
96 |
97 |
98 | 370
99 | 20
100 | 20
101 | 511
102 |
103 |
104 |
105 | Qt::Vertical
106 |
107 |
108 |
109 |
110 |
111 | 530
112 | 90
113 | 341
114 | 461
115 |
116 |
117 |
118 |
119 |
120 |
121 | 390
122 | 490
123 | 93
124 | 28
125 |
126 |
127 |
128 | Go!
129 |
130 |
131 |
132 |
133 |
134 | 10
135 | 460
136 | 93
137 | 28
138 |
139 |
140 |
141 | Reset
142 |
143 |
144 |
145 |
146 |
147 | 390
148 | 10
149 | 191
150 | 16
151 |
152 |
153 |
154 | Total Number of colours:
155 |
156 |
157 |
158 |
159 |
160 | 110
161 | 480
162 | 101
163 | 21
164 |
165 |
166 |
167 |
168 |
169 |
170 |
171 |
172 |
173 | 390
174 | 520
175 | 93
176 | 28
177 |
178 |
179 |
180 | Save
181 |
182 |
183 |
184 |
185 |
186 | 10
187 | 520
188 | 93
189 | 28
190 |
191 |
192 |
193 | Pixel Perfect
194 |
195 |
196 |
197 |
198 |
199 | 250
200 | 460
201 | 120
202 | 91
203 |
204 |
205 |
206 | Mouse colour
207 |
208 |
209 |
210 |
211 | 10
212 | 20
213 | 71
214 | 21
215 |
216 |
217 |
218 |
219 |
220 |
221 | 10
222 | 40
223 | 95
224 | 20
225 |
226 |
227 |
228 | Add
229 |
230 |
231 | true
232 |
233 |
234 |
235 |
236 |
237 | 10
238 | 60
239 | 95
240 | 20
241 |
242 |
243 |
244 | Change
245 |
246 |
247 |
248 |
249 |
250 |
251 | 530
252 | 50
253 | 331
254 | 31
255 |
256 |
257 |
258 |
259 | 10
260 |
261 |
262 |
263 |
264 |
265 |
266 |
267 |
268 |
269 | 390
270 | 90
271 | 131
272 | 121
273 |
274 |
275 |
276 | Colours
277 |
278 |
279 |
280 |
281 | 20
282 | 20
283 | 93
284 | 28
285 |
286 |
287 |
288 | Add colour
289 |
290 |
291 |
292 |
293 |
294 | 20
295 | 80
296 | 93
297 | 28
298 |
299 |
300 |
301 | Delete
302 |
303 |
304 |
305 |
306 |
307 | 20
308 | 50
309 | 93
310 | 28
311 |
312 |
313 |
314 | Change colour
315 |
316 |
317 |
318 |
319 |
320 |
321 | 390
322 | 220
323 | 131
324 | 91
325 |
326 |
327 |
328 | Auto-merging
329 |
330 |
331 |
332 |
333 | 10
334 | 50
335 | 93
336 | 28
337 |
338 |
339 |
340 | Merge
341 |
342 |
343 |
344 |
345 |
346 | 80
347 | 20
348 | 42
349 | 22
350 |
351 |
352 |
353 |
354 |
355 |
356 | 10
357 | 20
358 | 71
359 | 16
360 |
361 |
362 |
363 | Threshold:
364 |
365 |
366 |
367 |
368 |
369 |
370 | 390
371 | 320
372 | 120
373 | 101
374 |
375 |
376 |
377 | To DMC colours
378 |
379 |
380 |
381 |
382 | 10
383 | 20
384 | 95
385 | 20
386 |
387 |
388 |
389 | L*a*b*
390 |
391 |
392 | true
393 |
394 |
395 |
396 |
397 |
398 | 10
399 | 40
400 | 95
401 | 20
402 |
403 |
404 |
405 | RGB
406 |
407 |
408 |
409 |
410 |
411 | 10
412 | 60
413 | 93
414 | 28
415 |
416 |
417 |
418 | To DMC colour
419 |
420 |
421 |
422 |
423 |
433 |
434 |
435 |
436 |
437 |
438 |
--------------------------------------------------------------------------------
/ui/main_gui.py:
--------------------------------------------------------------------------------
1 | # -*- coding: utf-8 -*-
2 |
3 | # Form implementation generated from reading ui file 'main.ui'
4 | #
5 | # Created by: PyQt5 UI code generator 5.11.3
6 | #
7 | # WARNING! All changes made in this file will be lost!
8 |
9 | from PyQt5 import QtCore, QtGui, QtWidgets
10 |
11 | import json
12 |
13 | from math import floor
14 | from PIL import Image, ImageQt
15 | import numpy as np
16 |
17 | import ui_funcs
18 | from pixel_perfect import PixelPerfect
19 |
20 | class Ui_MainWindow(object):
21 | def __init__(self):
22 | self.path_to_img = None
23 | self.initial_img = None
24 | self.resized_initial_img = None
25 | self.new_img = None
26 | self.resized_new_img = None
27 | self.colours_to_display = []
28 | self.final_colour_number = 0
29 | self.model_listView_choosen_colours = None
30 | self.model_listView_mouse_colour = None
31 | self.pixel_perfect = None
32 | self.colour_corres_list = None
33 |
34 | try:
35 | with open('res/colours.json', 'r') as json_colours_file:
36 | self.colour_corres_list = json.load(json_colours_file)
37 | except FileNotFoundError:
38 | try:
39 | with open('../res/colours.json', 'r') as json_colours_file:
40 | self.colour_corres_list = json.load(json_colours_file)
41 | except FileNotFoundError:
42 | print('ERROR: can\'t find colour.json file. Are you sure the file is located in the folder (root or ui/)? Exiting...')
43 | return
44 |
45 | ui_funcs.convert_rgb_to_numpy_array(self.colour_corres_list)
46 | ui_funcs.add_Lab(self.colour_corres_list)
47 |
48 | def setupUi(self, MainWindow):
49 | MainWindow.setObjectName("MainWindow")
50 | MainWindow.resize(881, 609)
51 | self.centralwidget = QtWidgets.QWidget(MainWindow)
52 | self.centralwidget.setObjectName("centralwidget")
53 | self.pushButton_import = QtWidgets.QPushButton(self.centralwidget)
54 | self.pushButton_import.setGeometry(QtCore.QRect(10, 10, 93, 28))
55 | self.pushButton_import.setObjectName("pushButton_import")
56 | self.label_import_name = QtWidgets.QLabel(self.centralwidget)
57 | self.label_import_name.setGeometry(QtCore.QRect(120, 15, 241, 21))
58 | self.label_import_name.setText("")
59 | self.label_import_name.setObjectName("label_import_name")
60 | self.label_original_image = QtWidgets.QLabel(self.centralwidget)
61 | self.label_original_image.setGeometry(QtCore.QRect(10, 90, 361, 361))
62 | self.label_original_image.setText("")
63 | self.label_original_image.setAlignment(QtCore.Qt.AlignLeading|QtCore.Qt.AlignLeft|QtCore.Qt.AlignTop)
64 | self.label_original_image.setObjectName("label_original_image")
65 | self.spinBox_n_colours = QtWidgets.QSpinBox(self.centralwidget)
66 | self.spinBox_n_colours.setGeometry(QtCore.QRect(550, 30, 42, 22))
67 | self.spinBox_n_colours.setObjectName("spinBox_n_colours")
68 | self.label_n_colours = QtWidgets.QLabel(self.centralwidget)
69 | self.label_n_colours.setGeometry(QtCore.QRect(390, 30, 141, 20))
70 | self.label_n_colours.setObjectName("label_n_colours")
71 | self.pushButton_n_colours = QtWidgets.QPushButton(self.centralwidget)
72 | self.pushButton_n_colours.setGeometry(QtCore.QRect(600, 30, 51, 28))
73 | self.pushButton_n_colours.setObjectName("pushButton_n_colours")
74 | self.line = QtWidgets.QFrame(self.centralwidget)
75 | self.line.setGeometry(QtCore.QRect(370, 20, 20, 511))
76 | self.line.setFrameShape(QtWidgets.QFrame.VLine)
77 | self.line.setFrameShadow(QtWidgets.QFrame.Sunken)
78 | self.line.setObjectName("line")
79 | self.listView_choosen_colours = QtWidgets.QListView(self.centralwidget)
80 | self.listView_choosen_colours.setGeometry(QtCore.QRect(530, 90, 341, 461))
81 | self.listView_choosen_colours.setObjectName("listView_choosen_colours")
82 | self.pushButton_go = QtWidgets.QPushButton(self.centralwidget)
83 | self.pushButton_go.setGeometry(QtCore.QRect(390, 490, 93, 28))
84 | self.pushButton_go.setObjectName("pushButton_go")
85 | self.pushButton_reset = QtWidgets.QPushButton(self.centralwidget)
86 | self.pushButton_reset.setGeometry(QtCore.QRect(10, 460, 93, 28))
87 | self.pushButton_reset.setObjectName("pushButton_reset")
88 | self.label_total_number_of_colour = QtWidgets.QLabel(self.centralwidget)
89 | self.label_total_number_of_colour.setGeometry(QtCore.QRect(390, 10, 191, 16))
90 | self.label_total_number_of_colour.setObjectName("label_total_number_of_colour")
91 | self.label_image_generation = QtWidgets.QLabel(self.centralwidget)
92 | self.label_image_generation.setGeometry(QtCore.QRect(110, 480, 101, 21))
93 | self.label_image_generation.setText("")
94 | self.label_image_generation.setObjectName("label_image_generation")
95 | self.pushButton_save = QtWidgets.QPushButton(self.centralwidget)
96 | self.pushButton_save.setGeometry(QtCore.QRect(390, 520, 93, 28))
97 | self.pushButton_save.setObjectName("pushButton_save")
98 | self.pushButton_pixel_perfect = QtWidgets.QPushButton(self.centralwidget)
99 | self.pushButton_pixel_perfect.setGeometry(QtCore.QRect(10, 520, 93, 28))
100 | self.pushButton_pixel_perfect.setObjectName("pushButton_pixel_perfect")
101 | self.groupBox_mouse_colour = QtWidgets.QGroupBox(self.centralwidget)
102 | self.groupBox_mouse_colour.setGeometry(QtCore.QRect(250, 460, 120, 91))
103 | self.groupBox_mouse_colour.setObjectName("groupBox_mouse_colour")
104 | self.listView_mouse_colour = QtWidgets.QListView(self.groupBox_mouse_colour)
105 | self.listView_mouse_colour.setGeometry(QtCore.QRect(10, 20, 71, 21))
106 | self.listView_mouse_colour.setObjectName("listView_mouse_colour")
107 | self.radioButton_add = QtWidgets.QRadioButton(self.groupBox_mouse_colour)
108 | self.radioButton_add.setGeometry(QtCore.QRect(10, 40, 95, 20))
109 | self.radioButton_add.setChecked(True)
110 | self.radioButton_add.setObjectName("radioButton_add")
111 | self.radioButton_change = QtWidgets.QRadioButton(self.groupBox_mouse_colour)
112 | self.radioButton_change.setGeometry(QtCore.QRect(10, 60, 95, 20))
113 | self.radioButton_change.setObjectName("radioButton_change")
114 | self.label_already_in_list = QtWidgets.QLabel(self.centralwidget)
115 | self.label_already_in_list.setGeometry(QtCore.QRect(530, 50, 331, 31))
116 | font = QtGui.QFont()
117 | font.setPointSize(10)
118 | self.label_already_in_list.setFont(font)
119 | self.label_already_in_list.setText("")
120 | self.label_already_in_list.setObjectName("label_already_in_list")
121 | self.groupBox_colours = QtWidgets.QGroupBox(self.centralwidget)
122 | self.groupBox_colours.setGeometry(QtCore.QRect(390, 90, 131, 121))
123 | self.groupBox_colours.setObjectName("groupBox_colours")
124 | self.pushButton_add_colour = QtWidgets.QPushButton(self.groupBox_colours)
125 | self.pushButton_add_colour.setGeometry(QtCore.QRect(20, 20, 93, 28))
126 | self.pushButton_add_colour.setObjectName("pushButton_add_colour")
127 | self.pushButton_delete_colour = QtWidgets.QPushButton(self.groupBox_colours)
128 | self.pushButton_delete_colour.setGeometry(QtCore.QRect(20, 80, 93, 28))
129 | self.pushButton_delete_colour.setObjectName("pushButton_delete_colour")
130 | self.pushButton_change_colour = QtWidgets.QPushButton(self.groupBox_colours)
131 | self.pushButton_change_colour.setGeometry(QtCore.QRect(20, 50, 93, 28))
132 | self.pushButton_change_colour.setObjectName("pushButton_change_colour")
133 | self.groupBox_auto_merging = QtWidgets.QGroupBox(self.centralwidget)
134 | self.groupBox_auto_merging.setGeometry(QtCore.QRect(390, 220, 131, 91))
135 | self.groupBox_auto_merging.setObjectName("groupBox_auto_merging")
136 | self.pushButton_merge_colours = QtWidgets.QPushButton(self.groupBox_auto_merging)
137 | self.pushButton_merge_colours.setGeometry(QtCore.QRect(10, 50, 93, 28))
138 | self.pushButton_merge_colours.setObjectName("pushButton_merge_colours")
139 | self.spinBox_merge_colours = QtWidgets.QSpinBox(self.groupBox_auto_merging)
140 | self.spinBox_merge_colours.setGeometry(QtCore.QRect(80, 20, 42, 22))
141 | self.spinBox_merge_colours.setObjectName("spinBox_merge_colours")
142 | self.label_colours_merging = QtWidgets.QLabel(self.groupBox_auto_merging)
143 | self.label_colours_merging.setGeometry(QtCore.QRect(10, 20, 71, 16))
144 | self.label_colours_merging.setObjectName("label_colours_merging")
145 | self.groupBox_to_dmc = QtWidgets.QGroupBox(self.centralwidget)
146 | self.groupBox_to_dmc.setGeometry(QtCore.QRect(390, 320, 120, 101))
147 | self.groupBox_to_dmc.setObjectName("groupBox_to_dmc")
148 | self.radioButton_to_dmc_lab = QtWidgets.QRadioButton(self.groupBox_to_dmc)
149 | self.radioButton_to_dmc_lab.setGeometry(QtCore.QRect(10, 20, 95, 20))
150 | self.radioButton_to_dmc_lab.setChecked(True)
151 | self.radioButton_to_dmc_lab.setObjectName("radioButton_to_dmc_lab")
152 | self.radioButton_to_dmc_rgb = QtWidgets.QRadioButton(self.groupBox_to_dmc)
153 | self.radioButton_to_dmc_rgb.setGeometry(QtCore.QRect(10, 40, 95, 20))
154 | self.radioButton_to_dmc_rgb.setObjectName("radioButton_to_dmc_rgb")
155 | self.pushButton_to_dmc_colours = QtWidgets.QPushButton(self.groupBox_to_dmc)
156 | self.pushButton_to_dmc_colours.setGeometry(QtCore.QRect(10, 60, 93, 28))
157 | self.pushButton_to_dmc_colours.setObjectName("pushButton_to_dmc_colours")
158 | MainWindow.setCentralWidget(self.centralwidget)
159 | self.menubar = QtWidgets.QMenuBar(MainWindow)
160 | self.menubar.setGeometry(QtCore.QRect(0, 0, 739, 26))
161 | self.menubar.setObjectName("menubar")
162 | MainWindow.setMenuBar(self.menubar)
163 | self.statusbar = QtWidgets.QStatusBar(MainWindow)
164 | self.statusbar.setObjectName("statusbar")
165 | MainWindow.setStatusBar(self.statusbar)
166 |
167 | self.retranslateUi(MainWindow)
168 | QtCore.QMetaObject.connectSlotsByName(MainWindow)
169 |
170 | self.initialise()
171 | self.link_components()
172 |
173 | def retranslateUi(self, MainWindow):
174 | _translate = QtCore.QCoreApplication.translate
175 | MainWindow.setWindowTitle(_translate("MainWindow", "MainWindow"))
176 | self.pushButton_import.setText(_translate("MainWindow", "Import"))
177 | self.label_n_colours.setText(_translate("MainWindow", "Final number of colours:"))
178 | self.pushButton_n_colours.setText(_translate("MainWindow", "Ok"))
179 | self.pushButton_go.setText(_translate("MainWindow", "Go!"))
180 | self.pushButton_reset.setText(_translate("MainWindow", "Reset"))
181 | self.label_total_number_of_colour.setText(_translate("MainWindow", "Total Number of colours:"))
182 | self.pushButton_save.setText(_translate("MainWindow", "Save"))
183 | self.pushButton_pixel_perfect.setText(_translate("MainWindow", "Pixel Perfect"))
184 | self.groupBox_mouse_colour.setTitle(_translate("MainWindow", "Mouse colour"))
185 | self.radioButton_add.setText(_translate("MainWindow", "Add"))
186 | self.radioButton_change.setText(_translate("MainWindow", "Change"))
187 | self.groupBox_colours.setTitle(_translate("MainWindow", "Colours"))
188 | self.pushButton_add_colour.setText(_translate("MainWindow", "Add colour"))
189 | self.pushButton_delete_colour.setText(_translate("MainWindow", "Delete"))
190 | self.pushButton_change_colour.setText(_translate("MainWindow", "Change colour"))
191 | self.groupBox_auto_merging.setTitle(_translate("MainWindow", "Auto-merging"))
192 | self.pushButton_merge_colours.setText(_translate("MainWindow", "Merge"))
193 | self.label_colours_merging.setText(_translate("MainWindow", "Threshold:"))
194 | self.groupBox_to_dmc.setTitle(_translate("MainWindow", "To DMC colours"))
195 | self.radioButton_to_dmc_lab.setText(_translate("MainWindow", "L*a*b*"))
196 | self.radioButton_to_dmc_rgb.setText(_translate("MainWindow", "RGB"))
197 | self.pushButton_to_dmc_colours.setText(_translate("MainWindow", "To DMC colour"))
198 |
199 | def initialise(self):
200 | self.model_listView_choosen_colours = QtGui.QStandardItemModel(self.listView_choosen_colours)
201 | self.listView_choosen_colours.setModel(self.model_listView_choosen_colours)
202 | self.model_listView_mouse_colour = QtGui.QStandardItemModel(self.listView_mouse_colour)
203 | self.listView_mouse_colour.setModel(self.model_listView_mouse_colour)
204 |
205 | self.hide_all()
206 |
207 | def hide_all(self):
208 | self.label_n_colours.hide()
209 | self.pushButton_n_colours.hide()
210 | self.label_already_in_list.hide()
211 | self.pushButton_go.hide()
212 | self.pushButton_reset.hide()
213 | self.label_total_number_of_colour.hide()
214 | self.pushButton_save.hide()
215 | self.groupBox_colours.hide()
216 | self.listView_choosen_colours.hide()
217 | self.listView_mouse_colour.hide()
218 | self.spinBox_n_colours.hide()
219 | self.groupBox_auto_merging.hide()
220 | self.pushButton_pixel_perfect.hide()
221 | self.groupBox_mouse_colour.hide()
222 | self.groupBox_to_dmc.hide()
223 |
224 | def show_all(self):
225 | self.label_n_colours.show()
226 | self.pushButton_n_colours.show()
227 | self.label_already_in_list.show()
228 | self.pushButton_go.show()
229 | self.pushButton_reset.show()
230 | self.label_total_number_of_colour.show()
231 | self.pushButton_save.show()
232 | self.groupBox_colours.show()
233 | self.listView_choosen_colours.show()
234 | self.listView_mouse_colour.show()
235 | self.spinBox_n_colours.show()
236 | self.groupBox_auto_merging.show()
237 | self.pushButton_pixel_perfect.show()
238 | self.groupBox_mouse_colour.show()
239 | self.groupBox_to_dmc.show()
240 |
241 |
242 | def link_components(self):
243 | self.pushButton_import.clicked.connect(self.select_file)
244 | self.pushButton_n_colours.clicked.connect(self.get_colours)
245 | self.pushButton_go.clicked.connect(self.generate_output)
246 | self.pushButton_reset.clicked.connect(self.reset_displayed_image)
247 | self.pushButton_save.clicked.connect(self.save_output_image)
248 | self.pushButton_add_colour.clicked.connect(self.add_colour_from_picker)
249 | self.pushButton_delete_colour.clicked.connect(self.delete_colour)
250 | self.pushButton_change_colour.clicked.connect(self.change_colour_from_picker)
251 | self.label_original_image.mousePressEvent = self.get_colour_under_mouse
252 | self.pushButton_merge_colours.clicked.connect(self.merge_colours)
253 | self.pushButton_pixel_perfect.clicked.connect(self.open_pixel_perfect)
254 | self.pushButton_to_dmc_colours.clicked.connect(self.to_dmc_colours)
255 |
256 | def select_file(self):
257 | string = QtWidgets.QFileDialog.getOpenFileName(filter="Image Files (*.png *.jpg *.bmp)")
258 | self.path_to_img = string[0]
259 |
260 | if not self.path_to_img:
261 | return
262 |
263 | self.label_import_name.setText(self.path_to_img.split('/')[-1])
264 |
265 | self.initial_img = Image.open(self.path_to_img).convert('RGB')
266 |
267 | label_size = (self.label_original_image.size().height(), self.label_original_image.size().width())
268 |
269 | self.resized_initial_img = ui_funcs.resize_image(self.initial_img, label_size)
270 |
271 | self.resized_initial_img = ImageQt.ImageQt(self.resized_initial_img)
272 | reference_img = QtGui.QPixmap.fromImage(self.resized_initial_img)
273 | self.label_original_image.setPixmap(reference_img)
274 |
275 | self.label_image_generation.setText('')
276 | self.label_total_number_of_colour.setText(f"Total number of colours: {ui_funcs.get_number_of_colours(self.initial_img)}")
277 |
278 | self.show_all()
279 |
280 | def open_pixel_perfect(self):
281 | if self.new_img is not None:
282 | self.pixel_perfect = PixelPerfect(self.new_img)
283 | else:
284 | self.pixel_perfect = PixelPerfect(self.initial_img)
285 |
286 | def check_if_colour_exists(self, colour):
287 | for index in range(self.model_listView_choosen_colours.rowCount()):
288 | if colour == self.model_listView_choosen_colours.item(index).background().color().getRgb()[:-1]:
289 | return True
290 | return False
291 |
292 | def add_colour_to_listview(self, colour_to_add):
293 | if isinstance(colour_to_add, QtGui.QColor):
294 | colour_to_add = colour_to_add.getRgb()[:-1]
295 |
296 | colour_to_add = tuple(colour_to_add)
297 |
298 | if self.check_if_colour_exists(colour_to_add):
299 | self.colour_already_in_list(colour_to_add)
300 | return
301 |
302 | closest = ui_funcs.get_closest_colour(colour_to_add, self.colour_corres_list)
303 | rgb_value = f'({int(colour_to_add[0])},{int(colour_to_add[1])},{int(colour_to_add[2])})'
304 | item = QtGui.QStandardItem(f'{closest[1]["Floss"]} {closest[1]["DMC Name"]} {rgb_value}')
305 |
306 | item.setForeground((QtGui.QColor(int(closest[2][0] * 255),
307 | int(closest[2][1] * 255),
308 | int(closest[2][2] * 255))))
309 |
310 | item.setBackground(QtGui.QColor(int(colour_to_add[0]),
311 | int(colour_to_add[1]),
312 | int(colour_to_add[2])))
313 | self.model_listView_choosen_colours.appendRow(item)
314 |
315 | def get_colours(self):
316 | self.model_listView_choosen_colours.clear()
317 | self.final_colour_number = self.spinBox_n_colours.value()
318 | self.colours_to_display = ui_funcs.get_colours(self.initial_img, self.final_colour_number)
319 |
320 | if not self.colours_to_display:
321 | return
322 |
323 | # TODO: order the list by colour proximity (purely aesthetic)
324 | for colour in self.colours_to_display:
325 | self.add_colour_to_listview(colour)
326 |
327 | def colour_already_in_list(self, colour):
328 | self.label_already_in_list.setText(f"{colour} already in list")
329 |
330 | def add_colour_from_picker(self):
331 | new_colour = QtWidgets.QColorDialog.getColor()
332 |
333 | print(new_colour)
334 |
335 | if not new_colour:
336 | return
337 |
338 | self.add_colour_to_listview(new_colour)
339 |
340 | def change_colour_from_picker(self):
341 | new_colour = QtWidgets.QColorDialog.getColor()
342 |
343 | self.change_colour(new_colour)
344 |
345 | def add_mouse_colour(self):
346 | if self.model_listView_mouse_colour.item(0) is None:
347 | return
348 |
349 | new_colour = self.model_listView_mouse_colour.item(0).background().color()
350 |
351 | self.add_colour_to_listview(new_colour)
352 |
353 | def change_colour(self, new_colour):
354 | if self.check_if_colour_exists(new_colour):
355 | self.colour_already_in_list(new_colour)
356 | return
357 |
358 | index = self.listView_choosen_colours.selectedIndexes()
359 | if len(index) < 1:
360 | return
361 |
362 | bg_colour = QtGui.QColor(int(new_colour[0]),
363 | int(new_colour[1]),
364 | int(new_colour[2]))
365 | self.model_listView_choosen_colours.itemFromIndex(index[0]).setBackground(bg_colour)
366 |
367 |
368 | def delete_colour(self):
369 | index = self.listView_choosen_colours.selectedIndexes()
370 | if len(index) > 0:
371 | self.model_listView_choosen_colours.removeRow(index[0].row())
372 |
373 | def get_colour_under_mouse(self, event):
374 | if self.resized_initial_img is None:
375 | return
376 |
377 | # TODO: pixel offset sometimes (probably has something to do with resizing)
378 | x = event.localPos().x()
379 | y = event.localPos().y()
380 |
381 | colour = self.resized_initial_img.pixel(x, y)
382 | rgb = QtGui.QColor(colour).getRgb()[0:3]
383 |
384 | if self.radioButton_add.isChecked():
385 | self.add_colour_to_listview(rgb)
386 |
387 | elif self.radioButton_change.isChecked():
388 | self.change_colour(rgb)
389 |
390 | item = QtGui.QStandardItem()
391 | item.setBackground(QtGui.QColor(int(rgb[0]),
392 | int(rgb[1]),
393 | int(rgb[2])))
394 |
395 | self.model_listView_mouse_colour.removeRow(0)
396 | self.model_listView_mouse_colour.appendRow(item)
397 |
398 |
399 | def merge_colours(self):
400 | ui_funcs.merge_colours(self.model_listView_choosen_colours,
401 | self.spinBox_merge_colours.value())
402 |
403 | def to_dmc_colours(self):
404 | colours_list = []
405 | for i in range(self.model_listView_choosen_colours.rowCount()):
406 | item = self.model_listView_choosen_colours.item(i)
407 | colours_list.append(np.asarray(item.background().color().getRgb()[0:3]))
408 |
409 | colour_space = None
410 |
411 | if self.radioButton_to_dmc_lab.isChecked():
412 | colour_space = 'lab'
413 |
414 | elif self.radioButton_to_dmc_rgb.isChecked():
415 | colour_space = 'rgb'
416 |
417 | new_colours = ui_funcs.to_dmc_colours(colours_list, self.colour_corres_list, colour_space)
418 |
419 | self.model_listView_choosen_colours.clear()
420 |
421 | for colour in new_colours:
422 | self.add_colour_to_listview(colour)
423 |
424 |
425 |
426 | def generate_output(self):
427 | self.label_image_generation.setText('Generating image...')
428 |
429 | self.colours_to_display = []
430 | for i in range(self.model_listView_choosen_colours.rowCount()):
431 | item = self.model_listView_choosen_colours.item(i)
432 | self.colours_to_display.append(np.asarray(item.background().color().getRgb()[0:3], np.float64) / 255)
433 |
434 | self.new_img = ui_funcs.reduce_colours(self.initial_img, self.colours_to_display)
435 |
436 | label_size = (self.label_original_image.size().height(), self.label_original_image.size().width())
437 |
438 | self.new_img = np.asarray(self.new_img * 255, 'uint8')
439 | self.new_img = Image.fromarray(self.new_img, mode='RGB')
440 |
441 | self.new_resized_img = ui_funcs.resize_image(self.new_img, label_size)
442 |
443 | self.new_resized_img = ImageQt.ImageQt(self.new_resized_img)
444 | reference_img = QtGui.QPixmap.fromImage(self.new_resized_img)
445 | self.label_original_image.setPixmap(reference_img)
446 |
447 | self.label_image_generation.setText('Image generated!')
448 |
449 | def reset_displayed_image(self):
450 | reference_img = QtGui.QPixmap.fromImage(self.resized_initial_img)
451 | self.label_original_image.setPixmap(reference_img)
452 |
453 | def save_output_image(self):
454 | final_name = f"{self.path_to_img.split('.')[0]}_reduced.{self.path_to_img.split('.')[-1]}"
455 | self.new_img.save(final_name)
456 | msg = QtWidgets.QMessageBox()
457 | msg.setIcon(QtWidgets.QMessageBox.Information)
458 | msg.setText(f"Image successfully saved as {final_name} !")
459 | msg.exec_()
460 |
461 |
462 | if __name__ == "__main__":
463 | import sys
464 | app = QtWidgets.QApplication(sys.argv)
465 | MainWindow = QtWidgets.QMainWindow()
466 | ui = Ui_MainWindow()
467 | ui.setupUi(MainWindow)
468 | MainWindow.show()
469 | sys.exit(app.exec_())
470 |
--------------------------------------------------------------------------------
/res/colours.json:
--------------------------------------------------------------------------------
1 | [{"Floss": "3713", "DMC Name": "Salmon Very Light", "RGB": [255, 226, 226], "Hex": "ffe2e2"}, {"Floss": "761", "DMC Name": "Salmon Light", "RGB": [255, 201, 201], "Hex": "ffc9c9"}, {"Floss": "760", "DMC Name": "Salmon", "RGB": [245, 173, 173], "Hex": "f5adad"}, {"Floss": "3712", "DMC Name": "Salmon Medium", "RGB": [241, 135, 135], "Hex": "f18787"}, {"Floss": "3328", "DMC Name": "Salmon Dark", "RGB": [227, 109, 109], "Hex": "e36d6d"}, {"Floss": "347", "DMC Name": "Salmon Very Dark", "RGB": [191, 45, 45], "Hex": "bf2d2d"}, {"Floss": "353", "DMC Name": "Peach", "RGB": [254, 215, 204], "Hex": "fed7cc"}, {"Floss": "352", "DMC Name": "Coral Light", "RGB": [253, 156, 151], "Hex": "fd9c97"}, {"Floss": "351", "DMC Name": "Coral", "RGB": [233, 106, 103], "Hex": "e96a67"}, {"Floss": "350", "DMC Name": "Coral Medium", "RGB": [224, 72, 72], "Hex": "e04848"}, {"Floss": "349", "DMC Name": "Coral Dark", "RGB": [210, 16, 53], "Hex": "d21035"}, {"Floss": "817", "DMC Name": "Coral Red Very Dark", "RGB": [187, 5, 31], "Hex": "bb051f"}, {"Floss": "3708", "DMC Name": "Melon Light", "RGB": [255, 203, 213], "Hex": "ffcbd5"}, {"Floss": "3706", "DMC Name": "Melon Medium", "RGB": [255, 173, 188], "Hex": "ffadbc"}, {"Floss": "3705", "DMC Name": "Melon Dark", "RGB": [255, 121, 146], "Hex": "ff7992"}, {"Floss": "3801", "DMC Name": "Melon Very Dark", "RGB": [231, 73, 103], "Hex": "e74967"}, {"Floss": "666", "DMC Name": "Bright Red", "RGB": [227, 29, 66], "Hex": "e31d42"}, {"Floss": "321", "DMC Name": "Red", "RGB": [199, 43, 59], "Hex": "c72b3b"}, {"Floss": "304", "DMC Name": "Red Medium", "RGB": [183, 31, 51], "Hex": "b71f33"}, {"Floss": "498", "DMC Name": "Red Dark", "RGB": [167, 19, 43], "Hex": "a7132b"}, {"Floss": "816", "DMC Name": "Garnet", "RGB": [151, 11, 35], "Hex": "970b23"}, {"Floss": "815", "DMC Name": "Garnet Medium", "RGB": [135, 7, 31], "Hex": "87071f"}, {"Floss": "814", "DMC Name": "Garnet Dark", "RGB": [123, 0, 27], "Hex": "7b001b"}, {"Floss": "894", "DMC Name": "Carnation Very Light", "RGB": [255, 178, 187], "Hex": "ffb2bb"}, {"Floss": "893", "DMC Name": "Carnation Light", "RGB": [252, 144, 162], "Hex": "fc90a2"}, {"Floss": "892", "DMC Name": "Carnation Medium", "RGB": [255, 121, 140], "Hex": "ff798c"}, {"Floss": "891", "DMC Name": "Carnation Dark", "RGB": [255, 87, 115], "Hex": "ff5773"}, {"Floss": "818", "DMC Name": "Baby Pink", "RGB": [255, 223, 217], "Hex": "ffdfd9"}, {"Floss": "957", "DMC Name": "Geranium Pale", "RGB": [253, 181, 181], "Hex": "fdb5b5"}, {"Floss": "956", "DMC Name": "Geranium", "RGB": [255, 145, 145], "Hex": "ff9191"}, {"Floss": "309", "DMC Name": "Rose Dark", "RGB": [214, 43, 91], "Hex": "d62b5b"}, {"Floss": "963", "DMC Name": "Dusty Rose Ult Vy Lt", "RGB": [255, 215, 215], "Hex": "ffd7d7"}, {"Floss": "3716", "DMC Name": "Dusty Rose Med Vy Lt", "RGB": [255, 189, 189], "Hex": "ffbdbd"}, {"Floss": "962", "DMC Name": "Dusty Rose Medium", "RGB": [230, 138, 138], "Hex": "e68a8a"}, {"Floss": "961", "DMC Name": "Dusty Rose Dark", "RGB": [207, 115, 115], "Hex": "cf7373"}, {"Floss": "3833", "DMC Name": "Raspberry Light", "RGB": [234, 134, 153], "Hex": "ea8699"}, {"Floss": "3832", "DMC Name": "Raspberry Medium", "RGB": [219, 85, 110], "Hex": "db556e"}, {"Floss": "3831", "DMC Name": "Raspberry Dark", "RGB": [179, 47, 72], "Hex": "b32f48"}, {"Floss": "777", "DMC Name": "Raspberry Very Dark", "RGB": [145, 53, 70], "Hex": "913546"}, {"Floss": "819", "DMC Name": "Baby Pink Light", "RGB": [255, 238, 235], "Hex": "ffeeeb"}, {"Floss": "3326", "DMC Name": "Rose Light", "RGB": [251, 173, 180], "Hex": "fbadb4"}, {"Floss": "776", "DMC Name": "Pink Medium", "RGB": [252, 176, 185], "Hex": "fcb0b9"}, {"Floss": "899", "DMC Name": "Rose Medium", "RGB": [242, 118, 136], "Hex": "f27688"}, {"Floss": "335", "DMC Name": "Rose", "RGB": [238, 84, 110], "Hex": "ee546e"}, {"Floss": "326", "DMC Name": "Rose Very Dark", "RGB": [179, 59, 75], "Hex": "b33b4b"}, {"Floss": "151", "DMC Name": "Dusty Rose Vry Lt", "RGB": [240, 206, 212], "Hex": "f0ced4"}, {"Floss": "3354", "DMC Name": "Dusty Rose Light", "RGB": [228, 166, 172], "Hex": "e4a6ac"}, {"Floss": "3733", "DMC Name": "Dusty Rose", "RGB": [232, 135, 155], "Hex": "e8879b"}, {"Floss": "3731", "DMC Name": "Dusty Rose Very Dark", "RGB": [218, 103, 131], "Hex": "da6783"}, {"Floss": "3350", "DMC Name": "Dusty Rose Ultra Dark", "RGB": [188, 67, 101], "Hex": "bc4365"}, {"Floss": "150", "DMC Name": "Dusty Rose Ult Vy Dk", "RGB": [171, 2, 73], "Hex": "ab0249"}, {"Floss": "3689", "DMC Name": "Mauve Light", "RGB": [251, 191, 194], "Hex": "fbbfc2"}, {"Floss": "3688", "DMC Name": "Mauve Medium", "RGB": [231, 169, 172], "Hex": "e7a9ac"}, {"Floss": "3687", "DMC Name": "Mauve", "RGB": [201, 107, 112], "Hex": "c96b70"}, {"Floss": "3803", "DMC Name": "Mauve Dark", "RGB": [171, 51, 87], "Hex": "ab3357"}, {"Floss": "3685", "DMC Name": "Mauve Very Dark", "RGB": [136, 21, 49], "Hex": "881531"}, {"Floss": "605", "DMC Name": "Cranberry Very Light", "RGB": [255, 192, 205], "Hex": "ffc0cd"}, {"Floss": "604", "DMC Name": "Cranberry Light", "RGB": [255, 176, 190], "Hex": "ffb0be"}, {"Floss": "603", "DMC Name": "Cranberry", "RGB": [255, 164, 190], "Hex": "ffa4be"}, {"Floss": "602", "DMC Name": "Cranberry Medium", "RGB": [226, 72, 116], "Hex": "e24874"}, {"Floss": "601", "DMC Name": "Cranberry Dark", "RGB": [209, 40, 106], "Hex": "d1286a"}, {"Floss": "600", "DMC Name": "Cranberry Very Dark", "RGB": [205, 47, 99], "Hex": "cd2f63"}, {"Floss": "3806", "DMC Name": "Cyclamen Pink Light", "RGB": [255, 140, 174], "Hex": "ff8cae"}, {"Floss": "3805", "DMC Name": "Cyclamen Pink", "RGB": [243, 71, 139], "Hex": "f3478b"}, {"Floss": "3804", "DMC Name": "Cyclamen Pink Dark", "RGB": [224, 40, 118], "Hex": "e02876"}, {"Floss": "3609", "DMC Name": "Plum Ultra Light", "RGB": [244, 174, 213], "Hex": "f4aed5"}, {"Floss": "3608", "DMC Name": "Plum Very Light", "RGB": [234, 156, 196], "Hex": "ea9cc4"}, {"Floss": "3607", "DMC Name": "Plum Light", "RGB": [197, 73, 137], "Hex": "c54989"}, {"Floss": "718", "DMC Name": "Plum", "RGB": [156, 36, 98], "Hex": "9c2462"}, {"Floss": "917", "DMC Name": "Plum Medium", "RGB": [155, 19, 89], "Hex": "9b1359"}, {"Floss": "915", "DMC Name": "Plum Dark", "RGB": [130, 0, 67], "Hex": "820043"}, {"Floss": "225", "DMC Name": "Shell Pink Ult Vy Lt", "RGB": [255, 223, 213], "Hex": "ffdfd5"}, {"Floss": "224", "DMC Name": "Shell Pink Very Light", "RGB": [235, 183, 175], "Hex": "ebb7af"}, {"Floss": "152", "DMC Name": "Shell Pink Med Light", "RGB": [226, 160, 153], "Hex": "e2a099"}, {"Floss": "223", "DMC Name": "Shell Pink Light", "RGB": [204, 132, 124], "Hex": "cc847c"}, {"Floss": "3722", "DMC Name": "Shell Pink Med", "RGB": [188, 108, 100], "Hex": "bc6c64"}, {"Floss": "3721", "DMC Name": "Shell Pink Dark", "RGB": [161, 75, 81], "Hex": "a14b51"}, {"Floss": "221", "DMC Name": "Shell Pink Vy Dk", "RGB": [136, 62, 67], "Hex": "883e43"}, {"Floss": "778", "DMC Name": "Antique Mauve Vy Lt", "RGB": [223, 179, 187], "Hex": "dfb3bb"}, {"Floss": "3727", "DMC Name": "Antique Mauve Light", "RGB": [219, 169, 178], "Hex": "dba9b2"}, {"Floss": "316", "DMC Name": "Antique Mauve Med", "RGB": [183, 115, 127], "Hex": "b7737f"}, {"Floss": "3726", "DMC Name": "Antique Mauve Dark", "RGB": [155, 91, 102], "Hex": "9b5b66"}, {"Floss": "315", "DMC Name": "Antique Mauve Md Dk", "RGB": [129, 73, 82], "Hex": "814952"}, {"Floss": "3802", "DMC Name": "Antique Mauve Vy Dk", "RGB": [113, 65, 73], "Hex": "714149"}, {"Floss": "902", "DMC Name": "Garnet Very Dark", "RGB": [130, 38, 55], "Hex": "822637"}, {"Floss": "3743", "DMC Name": "Antique Violet Vy Lt", "RGB": [215, 203, 211], "Hex": "d7cbd3"}, {"Floss": "3042", "DMC Name": "Antique Violet Light", "RGB": [183, 157, 167], "Hex": "b79da7"}, {"Floss": "3041", "DMC Name": "Antique Violet Medium", "RGB": [149, 111, 124], "Hex": "956f7c"}, {"Floss": "3740", "DMC Name": "Antique Violet Dark", "RGB": [120, 87, 98], "Hex": "785762"}, {"Floss": "3836", "DMC Name": "Grape Light", "RGB": [186, 145, 170], "Hex": "ba91aa"}, {"Floss": "3835", "DMC Name": "Grape Medium", "RGB": [148, 96, 131], "Hex": "946083"}, {"Floss": "3834", "DMC Name": "Grape Dark", "RGB": [114, 55, 93], "Hex": "72375d"}, {"Floss": "154", "DMC Name": "Grape Very Dark", "RGB": [87, 36, 51], "Hex": "572433"}, {"Floss": "211", "DMC Name": "Lavender Light", "RGB": [227, 203, 227], "Hex": "e3cbe3"}, {"Floss": "210", "DMC Name": "Lavender Medium", "RGB": [195, 159, 195], "Hex": "c39fc3"}, {"Floss": "209", "DMC Name": "Lavender Dark", "RGB": [163, 123, 167], "Hex": "a37ba7"}, {"Floss": "208", "DMC Name": "Lavender Very Dark", "RGB": [131, 91, 139], "Hex": "835b8b"}, {"Floss": "3837", "DMC Name": "Lavender Ultra Dark", "RGB": [108, 58, 110], "Hex": "6c3a6e"}, {"Floss": "327", "DMC Name": "Violet Dark", "RGB": [99, 54, 102], "Hex": "633666"}, {"Floss": "153", "DMC Name": "Violet Very Light", "RGB": [230, 204, 217], "Hex": "e6ccd9"}, {"Floss": "554", "DMC Name": "Violet Light", "RGB": [219, 179, 203], "Hex": "dbb3cb"}, {"Floss": "553", "DMC Name": "Violet", "RGB": [163, 99, 139], "Hex": "a3638b"}, {"Floss": "552", "DMC Name": "Violet Medium", "RGB": [128, 58, 107], "Hex": "803a6b"}, {"Floss": "550", "DMC Name": "Violet Very Dark", "RGB": [92, 24, 78], "Hex": "5c184e"}, {"Floss": "3747", "DMC Name": "Blue Violet Vy Lt", "RGB": [211, 215, 237], "Hex": "d3d7ed"}, {"Floss": "341", "DMC Name": "Blue Violet Light", "RGB": [183, 191, 221], "Hex": "b7bfdd"}, {"Floss": "156", "DMC Name": "Blue Violet Med Lt", "RGB": [163, 174, 209], "Hex": "a3aed1"}, {"Floss": "340", "DMC Name": "Blue Violet Medium", "RGB": [173, 167, 199], "Hex": "ada7c7"}, {"Floss": "155", "DMC Name": "Blue Violet Med Dark", "RGB": [152, 145, 182], "Hex": "9891b6"}, {"Floss": "3746", "DMC Name": "Blue Violet Dark", "RGB": [119, 107, 152], "Hex": "776b98"}, {"Floss": "333", "DMC Name": "Blue Violet Very Dark", "RGB": [92, 84, 120], "Hex": "5c5478"}, {"Floss": "157", "DMC Name": "Cornflower Blue Vy Lt", "RGB": [187, 195, 217], "Hex": "bbc3d9"}, {"Floss": "794", "DMC Name": "Cornflower Blue Light", "RGB": [143, 156, 193], "Hex": "8f9cc1"}, {"Floss": "793", "DMC Name": "Cornflower Blue Med", "RGB": [112, 125, 162], "Hex": "707da2"}, {"Floss": "3807", "DMC Name": "Cornflower Blue", "RGB": [96, 103, 140], "Hex": "60678c"}, {"Floss": "792", "DMC Name": "Cornflower Blue Dark", "RGB": [85, 91, 123], "Hex": "555b7b"}, {"Floss": "158", "DMC Name": "Cornflower Blu M V D", "RGB": [76, 82, 110], "Hex": "4c526e"}, {"Floss": "791", "DMC Name": "Cornflower Blue V D", "RGB": [70, 69, 99], "Hex": "464563"}, {"Floss": "3840", "DMC Name": "Lavender Blue Light", "RGB": [176, 192, 218], "Hex": "b0c0da"}, {"Floss": "3839", "DMC Name": "Lavender Blue Med", "RGB": [123, 142, 171], "Hex": "7b8eab"}, {"Floss": "3838", "DMC Name": "Lavender Blue Dark", "RGB": [92, 114, 148], "Hex": "5c7294"}, {"Floss": "800", "DMC Name": "Delft Blue Pale", "RGB": [192, 204, 222], "Hex": "c0ccde"}, {"Floss": "809", "DMC Name": "Delft Blue", "RGB": [148, 168, 198], "Hex": "94a8c6"}, {"Floss": "799", "DMC Name": "Delft Blue Medium", "RGB": [116, 142, 182], "Hex": "748eb6"}, {"Floss": "798", "DMC Name": "Delft Blue Dark", "RGB": [70, 106, 142], "Hex": "466a8e"}, {"Floss": "797", "DMC Name": "Royal Blue", "RGB": [19, 71, 125], "Hex": "13477d"}, {"Floss": "796", "DMC Name": "Royal Blue Dark", "RGB": [17, 65, 109], "Hex": "11416d"}, {"Floss": "820", "DMC Name": "Royal Blue Very Dark", "RGB": [14, 54, 92], "Hex": "0e365c"}, {"Floss": "162", "DMC Name": "Blue Ultra Very Light", "RGB": [219, 236, 245], "Hex": "dbecf5"}, {"Floss": "827", "DMC Name": "Blue Very Light", "RGB": [189, 221, 237], "Hex": "bddded"}, {"Floss": "813", "DMC Name": "Blue Light", "RGB": [161, 194, 215], "Hex": "a1c2d7"}, {"Floss": "826", "DMC Name": "Blue Medium", "RGB": [107, 158, 191], "Hex": "6b9ebf"}, {"Floss": "825", "DMC Name": "Blue Dark", "RGB": [71, 129, 165], "Hex": "4781a5"}, {"Floss": "824", "DMC Name": "Blue Very Dark", "RGB": [57, 105, 135], "Hex": "396987"}, {"Floss": "996", "DMC Name": "Electric Blue Medium", "RGB": [48, 194, 236], "Hex": "30c2ec"}, {"Floss": "3843", "DMC Name": "Electric Blue", "RGB": [20, 170, 208], "Hex": "14aad0"}, {"Floss": "995", "DMC Name": "Electric Blue Dark", "RGB": [38, 150, 182], "Hex": "2696b6"}, {"Floss": "3846", "DMC Name": "Turquoise Bright Light", "RGB": [6, 227, 230], "Hex": "06e3e6"}, {"Floss": "3845", "DMC Name": "Turquoise Bright Med", "RGB": [4, 196, 202], "Hex": "04c4ca"}, {"Floss": "3844", "DMC Name": "Turquoise Bright Dark", "RGB": [18, 174, 186], "Hex": "12aeba"}, {"Floss": "159", "DMC Name": "Blue Gray Light", "RGB": [199, 202, 215], "Hex": "c7cad7"}, {"Floss": "160", "DMC Name": "Blue Gray Medium", "RGB": [153, 159, 183], "Hex": "999fb7"}, {"Floss": "161", "DMC Name": "Blue Gray", "RGB": [120, 128, 164], "Hex": "7880a4"}, {"Floss": "3756", "DMC Name": "Baby Blue Ult Vy Lt", "RGB": [238, 252, 252], "Hex": "eefcfc"}, {"Floss": "775", "DMC Name": "Baby Blue Very Light", "RGB": [217, 235, 241], "Hex": "d9ebf1"}, {"Floss": "3841", "DMC Name": "Baby Blue Pale", "RGB": [205, 223, 237], "Hex": "cddfed"}, {"Floss": "3325", "DMC Name": "Baby Blue Light", "RGB": [184, 210, 230], "Hex": "b8d2e6"}, {"Floss": "3755", "DMC Name": "Baby Blue", "RGB": [147, 180, 206], "Hex": "93b4ce"}, {"Floss": "334", "DMC Name": "Baby Blue Medium", "RGB": [115, 159, 193], "Hex": "739fc1"}, {"Floss": "322", "DMC Name": "Baby Blue Dark", "RGB": [90, 143, 184], "Hex": "5a8fb8"}, {"Floss": "312", "DMC Name": "Baby Blue Very Dark", "RGB": [53, 102, 139], "Hex": "35668b"}, {"Floss": "803", "DMC Name": "Baby Blue Ult Vy Dk", "RGB": [44, 89, 124], "Hex": "2c597c"}, {"Floss": "336", "DMC Name": "Navy Blue", "RGB": [37, 59, 115], "Hex": "253b73"}, {"Floss": "823", "DMC Name": "Navy Blue Dark", "RGB": [33, 48, 99], "Hex": "213063"}, {"Floss": "939", "DMC Name": "Navy Blue Very Dark", "RGB": [27, 40, 83], "Hex": "1b2853"}, {"Floss": "3753", "DMC Name": "Antique Blue Ult Vy Lt", "RGB": [219, 226, 233], "Hex": "dbe2e9"}, {"Floss": "3752", "DMC Name": "Antique Blue Very Lt", "RGB": [199, 209, 219], "Hex": "c7d1db"}, {"Floss": "932", "DMC Name": "Antique Blue Light", "RGB": [162, 181, 198], "Hex": "a2b5c6"}, {"Floss": "931", "DMC Name": "Antique Blue Medium", "RGB": [106, 133, 158], "Hex": "6a859e"}, {"Floss": "930", "DMC Name": "Antique Blue Dark", "RGB": [69, 92, 113], "Hex": "455c71"}, {"Floss": "3750", "DMC Name": "Antique Blue Very Dk", "RGB": [56, 76, 94], "Hex": "384c5e"}, {"Floss": "828", "DMC Name": "Sky Blue Vy Lt", "RGB": [197, 232, 237], "Hex": "c5e8ed"}, {"Floss": "3761", "DMC Name": "Sky Blue Light", "RGB": [172, 216, 226], "Hex": "acd8e2"}, {"Floss": "519", "DMC Name": "Sky Blue", "RGB": [126, 177, 200], "Hex": "7eb1c8"}, {"Floss": "518", "DMC Name": "Wedgewood Light", "RGB": [79, 147, 167], "Hex": "4f93a7"}, {"Floss": "3760", "DMC Name": "Wedgewood Med", "RGB": [62, 133, 162], "Hex": "3e85a2"}, {"Floss": "517", "DMC Name": "Wedgewood Dark", "RGB": [59, 118, 143], "Hex": "3b768f"}, {"Floss": "3842", "DMC Name": "Wedgewood Vry Dk", "RGB": [50, 102, 124], "Hex": "32667c"}, {"Floss": "311", "DMC Name": "Wedgewood Ult VyDk", "RGB": [28, 80, 102], "Hex": "1c5066"}, {"Floss": "747", "DMC Name": "Peacock Blue Vy Lt", "RGB": [229, 252, 253], "Hex": "e5fcfd"}, {"Floss": "3766", "DMC Name": "Peacock Blue Light", "RGB": [153, 207, 217], "Hex": "99cfd9"}, {"Floss": "807", "DMC Name": "Peacock Blue", "RGB": [100, 171, 186], "Hex": "64abba"}, {"Floss": "806", "DMC Name": "Peacock Blue Dark", "RGB": [61, 149, 165], "Hex": "3d95a5"}, {"Floss": "3765", "DMC Name": "Peacock Blue Vy Dk", "RGB": [52, 127, 140], "Hex": "347f8c"}, {"Floss": "3811", "DMC Name": "Turquoise Very Light", "RGB": [188, 227, 230], "Hex": "bce3e6"}, {"Floss": "598", "DMC Name": "Turquoise Light", "RGB": [144, 195, 204], "Hex": "90c3cc"}, {"Floss": "597", "DMC Name": "Turquoise", "RGB": [91, 163, 179], "Hex": "5ba3b3"}, {"Floss": "3810", "DMC Name": "Turquoise Dark", "RGB": [72, 142, 154], "Hex": "488e9a"}, {"Floss": "3809", "DMC Name": "Turquoise Vy Dark", "RGB": [63, 124, 133], "Hex": "3f7c85"}, {"Floss": "3808", "DMC Name": "Turquoise Ult Vy Dk", "RGB": [54, 105, 112], "Hex": "366970"}, {"Floss": "928", "DMC Name": "Gray Green Vy Lt", "RGB": [221, 227, 227], "Hex": "dde3e3"}, {"Floss": "927", "DMC Name": "Gray Green Light", "RGB": [189, 203, 203], "Hex": "bdcbcb"}, {"Floss": "926", "DMC Name": "Gray Green Med", "RGB": [152, 174, 174], "Hex": "98aeae"}, {"Floss": "3768", "DMC Name": "Gray Green Dark", "RGB": [101, 127, 127], "Hex": "657f7f"}, {"Floss": "924", "DMC Name": "Gray Green Vy Dark", "RGB": [86, 106, 106], "Hex": "566a6a"}, {"Floss": "3849", "DMC Name": "Teal Green Light", "RGB": [82, 179, 164], "Hex": "52b3a4"}, {"Floss": "3848", "DMC Name": "Teal Green Med", "RGB": [85, 147, 146], "Hex": "559392"}, {"Floss": "3847", "DMC Name": "Teal Green Dark", "RGB": [52, 125, 117], "Hex": "347d75"}, {"Floss": "964", "DMC Name": "Sea Green Light", "RGB": [169, 226, 216], "Hex": "a9e2d8"}, {"Floss": "959", "DMC Name": "Sea Green Med", "RGB": [89, 199, 180], "Hex": "59c7b4"}, {"Floss": "958", "DMC Name": "Sea Green Dark", "RGB": [62, 182, 161], "Hex": "3eb6a1"}, {"Floss": "3812", "DMC Name": "Sea Green Vy Dk", "RGB": [47, 140, 132], "Hex": "2f8c84"}, {"Floss": "3851", "DMC Name": "Green Bright Lt", "RGB": [73, 179, 161], "Hex": "49b3a1"}, {"Floss": "943", "DMC Name": "Green Bright Md", "RGB": [61, 147, 132], "Hex": "3d9384"}, {"Floss": "3850", "DMC Name": "Green Bright Dk", "RGB": [55, 132, 119], "Hex": "378477"}, {"Floss": "993", "DMC Name": "Aquamarine Vy Lt", "RGB": [144, 192, 180], "Hex": "90c0b4"}, {"Floss": "992", "DMC Name": "Aquamarine Lt", "RGB": [111, 174, 159], "Hex": "6fae9f"}, {"Floss": "3814", "DMC Name": "Aquamarine", "RGB": [80, 139, 125], "Hex": "508b7d"}, {"Floss": "991", "DMC Name": "Aquamarine Dk", "RGB": [71, 123, 110], "Hex": "477b6e"}, {"Floss": "966", "DMC Name": "Jade Ultra Vy Lt", "RGB": [185, 215, 192], "Hex": "b9d7c0"}, {"Floss": "564", "DMC Name": "Jade Very Light", "RGB": [167, 205, 175], "Hex": "a7cdaf"}, {"Floss": "563", "DMC Name": "Jade Light", "RGB": [143, 192, 152], "Hex": "8fc098"}, {"Floss": "562", "DMC Name": "Jade Medium", "RGB": [83, 151, 106], "Hex": "53976a"}, {"Floss": "505", "DMC Name": "Jade Green", "RGB": [51, 131, 98], "Hex": "338362"}, {"Floss": "3817", "DMC Name": "Celadon Green Lt", "RGB": [153, 195, 170], "Hex": "99c3aa"}, {"Floss": "3816", "DMC Name": "Celadon Green", "RGB": [101, 165, 125], "Hex": "65a57d"}, {"Floss": "163", "DMC Name": "Celadon Green Md", "RGB": [77, 131, 97], "Hex": "4d8361"}, {"Floss": "3815", "DMC Name": "Celadon Green Dk", "RGB": [71, 119, 89], "Hex": "477759"}, {"Floss": "561", "DMC Name": "Celadon Green VD", "RGB": [44, 106, 69], "Hex": "2c6a45"}, {"Floss": "504", "DMC Name": "Blue Green Vy Lt", "RGB": [196, 222, 204], "Hex": "c4decc"}, {"Floss": "3813", "DMC Name": "Blue Green Lt", "RGB": [178, 212, 189], "Hex": "b2d4bd"}, {"Floss": "503", "DMC Name": "Blue Green Med", "RGB": [123, 172, 148], "Hex": "7bac94"}, {"Floss": "502", "DMC Name": "Blue Green", "RGB": [91, 144, 113], "Hex": "5b9071"}, {"Floss": "501", "DMC Name": "Blue Green Dark", "RGB": [57, 111, 82], "Hex": "396f52"}, {"Floss": "500", "DMC Name": "Blue Green Vy Dk", "RGB": [4, 77, 51], "Hex": "044d33"}, {"Floss": "955", "DMC Name": "Nile Green Light", "RGB": [162, 214, 173], "Hex": "a2d6ad"}, {"Floss": "954", "DMC Name": "Nile Green", "RGB": [136, 186, 145], "Hex": "88ba91"}, {"Floss": "913", "DMC Name": "Nile Green Med", "RGB": [109, 171, 119], "Hex": "6dab77"}, {"Floss": "912", "DMC Name": "Emerald Green Lt", "RGB": [27, 157, 107], "Hex": "1b9d6b"}, {"Floss": "911", "DMC Name": "Emerald Green Med", "RGB": [24, 144, 101], "Hex": "189065"}, {"Floss": "910", "DMC Name": "Emerald Green Dark", "RGB": [24, 126, 86], "Hex": "187e56"}, {"Floss": "909", "DMC Name": "Emerald Green Vy Dk", "RGB": [21, 111, 73], "Hex": "156f49"}, {"Floss": "3818", "DMC Name": "Emerald Grn Ult V Dk", "RGB": [17, 90, 59], "Hex": "115a3b"}, {"Floss": "369", "DMC Name": "Pistachio Green Vy Lt", "RGB": [215, 237, 204], "Hex": "d7edcc"}, {"Floss": "368", "DMC Name": "Pistachio Green Lt", "RGB": [166, 194, 152], "Hex": "a6c298"}, {"Floss": "320", "DMC Name": "Pistachio Green Med", "RGB": [105, 136, 90], "Hex": "69885a"}, {"Floss": "367", "DMC Name": "Pistachio Green Dk", "RGB": [97, 122, 82], "Hex": "617a52"}, {"Floss": "319", "DMC Name": "Pistachio Grn Vy Dk", "RGB": [32, 95, 46], "Hex": "205f2e"}, {"Floss": "890", "DMC Name": "Pistachio Grn Ult V D", "RGB": [23, 73, 35], "Hex": "174923"}, {"Floss": "164", "DMC Name": "Forest Green Lt", "RGB": [200, 216, 184], "Hex": "c8d8b8"}, {"Floss": "989", "DMC Name": "Forest Green ", "RGB": [141, 166, 117], "Hex": "8da675"}, {"Floss": "988", "DMC Name": "Forest Green Med", "RGB": [115, 139, 91], "Hex": "738b5b"}, {"Floss": "987", "DMC Name": "Forest Green Dk", "RGB": [88, 113, 65], "Hex": "587141"}, {"Floss": "986", "DMC Name": "Forest Green Vy Dk", "RGB": [64, 82, 48], "Hex": "405230"}, {"Floss": "772", "DMC Name": "Yellow Green Vy Lt", "RGB": [228, 236, 212], "Hex": "e4ecd4"}, {"Floss": "3348", "DMC Name": "Yellow Green Lt", "RGB": [204, 217, 177], "Hex": "ccd9b1"}, {"Floss": "3347", "DMC Name": "Yellow Green Med", "RGB": [113, 147, 92], "Hex": "71935c"}, {"Floss": "3346", "DMC Name": "Hunter Green", "RGB": [64, 106, 58], "Hex": "406a3a"}, {"Floss": "3345", "DMC Name": "Hunter Green Dk", "RGB": [27, 89, 21], "Hex": "1b5915"}, {"Floss": "895", "DMC Name": "Hunter Green Vy Dk", "RGB": [27, 83, 0], "Hex": "1b5300"}, {"Floss": "704", "DMC Name": "Chartreuse Bright", "RGB": [158, 207, 52], "Hex": "9ecf34"}, {"Floss": "703", "DMC Name": "Chartreuse", "RGB": [123, 181, 71], "Hex": "7bb547"}, {"Floss": "702", "DMC Name": "Kelly Green", "RGB": [71, 167, 47], "Hex": "47a72f"}, {"Floss": "701", "DMC Name": "Green Light", "RGB": [63, 143, 41], "Hex": "3f8f29"}, {"Floss": "700", "DMC Name": "Green Bright", "RGB": [7, 115, 27], "Hex": "07731b"}, {"Floss": "699", "DMC Name": "Green", "RGB": [5, 101, 23], "Hex": "056517"}, {"Floss": "907", "DMC Name": "Parrot Green Lt", "RGB": [199, 230, 102], "Hex": "c7e666"}, {"Floss": "906", "DMC Name": "Parrot Green Md", "RGB": [127, 179, 53], "Hex": "7fb335"}, {"Floss": "905", "DMC Name": "Parrot Green Dk", "RGB": [98, 138, 40], "Hex": "628a28"}, {"Floss": "904", "DMC Name": "Parrot Green V Dk", "RGB": [85, 120, 34], "Hex": "557822"}, {"Floss": "472", "DMC Name": "Avocado Grn U Lt", "RGB": [216, 228, 152], "Hex": "d8e498"}, {"Floss": "471", "DMC Name": "Avocado Grn V Lt", "RGB": [174, 191, 121], "Hex": "aebf79"}, {"Floss": "470", "DMC Name": "Avocado Grn Lt", "RGB": [148, 171, 79], "Hex": "94ab4f"}, {"Floss": "469", "DMC Name": "Avocado Green", "RGB": [114, 132, 60], "Hex": "72843c"}, {"Floss": "937", "DMC Name": "Avocado Green Md", "RGB": [98, 113, 51], "Hex": "627133"}, {"Floss": "936", "DMC Name": "Avocado Grn V Dk", "RGB": [76, 88, 38], "Hex": "4c5826"}, {"Floss": "935", "DMC Name": "Avocado Green Dk", "RGB": [66, 77, 33], "Hex": "424d21"}, {"Floss": "934", "DMC Name": "Avocado Grn Black", "RGB": [49, 57, 25], "Hex": "313919"}, {"Floss": "523", "DMC Name": "Fern Green Lt", "RGB": [171, 177, 151], "Hex": "abb197"}, {"Floss": "3053", "DMC Name": "Green Gray", "RGB": [156, 164, 130], "Hex": "9ca482"}, {"Floss": "3052", "DMC Name": "Green Gray Md", "RGB": [136, 146, 104], "Hex": "889268"}, {"Floss": "3051", "DMC Name": "Green Gray Dk", "RGB": [95, 102, 72], "Hex": "5f6648"}, {"Floss": "524", "DMC Name": "Fern Green Vy Lt", "RGB": [196, 205, 172], "Hex": "c4cdac"}, {"Floss": "522", "DMC Name": "Fern Green", "RGB": [150, 158, 126], "Hex": "969e7e"}, {"Floss": "520", "DMC Name": "Fern Green Dark", "RGB": [102, 109, 79], "Hex": "666d4f"}, {"Floss": "3364", "DMC Name": "Pine Green", "RGB": [131, 151, 95], "Hex": "83975f"}, {"Floss": "3363", "DMC Name": "Pine Green Md", "RGB": [114, 130, 86], "Hex": "728256"}, {"Floss": "3362", "DMC Name": "Pine Green Dk", "RGB": [94, 107, 71], "Hex": "5e6b47"}, {"Floss": "165", "DMC Name": "Moss Green Vy Lt", "RGB": [239, 244, 164], "Hex": "eff4a4"}, {"Floss": "3819", "DMC Name": "Moss Green Lt", "RGB": [224, 232, 104], "Hex": "e0e868"}, {"Floss": "166", "DMC Name": "Moss Green Md Lt", "RGB": [192, 200, 64], "Hex": "c0c840"}, {"Floss": "581", "DMC Name": "Moss Green", "RGB": [167, 174, 56], "Hex": "a7ae38"}, {"Floss": "580", "DMC Name": "Moss Green Dk", "RGB": [136, 141, 51], "Hex": "888d33"}, {"Floss": "734", "DMC Name": "Olive Green Lt", "RGB": [199, 192, 119], "Hex": "c7c077"}, {"Floss": "733", "DMC Name": "Olive Green Md", "RGB": [188, 179, 76], "Hex": "bcb34c"}, {"Floss": "732", "DMC Name": "Olive Green", "RGB": [148, 140, 54], "Hex": "948c36"}, {"Floss": "731", "DMC Name": "Olive Green Dk", "RGB": [147, 139, 55], "Hex": "938b37"}, {"Floss": "730", "DMC Name": "Olive Green V Dk", "RGB": [130, 123, 48], "Hex": "827b30"}, {"Floss": "3013", "DMC Name": "Khaki Green Lt", "RGB": [185, 185, 130], "Hex": "b9b982"}, {"Floss": "3012", "DMC Name": "Khaki Green Md", "RGB": [166, 167, 93], "Hex": "a6a75d"}, {"Floss": "3011", "DMC Name": "Khaki Green Dk", "RGB": [137, 138, 88], "Hex": "898a58"}, {"Floss": "372", "DMC Name": "Mustard Lt", "RGB": [204, 183, 132], "Hex": "ccb784"}, {"Floss": "371", "DMC Name": "Mustard", "RGB": [191, 166, 113], "Hex": "bfa671"}, {"Floss": "370", "DMC Name": "Mustard Medium", "RGB": [184, 157, 100], "Hex": "b89d64"}, {"Floss": "834", "DMC Name": "Golden Olive Vy Lt", "RGB": [219, 190, 127], "Hex": "dbbe7f"}, {"Floss": "833", "DMC Name": "Golden Olive Lt", "RGB": [200, 171, 108], "Hex": "c8ab6c"}, {"Floss": "832", "DMC Name": "Golden Olive", "RGB": [189, 155, 81], "Hex": "bd9b51"}, {"Floss": "831", "DMC Name": "Golden Olive Md", "RGB": [170, 143, 86], "Hex": "aa8f56"}, {"Floss": "830", "DMC Name": "Golden Olive Dk", "RGB": [141, 120, 75], "Hex": "8d784b"}, {"Floss": "829", "DMC Name": "Golden Olive Vy Dk", "RGB": [126, 107, 66], "Hex": "7e6b42"}, {"Floss": "613", "DMC Name": "Drab Brown V Lt", "RGB": [220, 196, 170], "Hex": "dcc4aa"}, {"Floss": "612", "DMC Name": "Drab Brown Lt", "RGB": [188, 154, 120], "Hex": "bc9a78"}, {"Floss": "611", "DMC Name": "Drab Brown", "RGB": [150, 118, 86], "Hex": "967656"}, {"Floss": "610", "DMC Name": "Drab Brown Dk", "RGB": [121, 96, 71], "Hex": "796047"}, {"Floss": "3047", "DMC Name": "Yellow Beige Lt", "RGB": [231, 214, 193], "Hex": "e7d6c1"}, {"Floss": "3046", "DMC Name": "Yellow Beige Md", "RGB": [216, 188, 154], "Hex": "d8bc9a"}, {"Floss": "3045", "DMC Name": "Yellow Beige Dk", "RGB": [188, 150, 106], "Hex": "bc966a"}, {"Floss": "167", "DMC Name": "Yellow Beige V Dk", "RGB": [167, 124, 73], "Hex": "a77c49"}, {"Floss": "746", "DMC Name": "Off White", "RGB": [252, 252, 238], "Hex": "fcfcee"}, {"Floss": "677", "DMC Name": "Old Gold Vy Lt", "RGB": [245, 236, 203], "Hex": "f5eccb"}, {"Floss": "422", "DMC Name": "Hazelnut Brown Lt", "RGB": [198, 159, 123], "Hex": "c69f7b"}, {"Floss": "3828", "DMC Name": "Hazelnut Brown", "RGB": [183, 139, 97], "Hex": "b78b61"}, {"Floss": "420", "DMC Name": "Hazelnut Brown Dk", "RGB": [160, 112, 66], "Hex": "a07042"}, {"Floss": "869", "DMC Name": "Hazelnut Brown V Dk", "RGB": [131, 94, 57], "Hex": "835e39"}, {"Floss": "728", "DMC Name": "Topaz", "RGB": [228, 180, 104], "Hex": "e4b468"}, {"Floss": "783", "DMC Name": "Topaz Medium", "RGB": [206, 145, 36], "Hex": "ce9124"}, {"Floss": "782", "DMC Name": "Topaz Dark", "RGB": [174, 119, 32], "Hex": "ae7720"}, {"Floss": "781", "DMC Name": "Topaz Very Dark", "RGB": [162, 109, 32], "Hex": "a26d20"}, {"Floss": "780", "DMC Name": "Topaz Ultra Vy Dk", "RGB": [148, 99, 26], "Hex": "94631a"}, {"Floss": "676", "DMC Name": "Old Gold Lt", "RGB": [229, 206, 151], "Hex": "e5ce97"}, {"Floss": "729", "DMC Name": "Old Gold Medium", "RGB": [208, 165, 62], "Hex": "d0a53e"}, {"Floss": "680", "DMC Name": "Old Gold Dark", "RGB": [188, 141, 14], "Hex": "bc8d0e"}, {"Floss": "3829", "DMC Name": "Old Gold Vy Dark", "RGB": [169, 130, 4], "Hex": "a98204"}, {"Floss": "3822", "DMC Name": "Straw Light", "RGB": [246, 220, 152], "Hex": "f6dc98"}, {"Floss": "3821", "DMC Name": "Straw", "RGB": [243, 206, 117], "Hex": "f3ce75"}, {"Floss": "3820", "DMC Name": "Straw Dark", "RGB": [223, 182, 95], "Hex": "dfb65f"}, {"Floss": "3852", "DMC Name": "Straw Very Dark", "RGB": [205, 157, 55], "Hex": "cd9d37"}, {"Floss": "445", "DMC Name": "Lemon Light", "RGB": [255, 251, 139], "Hex": "fffb8b"}, {"Floss": "307", "DMC Name": "Lemon", "RGB": [253, 237, 84], "Hex": "fded54"}, {"Floss": "973", "DMC Name": "Canary Bright", "RGB": [255, 227, 0], "Hex": "ffe300"}, {"Floss": "444", "DMC Name": "Lemon Dark", "RGB": [255, 214, 0], "Hex": "ffd600"}, {"Floss": "3078", "DMC Name": "Golden Yellow Vy Lt", "RGB": [253, 249, 205], "Hex": "fdf9cd"}, {"Floss": "727", "DMC Name": "Topaz Vy Lt", "RGB": [255, 241, 175], "Hex": "fff1af"}, {"Floss": "726", "DMC Name": "Topaz Light", "RGB": [253, 215, 85], "Hex": "fdd755"}, {"Floss": "725", "DMC Name": "Topaz Med Lt", "RGB": [255, 200, 64], "Hex": "ffc840"}, {"Floss": "972", "DMC Name": "Canary Deep", "RGB": [255, 181, 21], "Hex": "ffb515"}, {"Floss": "745", "DMC Name": "Yellow Pale Light", "RGB": [255, 233, 173], "Hex": "ffe9ad"}, {"Floss": "744", "DMC Name": "Yellow Pale", "RGB": [255, 231, 147], "Hex": "ffe793"}, {"Floss": "743", "DMC Name": "Yellow Med", "RGB": [254, 211, 118], "Hex": "fed376"}, {"Floss": "742", "DMC Name": "Tangerine Light", "RGB": [255, 191, 87], "Hex": "ffbf57"}, {"Floss": "741", "DMC Name": "Tangerine Med", "RGB": [255, 163, 43], "Hex": "ffa32b"}, {"Floss": "740", "DMC Name": "Tangerine", "RGB": [255, 139, 0], "Hex": "ff8b00"}, {"Floss": "970", "DMC Name": "Pumpkin Light", "RGB": [247, 139, 19], "Hex": "f78b13"}, {"Floss": "971", "DMC Name": "Pumpkin", "RGB": [246, 127, 0], "Hex": "f67f00"}, {"Floss": "947", "DMC Name": "Burnt Orange", "RGB": [255, 123, 77], "Hex": "ff7b4d"}, {"Floss": "946", "DMC Name": "Burnt Orange Med", "RGB": [235, 99, 7], "Hex": "eb6307"}, {"Floss": "900", "DMC Name": "Burnt Orange Dark", "RGB": [209, 88, 7], "Hex": "d15807"}, {"Floss": "967", "DMC Name": "Apricot Very Light", "RGB": [255, 222, 213], "Hex": "ffded5"}, {"Floss": "3824", "DMC Name": "Apricot Light", "RGB": [254, 205, 194], "Hex": "fecdc2"}, {"Floss": "3341", "DMC Name": "Apricot", "RGB": [252, 171, 152], "Hex": "fcab98"}, {"Floss": "3340", "DMC Name": "Apricot Med", "RGB": [255, 131, 111], "Hex": "ff836f"}, {"Floss": "608", "DMC Name": "Burnt Orange Bright", "RGB": [253, 93, 53], "Hex": "fd5d35"}, {"Floss": "606", "DMC Name": "Orange?Red Bright", "RGB": [250, 50, 3], "Hex": "fa3203"}, {"Floss": "951", "DMC Name": "Tawny Light", "RGB": [255, 226, 207], "Hex": "ffe2cf"}, {"Floss": "3856", "DMC Name": "Mahogany Ult Vy Lt", "RGB": [255, 211, 181], "Hex": "ffd3b5"}, {"Floss": "722", "DMC Name": "Orange Spice Light", "RGB": [247, 151, 111], "Hex": "f7976f"}, {"Floss": "721", "DMC Name": "Orange Spice Med", "RGB": [242, 120, 66], "Hex": "f27842"}, {"Floss": "720", "DMC Name": "Orange Spice Dark", "RGB": [229, 92, 31], "Hex": "e55c1f"}, {"Floss": "3825", "DMC Name": "Pumpkin Pale", "RGB": [253, 189, 150], "Hex": "fdbd96"}, {"Floss": "922", "DMC Name": "Copper Light", "RGB": [226, 115, 35], "Hex": "e27323"}, {"Floss": "921", "DMC Name": "Copper", "RGB": [198, 98, 24], "Hex": "c66218"}, {"Floss": "920", "DMC Name": "Copper Med", "RGB": [172, 84, 20], "Hex": "ac5414"}, {"Floss": "919", "DMC Name": "Red Copper", "RGB": [166, 69, 16], "Hex": "a64510"}, {"Floss": "918", "DMC Name": "Red Copper Dark", "RGB": [130, 52, 10], "Hex": "82340a"}, {"Floss": "3770", "DMC Name": "Tawny Vy Light", "RGB": [255, 238, 227], "Hex": "ffeee3"}, {"Floss": "945", "DMC Name": "Tawny", "RGB": [251, 213, 187], "Hex": "fbd5bb"}, {"Floss": "402", "DMC Name": "Mahogany Vy Lt", "RGB": [247, 167, 119], "Hex": "f7a777"}, {"Floss": "3776", "DMC Name": "Mahogany Light", "RGB": [207, 121, 57], "Hex": "cf7939"}, {"Floss": "301", "DMC Name": "Mahogany Med", "RGB": [179, 95, 43], "Hex": "b35f2b"}, {"Floss": "400", "DMC Name": "Mahogany Dark", "RGB": [143, 67, 15], "Hex": "8f430f"}, {"Floss": "300", "DMC Name": "Mahogany Vy Dk", "RGB": [111, 47, 0], "Hex": "6f2f00"}, {"Floss": "3823", "DMC Name": "Yellow Ultra Pale", "RGB": [255, 253, 227], "Hex": "fffde3"}, {"Floss": "3855", "DMC Name": "Autumn Gold Lt", "RGB": [250, 211, 150], "Hex": "fad396"}, {"Floss": "3854", "DMC Name": "Autumn Gold Med", "RGB": [242, 175, 104], "Hex": "f2af68"}, {"Floss": "3853", "DMC Name": "Autumn Gold Dk", "RGB": [242, 151, 70], "Hex": "f29746"}, {"Floss": "3827", "DMC Name": "Golden Brown Pale", "RGB": [247, 187, 119], "Hex": "f7bb77"}, {"Floss": "977", "DMC Name": "Golden Brown Light", "RGB": [220, 156, 86], "Hex": "dc9c56"}, {"Floss": "976", "DMC Name": "Golden Brown Med", "RGB": [194, 129, 66], "Hex": "c28142"}, {"Floss": "3826", "DMC Name": "Golden Brown", "RGB": [173, 114, 57], "Hex": "ad7239"}, {"Floss": "975", "DMC Name": "Golden Brown Dk", "RGB": [145, 79, 18], "Hex": "914f12"}, {"Floss": "948", "DMC Name": "Peach Very Light", "RGB": [254, 231, 218], "Hex": "fee7da"}, {"Floss": "754", "DMC Name": "Peach Light", "RGB": [247, 203, 191], "Hex": "f7cbbf"}, {"Floss": "3771", "DMC Name": "Terra Cotta Ult Vy Lt", "RGB": [244, 187, 169], "Hex": "f4bba9"}, {"Floss": "758", "DMC Name": "Terra Cotta Vy Lt", "RGB": [238, 170, 155], "Hex": "eeaa9b"}, {"Floss": "3778", "DMC Name": "Terra Cotta Light", "RGB": [217, 137, 120], "Hex": "d98978"}, {"Floss": "356", "DMC Name": "Terra Cotta Med", "RGB": [197, 106, 91], "Hex": "c56a5b"}, {"Floss": "3830", "DMC Name": "Terra Cotta", "RGB": [185, 85, 68], "Hex": "b95544"}, {"Floss": "355", "DMC Name": "Terra Cotta Dark", "RGB": [152, 68, 54], "Hex": "984436"}, {"Floss": "3777", "DMC Name": "Terra Cotta Vy Dk", "RGB": [134, 48, 34], "Hex": "863022"}, {"Floss": "3779", "DMC Name": "Rosewood Ult Vy Lt", "RGB": [248, 202, 200], "Hex": "f8cac8"}, {"Floss": "3859", "DMC Name": "Rosewood Light", "RGB": [186, 139, 124], "Hex": "ba8b7c"}, {"Floss": "3858", "DMC Name": "Rosewood Med", "RGB": [150, 74, 63], "Hex": "964a3f"}, {"Floss": "3857", "DMC Name": "Rosewood Dark", "RGB": [104, 37, 26], "Hex": "68251a"}, {"Floss": "3774", "DMC Name": "Desert Sand Vy Lt", "RGB": [243, 225, 215], "Hex": "f3e1d7"}, {"Floss": "950", "DMC Name": "Desert Sand Light", "RGB": [238, 211, 196], "Hex": "eed3c4"}, {"Floss": "3064", "DMC Name": "Desert Sand", "RGB": [196, 142, 112], "Hex": "c48e70"}, {"Floss": "407", "DMC Name": "Desert Sand Med", "RGB": [187, 129, 97], "Hex": "bb8161"}, {"Floss": "3773", "DMC Name": "Desert Sand Dark", "RGB": [182, 117, 82], "Hex": "b67552"}, {"Floss": "3772", "DMC Name": "Desert Sand Vy Dk", "RGB": [160, 108, 80], "Hex": "a06c50"}, {"Floss": "632", "DMC Name": "Desert Sand Ult Vy Dk", "RGB": [135, 85, 57], "Hex": "875539"}, {"Floss": "453", "DMC Name": "Shell Gray Light", "RGB": [215, 206, 203], "Hex": "d7cecb"}, {"Floss": "452", "DMC Name": "Shell Gray Med", "RGB": [192, 179, 174], "Hex": "c0b3ae"}, {"Floss": "451", "DMC Name": "Shell Gray Dark", "RGB": [145, 123, 115], "Hex": "917b73"}, {"Floss": "3861", "DMC Name": "Cocoa Light", "RGB": [166, 136, 129], "Hex": "a68881"}, {"Floss": "3860", "DMC Name": "Cocoa", "RGB": [125, 93, 87], "Hex": "7d5d57"}, {"Floss": "779", "DMC Name": "Cocoa Dark", "RGB": [98, 75, 69], "Hex": "624b45"}, {"Floss": "712", "DMC Name": "Cream", "RGB": [255, 251, 239], "Hex": "fffbef"}, {"Floss": "739", "DMC Name": "Tan Ult Vy Lt", "RGB": [248, 228, 200], "Hex": "f8e4c8"}, {"Floss": "738", "DMC Name": "Tan Very Light", "RGB": [236, 204, 158], "Hex": "eccc9e"}, {"Floss": "437", "DMC Name": "Tan Light", "RGB": [228, 187, 142], "Hex": "e4bb8e"}, {"Floss": "436", "DMC Name": "Tan", "RGB": [203, 144, 81], "Hex": "cb9051"}, {"Floss": "435", "DMC Name": "Brown Very Light", "RGB": [184, 119, 72], "Hex": "b87748"}, {"Floss": "434", "DMC Name": "Brown Light", "RGB": [152, 94, 51], "Hex": "985e33"}, {"Floss": "433", "DMC Name": "Brown Med", "RGB": [122, 69, 31], "Hex": "7a451f"}, {"Floss": "801", "DMC Name": "Coffee Brown Dk", "RGB": [101, 57, 25], "Hex": "653919"}, {"Floss": "898", "DMC Name": "Coffee Brown Vy Dk", "RGB": [73, 42, 19], "Hex": "492a13"}, {"Floss": "938", "DMC Name": "Coffee Brown Ult Dk", "RGB": [54, 31, 14], "Hex": "361f0e"}, {"Floss": "3371", "DMC Name": "Black Brown", "RGB": [30, 17, 8], "Hex": "1e1108"}, {"Floss": "543", "DMC Name": "Beige Brown Ult Vy Lt", "RGB": [242, 227, 206], "Hex": "f2e3ce"}, {"Floss": "3864", "DMC Name": "Mocha Beige Light", "RGB": [203, 182, 156], "Hex": "cbb69c"}, {"Floss": "3863", "DMC Name": "Mocha Beige Med", "RGB": [164, 131, 92], "Hex": "a4835c"}, {"Floss": "3862", "DMC Name": "Mocha Beige Dark", "RGB": [138, 110, 78], "Hex": "8a6e4e"}, {"Floss": "3031", "DMC Name": "Mocha Brown Vy Dk", "RGB": [75, 60, 42], "Hex": "4b3c2a"}, {"Floss": "B5200", "DMC Name": "Snow White", "RGB": [255, 255, 255], "Hex": "ffffff"}, {"Floss": "White", "DMC Name": "White", "RGB": [252, 251, 248], "Hex": "fcfbf8"}, {"Floss": "3865", "DMC Name": "Winter White", "RGB": [249, 247, 241], "Hex": "f9f7f1"}, {"Floss": "Ecru", "DMC Name": "Ecru", "RGB": [240, 234, 218], "Hex": "f0eada"}, {"Floss": "822", "DMC Name": "Beige Gray Light", "RGB": [231, 226, 211], "Hex": "e7e2d3"}, {"Floss": "644", "DMC Name": "Beige Gray Med", "RGB": [221, 216, 203], "Hex": "ddd8cb"}, {"Floss": "642", "DMC Name": "Beige Gray Dark", "RGB": [164, 152, 120], "Hex": "a49878"}, {"Floss": "640", "DMC Name": "Beige Gray Vy Dk", "RGB": [133, 123, 97], "Hex": "857b61"}, {"Floss": "3787", "DMC Name": "Brown Gray Dark", "RGB": [98, 93, 80], "Hex": "625d50"}, {"Floss": "3021", "DMC Name": "Brown Gray Vy Dk", "RGB": [79, 75, 65], "Hex": "4f4b41"}, {"Floss": "3024", "DMC Name": "Brown Gray Vy Lt", "RGB": [235, 234, 231], "Hex": "ebeae7"}, {"Floss": "3023", "DMC Name": "Brown Gray Light", "RGB": [177, 170, 151], "Hex": "b1aa97"}, {"Floss": "3022", "DMC Name": "Brown Gray Med", "RGB": [142, 144, 120], "Hex": "8e9078"}, {"Floss": "535", "DMC Name": "Ash Gray Vy Lt", "RGB": [99, 100, 88], "Hex": "636458"}, {"Floss": "3033", "DMC Name": "Mocha Brown Vy Lt", "RGB": [227, 216, 204], "Hex": "e3d8cc"}, {"Floss": "3782", "DMC Name": "Mocha Brown Lt", "RGB": [210, 188, 166], "Hex": "d2bca6"}, {"Floss": "3032", "DMC Name": "Mocha Brown Med", "RGB": [179, 159, 139], "Hex": "b39f8b"}, {"Floss": "3790", "DMC Name": "Beige Gray Ult Dk", "RGB": [127, 106, 85], "Hex": "7f6a55"}, {"Floss": "3781", "DMC Name": "Mocha Brown Dk", "RGB": [107, 87, 67], "Hex": "6b5743"}, {"Floss": "3866", "DMC Name": "Mocha Brn Ult Vy Lt", "RGB": [250, 246, 240], "Hex": "faf6f0"}, {"Floss": "842", "DMC Name": "Beige Brown Vy Lt", "RGB": [209, 186, 161], "Hex": "d1baa1"}, {"Floss": "841", "DMC Name": "Beige Brown Lt", "RGB": [182, 155, 126], "Hex": "b69b7e"}, {"Floss": "840", "DMC Name": "Beige Brown Med", "RGB": [154, 124, 92], "Hex": "9a7c5c"}, {"Floss": "839", "DMC Name": "Beige Brown Dk", "RGB": [103, 85, 65], "Hex": "675541"}, {"Floss": "838", "DMC Name": "Beige Brown Vy Dk", "RGB": [89, 73, 55], "Hex": "594937"}, {"Floss": "3072", "DMC Name": "Beaver Gray Vy Lt", "RGB": [230, 232, 232], "Hex": "e6e8e8"}, {"Floss": "648", "DMC Name": "Beaver Gray Lt", "RGB": [188, 180, 172], "Hex": "bcb4ac"}, {"Floss": "647", "DMC Name": "Beaver Gray Med", "RGB": [176, 166, 156], "Hex": "b0a69c"}, {"Floss": "646", "DMC Name": "Beaver Gray Dk", "RGB": [135, 125, 115], "Hex": "877d73"}, {"Floss": "645", "DMC Name": "Beaver Gray Vy Dk", "RGB": [110, 101, 92], "Hex": "6e655c"}, {"Floss": "844", "DMC Name": "Beaver Gray Ult Dk", "RGB": [72, 72, 72], "Hex": "484848"}, {"Floss": "762", "DMC Name": "Pearl Gray Vy Lt", "RGB": [236, 236, 236], "Hex": "ececec"}, {"Floss": "415", "DMC Name": "Pearl Gray", "RGB": [211, 211, 214], "Hex": "d3d3d6"}, {"Floss": "318", "DMC Name": "Steel Gray Lt", "RGB": [171, 171, 171], "Hex": "ababab"}, {"Floss": "414", "DMC Name": "Steel Gray Dk", "RGB": [140, 140, 140], "Hex": "8c8c8c"}, {"Floss": "168", "DMC Name": "Pewter Very Light", "RGB": [209, 209, 209], "Hex": "d1d1d1"}, {"Floss": "169", "DMC Name": "Pewter Light", "RGB": [132, 132, 132], "Hex": "848484"}, {"Floss": "317", "DMC Name": "Pewter Gray", "RGB": [108, 108, 108], "Hex": "6c6c6c"}, {"Floss": "413", "DMC Name": "Pewter Gray Dark", "RGB": [86, 86, 86], "Hex": "565656"}, {"Floss": "3799", "DMC Name": "Pewter Gray Vy Dk", "RGB": [66, 66, 66], "Hex": "424242"}, {"Floss": "310", "DMC Name": "Black", "RGB": [0, 0, 0], "Hex": "000000"}]
--------------------------------------------------------------------------------