pull/32/head
Haoming 2024-08-28 12:30:01 +08:00
parent df3824aa6c
commit 3fd644f9d7
12 changed files with 108 additions and 113 deletions

2
.github/FUNDING.yml vendored
View File

@ -1 +1 @@
ko_fi: haoming ko_fi: haoming

View File

@ -1,3 +1,7 @@
### v2.2.4 - 2024 Aug.28
- Optimization *(`internal`)*
- Improve Color **Accuracy** ~~Slightly~~
### v2.2.3 - 2024 Aug.27 ### v2.2.3 - 2024 Aug.27
- Lib *(`internal`)* - Lib *(`internal`)*

View File

@ -10,10 +10,10 @@ allowing you to adjust the brightness, contrast, and color of the generations.
After installing this Extension, you will see a new section in both **txt2img** and **img2img** tabs. After installing this Extension, you will see a new section in both **txt2img** and **img2img** tabs.
Refer to the parameters and sample images below and play around with the values. Refer to the parameters and sample images below and play around with the values.
**Note:** Since this modifies the underlying latent noise, the composition may change drastically. > **Note:** Since this modifies the underlying latent noise, the composition may change drastically
#### Parameters #### Parameters
- **Enable:** Turn on/off this Extension - **Enable:** Turn on / off this Extension
- **Alt:** Modify an alternative Tensor instead, causing the effects to be significantly stronger - **Alt:** Modify an alternative Tensor instead, causing the effects to be significantly stronger
- **Brightness:** Adjust the overall brightness of the image - **Brightness:** Adjust the overall brightness of the image
- **Contrast:** Adjust the overall contrast of the image - **Contrast:** Adjust the overall contrast of the image

View File

@ -1,7 +1,11 @@
class VectorscopeCC { class VectorscopeCC {
static dot = { 'txt': null, 'img': null }; static dot = { 'txt': undefined, 'img': undefined };
/**
* @param {number} r @param {number} g @param {number} b
* @param {string} mode "txt" | "img"
*/
static updateCursor(r, g, b, mode) { static updateCursor(r, g, b, mode) {
const mag = Math.abs(r) + Math.abs(g) + Math.abs(b); const mag = Math.abs(r) + Math.abs(g) + Math.abs(b);
var condX, condY; var condX, condY;
@ -18,6 +22,11 @@ class VectorscopeCC {
this.dot[mode].style.top = `calc(50% + ${condY - 12}px)`; this.dot[mode].style.top = `calc(50% + ${condY - 12}px)`;
} }
/**
* @param {HTMLImageElement} wheel
* @param {HTMLInputElement[]} sliders
* @param {HTMLImageElement} dot
*/
static registerPicker(wheel, sliders, dot) { static registerPicker(wheel, sliders, dot) {
['mousemove', 'click'].forEach((event) => { ['mousemove', 'click'].forEach((event) => {
wheel.addEventListener(event, (e) => { wheel.addEventListener(event, (e) => {
@ -35,20 +44,7 @@ class VectorscopeCC {
const x = ((e.clientX - rect.left) - 100.0) / 25; const x = ((e.clientX - rect.left) - 100.0) / 25;
const y = ((e.clientY - rect.top) - 100.0) / 25; const y = ((e.clientY - rect.top) - 100.0) / 25;
const zeta = Math.atan(y / x); var r = -0.077 * (4.33 * x + 7.5 * y);
var degree = 0;
if (x >= 0) {
if (y >= 0)
degree = zeta * 180 / Math.PI;
else
degree = 360 + zeta * 180 / Math.PI;
}
else if (x < 0) {
degree = 180 + zeta * 180 / Math.PI;
}
var r = -(0.00077 * (433 * x * degree + 750 * y * degree) / degree);
var g = y / 0.866 + r; var g = y / 0.866 + r;
var b = x + 0.5 * r + 0.5 * g; var b = x + 0.5 * r + 0.5 * g;

View File

@ -1,5 +1,5 @@
from modules.sd_samplers_kdiffusion import KDiffusionSampler from modules.sd_samplers_kdiffusion import KDiffusionSampler
from modules import script_callbacks, devices from modules.script_callbacks import on_script_unloaded
from functools import wraps from functools import wraps
from random import random from random import random
import torch import torch
@ -45,19 +45,19 @@ class NoiseMethods:
""" """
noise = NoiseMethods.zeros(latent) if use_zero else NoiseMethods.ones(latent) noise = NoiseMethods.zeros(latent) if use_zero else NoiseMethods.ones(latent)
batchSize, c, w, h = noise.shape b, c, w, h = noise.shape
device = devices.get_optimal_device() device = latent.device
upsampler = torch.nn.Upsample(size=(w, h), mode="bilinear").to(device) upsampler = torch.nn.Upsample(size=(w, h), mode="bilinear").to(device)
for b in range(batchSize): for batch in range(b):
for i in range(iterations): for i in range(iterations):
r = random() * 2 + 2 r = random() * 2 + 2
wn = max(1, int(w / (r**i))) wn = max(1, int(w / (r**i)))
hn = max(1, int(h / (r**i))) hn = max(1, int(h / (r**i)))
noise[b] += ( noise[batch] += (
upsampler(torch.randn(1, c, hn, wn).to(device)) * discount**i upsampler(torch.randn(1, c, hn, wn).to(device)) * discount**i
)[0] )[0]
@ -67,10 +67,10 @@ class NoiseMethods:
return noise / noise.std() return noise / noise.std()
def RGB_2_CbCr(r: float, g: float, b: float) -> float: def RGB_2_CbCr(r: float, g: float, b: float) -> tuple[float, float]:
"""Convert RGB channels into YCbCr for SDXL""" """Convert RGB channels into YCbCr for SDXL"""
cb = -0.15 * r - 0.29 * g + 0.44 * b cb = -0.17 * r - 0.33 * g + 0.5 * b
cr = 0.44 * r - 0.37 * g - 0.07 * b cr = 0.5 * r - 0.41 * g - 0.08 * b
return cb, cr return cb, cr
@ -94,7 +94,8 @@ def cc_callback(self, d):
mode = str(self.vec_cc["mode"]) mode = str(self.vec_cc["mode"])
method = str(self.vec_cc["method"]) method = str(self.vec_cc["method"])
source = d[mode] source: torch.Tensor = d[mode]
target: torch.Tensor = None
if "Straight" in method: if "Straight" in method:
target = d[mode].detach().clone() target = d[mode].detach().clone()
@ -175,4 +176,4 @@ def restore_callback():
KDiffusionSampler.callback_state = original_callback KDiffusionSampler.callback_state = original_callback
script_callbacks.on_script_unloaded(restore_callback) on_script_unloaded(restore_callback)

View File

@ -7,17 +7,17 @@ DOT = os.path.join(scripts.basedir(), "scripts", "dot.png")
def create_colorpicker(is_img: bool): def create_colorpicker(is_img: bool):
m = "img" if is_img else "txt" m: str = "img" if is_img else "txt"
gr.Image( gr.Image(
WHEEL, value=WHEEL,
interactive=False, interactive=False,
container=False, container=False,
elem_id=f"cc-colorwheel-{m}", elem_id=f"cc-colorwheel-{m}",
) )
gr.Image( gr.Image(
DOT, value=DOT,
interactive=False, interactive=False,
container=False, container=False,
elem_id=f"cc-temp-{m}", elem_id=f"cc-temp-{m}",

View File

@ -11,7 +11,7 @@ EMPTY_STYLE = {"styles": {}, "deleted": {}}
class StyleManager: class StyleManager:
def __init__(self): def __init__(self):
self.STYLE_SHEET = None self.STYLE_SHEET: dict = None
def load_styles(self): def load_styles(self):
if os.path.isfile(STYLE_FILE): if os.path.isfile(STYLE_FILE):
@ -27,10 +27,10 @@ class StyleManager:
return self.list_style() return self.list_style()
def list_style(self): def list_style(self) -> list[str]:
return list(self.STYLE_SHEET["styles"].keys()) return list(self.STYLE_SHEET["styles"].keys())
def get_style(self, style_name: str): def get_style(self, style_name: str) -> tuple[bool | str | float]:
style: dict = self.STYLE_SHEET["styles"].get(style_name, None) style: dict = self.STYLE_SHEET["styles"].get(style_name, None)
if not style: if not style:

View File

@ -13,6 +13,7 @@ def grid_reference():
def xyz_support(cache: dict): def xyz_support(cache: dict):
def apply_field(field): def apply_field(field):
def _(p, x, xs): def _(p, x, xs):
cache.update({field: x}) cache.update({field: x})

Binary file not shown.

Before

Width:  |  Height:  |  Size: 166 KiB

View File

@ -11,7 +11,7 @@ import gradio as gr
import lib_cc import lib_cc
VERSION = "v2.2.3" VERSION = "2.2.4"
style_manager = StyleManager() style_manager = StyleManager()
@ -19,6 +19,7 @@ style_manager.load_styles()
class VectorscopeCC(scripts.Script): class VectorscopeCC(scripts.Script):
def __init__(self): def __init__(self):
self.xyzCache = {} self.xyzCache = {}
xyz_support(self.xyzCache) xyz_support(self.xyzCache)
@ -30,11 +31,11 @@ class VectorscopeCC(scripts.Script):
return scripts.AlwaysVisible return scripts.AlwaysVisible
def ui(self, is_img2img): def ui(self, is_img2img):
mode = "img" if is_img2img else "txt" mode: str = "img" if is_img2img else "txt"
m = f'"{mode}"' m: str = f'"{mode}"'
with gr.Accordion( with gr.Accordion(
f"Vectorscope CC {VERSION}", elem_id=f"vec-cc-{mode}", open=False f"Vectorscope CC v{VERSION}", elem_id=f"vec-cc-{mode}", open=False
): ):
with gr.Row(): with gr.Row():
@ -151,13 +152,14 @@ class VectorscopeCC(scripts.Script):
label="Noise Settings", label="Noise Settings",
value="Straight Abs.", value="Straight Abs.",
) )
scaling = gr.Radio( scaling = gr.Radio(
["Flat", "Cos", "Sin", "1 - Cos", "1 - Sin"], ["Flat", "Cos", "Sin", "1 - Cos", "1 - Sin"],
label="Scaling Settings", label="Scaling Settings",
value="Flat", value="Flat",
) )
comps = ( comps: tuple[gr.components.Component] = (
latent, latent,
bri, bri,
con, con,
@ -297,49 +299,40 @@ class VectorscopeCC(scripts.Script):
enable = self.xyzCache["Enable"].lower().strip() == "true" enable = self.xyzCache["Enable"].lower().strip() == "true"
if not enable: if not enable:
if "Enable" not in self.xyzCache.keys(): if len(self.xyzCache) > 0:
if len(self.xyzCache) > 0: if "Enable" not in self.xyzCache.keys():
print("\n[Vec.CC] x [X/Y/Z Plot] Extension is not Enabled!\n") print("\n[Vec.CC] x [X/Y/Z Plot] Extension is not Enabled!\n")
self.xyzCache.clear() self.xyzCache.clear()
KDiffusionSampler.vec_cc = {"enable": False} KDiffusionSampler.vec_cc = {"enable": False}
return p return p
if "Random" in self.xyzCache.keys(): if "Random" in self.xyzCache.keys():
print("[X/Y/Z Plot] x [Vec.CC] Randomize is Enabled.")
if len(self.xyzCache) > 1: if len(self.xyzCache) > 1:
print( print("Some parameters will not apply!")
"\n[X/Y/Z Plot] x [Vec.CC] Randomize is Enabled.\nSome settings will not apply!\n"
)
else:
print("\n[X/Y/Z Plot] x [Vec.CC] Randomize is Enabled.\n")
cc_seed = int(seeds[0]) if doRN else None cc_seed = int(seeds[0]) if doRN else None
for k, v in self.xyzCache.items(): if "Alt" in self.xyzCache.keys():
match k: latent = self.xyzCache["Alt"].lower().strip() == "true"
case "Alt":
latent = self.xyzCache["Alt"].lower().strip() == "true" if "DoHR" in self.xyzCache.keys():
case "Brightness": doHR = self.xyzCache["DoHR"].lower().strip() == "true"
bri = float(v)
case "Contrast": if "Random" in self.xyzCache.keys():
con = float(v) cc_seed = int(self.xyzCache["Random"])
case "Saturation":
sat = float(v) bri = float(self.xyzCache.get("Brightness", bri))
case "R": con = float(self.xyzCache.get("Contrast", con))
r = float(v) sat = float(self.xyzCache.get("Saturation", sat))
case "G":
g = float(v) r = float(self.xyzCache.get("R", r))
case "B": g = float(self.xyzCache.get("G", g))
b = float(v) b = float(self.xyzCache.get("B", b))
case "DoHR":
doHR = self.xyzCache["DoHR"].lower().strip() == "true" method = str(self.xyzCache.get("Method", method))
case "Method": scaling = str(self.xyzCache.get("Scaling", scaling))
method = str(v)
case "Scaling":
scaling = str(v)
case "Random":
cc_seed = int(v)
self.xyzCache.clear() self.xyzCache.clear()
@ -347,11 +340,7 @@ class VectorscopeCC(scripts.Script):
KDiffusionSampler.vec_cc = {"enable": False} KDiffusionSampler.vec_cc = {"enable": False}
return p return p
steps: int = p.steps steps: int = getattr(p, "firstpass_steps", None) or p.steps
# is img2img & do full steps
if not hasattr(p, "enable_hr") and not shared.opts.img2img_fix_steps:
if getattr(p, "denoising_strength", 1.0) < 1.0:
steps = int(steps * getattr(p, "denoising_strength", 1.0) + 1.0)
if cc_seed: if cc_seed:
seed(cc_seed) seed(cc_seed)
@ -373,19 +362,24 @@ class VectorscopeCC(scripts.Script):
print(f"B:\t\t{b}\n") print(f"B:\t\t{b}\n")
if getattr(shared.opts, "cc_metadata", True): if getattr(shared.opts, "cc_metadata", True):
p.extra_generation_params["Vec CC Enabled"] = enable p.extra_generation_params.update(
p.extra_generation_params["Vec CC Alt"] = latent {
p.extra_generation_params["Vec CC Brightness"] = bri "Vec CC Enabled": enable,
p.extra_generation_params["Vec CC Contrast"] = con "Vec CC Alt": latent,
p.extra_generation_params["Vec CC Saturation"] = sat "Vec CC Brightness": bri,
p.extra_generation_params["Vec CC R"] = r "Vec CC Contrast": con,
p.extra_generation_params["Vec CC G"] = g "Vec CC Saturation": sat,
p.extra_generation_params["Vec CC B"] = b "Vec CC R": r,
p.extra_generation_params["Vec CC Noise"] = method "Vec CC G": g,
p.extra_generation_params["Vec CC Proc HrF"] = doHR "Vec CC B": b,
p.extra_generation_params["Vec CC Proc Ade"] = doAD "Vec CC Noise": method,
p.extra_generation_params["Vec CC Scaling"] = scaling "Vec CC Proc HrF": doHR,
p.extra_generation_params["Vec CC Version"] = VERSION "Vec CC Proc Ade": doAD,
"Vec CC Seed Randomize": doRN,
"Vec CC Scaling": scaling,
"Vec CC Version": VERSION,
}
)
bri /= steps bri /= steps
con /= steps con /= steps
@ -394,7 +388,7 @@ class VectorscopeCC(scripts.Script):
g /= steps g /= steps
b /= steps b /= steps
mode = "x" if latent else "denoised" mode: str = "x" if latent else "denoised"
KDiffusionSampler.vec_cc = { KDiffusionSampler.vec_cc = {
"enable": True, "enable": True,

View File

@ -7,16 +7,15 @@ import cv2 as cv
# https://docs.opencv.org/4.8.0/d2/df0/tutorial_py_hdr.html # https://docs.opencv.org/4.8.0/d2/df0/tutorial_py_hdr.html
def merge_HDR(imgs: list, path: str, depth: str, fmt: str, gamma: float): def merge_HDR(imgs: list, path: str, depth: str, fmt: str, gamma: float) -> np.ndarray:
import datetime import datetime
import math import math
import os import os
output_folder = os.path.join(path, "hdr") output_folder = os.path.join(path, "hdr")
if not os.path.exists(output_folder): os.makedirs(output_folder, exist_ok=True)
os.makedirs(output_folder)
imgs_np = [np.array(img, dtype=np.uint8) for img in imgs] imgs_np = [np.asarray(img).astype(np.uint8) for img in imgs]
merge = cv.createMergeMertens() merge = cv.createMergeMertens()
hdr = merge.process(imgs_np) hdr = merge.process(imgs_np)
@ -39,8 +38,11 @@ def merge_HDR(imgs: list, path: str, depth: str, fmt: str, gamma: float):
rgb, rgb,
) )
return ldr
class VectorHDR(scripts.Script): class VectorHDR(scripts.Script):
def title(self): def title(self):
return "High Dynamic Range" return "High Dynamic Range"
@ -49,14 +51,14 @@ class VectorHDR(scripts.Script):
def ui(self, is_img2img): def ui(self, is_img2img):
with gr.Row(): with gr.Row():
count = gr.Slider(label="Brackets", minimum=3, maximum=9, step=2, value=7) count = gr.Slider(label="Brackets", minimum=3, maximum=9, step=2, value=5)
gap = gr.Slider( gap = gr.Slider(
label="Gaps", minimum=0.50, maximum=2.50, step=0.25, value=1.50 label="Gaps", minimum=0.50, maximum=2.50, step=0.25, value=1.25
) )
with gr.Accordion( with gr.Accordion(
"Merge Options", "Merge Options",
elem_id="vec-hdr-" + ("img" if is_img2img else "txt"), elem_id=f'vec-hdr-{"img" if is_img2img else "txt"}',
open=False, open=False,
): ):
auto = gr.Checkbox(label="Automatically Merge", value=True) auto = gr.Checkbox(label="Automatically Merge", value=True)
@ -85,16 +87,7 @@ class VectorHDR(scripts.Script):
center = count // 2 center = count // 2
p.seed = get_fixed_seed(p.seed) p.seed = get_fixed_seed(p.seed)
p.scripts.script("vectorscope cc").xyzCache.update( p.scripts.script("vectorscope cc").xyzCache.update({"Enable": "False"})
{
"Enable": "True",
"Alt": "True",
"Brightness": 0,
"DoHR": "False",
"Method": "Ones",
"Scaling": "1 - Cos",
}
)
baseline = process_images(p) baseline = process_images(p)
pc = copy(p) pc = copy(p)
@ -109,7 +102,14 @@ class VectorHDR(scripts.Script):
continue continue
pc.scripts.script("vectorscope cc").xyzCache.update( pc.scripts.script("vectorscope cc").xyzCache.update(
{"Brightness": brackets[it]} {
"Enable": "True",
"Alt": "True",
"Brightness": brackets[it],
"DoHR": "False",
"Method": "Ones",
"Scaling": "1 - Cos",
}
) )
proc = process_images(pc) proc = process_images(pc)
@ -117,13 +117,12 @@ class VectorHDR(scripts.Script):
if not auto: if not auto:
baseline.images = imgs baseline.images = imgs
return baseline
else: else:
merge_HDR(imgs, p.outpath_samples, depth, fmt, gamma) baseline.images = [merge_HDR(imgs, p.outpath_samples, depth, fmt, gamma)]
return baseline
return baseline
def brightness_brackets(count, gap): def brightness_brackets(count: int, gap: int) -> list[int]:
half = count // 2 half = count // 2
return [gap * (i - half) for i in range(count)] return [gap * (i - half) for i in range(count)]

BIN
scripts/vectorscope.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 178 KiB