merged auto-level into old level node
This commit is contained in:
@@ -138,8 +138,8 @@ Nodes that have been migrated:
|
||||
|
||||
[Migrated to Jovi_GLSL](https://github.com/Amorano/Jovi_GLSL)
|
||||
|
||||
**2025/09/04** @2.1.24:
|
||||
* `AUTO LEVEL` node
|
||||
**2025/09/04** @2.1.25:
|
||||
* Auto-level for `LEVEL` node
|
||||
* `HISTOGRAM` node
|
||||
* new support for cozy_comfy (v3+ comfy node spec)
|
||||
|
||||
|
||||
+51
-16
@@ -3,6 +3,7 @@
|
||||
import sys
|
||||
from enum import Enum
|
||||
from typing import Any
|
||||
from typing_extensions import override
|
||||
|
||||
import comfy.model_management
|
||||
from comfy_api.latest import ComfyExtension, io
|
||||
@@ -28,7 +29,8 @@ from cozy_comfyui.image.adjust import \
|
||||
image_contrast, image_brightness, image_equalize, image_gamma, \
|
||||
image_exposure, image_pixelate, image_pixelscale, \
|
||||
image_posterize, image_quantize, image_sharpen, image_morphology, \
|
||||
image_emboss, image_blur, image_edge, image_color
|
||||
image_emboss, image_blur, image_edge, image_color, \
|
||||
image_autolevel, image_autolevel_histogram
|
||||
|
||||
from cozy_comfyui.image.channel import \
|
||||
channel_solid
|
||||
@@ -52,6 +54,11 @@ JOV_CATEGORY = "ADJUST"
|
||||
# === ENUMERATION ===
|
||||
# ==============================================================================
|
||||
|
||||
class EnumAutoLevel(Enum):
|
||||
MANUAL = 10
|
||||
AUTO = 20
|
||||
HISTOGRAM = 30
|
||||
|
||||
class EnumAdjustLight(Enum):
|
||||
EXPOSURE = 10
|
||||
GAMMA = 20
|
||||
@@ -229,7 +236,8 @@ class AdjustLevelNode(CozyImageNode):
|
||||
NAME = "ADJUST: LEVELS (JOV)"
|
||||
CATEGORY = JOV_CATEGORY
|
||||
DESCRIPTION = """
|
||||
|
||||
Manual or automatic adjust image levels so that the darkest pixel becomes black
|
||||
and the brightest pixel becomes white, enhancing overall contrast.
|
||||
"""
|
||||
|
||||
@classmethod
|
||||
@@ -243,7 +251,14 @@ class AdjustLevelNode(CozyImageNode):
|
||||
"label": ["LOW", "MID", "HIGH"]}),
|
||||
Lexicon.RANGE: ("VEC2", {
|
||||
"default": (0, 1), "mij": 0, "maj": 1, "step": 0.01,
|
||||
"label": ["IN", "OUT"]})
|
||||
"label": ["IN", "OUT"]}),
|
||||
Lexicon.MODE: (EnumAutoLevel._member_names_, {
|
||||
"default": EnumAutoLevel.MANUAL.name,
|
||||
"tooltip": "Autolevel linearly or with Histogram bin values, per channel"
|
||||
}),
|
||||
"clip": ("FLOAT", {
|
||||
"default": 0.5, "min": 0, "max": 1.0, "step": 0.01
|
||||
})
|
||||
}
|
||||
})
|
||||
return Lexicon._parse(d)
|
||||
@@ -252,18 +267,29 @@ class AdjustLevelNode(CozyImageNode):
|
||||
pA = parse_param(kw, Lexicon.IMAGE, EnumConvertType.IMAGE, None)
|
||||
LMH = parse_param(kw, Lexicon.LMH, EnumConvertType.VEC3, (0,0.5,1))
|
||||
inout = parse_param(kw, Lexicon.RANGE, EnumConvertType.VEC2, (0,1))
|
||||
params = list(zip_longest_fill(pA, LMH, inout))
|
||||
mode = parse_param(kw, Lexicon.MODE, EnumAutoLevel, EnumAutoLevel.AUTO.name)
|
||||
clip = parse_param(kw, "clip", EnumConvertType.FLOAT, 0.5, 0, 1)
|
||||
params = list(zip_longest_fill(pA, LMH, inout, mode, clip))
|
||||
images = []
|
||||
pbar = ProgressBar(len(params))
|
||||
for idx, (pA, LMH, inout) in enumerate(params):
|
||||
for idx, (pA, LMH, inout, mode, clip) in enumerate(params):
|
||||
pA = channel_solid() if pA is None else tensor_to_cv(pA)
|
||||
'''
|
||||
h, s, v = hsv
|
||||
img_new = image_hsv(img_new, h, s, v)
|
||||
'''
|
||||
low, mid, high = LMH
|
||||
start, end = inout
|
||||
pA = image_levels(pA, low, mid, high, start, end)
|
||||
match mode:
|
||||
case EnumAutoLevel.MANUAL:
|
||||
low, mid, high = LMH
|
||||
start, end = inout
|
||||
pA = image_levels(pA, low, mid, high, start, end)
|
||||
|
||||
case EnumAutoLevel.AUTO:
|
||||
pA = image_autolevel(pA)
|
||||
|
||||
case EnumAutoLevel.HISTOGRAM:
|
||||
pA = image_autolevel_histogram(pA, clip)
|
||||
|
||||
images.append(cv_to_tensor_full(pA))
|
||||
pbar.update_absolute(idx)
|
||||
return image_stack(images)
|
||||
@@ -463,15 +489,13 @@ Sharpen the pixels of an image.
|
||||
return image_stack(images)
|
||||
|
||||
class AdjustSharpenNodev3(CozyImageNodev3):
|
||||
NAME = "ADJUST: SHARPEN (JOV)"
|
||||
CATEGORY = JOV_CATEGORY
|
||||
DESCRIPTION = """
|
||||
Sharpen the pixels of an image.
|
||||
"""
|
||||
@classmethod
|
||||
def define_schema(cls, **kwarg) -> io.Schema:
|
||||
schema = super(**kwarg).define_schema()
|
||||
# schema.
|
||||
schema.display_name = "ADJUST: SHARPEN (JOV)"
|
||||
schema.category = JOV_CATEGORY
|
||||
schema.description = "Sharpen the pixels of an image."
|
||||
|
||||
schema.inputs.extend([
|
||||
io.MultiType.Input(
|
||||
id=Lexicon.IMAGE[0],
|
||||
@@ -504,7 +528,8 @@ Sharpen the pixels of an image.
|
||||
])
|
||||
return schema
|
||||
|
||||
def run(self, **kw) -> RGBAMaskType:
|
||||
@classmethod
|
||||
def execute(self, *arg, **kw) -> io.NodeOutput:
|
||||
pA = parse_param(kw, Lexicon.IMAGE, EnumConvertType.IMAGE, None)
|
||||
amount = parse_param(kw, Lexicon.AMOUNT, EnumConvertType.FLOAT, 0)
|
||||
threshold = parse_param(kw, Lexicon.THRESHOLD, EnumConvertType.FLOAT, 0)
|
||||
@@ -516,4 +541,14 @@ Sharpen the pixels of an image.
|
||||
pA = image_sharpen(pA, amount / 2., threshold=threshold / 25.5)
|
||||
images.append(cv_to_tensor_full(pA))
|
||||
pbar.update_absolute(idx)
|
||||
return image_stack(images)
|
||||
return io.NodeOutput(image_stack(images))
|
||||
|
||||
class AdjustExtension(ComfyExtension):
|
||||
@override
|
||||
async def get_node_list(self) -> list[type[io.ComfyNode]]:
|
||||
return [
|
||||
AdjustSharpenNodev3
|
||||
]
|
||||
|
||||
async def comfy_entrypoint() -> AdjustExtension:
|
||||
return AdjustExtension()
|
||||
+1
-60
@@ -1,7 +1,5 @@
|
||||
""" Jovimetrix - Composition """
|
||||
|
||||
from enum import Enum
|
||||
|
||||
import numpy as np
|
||||
|
||||
from comfy.utils import ProgressBar
|
||||
@@ -23,8 +21,7 @@ from cozy_comfyui.image import \
|
||||
|
||||
from cozy_comfyui.image.adjust import \
|
||||
EnumThreshold, EnumThresholdAdapt, \
|
||||
image_histogram2, image_invert, image_filter, image_threshold, \
|
||||
image_autolevel, image_autolevel_histogram
|
||||
image_histogram2, image_invert, image_filter, image_threshold
|
||||
|
||||
from cozy_comfyui.image.channel import \
|
||||
EnumPixelSwizzle, \
|
||||
@@ -47,66 +44,10 @@ from cozy_comfyui.image.misc import \
|
||||
|
||||
JOV_CATEGORY = "COMPOSE"
|
||||
|
||||
# ==============================================================================
|
||||
# === ENUMERATION ===
|
||||
# ==============================================================================
|
||||
|
||||
class EnumAutoLevel(Enum):
|
||||
AUTO = 10
|
||||
HISTOGRAM = 20
|
||||
|
||||
# ==============================================================================
|
||||
# === CLASS ===
|
||||
# ==============================================================================
|
||||
|
||||
class AutoLevelNode(CozyImageNode):
|
||||
NAME = "AUTO LEVEL (JOV)"
|
||||
CATEGORY = JOV_CATEGORY
|
||||
DESCRIPTION = """
|
||||
Automatically adjusts image levels so that the darkest pixel becomes black
|
||||
and the brightest pixel becomes white, enhancing overall contrast.
|
||||
"""
|
||||
|
||||
@classmethod
|
||||
def INPUT_TYPES(cls) -> InputType:
|
||||
d = super().INPUT_TYPES()
|
||||
d = deep_merge(d, {
|
||||
"required": {
|
||||
Lexicon.IMAGE: (COZY_TYPE_IMAGE, {
|
||||
"tooltip": "Pixel Data (RGBA, RGB, or Grayscale)"
|
||||
}),
|
||||
Lexicon.MODE: (EnumAutoLevel._member_names_, {
|
||||
"default": EnumAutoLevel.AUTO.name,
|
||||
"tooltip": "Autolevel linearly or with Histogram bin values, per channel"
|
||||
}),
|
||||
"clip": ("FLOAT", {
|
||||
"default": 0.5, "min": 0, "max": 1.0, "step": 0.01
|
||||
})
|
||||
}
|
||||
})
|
||||
return Lexicon._parse(d)
|
||||
|
||||
def run(self, **kw) -> RGBAMaskType:
|
||||
pA = parse_param(kw, Lexicon.IMAGE, EnumConvertType.IMAGE, None)
|
||||
mode = parse_param(kw, Lexicon.MODE, EnumAutoLevel, EnumAutoLevel.AUTO.name)
|
||||
clip = parse_param(kw, "clip", EnumConvertType.FLOAT, 0.5, 0, 1)
|
||||
|
||||
params = list(zip_longest_fill(pA, mode, clip))
|
||||
images = []
|
||||
pbar = ProgressBar(len(params))
|
||||
for idx, (pA, mode, clip) in enumerate(params):
|
||||
img = tensor_to_cv(pA)
|
||||
match mode:
|
||||
case EnumAutoLevel.AUTO:
|
||||
leveled = image_autolevel(img)
|
||||
|
||||
case EnumAutoLevel.HISTOGRAM:
|
||||
leveled = image_autolevel_histogram(img, clip)
|
||||
|
||||
images.append(cv_to_tensor_full(leveled))
|
||||
pbar.update_absolute(idx)
|
||||
return image_stack(images)
|
||||
|
||||
class BlendNode(CozyImageNode):
|
||||
NAME = "BLEND (JOV) ⚗️"
|
||||
CATEGORY = JOV_CATEGORY
|
||||
|
||||
+1
-2
@@ -3,14 +3,13 @@
|
||||
"ADJUST: COLOR (JOV)": "Enhance and modify images with various blur effects",
|
||||
"ADJUST: EDGE (JOV)": "Enhanced edge detection",
|
||||
"ADJUST: EMBOSS (JOV)": "Emboss boss mode",
|
||||
"ADJUST: LEVELS (JOV)": "",
|
||||
"ADJUST: LEVELS (JOV)": "Manual or automatic adjust image levels so that the darkest pixel becomes black\nand the brightest pixel becomes white, enhancing overall contrast",
|
||||
"ADJUST: LIGHT (JOV)": "Tonal adjustments",
|
||||
"ADJUST: MORPHOLOGY (JOV)": "Operations based on the image shape",
|
||||
"ADJUST: PIXEL (JOV)": "Pixel-level transformations",
|
||||
"ADJUST: SHARPEN (JOV)": "Sharpen the pixels of an image",
|
||||
"AKASHIC (JOV) \ud83d\udcd3": "Visualize data",
|
||||
"ARRAY (JOV) \ud83d\udcda": "Processes a batch of data based on the selected mode",
|
||||
"AUTO LEVEL (JOV)": "Automatically adjusts image levels so that the darkest pixel becomes black\nand the brightest pixel becomes white, enhancing overall contrast",
|
||||
"BATCH TO LIST (JOV)": "Convert a batch of values into a pure python list of values",
|
||||
"BIT SPLIT (JOV) \u2b44": "Split an input into separate bits",
|
||||
"BLEND (JOV) \u2697\ufe0f": "Combine two input images using various blending modes, such as normal, screen, multiply, overlay, etc",
|
||||
|
||||
+1
-1
@@ -1,7 +1,7 @@
|
||||
[project]
|
||||
name = "jovimetrix"
|
||||
description = "Animation via tick. Parameter manipulation with wave generator. Unary and Binary math support. Value convert int/float/bool, VectorN and Image, Mask types. Shape mask generator. Stack images, do channel ops, split, merge and randomize arrays and batches. Load images & video from anywhere. Dynamic bus routing. Save output anywhere! Flatten, crop, transform; check colorblindness or linear interpolate values."
|
||||
version = "2.1.24"
|
||||
version = "2.1.25"
|
||||
license = { file = "LICENSE" }
|
||||
readme = "README.md"
|
||||
authors = [{ name = "Alexander G. Morano", email = "amorano@gmail.com" }]
|
||||
|
||||
Reference in New Issue
Block a user