|
|
|
|
|
from .categories import NodeCategories |
|
from .shared import * |
|
from .dreamtypes import * |
|
|
|
|
|
class DreamImageAreaSampler: |
|
NODE_NAME = "Sample Image Area as Palette" |
|
|
|
@classmethod |
|
def INPUT_TYPES(cls): |
|
return { |
|
"required": { |
|
"image": ("IMAGE",), |
|
"samples": ("INT", {"default": 256, "min": 1, "max": 1024 * 4}), |
|
"seed": ("INT", {"default": 0, "min": 0, "max": 0xffffffffffffffff}), |
|
"area": (["top-left", "top-center", "top-right", |
|
"center-left", "center", "center-right", |
|
"bottom-left", "bottom-center", "bottom-right"],) |
|
}, |
|
} |
|
|
|
CATEGORY = NodeCategories.IMAGE_COLORS |
|
RETURN_TYPES = (RGBPalette.ID,) |
|
RETURN_NAMES = ("palette",) |
|
FUNCTION = "result" |
|
|
|
@classmethod |
|
def IS_CHANGED(cls, *values): |
|
return ALWAYS_CHANGED_FLAG |
|
|
|
def _get_pixel_area(self, img: DreamImage, area): |
|
w = img.width |
|
h = img.height |
|
wpart = round(w / 3) |
|
hpart = round(h / 3) |
|
x0 = 0 |
|
x1 = wpart - 1 |
|
x2 = wpart |
|
x3 = wpart + wpart - 1 |
|
x4 = wpart + wpart |
|
x5 = w - 1 |
|
y0 = 0 |
|
y1 = hpart - 1 |
|
y2 = hpart |
|
y3 = hpart + hpart - 1 |
|
y4 = hpart + hpart |
|
y5 = h - 1 |
|
if area == "center": |
|
return (x2, y2, x3, y3) |
|
elif area == "top-center": |
|
return (x2, y0, x3, y1) |
|
elif area == "bottom-center": |
|
return (x2, y4, x3, y5) |
|
elif area == "center-left": |
|
return (x0, y2, x1, y3) |
|
elif area == "top-left": |
|
return (x0, y0, x1, y1) |
|
elif area == "bottom-left": |
|
return (x0, y4, x1, y5) |
|
elif area == "center-right": |
|
return (x4, y2, x5, y3) |
|
elif area == "top-right": |
|
return (x4, y0, x5, y1) |
|
elif area == "bottom-right": |
|
return (x4, y4, x5, y5) |
|
|
|
def result(self, image, samples, seed, area): |
|
result = list() |
|
r = random.Random() |
|
r.seed(seed) |
|
for data in image: |
|
di = DreamImage(tensor_image=data) |
|
area = self._get_pixel_area(di, area) |
|
|
|
pixels = list() |
|
for i in range(samples): |
|
x = r.randint(area[0], area[2]) |
|
y = r.randint(area[1], area[3]) |
|
pixels.append(di.get_pixel(x, y)) |
|
result.append(RGBPalette(colors=pixels)) |
|
|
|
return (tuple(result),) |
|
|
|
|
|
class DreamImageSampler: |
|
NODE_NAME = "Sample Image as Palette" |
|
|
|
@classmethod |
|
def INPUT_TYPES(cls): |
|
return { |
|
"required": { |
|
"image": ("IMAGE",), |
|
"samples": ("INT", {"default": 1024, "min": 1, "max": 1024 * 4}), |
|
"seed": ("INT", {"default": 0, "min": 0, "max": 0xffffffffffffffff}) |
|
}, |
|
} |
|
|
|
CATEGORY = NodeCategories.IMAGE_COLORS |
|
RETURN_TYPES = (RGBPalette.ID,) |
|
RETURN_NAMES = ("palette",) |
|
FUNCTION = "result" |
|
|
|
@classmethod |
|
def IS_CHANGED(cls, *values): |
|
return ALWAYS_CHANGED_FLAG |
|
|
|
def result(self, image, samples, seed): |
|
result = list() |
|
r = random.Random() |
|
r.seed(seed) |
|
for data in image: |
|
di = DreamImage(tensor_image=data) |
|
pixels = list() |
|
for i in range(samples): |
|
x = r.randint(0, di.width - 1) |
|
y = r.randint(0, di.height - 1) |
|
pixels.append(di.get_pixel(x, y)) |
|
result.append(RGBPalette(colors=pixels)) |
|
|
|
return (tuple(result),) |
|
|
|
|
|
class DreamColorAlign: |
|
NODE_NAME = "Palette Color Align" |
|
|
|
@classmethod |
|
def INPUT_TYPES(cls): |
|
return { |
|
"required": SharedTypes.palette | { |
|
"target_align": (RGBPalette.ID,), |
|
"alignment_factor": ("FLOAT", {"default": 0.5, "min": 0.0, "max": 10.0, "step": 0.1}), |
|
} |
|
} |
|
|
|
CATEGORY = NodeCategories.IMAGE_COLORS |
|
RETURN_TYPES = (RGBPalette.ID,) |
|
RETURN_NAMES = ("palette",) |
|
FUNCTION = "result" |
|
|
|
@classmethod |
|
def IS_CHANGED(cls, *values): |
|
return ALWAYS_CHANGED_FLAG |
|
|
|
def result(self, palette: Tuple[RGBPalette], target_align: Tuple[RGBPalette], alignment_factor: float): |
|
results = list() |
|
|
|
def _limit(c): |
|
return max(min(c, 255), 0) |
|
|
|
for i in range(len(palette)): |
|
p = palette[i] |
|
t = target_align[i] |
|
(_, _, r1, g1, b1) = p.analyze() |
|
(_, _, r2, g2, b2) = t.analyze() |
|
|
|
dr = (r2 - r1) * alignment_factor |
|
dg = (g2 - g1) * alignment_factor |
|
db = (b2 - b1) * alignment_factor |
|
new_pixels = list() |
|
for pixel in p: |
|
r = _limit(round(pixel[0] + (255 * dr))) |
|
g = _limit(round(pixel[1] + (255 * dg))) |
|
b = _limit(round(pixel[1] + (255 * db))) |
|
new_pixels.append((r, g, b)) |
|
results.append(RGBPalette(colors=new_pixels)) |
|
return (tuple(results),) |
|
|
|
|
|
class DreamColorShift: |
|
NODE_NAME = "Palette Color Shift" |
|
|
|
@classmethod |
|
def INPUT_TYPES(cls): |
|
return { |
|
"required": SharedTypes.palette | { |
|
"red_multiplier": ("FLOAT", {"default": 1.0, "min": 0.0, "max": 100.0, "step": 0.1}), |
|
"green_multiplier": ("FLOAT", {"default": 1.0, "min": 0.0, "max": 100.0, "step": 0.1}), |
|
"blue_multiplier": ("FLOAT", {"default": 1.0, "min": 0.0, "max": 100.0, "step": 0.1}), |
|
"fixed_brightness": (["yes", "no"],), |
|
} |
|
} |
|
|
|
CATEGORY = NodeCategories.IMAGE_COLORS |
|
RETURN_TYPES = (RGBPalette.ID,) |
|
RETURN_NAMES = ("palette",) |
|
FUNCTION = "result" |
|
|
|
@classmethod |
|
def IS_CHANGED(cls, *values): |
|
return ALWAYS_CHANGED_FLAG |
|
|
|
def result(self, palette, red_multiplier, green_multiplier, blue_multiplier, fixed_brightness): |
|
results = list() |
|
|
|
def _limit(c): |
|
return max(min(c, 255), 0) |
|
|
|
for p in palette: |
|
new_pixels = list() |
|
for pixel in p: |
|
s = pixel[0] + pixel[1] + pixel[2] |
|
r = _limit(round(pixel[0] * red_multiplier)) |
|
g = _limit(round(pixel[1] * green_multiplier)) |
|
b = _limit(round(pixel[2] * blue_multiplier)) |
|
if fixed_brightness == "yes": |
|
brightness_factor = max(s, 1) / float(max(r + g + b, 1)) |
|
r = _limit(round(r * brightness_factor)) |
|
g = _limit(round(g * brightness_factor)) |
|
b = _limit(round(b * brightness_factor)) |
|
|
|
new_pixels.append((r, g, b)) |
|
results.append(RGBPalette(colors=new_pixels)) |
|
return (tuple(results),) |
|
|
|
|
|
class DreamImageColorShift: |
|
NODE_NAME = "Image Color Shift" |
|
ICON = "๐ผ" |
|
@classmethod |
|
def INPUT_TYPES(cls): |
|
return { |
|
"required": {"image": ("IMAGE",), |
|
"red_multiplier": ("FLOAT", {"default": 1.0, "min": 0.0}), |
|
"green_multiplier": ("FLOAT", {"default": 1.0, "min": 0.0}), |
|
"blue_multiplier": ("FLOAT", {"default": 1.0, "min": 0.0}), |
|
}, |
|
|
|
} |
|
|
|
CATEGORY = NodeCategories.IMAGE_COLORS |
|
RETURN_TYPES = ("IMAGE",) |
|
RETURN_NAMES = ("image",) |
|
FUNCTION = "result" |
|
|
|
@classmethod |
|
def IS_CHANGED(cls, *values): |
|
return ALWAYS_CHANGED_FLAG |
|
|
|
def result(self, image, red_multiplier, green_multiplier, blue_multiplier): |
|
proc = DreamImageProcessor(inputs=image) |
|
|
|
def recolor(im: DreamImage, *a, **args): |
|
return (im.adjust_colors(red_multiplier, green_multiplier, blue_multiplier),) |
|
|
|
return proc.process(recolor) |
|
|
|
|
|
class DreamImageBrightness: |
|
NODE_NAME = "Image Brightness Adjustment" |
|
ICON = "โผ" |
|
|
|
@classmethod |
|
def INPUT_TYPES(cls): |
|
return { |
|
"required": {"image": ("IMAGE",), |
|
"factor": ("FLOAT", {"default": 1.0, "min": 0.0}), |
|
}, |
|
|
|
} |
|
|
|
CATEGORY = NodeCategories.IMAGE_COLORS |
|
RETURN_TYPES = ("IMAGE",) |
|
RETURN_NAMES = ("image",) |
|
FUNCTION = "result" |
|
|
|
@classmethod |
|
def IS_CHANGED(cls, *values): |
|
return ALWAYS_CHANGED_FLAG |
|
|
|
def result(self, image, factor): |
|
proc = DreamImageProcessor(inputs=image) |
|
|
|
def change(im: DreamImage, *a, **args): |
|
return (im.change_brightness(factor),) |
|
|
|
return proc.process(change) |
|
|
|
|
|
class DreamImageContrast: |
|
NODE_NAME = "Image Contrast Adjustment" |
|
ICON = "โ" |
|
|
|
@classmethod |
|
def INPUT_TYPES(cls): |
|
return { |
|
"required": {"image": ("IMAGE",), |
|
"factor": ("FLOAT", {"default": 1.0, "min": 0.0}), |
|
}, |
|
|
|
} |
|
|
|
CATEGORY = NodeCategories.IMAGE_COLORS |
|
RETURN_TYPES = ("IMAGE",) |
|
RETURN_NAMES = ("image",) |
|
FUNCTION = "result" |
|
|
|
@classmethod |
|
def IS_CHANGED(cls, *values): |
|
return ALWAYS_CHANGED_FLAG |
|
|
|
def result(self, image, factor): |
|
proc = DreamImageProcessor(inputs=image) |
|
|
|
def change(im: DreamImage, *a, **args): |
|
return (im.change_contrast(factor),) |
|
|
|
return proc.process(change) |
|
|
|
|
|
class DreamComparePalette: |
|
NODE_NAME = "Compare Palettes" |
|
ICON = "๐" |
|
|
|
@classmethod |
|
def INPUT_TYPES(cls): |
|
return { |
|
"required": { |
|
"a": (RGBPalette.ID,), |
|
"b": (RGBPalette.ID,), |
|
}, |
|
} |
|
|
|
CATEGORY = NodeCategories.IMAGE_COLORS |
|
RETURN_TYPES = ("FLOAT", "FLOAT", "FLOAT", "FLOAT") |
|
RETURN_NAMES = ( |
|
"brightness_multiplier", "contrast_multiplier", "red_multiplier", "green_multiplier", "blue_multiplier") |
|
FUNCTION = "result" |
|
|
|
@classmethod |
|
def IS_CHANGED(cls, *values): |
|
return ALWAYS_CHANGED_FLAG |
|
|
|
def result(self, a, b): |
|
MIN_VALUE = 1 / 255.0 |
|
|
|
brightness = list() |
|
contrasts = list() |
|
reds = list() |
|
greens = list() |
|
blues = list() |
|
|
|
for i in range(min(len(a), len(b))): |
|
(bright, ctr, red, green, blue) = a[i].analyze() |
|
(bright2, ctr2, red2, green2, blue2) = b[i].analyze() |
|
brightness.append(bright2 / max(MIN_VALUE, bright)) |
|
contrasts.append(ctr2 / max(MIN_VALUE, ctr)) |
|
reds.append(red2 / max(MIN_VALUE, red)) |
|
greens.append(green2 / max(MIN_VALUE, green)) |
|
blues.append(blue2 / max(MIN_VALUE, blue)) |
|
|
|
n = len(brightness) |
|
|
|
return (sum(brightness) / n, sum(contrasts) / n, sum(reds) / n, |
|
sum(greens) / n, sum(blues) / n) |
|
|
|
|
|
class DreamAnalyzePalette: |
|
NODE_NAME = "Analyze Palette" |
|
ICON = "๐" |
|
|
|
@classmethod |
|
def INPUT_TYPES(cls): |
|
return { |
|
"required": SharedTypes.palette |
|
, |
|
} |
|
|
|
CATEGORY = NodeCategories.IMAGE_COLORS |
|
RETURN_TYPES = ("FLOAT", "FLOAT", "FLOAT", "FLOAT", "FLOAT") |
|
RETURN_NAMES = ("brightness", "contrast", "redness", "greenness", "blueness") |
|
FUNCTION = "result" |
|
|
|
@classmethod |
|
def IS_CHANGED(cls, *values): |
|
return ALWAYS_CHANGED_FLAG |
|
|
|
def result(self, palette): |
|
f = 1.0 / len(palette) |
|
(w, c, r, g, b) = (0, 0, 0, 0, 0) |
|
for p in palette: |
|
(brightness, contrast, red, green, blue) = p.analyze() |
|
w += brightness |
|
c += contrast |
|
r += red |
|
g += green |
|
b += blue |
|
|
|
return w * f, c * f, r * f, g * f, b * f |
|
|