Skip to content

Commit

Permalink
1.2
Browse files Browse the repository at this point in the history
  • Loading branch information
Amorano committed Jun 25, 2024
1 parent 1914203 commit 02dafd7
Show file tree
Hide file tree
Showing 16 changed files with 261 additions and 225 deletions.
69 changes: 45 additions & 24 deletions core/calc.py
Original file line number Diff line number Diff line change
Expand Up @@ -321,10 +321,20 @@ def run(self, **kw) -> Tuple[bool]:
pbar = ProgressBar(len(params))
for idx, (A, B, a_xyzw, b_xyzw, op, typ, flip) in enumerate(params):
logger.debug(f'val {A}, {B}, {a_xyzw}, {b_xyzw}')
# [[0.008793391303918097, 0.008793391303918097, 0.008793391303918097]], [[0.008793391303918097, 0.008793391303918097, 0.008793391303918097]], (0, 0, 0, 0), (0, 0, 0, 0)
typ = EnumConvertType[typ]

size = min(3, max(0 if not isinstance(A, (list,)) else len(A), 0 if not isinstance(B, (list,)) else len(B)))
best_type = [EnumConvertType.FLOAT, EnumConvertType.VEC2, EnumConvertType.VEC3, EnumConvertType.VEC4][size]
val_a = parse_value(A, best_type, a_xyzw)
val_a = parse_value(val_a, EnumConvertType.VEC4, a_xyzw)
val_b = parse_value(B, best_type, b_xyzw)
val_b = parse_value(val_b, EnumConvertType.VEC4, b_xyzw)

val_a = parse_value(A, EnumConvertType.VEC4, A if A is not None else a_xyzw)
val_b = parse_value(B, EnumConvertType.VEC4, B if B is not None else b_xyzw)
logger.debug(f'val {val_a}, {val_b}')
# (0, 0, 0, 0), (0, 0, 0, 0)
if flip:
val_a, val_b = val_b, val_a
size = max(1, int(typ.value / 10))
Expand Down Expand Up @@ -571,7 +581,7 @@ def INPUT_TYPES(cls) -> dict:
"optional": {
Lexicon.IN_A: (WILDCARD, {"tooltip": "Custom Start Point"}),
Lexicon.IN_B: (WILDCARD, {"tooltip": "Custom End Point"}),
Lexicon.FLOAT: ("FLOAT", {"default": 0., "min": 0., "max": 1.0,
Lexicon.FLOAT: ("FLOAT", {"default": 0.5, "min": 0., "max": 1.0,
"step": 0.001, "precision": 4, "round": 0.00001,
"tooltip": "Blend Amount. 0 = full A, 1 = full B"}),
Lexicon.EASE: (["NONE"] + EnumEase._member_names_, {"default": "NONE"}),
Expand All @@ -593,11 +603,12 @@ def INPUT_TYPES(cls) -> dict:
return Lexicon._parse(d, cls)

def run(self, **kw) -> Tuple[Any, Any]:
A = parse_param(kw, Lexicon.IN_A, EnumConvertType.ANY, (0,0,0,0), 0, 1)
B = parse_param(kw, Lexicon.IN_B, EnumConvertType.ANY, (0,0,0,0), 0, 1)
A = parse_param(kw, Lexicon.IN_A, EnumConvertType.ANY, None)
B = parse_param(kw, Lexicon.IN_B, EnumConvertType.ANY, None)
print(A, B)
a_xyzw = parse_param(kw, Lexicon.IN_A+Lexicon.IN_A, EnumConvertType.VEC4, (0, 0, 0, 0))
b_xyzw = parse_param(kw, Lexicon.IN_B+Lexicon.IN_B, EnumConvertType.VEC4, (1, 1, 1, 1))
alpha = parse_param(kw, Lexicon.FLOAT,EnumConvertType.FLOAT, 0, 0, 1)
alpha = parse_param(kw, Lexicon.FLOAT,EnumConvertType.FLOAT, 0.5, 0, 1)
op = parse_param(kw, Lexicon.EASE, EnumConvertType.STRING, "NONE")
typ = parse_param(kw, Lexicon.TYPE, EnumConvertType.STRING, EnumNumberType.FLOAT.name)
values = []
Expand All @@ -607,12 +618,11 @@ def run(self, **kw) -> Tuple[Any, Any]:
# make sure we only interpolate between the longest "stride" we can
size = min(3, max(0 if not isinstance(A, (list,)) else len(A), 0 if not isinstance(B, (list,)) else len(B)))
best_type = [EnumConvertType.FLOAT, EnumConvertType.VEC2, EnumConvertType.VEC3, EnumConvertType.VEC4][size]
val_a = parse_value(A, EnumConvertType.VEC4, a_xyzw)
val_b = parse_value(B, EnumConvertType.VEC4, b_xyzw)
val_a = parse_value(A, best_type, a_xyzw)
val_a = parse_value(val_a, EnumConvertType.VEC4, a_xyzw)
val_b = parse_value(B, best_type, b_xyzw)
val_b = parse_value(val_b, EnumConvertType.VEC4, b_xyzw)
alpha = parse_value(alpha, EnumConvertType.VEC4, alpha)
# val_a = parse_value(A, EnumConvertType.VEC4, A if A is not None else a_xyzw)
# val_b = parse_value(B, EnumConvertType.VEC4, B if B is not None else b_xyzw)
# alpha = parse_value(alpha, EnumConvertType.VEC4, alpha)
typ = EnumConvertType[typ]
size = max(1, int(typ.value / 10))
if size > 1:
Expand Down Expand Up @@ -675,9 +685,7 @@ def run(self, **kw) -> Tuple[torch.Tensor, torch.Tensor]:
params = list(zip_longest_fill(pA, pB, swap_x, x, swap_y, y, swap_z, z, swap_w, w))
results = []
pbar = ProgressBar(len(params))
print(pA, pB, swap_x, x, swap_y, y, swap_z, z, swap_w, w)
for idx, (pA, pB, swap_x, x, swap_y, y, swap_z, z, swap_w, w) in enumerate(params):
print(pA, pB, swap_x, x, swap_y, y, swap_z, z, swap_w, w)
swap_x = EnumSwizzle[swap_x]
swap_y = EnumSwizzle[swap_y]
swap_z = EnumSwizzle[swap_z]
Expand Down Expand Up @@ -789,6 +797,7 @@ class ValueNode(JOVBaseNode):
DESCRIPTION = """
The Value Node supplies raw or default values for various data types, supporting vector input with components for X, Y, Z, and W. It also provides a string input option.
"""
UPDATE = False

@classmethod
def INPUT_TYPES(cls) -> dict:
Expand Down Expand Up @@ -835,6 +844,12 @@ def INPUT_TYPES(cls) -> dict:
})
return Lexicon._parse(d, cls)

@classmethod
def IS_CHANGED(cls) -> float:
if cls.UPDATE:
return float("nan")
return super().IS_CHANGED()

def run(self, **kw) -> Tuple[bool]:
raw = parse_param(kw, Lexicon.IN_A, EnumConvertType.ANY, None)
r_x = parse_param(kw, Lexicon.X, EnumConvertType.FLOAT, None)
Expand All @@ -843,7 +858,7 @@ def run(self, **kw) -> Tuple[bool]:
r_w = parse_param(kw, Lexicon.W, EnumConvertType.FLOAT, None)
typ = parse_param(kw, Lexicon.TYPE, EnumConvertType.STRING, EnumConvertType.BOOLEAN.name)
xyzw = parse_param(kw, Lexicon.IN_A+Lexicon.IN_A, EnumConvertType.VEC4, (0, 0, 0, 0))
seed = parse_param(kw, Lexicon.RANDOM, EnumConvertType.INT, 0, 0)
seed = parse_param(kw, Lexicon.SEED, EnumConvertType.INT, 0, 0)
yyzw = parse_param(kw, Lexicon.IN_B+Lexicon.IN_B, EnumConvertType.VEC4, (1, 1, 1, 1))
x_str = parse_param(kw, Lexicon.STRING, EnumConvertType.STRING, "")
params = list(zip_longest_fill(raw, r_x, r_y, r_z, r_w, typ, xyzw, seed, yyzw, x_str))
Expand All @@ -855,7 +870,8 @@ def run(self, **kw) -> Tuple[bool]:
default2 = None
if typ not in [EnumConvertType.STRING, EnumConvertType.LIST, \
EnumConvertType.DICT,\
EnumConvertType.IMAGE, EnumConvertType.LATENT, EnumConvertType.ANY, EnumConvertType.MASK]:
EnumConvertType.IMAGE, EnumConvertType.LATENT, \
EnumConvertType.ANY, EnumConvertType.MASK]:
a, b, c, d = xyzw
a2, b2, c2, d2 = yyzw
default = (a if r_x is None else r_x,
Expand All @@ -871,25 +887,30 @@ def run(self, **kw) -> Tuple[bool]:
else EnumConvertType.VEC4INT

# check if set to randomize....
if seed != 0:
val = list(val)
val2 = list(val2)
default = list(default)
for i, x in enumerate(val):
self.UPDATE = False
if seed != 0 and isinstance(val, (tuple, list,)) and isinstance(val2, (tuple, list,)):
self.UPDATE = True
# val = list(val) if isinstance(val, (tuple, list,)) else [val]
# val2 = list(val2) if isinstance(val2, (tuple, list,)) else [val2]
for i in range(len(val)):
mx = max(val[i], val2[i])
mn = min(val[i], val2[i])
logger.debug(f"{i}, {x}, {mx}, {mn}")
if typ == EnumConvertType.VEC4:
val[i] = default[i] = mn + random.random() * (mx - mn)
if mn == mx:
val[i] = mn
else:
val[i] = default[i] = random.randrange(mn, mx)
random.seed(seed)
if typ == EnumConvertType.VEC4:
val[i] = mn + random.random() * (mx - mn)
else:
logger.debug(f"{i}, {mx}, {mn}")
val[i] = random.randint(mn, mx)

extra = parse_value(val, typ, default)
extra = parse_value(val, typ, val)
ret = [val]
ret.extend(extra)
results.append(ret)
pbar.update_absolute(idx)
return *list(zip(*results)),
return [x for x in zip(*results)]

class WaveGeneratorNode(JOVBaseNode):
NAME = "WAVE GEN (JOV) 🌊"
Expand Down
11 changes: 4 additions & 7 deletions core/compose.py
Original file line number Diff line number Diff line change
Expand Up @@ -703,13 +703,10 @@ def INPUT_TYPES(cls) -> dict:
def run(self, **kw) -> Tuple[torch.Tensor, torch.Tensor]:
images = []
pA = parse_param(kw, Lexicon.PIXEL, EnumConvertType.IMAGE, None)
print(pA[0].shape)
pbar = ProgressBar(len(pA))
for idx, pA in enumerate(pA):
pA = channel_solid(chan=EnumImageType.BGRA) if pA is None else tensor2cv(pA)
print(pA.shape)
pA = image_mask_add(pA)
print(pA.shape)
pA = [cv2tensor(x, True) for x in image_split(pA)]
images.append(pA)
pbar.update_absolute(idx)
Expand Down Expand Up @@ -827,17 +824,17 @@ def run(self, **kw) -> Tuple[torch.Tensor, torch.Tensor]:
if len(images) == 0:
logger.warning("no images to stack")
return
data = []
for i in images:
data.extend(i)
images = [tensor2cv(i) for i in data]

axis = parse_param(kw, Lexicon.AXIS, EnumConvertType.STRING, EnumOrientation.GRID.name)[0]
stride = parse_param(kw, Lexicon.STEP, EnumConvertType.INT, 1)[0]
mode = parse_param(kw, Lexicon.MODE, EnumConvertType.STRING, EnumScaleMode.NONE.name)[0]
wihi = parse_param(kw, Lexicon.WH, EnumConvertType.VEC2INT, (512, 512), MIN_IMAGE_SIZE)[0]
sample = parse_param(kw, Lexicon.SAMPLE, EnumConvertType.STRING, EnumInterpolation.LANCZOS4.name)[0]
matte = parse_param(kw, Lexicon.MATTE, EnumConvertType.VEC4INT, (0, 0, 0, 255), 0, 255)[0]
data = []
for i in images:
data.extend(i)
images = [tensor2cv(i) for i in data]
axis = EnumOrientation[axis]
img = image_stack(images, axis, stride) #, matte)
mode = EnumScaleMode[mode]
Expand Down
6 changes: 1 addition & 5 deletions core/create.py
Original file line number Diff line number Diff line change
Expand Up @@ -128,8 +128,7 @@ def INPUT_TYPES(cls) -> dict:

def run(self, **kw) -> Tuple[torch.Tensor, torch.Tensor]:
shape = parse_param(kw, Lexicon.SHAPE, EnumConvertType.STRING, EnumShapes.CIRCLE.name)
print(kw[Lexicon.SIDES])
sides = parse_param(kw, Lexicon.SIDES, EnumConvertType.INT, 3, 3, 512)
sides = parse_param(kw, Lexicon.SIDES, EnumConvertType.INT, 3, 3, 100)
angle = parse_param(kw, Lexicon.ANGLE, EnumConvertType.FLOAT, 0)
edge = parse_param(kw, Lexicon.EDGE, EnumConvertType.STRING, EnumEdge.CLIP.name)
offset = parse_param(kw, Lexicon.XY, EnumConvertType.VEC2, (0, 0))
Expand All @@ -146,10 +145,7 @@ def run(self, **kw) -> Tuple[torch.Tensor, torch.Tensor]:
sizeX, sizeY = size
edge = EnumEdge[edge]
shape = EnumShapes[shape]
#color = pixel_eval(color, EnumImageType.BGRA)
#matte = pixel_eval(matte, EnumImageType.BGRA)
alpha_m = int(matte[3])
print(sides)
match shape:
case EnumShapes.SQUARE:
pA = shape_quad(width, height, sizeX, sizeX, fill=color[:3], back=matte[:3])
Expand Down
6 changes: 2 additions & 4 deletions core/utility.py
Original file line number Diff line number Diff line change
Expand Up @@ -399,11 +399,9 @@ def run(self, ident, **kw) -> Tuple[torch.Tensor]:
self.__history = []
longest_edge = 0
dynamic = parse_dynamic(kw, Lexicon.UNKNOWN, EnumConvertType.FLOAT, 0)
# each of the plugs
dynamic = [i[0] for i in dynamic]
self.__ax.clear()
for idx, val in enumerate(dynamic):
logger.debug(idx)
logger.debug(val)
if isinstance(val, (set, tuple,)):
val = list(val)
if not isinstance(val, (list, )):
Expand All @@ -412,7 +410,7 @@ def run(self, ident, **kw) -> Tuple[torch.Tensor]:
self.__history.append([])
self.__history[idx].extend(val)
if slice > 0:
stride = max(1, -slice + len(self.__history[idx]) + 1)
stride = max(0, -slice + len(self.__history[idx]) + 1)
longest_edge = max(longest_edge, stride)
self.__history[idx] = self.__history[idx][stride:]
self.__ax.plot(self.__history[idx], color="rgbcymk"[idx])
Expand Down
2 changes: 1 addition & 1 deletion pyproject.toml
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
[project]
name = "jovimetrix"
description = "Compose like Substance Designer. Webcams, Media Streams (in/out), Tick animation, Color correction, Geometry manipulation, Pixel shader, Polygonal shape generator, Remap images gometry and color, Heavily inspired by WAS and MTB Node Suites."
version = "1.1.1"
version = "1.2"
license = "MIT"
dependencies = [
"aenum<4,>=3.1.15",
Expand Down
13 changes: 7 additions & 6 deletions sup/image.py
Original file line number Diff line number Diff line change
Expand Up @@ -348,15 +348,17 @@ def cv2pil(image: TYPE_IMAGE) -> Image.Image:
def cv2tensor(image: TYPE_IMAGE, mask:bool=False) -> torch.Tensor:
"""Convert a CV2 image to a torch tensor."""
if mask or len(image.shape) == 2:
image = image_mask(image)
image = image[:,:,0][:,:]
# image = np.expand_dims(image, -1)
return torch.from_numpy(image.astype(np.float32) / 255.0).unsqueeze(0)
image = image_grayscale(image)
ret = torch.from_numpy(image.astype(np.float32) / 255.0).unsqueeze(0)
if mask:
ret = ret.squeeze(-1)
return ret

def cv2tensor_full(image: TYPE_IMAGE, matte:TYPE_PIXEL=0) -> Tuple[torch.Tensor, ...]:
mask = image_mask(image)
mask = mask[:,:,0][:,:]
mask = torch.from_numpy(mask.astype(np.float32) / 255.0).unsqueeze(0)
#
image = image_matte(image, matte)
rgb = image_convert(image, 3)
image = torch.from_numpy(image.astype(np.float32) / 255.0).unsqueeze(0)
Expand Down Expand Up @@ -1373,7 +1375,7 @@ def image_stack(image_list: List[TYPE_IMAGE], axis:EnumOrientation=EnumOrientati
height = max(height, h)
images.append(i)
count += 1
print('stride:', stride)

images = [image_matte(image_convert(i, 4), matte, width, height) for i in images]
matte = pixel_convert(matte, 4)
match axis:
Expand All @@ -1386,7 +1388,6 @@ def image_stack(image_list: List[TYPE_IMAGE], axis:EnumOrientation=EnumOrientati

rows = []
for i in range(0, count, stride):
print(i)
row = images[i:i + stride]
row_stacked = np.hstack(row)
rows.append(row_stacked)
Expand Down
4 changes: 2 additions & 2 deletions sup/lexicon.py
Original file line number Diff line number Diff line change
Expand Up @@ -196,9 +196,9 @@ class Lexicon(metaclass=LexiconMeta):
SEED = 'seed', "Random generator's initial value"
SEGMENT = 'SEGMENT', "Number of parts which the input image should be split"
SELECT = 'SELECT', "Select"
SHAPE = '🇸🇴', "Circle, Square or Polygonal forms"
SHAPE = 'SHAPE', "Circle, Square or Polygonal forms"
SHIFT = 'SHIFT', "Shift"
SIDES = '♾️', "Number of sides polygon has (3-100)"
SIDES = 'SIDES', "Number of sides polygon has (3-100)"
SIMULATOR = 'SIMULATOR', "Solver to use when translating to new color space"
SIZE = '📏', "Scalar by which to scale the input"
SKIP = 'SKIP', "Interval between segments"
Expand Down
16 changes: 10 additions & 6 deletions sup/util.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
import json
import math
from enum import Enum
from re import L
from typing import Any, List, Generator, Optional, Tuple

import numpy as np
Expand Down Expand Up @@ -75,15 +76,14 @@ def parse_dynamic(data:dict, prefix:str, typ:EnumConvertType, default: Any) -> L
found = None
for k in keys:
if k.startswith(f"{i}_") or k.startswith(f"{i}_{prefix}_"):
found = k
val = parse_param(data, k, typ, default)
vals.append(val)
found = True
break

if found is None:
fail += 1
continue

val = parse_param(data, found, typ, default)
vals.append(val)
return vals

def parse_value(val:Any, typ:EnumConvertType, default: Any,
Expand Down Expand Up @@ -141,7 +141,7 @@ def parse_value(val:Any, typ:EnumConvertType, default: Any,
if v == 0:
v = zero
except Exception as e:
logger.exception(e)
# logger.exception(e)
logger.error(f"Error converting value: {e}")
v = 0
new_val.append(v)
Expand Down Expand Up @@ -241,10 +241,14 @@ def parse_param(data:dict, key:str, typ:EnumConvertType, default: Any,
elif isinstance(val, (list, tuple, set)):
if len(val) == 0:
val = [None]
if isinstance(val, (tuple, set,)):
val = list(val)
elif issubclass(type(val), (Enum,)):
val = [str(val.name)]
if typ == EnumConvertType.ANY:
return [val]
if not isinstance(val, (list, tuple, set)):
return [val]
return val
if not isinstance(val, (list,)):
val = [val]
return [parse_value(v, typ, default, clip_min, clip_max, zero) for v in val]
Expand Down
2 changes: 1 addition & 1 deletion web/nodes/array.js
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@ app.registerExtension({
const widget_idx = this.widgets.find(w => w.name === 'INDEX');
const widget_range = this.widgets.find(w => w.name === 'RANGE');
const widget_str = this.widgets.find(w => w.name === '📝');
const widget_seed = this.widgets.find(w => w.name === 'seed');
const widget_seed = this.widgets.find(w => w.name === 'SEED');
const widget_mode = this.widgets.find(w => w.name === 'MODE');
const widget_count = this.widgets.find(w => w.name === 'COUNT');
widget_mode.callback = async () => {
Expand Down
Loading

0 comments on commit 02dafd7

Please sign in to comment.