From 3f7ba3ad67212b76a987238a8c687b9c7ec9d6f7 Mon Sep 17 00:00:00 2001 From: mattmcw Date: Mon, 23 Oct 2023 22:05:58 -0400 Subject: [PATCH] Pallete script can generate valid pallete json --- py/pallete.py | 53 ++++++++++++++++++++++++++++++++++++++++++-- py/pallete_schema.py | 19 +++++++++++----- py/posterize.py | 11 +++++++-- py/test_pallete.json | 9 +++++--- 4 files changed, 80 insertions(+), 12 deletions(-) diff --git a/py/pallete.py b/py/pallete.py index 6f4f290..0925c0b 100644 --- a/py/pallete.py +++ b/py/pallete.py @@ -1,5 +1,7 @@ import argparse import cv2 +import numpy as np +from math import floor from pallete_schema import PalleteSchema from os.path import isfile, realpath, basename, dirname, splitext, join @@ -12,6 +14,9 @@ class Pallete : input = '' output = '' image = None + selection = [] + colors = [] + i = 0 def __init__ (self, args) : if isfile(args.input) : @@ -19,16 +24,60 @@ class Pallete : else : print(f'File {self.input} does not exist') exit(1) + self.set_output() + self.load() + self.display_ui() + self.write() def set_output (self) : dir = dirname(self.input) stem = splitext(basename(self.input))[0] + name = basename(self.input) + print(f'Using image {name}') self.output = join(dir, f'{stem}.json') print(f'Writing to {stem}.json') - def process (self) : - image = cv2.imread(self.input) + def load (self) : + self.image = cv2.imread(self.input) + + def display_ui (self) : + cv2.imshow('pallete', self.image) + cv2.namedWindow('pallete') + cv2.setMouseCallback('pallete', self.on_click) + cv2.waitKey(0) + cv2.destroyAllWindows() + + def on_click (self, event, x, y, flags, param) : + if event == cv2.EVENT_LBUTTONDOWN: + #print(f'{x},{y}') + if len(self.selection) == 0 : + self.selection.append([x, y]) + elif len(self.selection) == 1 : + self.selection.append([x, y]) + self.process_color(self.selection) + self.selection = [] + + def process_color (self, selection) : + top_left = selection[0] + bottom_right = selection[1] + color_select = self.image[top_left[1]:bottom_right[1], top_left[0]:bottom_right[0]] + avg_color_per_row = np.average(color_select, axis=0) + avg_color = np.average(avg_color_per_row, axis=0) + int_color = [] + for i in avg_color : + int_color.append( int( round(i) ) ) + self.colors.append({ + 'name' : str(self.i), + 'color' : int_color, + 'space' : 'BGR' + }) + print(f'Added {self.i} = {int_color}') + self.i += 1 + + def write (self) : + PalleteSchema(self.output, self.colors) + if __name__ == "__main__" : args = parser.parse_args() diff --git a/py/pallete_schema.py b/py/pallete_schema.py index d6af7ec..f46d1ce 100644 --- a/py/pallete_schema.py +++ b/py/pallete_schema.py @@ -12,14 +12,17 @@ class PalleteSchema : "color" : { "type" : "array", "items" : { "type" : "number" } - } + }, + "space" : { "type" : "string" } }, - "required" : [ "name", "color" ] + "required" : [ "name", "color", "space" ] } } - def __init__ (self, file = None): - if file is not None: + def __init__ (self, file = None, obj = None): + if file is not None and obj is None: self.parse_file(file) + else : + self.write(file, obj) def parse_file (self, file) : with open(file) as f : @@ -29,4 +32,10 @@ class PalleteSchema : def parse (self, jsonstr) : obj = loads(jsonstr) validate( instance = obj, schema = self.schema) - self.colors = obj \ No newline at end of file + self.colors = obj + + def write(self, filepath, obj) : + validate( instance = obj, schema = self.schema) + jsonstr = dumps(obj, indent = 4) + with open(filepath, 'w') as outfile : + outfile.write(jsonstr) \ No newline at end of file diff --git a/py/posterize.py b/py/posterize.py index 0ee00aa..23ffdf1 100644 --- a/py/posterize.py +++ b/py/posterize.py @@ -50,13 +50,20 @@ class Posterize: self.original_colors = np.unique(reshaped, axis=0) #print(self.original_colors) for i in range(self.n_colors) : - mask = self.extract_color(self.image, self.original_colors[i]) + mask = self.extract_color_mask(self.image, self.original_colors[i]) cv2.imwrite(f'{i}.png', mask) - def extract_color (self, image, color): + def extract_color_mask (self, image, color): mask = cv2.inRange(image, color, color) return cv2.bitwise_not(mask) + def convert_color (self, color, color_space_a, color_space_b) : + pixel = np.zeros([1, 1, 3], dtype=np.uint8) + pixel = cv2.cvtColor(pixel, color_space_a) + pixel[:] = color + cvt = cv2.cvtColor(pixel, color_space_b) + return cvt[0, 0] + def closest(self, colors, color): colors = np.array(colors) color = np.array(color) diff --git a/py/test_pallete.json b/py/test_pallete.json index a887c64..b1090a3 100644 --- a/py/test_pallete.json +++ b/py/test_pallete.json @@ -1,14 +1,17 @@ [ { "name" : "red", - "color" : [255, 0, 0] + "color" : [255, 0, 0], + "space" : "RGB" }, { "name" : "green", - "color" : [0, 255, 0] + "color" : [0, 255, 0], + "space" : "RGB" }, { "name" : "blue", - "color" : [0, 0, 255] + "color" : [0, 0, 255], + "space" : "RGB" } ] \ No newline at end of file