mirror of
https://github.com/vladmandic/sdnext.git
synced 2026-01-27 15:02:48 +03:00
130 lines
5.2 KiB
Python
Executable File
130 lines
5.2 KiB
Python
Executable File
#!/usr/bin/env python
|
|
# based on <https://towardsdatascience.com/image-color-extraction-with-python-in-4-steps-8d9370d9216e>
|
|
|
|
import os
|
|
import io
|
|
import pathlib
|
|
import argparse
|
|
import importlib
|
|
import pandas as pd
|
|
import numpy as np
|
|
import extcolors
|
|
import filetype
|
|
import matplotlib.pyplot as plt
|
|
import matplotlib.patches as patches
|
|
from matplotlib.offsetbox import OffsetImage, AnnotationBbox
|
|
from colormap import rgb2hex
|
|
from PIL import Image
|
|
from util import log
|
|
grid = importlib.import_module('image-grid').grid
|
|
|
|
|
|
def color_to_df(param):
|
|
colors_pre_list = str(param).replace('([(','').split(', (')[0:-1]
|
|
df_rgb = [i.split('), ')[0] + ')' for i in colors_pre_list]
|
|
df_percent = [i.split('), ')[1].replace(')','') for i in colors_pre_list]
|
|
#convert RGB to HEX code
|
|
df_color_up = [rgb2hex(int(i.split(", ")[0].replace("(","")),
|
|
int(i.split(", ")[1]),
|
|
int(i.split(", ")[2].replace(")",""))) for i in df_rgb]
|
|
df = pd.DataFrame(zip(df_color_up, df_percent), columns = ['c_code','occurence'])
|
|
return df
|
|
|
|
|
|
def palette(img, params, output):
|
|
size = 1024
|
|
img.thumbnail((size, size), Image.Resampling.HAMMING)
|
|
|
|
#crate dataframe
|
|
colors_x = extcolors.extract_from_image(img, tolerance = params.color, limit = 13)
|
|
df_color = color_to_df(colors_x)
|
|
|
|
#annotate text
|
|
list_color = list(df_color['c_code'])
|
|
list_precent = [int(i) for i in list(df_color['occurence'])]
|
|
text_c = [c + ' ' + str(round(p * 100 / sum(list_precent), 1)) +'%' for c, p in zip(list_color, list_precent)]
|
|
fig, (ax1, ax2) = plt.subplots(1, 2, figsize=(120,60), dpi=10)
|
|
fig.set_facecolor('black')
|
|
|
|
#donut plot
|
|
wedges, _text = ax1.pie(list_precent, labels= text_c, labeldistance= 1.05, colors = list_color, textprops={'fontsize': 100, 'color':'white'})
|
|
plt.setp(wedges, width=0.3)
|
|
|
|
#add image in the center of donut plot
|
|
data = np.asarray(img)
|
|
imagebox = OffsetImage(data, zoom=2.5)
|
|
ab = AnnotationBbox(imagebox, (0, 0))
|
|
ax1.add_artist(ab)
|
|
|
|
#color palette
|
|
x_posi, y_posi, y_posi2 = 160, -260, -260
|
|
for c in list_color:
|
|
if list_color.index(c) <= 5:
|
|
y_posi += 240
|
|
rect = patches.Rectangle((x_posi, y_posi), 540, 230, facecolor = c)
|
|
ax2.add_patch(rect)
|
|
ax2.text(x = x_posi + 100, y = y_posi + 140, s = c, fontdict={'fontsize': 140}, color = 'white')
|
|
else:
|
|
y_posi2 += 240
|
|
rect = patches.Rectangle((x_posi + 600, y_posi2), 540, 230, facecolor = c)
|
|
ax2.add_artist(rect)
|
|
ax2.text(x = x_posi + 700, y = y_posi2 + 140, s = c, fontdict={'fontsize': 140}, color = 'white')
|
|
|
|
# add background to force layout
|
|
fig.set_facecolor('black')
|
|
ax2.axis('off')
|
|
tmp = Image.new('RGB', (2000, 1400), (0, 0, 0))
|
|
plt.imshow(tmp)
|
|
plt.tight_layout(rect = (-0.08, -0.2, 1.18, 1.05))
|
|
|
|
# save image
|
|
if output is not None:
|
|
buf = io.BytesIO()
|
|
plt.savefig(buf, format='png')
|
|
pltimg = Image.open(buf)
|
|
pltimg = pltimg.convert('RGB')
|
|
pltimg.save(output)
|
|
buf.close()
|
|
log.info({ 'palette created': output })
|
|
|
|
plt.close()
|
|
|
|
|
|
if __name__ == '__main__':
|
|
parser = argparse.ArgumentParser(description = 'extract image color palette')
|
|
parser.add_argument('--color', type=int, default=20, help="color tolerance threshdold")
|
|
parser.add_argument('--output', type=str, required=False, default='', help='folder to store images')
|
|
parser.add_argument('--suffix', type=str, required=False, default='pallete', help='add suffix to image name')
|
|
parser.add_argument('--grid', default=False, action='store_true', help = "create grid of images before processing")
|
|
parser.add_argument('input', type=str, nargs='*')
|
|
args = parser.parse_args()
|
|
log.info({ 'palette args': vars(args) })
|
|
if args.output != '':
|
|
pathlib.Path(args.output).mkdir(parents = True, exist_ok = True)
|
|
if not args.grid:
|
|
for arg in args.input:
|
|
if os.path.isfile(arg) and filetype.is_image(arg):
|
|
image = Image.open(arg)
|
|
fn = os.path.join(args.output, pathlib.Path(arg).stem + '-' + args.suffix + '.jpg')
|
|
palette(image, args, fn)
|
|
elif os.path.isdir(arg):
|
|
for root, _dirs, files in os.walk(arg):
|
|
for f in files:
|
|
if filetype.is_image(os.path.join(root, f)):
|
|
image = Image.open(os.path.join(root, f))
|
|
fn = os.path.join(args.output, pathlib.Path(f).stem + '-' + args.suffix + '.jpg')
|
|
palette(image, args, fn)
|
|
else:
|
|
images = []
|
|
for arg in args.input:
|
|
if os.path.isfile(arg) and filetype.is_image(arg):
|
|
images.append(Image.open(arg))
|
|
elif os.path.isdir(arg):
|
|
for root, _dirs, files in os.walk(arg):
|
|
for f in files:
|
|
if filetype.is_image(os.path.join(root, f)):
|
|
images.append(Image.open(os.path.join(root, f)))
|
|
image = grid(images)
|
|
fn = os.path.join(args.output, args.suffix + '.jpg')
|
|
palette(image, args, fn)
|