add palette module

This commit is contained in:
Vladimir Mandic
2023-02-05 20:04:11 -05:00
parent aee4823e26
commit f4a3ee056f
4 changed files with 156 additions and 168 deletions
+24 -17
View File
@@ -82,21 +82,28 @@ Cool stuff that is not integrated anywhere...
- Prevalent colors to interrogate
- Auto-Sort inputs by face recognition
## Updates
core library updates:
- run `./automatic.sh install`
- note, this is quite a big one so some testing is reccomended after upgrade
ui updates
new script:
- `cli/watermark.py` to a) strip exif from images, b) add invisible watermark to images which persists even if user modifies image so we can always track it
expose variation seed in main ui
integrated seed travel functionality into core
integrated `pix2pix` functionality to standard `img2img` workflow
- note: requires **pix2pix** model to be loaded
integrated large `cfg scale` values fix
tested `aesthetic gradients` training, not worth it
updated `image browser`
initial work on **queue management** allowing to submit multiple requests to server
initial work on `lora` integration (hidden)
initial work on `custom diffusion` integration (hidden)
spent quite some time making stable-diffusion compatible with upcomming `pytorch` 2.0 release
- core library updates:
- must run `./automatic.sh install`
- note: this is quite a big one so some testing is reccomended after upgrade
- non-trivial ui updates
- added **brightness dynamic range** check to `process.py`
- new script: `watermark.py`
- optionally strip exif from images
- add invisible watermark to images which persists even if user modifies image so we can always track it
- new script: `palette.py`
- creates color palette wheel from image
- not finished
- expose variation seed in main ui
- integrated seed travel functionality into core
- integrated `pix2pix` functionality to standard `img2img` workflow
- note: requires **pix2pix** model to be loaded
- integrated large `cfg scale` values fix
- tested `aesthetic gradients` training, not worth it
- updated `image browser`
was broken for a while and maintainer is gone
- initial work on **queue management** allowing to submit multiple requests to server
- initial work on `lora` integration (hidden)
- initial work on `custom diffusion` integration (hidden)
- spent quite some time making stable-diffusion compatible with upcomming `pytorch` 2.0 release
+92
View File
@@ -0,0 +1,92 @@
#!/bin/env python
# based on <https://towardsdatascience.com/image-color-extraction-with-python-in-4-steps-8d9370d9216e>
import os
import sys
import pandas as pd
import numpy as np
import extcolors
import matplotlib.pyplot as plt
import matplotlib.patches as patches
import matplotlib.image as mpimg
from matplotlib.offsetbox import OffsetImage, AnnotationBbox
from colormap import rgb2hex
from PIL import Image
def color_to_df(input):
colors_pre_list = str(input).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 color_wheel(input_image, resize, tolerance, zoom):
#resize
img = Image.open(input_image)
if img.size[0] >= resize:
wpercent = (resize / float(img.size[0]))
hsize = int((float(img.size[1]) * float(wpercent)))
img = img.resize((resize, hsize))
#crate dataframe
colors_x = extcolors.extract_from_image(img, tolerance = tolerance, 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)
#donut plot
wedges, _text = ax1.pie(list_precent, labels= text_c, labeldistance= 1.05, colors = list_color, textprops={'fontsize': 140, 'color':'black'})
plt.setp(wedges, width=0.3)
#add image in the center of donut plot
data = np.asarray(img)
imagebox = OffsetImage(data, zoom=zoom)
ab = AnnotationBbox(imagebox, (0, 0))
ax1.add_artist(ab)
#color palette
x_posi, y_posi, y_posi2 = 160, -200, -200
for c in list_color:
if list_color.index(c) <= 5:
y_posi += 220
rect = patches.Rectangle((x_posi, y_posi), 480, 200, facecolor = c)
ax2.add_patch(rect)
ax2.text(x = x_posi + 40, y = y_posi + 120, s = c, fontdict={'fontsize': 140})
else:
y_posi2 += 220
rect = patches.Rectangle((x_posi + 600, y_posi2), 480, 200, facecolor = c)
ax2.add_artist(rect)
ax2.text(x = x_posi + 640, y = y_posi2 + 120, s = c, fontdict={'fontsize': 140})
#background
tmp_file = 'tmp.png'
fig, _ax = plt.subplots(figsize=(200,140),dpi=10)
fig.set_facecolor('white')
plt.savefig(tmp_file)
plt.close(fig)
fig.set_facecolor('white')
ax2.axis('off')
tmp = plt.imread(tmp_file)
plt.imshow(tmp)
plt.tight_layout()
plt.savefig('palette.jpg')
plt.close()
os.remove(tmp_file)
return
if __name__ == '__main__':
sys.argv.pop(0)
for arg in sys.argv:
color_wheel(arg, 512, 10, 2)
+40 -3
View File
@@ -20,14 +20,16 @@ process people images
import os
import sys
import io
import filetype
import math
import base64
import pathlib
import filetype
import numpy as np
import mediapipe as mp
from PIL import Image, ImageOps
from skimage.metrics import structural_similarity as ssim
from scipy.stats import beta
from util import log, Map
from sdapi import postsync
@@ -45,13 +47,15 @@ params = Map({
'face_score': 0.7, # min face detection score
'face_pad': 0.07, # pad face image percentage
'face_model': 1, # which face model to use 0/close-up 1/standard
'face_blur_score': 1.4, # max score for face blur detection
'face_blur_score': 1.5, # max score for face blur detection
'face_range_score': 0.5, # min score for face dynamic range detection
'body_score': 0.9, # min body detection score
'body_visibility': 0.5, # min visibility score for each detected body part
'body_parts': 15, # min number of detected body parts with sufficient visibility
'body_pad': 0.2, # pad body image percentage
'body_model': 2, # body model to use 0/low 1/medium 2/high
'body_blur_score': 1.6, # max score for body blur detection
'body_blur_score': 1.8, # max score for body blur detection
'body_range_score': 0.5, # min score for body dynamic range detection
'segmentation_face': True, # segmentation enabled
'segmentation_body': False, # segmentation enabled
'segmentation_model': 0, # segmentation model 0/general 1/landscape
@@ -76,6 +80,25 @@ def detect_blur(image):
return mean
def detect_dynamicrange(image):
# based on <https://towardsdatascience.com/measuring-enhancing-image-quality-attributes-234b0f250e10>
data = np.asarray(image)
image = np.float32(data)
RGB = [0.299, 0.587, 0.114]
height, width = image.shape[:2]
brightness_image = np.sqrt(image[..., 0] ** 2 * RGB[0] + image[..., 1] ** 2 * RGB[1] + image[..., 2] ** 2 * RGB[2])
hist, _ = np.histogram(brightness_image, bins=256, range=(0, 255))
img_brightness_pmf = hist / (height * width)
dist = beta(2, 2)
ys = dist.pdf(np.linspace(0, 1, 256))
ref_pmf = ys / np.sum(ys)
dot_product = np.dot(ref_pmf, img_brightness_pmf)
squared_dist_a = np.sum(ref_pmf ** 2)
squared_dist_b = np.sum(img_brightness_pmf ** 2)
res = dot_product / math.sqrt(squared_dist_a * squared_dist_b)
return round(res, 2)
images = []
def detect_simmilar(image):
img = image.resize((params.similarity_size, params.similarity_size))
@@ -149,6 +172,13 @@ def extract_face(img):
else:
log.debug({ 'extract face blur': blur })
range = detect_dynamicrange(squared)
if range < params.face_range_score:
log.info({ 'extract face': 'dynamic range check fail', 'range': range })
return None, True
else:
log.debug({ 'extract face dynamic range': range })
similarity = detect_simmilar(squared)
if similarity > params.similarity_score:
log.info({ 'extract face': 'similarity check fail', 'score': round(similarity, 2) })
@@ -202,6 +232,13 @@ def extract_body(img):
else:
log.debug({ 'extract body blur': blur })
range = detect_dynamicrange(squared)
if range < params.body_range_score:
log.info({ 'extract body': 'dynamic range check fail', 'range': range })
return None, True
else:
log.debug({ 'extract body dynamic range': range })
similarity = detect_simmilar(squared)
if similarity > params.similarity_score:
log.info({ 'extract body': 'similarity check fail', 'score': similarity })
-148
View File
@@ -1,148 +0,0 @@
# based on <https://towardsdatascience.com/image-color-extraction-with-python-in-4-steps-8d9370d9216e>
import numpy as np
import pandas as pd
import matplotlib.pyplot as plt
import matplotlib.patches as patches
import matplotlib.image as mpimg
from PIL import Image
from matplotlib.offsetbox import OffsetImage, AnnotationBbox
#!pip install easydev #version 0.12.0
#!pip install colormap #version 1.0.4
#!pip install opencv-python #version 4.5.5.64
#!pip install colorgram.py #version 1.2.0
#!pip install extcolors #version 1.0.0
import cv2
import extcolors
from colormap import rgb2hex
input_name = '<photo location/name>'
output_width = 900 #set the output size
img = Image.open(input_name)
wpercent = (output_width/float(img.size[0]))
hsize = int((float(img.size[1])*float(wpercent)))
img = img.resize((output_width,hsize), Image.ANTIALIAS)
#save
resize_name = 'resize_' + input_name #the resized image name
img.save(resize_name) #output location can be specified before resize_name
#read
plt.figure(figsize=(9, 9))
img_url = resize_name
img = plt.imread(img_url)
plt.imshow(img)
plt.axis('off')
plt.show()
colors_x = extcolors.extract_from_path(img_url, tolerance = 12, limit = 12)
colors_x
def color_to_df(input):
colors_pre_list = str(input).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
df_color = color_to_df(colors_x)
df_color
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, ax = plt.subplots(figsize=(90,90),dpi=10)
wedges, text = ax.pie(list_precent,
labels= text_c,
labeldistance= 1.05,
colors = list_color,
textprops={'fontsize': 120, 'color':'black'}
)
plt.setp(wedges, width=0.3)
#create space in the center
plt.setp(wedges, width=0.36)
ax.set_aspect("equal")
fig.set_facecolor('white')
plt.show()
#create background color
fig, ax = plt.subplots(figsize=(192,108),dpi=10)
fig.set_facecolor('white')
plt.savefig('bg.png')
plt.close(fig)
#create color palette
bg = plt.imread('bg.png')
fig = plt.figure(figsize=(90, 90), dpi = 10)
ax = fig.add_subplot(1,1,1)
x_posi, y_posi, y_posi2 = 320, 25, 25
for c in list_color:
if list_color.index(c) <= 5:
y_posi += 125
rect = patches.Rectangle((x_posi, y_posi), 290, 115, facecolor = c)
ax.add_patch(rect)
ax.text(x = x_posi+360, y = y_posi+80, s = c, fontdict={'fontsize': 150})
else:
y_posi2 += 125
rect = patches.Rectangle((x_posi + 800, y_posi2), 290, 115, facecolor = c)
ax.add_artist(rect)
ax.text(x = x_posi+1160, y = y_posi2+80, s = c, fontdict={'fontsize': 150})
ax.axis('off')
plt.imshow(bg)
plt.tight_layout()
img = mpimg.imread('<photo location/name>')
bg = plt.imread('bg.png')
fig, (ax1, ax2) = plt.subplots(1, 2, figsize=(160,120), dpi = 10)
#donut plot
wedges, text = ax1.pie(list_precent,
labels= text_c,
labeldistance= 1.05,
colors = list_color,
textprops={'fontsize': 160, 'color':'black'})
plt.setp(wedges, width=0.3)
#add image in the center of donut plot
imagebox = OffsetImage(img, zoom=2.3)
ab = AnnotationBbox(imagebox, (0, 0))
ax1.add_artist(ab)
#color palette
x_posi, y_posi, y_posi2 = 160, -170, -170
for c in list_color:
if list_color.index(c) <= 5:
y_posi += 180
rect = patches.Rectangle((x_posi, y_posi), 360, 160, facecolor = c)
ax2.add_patch(rect)
ax2.text(x = x_posi+400, y = y_posi+100, s = c, fontdict={'fontsize': 190})
else:
y_posi2 += 180
rect = patches.Rectangle((x_posi + 1000, y_posi2), 360, 160, facecolor = c)
ax2.add_artist(rect)
ax2.text(x = x_posi+1400, y = y_posi2+100, s = c, fontdict={'fontsize': 190})
ax2.axis('off')
fig.set_facecolor('white')
plt.imshow(bg)
plt.tight_layout()