Now posterizes an image to a number of colors determined by the command line arguments on separator.py. Still needs to color match and then export to different layer files.

This commit is contained in:
Matt McWilliams 2023-10-21 13:51:38 -04:00
parent d7ec5bb111
commit f862e28a8b
6 changed files with 133 additions and 10 deletions

35
py/pallete.py Normal file
View File

@ -0,0 +1,35 @@
import argparse
import cv2
from pallete_schema import PalleteSchema
from os.path import isfile, realpath, basename, dirname, splitext, join
parser = argparse.ArgumentParser(description='Separate an image into most similar colors specified')
parser.add_argument('input', type=str, help='Input image to extract the pallete from')
class Pallete :
input = ''
output = ''
image = None
def __init__ (self, args) :
if isfile(args.input) :
self.input = realpath(args.input)
else :
print(f'File {self.input} does not exist')
exit(1)
self.set_output()
def set_output (self) :
dir = dirname(self.input)
stem = splitext(basename(self.input))[0]
self.output = join(dir, f'{stem}.json')
print(f'Writing to {stem}.json')
def process (self) :
image = cv2.imread(self.input)
if __name__ == "__main__" :
args = parser.parse_args()
Pallete(args)

32
py/pallete_schema.py Normal file
View File

@ -0,0 +1,32 @@
from jsonschema import validate
from json import dumps, loads
class PalleteSchema :
colors = None
schema = {
"type" : "array",
"items" : {
"type" : "object",
"properties" : {
"name" : { "type" : "string" },
"color" : {
"type" : "array",
"items" : { "type" : "number" }
}
},
"required" : [ "name", "color" ]
}
}
def __init__ (self, file = None):
if file is not None:
self.parse_file(file)
def parse_file (self, file) :
with open(file) as f :
self.parse(f.read())
print(f'Parsed pallete file {file}')
def parse (self, jsonstr) :
obj = loads(jsonstr)
validate( instance = obj, schema = self.schema)
self.colors = obj

View File

@ -6,7 +6,37 @@ import cv2
class Posterize: class Posterize:
"""Posterize an image and then find nearest colors to use""" """Posterize an image and then find nearest colors to use"""
colors = [] colors = []
#def __init__ (self) : image = None
pallete = None
h = 0
w = 0
n_colors = 3
def __init__ (self, image, pallete, n_colors) :
self.image = cv2.imread(image)
(self.h, self.w) = self.image.shape[:2]
self.pallete = pallete
self.n_colors = n_colors
self.process()
def process (self) :
lab = cv2.cvtColor(self.image, cv2.COLOR_BGR2LAB)
feature = lab.reshape((self.h * self.w, 3))
clusters = MiniBatchKMeans(n_clusters = self.n_colors, n_init = 'auto')
labels = clusters.fit_predict(feature)
quant = clusters.cluster_centers_.astype('uint8')[labels]
rquant = quant.reshape((self.h, self.w, 3))
rfeature = feature.reshape((self.h, self.w, 3))
bgrquant = cv2.cvtColor(rquant, cv2.COLOR_LAB2BGR)
bgrfeature = cv2.cvtColor(rfeature, cv2.COLOR_LAB2BGR)
cv2.imshow("image", bgrquant)
cv2.waitKey(0)
cv2.destroyAllWindows()
def closest(self, colors, color): def closest(self, colors, color):
@ -16,6 +46,3 @@ class Posterize:
index_of_smallest = np.where(distances == np.amin(distances)) index_of_smallest = np.where(distances == np.amin(distances))
smallest_distance = colors[index_of_smallest] smallest_distance = colors[index_of_smallest]
return smallest_distance return smallest_distance
if __name__ == "__main__" :
posterize = Posterize()

View File

@ -1,3 +1,4 @@
opencv-python opencv-python
numpy numpy
scikit-learn scikit-learn
jsonschema

View File

@ -1,18 +1,32 @@
import argparse import argparse
from posterize import Posterize from posterize import Posterize
from os.path import abspath from pallete_schema import PalleteSchema
from os.path import isfile, realpath, basename
from os.path import isfile
parser = argparse.ArgumentParser(description='Separate an image into most similar colors specified') parser = argparse.ArgumentParser(description='Separate an image into most similar colors specified')
parser.add_argument('input', type=str, help='Input image to separate') parser.add_argument('input', type=str, help='Input image to separate')
parser.add_argument('colors', type=int, help='Number of colors to separate into')
parser.add_argument('pallete', type=str, help='Pallete file')
parser.add_argument('output', type=str, help='Output dir to write to') parser.add_argument('output', type=str, help='Output dir to write to')
class Separator : class Separator :
posterize = Posterize() input = ''
output = ''
pallete = None
def __init__ (self, args) : def __init__ (self, args) :
print(args) if isfile(args.input) :
self.input = realpath(args.input)
else :
print(f'File {args.input} does not exist')
exit(1)
if isfile(args.pallete) :
self.pallete = PalleteSchema(args.pallete)
else :
print(f'File {args.pallete} does not exist')
exit(2)
Posterize(self.input, self.pallete, args.colors)
if __name__ == "__main__" : if __name__ == "__main__" :

14
py/test_pallete.json Normal file
View File

@ -0,0 +1,14 @@
[
{
"name" : "red",
"color" : [255, 0, 0]
},
{
"name" : "green",
"color" : [0, 255, 0]
},
{
"name" : "blue",
"color" : [0, 0, 255]
}
]