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

View File

@ -1,3 +1,7 @@
### v2.2.4 - 2024 Aug.28
- Optimization *(`internal`)*
- Improve Color **Accuracy** ~~Slightly~~
### v2.2.3 - 2024 Aug.27
- 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.
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
- **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
- **Brightness:** Adjust the overall brightness of the image
- **Contrast:** Adjust the overall contrast of the image

View File

@ -1,7 +1,11 @@
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) {
const mag = Math.abs(r) + Math.abs(g) + Math.abs(b);
var condX, condY;
@ -18,6 +22,11 @@ class VectorscopeCC {
this.dot[mode].style.top = `calc(50% + ${condY - 12}px)`;
}
/**
* @param {HTMLImageElement} wheel
* @param {HTMLInputElement[]} sliders
* @param {HTMLImageElement} dot
*/
static registerPicker(wheel, sliders, dot) {
['mousemove', 'click'].forEach((event) => {
wheel.addEventListener(event, (e) => {
@ -35,20 +44,7 @@ class VectorscopeCC {
const x = ((e.clientX - rect.left) - 100.0) / 25;
const y = ((e.clientY - rect.top) - 100.0) / 25;
const zeta = Math.atan(y / x);
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 r = -0.077 * (4.33 * x + 7.5 * y);
var g = y / 0.866 + r;
var b = x + 0.5 * r + 0.5 * g;

View File

@ -1,5 +1,5 @@
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 random import random
import torch
@ -45,19 +45,19 @@ class NoiseMethods:
"""
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)
for b in range(batchSize):
for batch in range(b):
for i in range(iterations):
r = random() * 2 + 2
wn = max(1, int(w / (r**i)))
hn = max(1, int(h / (r**i)))
noise[b] += (
noise[batch] += (
upsampler(torch.randn(1, c, hn, wn).to(device)) * discount**i
)[0]
@ -67,10 +67,10 @@ class NoiseMethods:
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"""
cb = -0.15 * r - 0.29 * g + 0.44 * b
cr = 0.44 * r - 0.37 * g - 0.07 * b
cb = -0.17 * r - 0.33 * g + 0.5 * b
cr = 0.5 * r - 0.41 * g - 0.08 * b
return cb, cr
@ -94,7 +94,8 @@ def cc_callback(self, d):
mode = str(self.vec_cc["mode"])
method = str(self.vec_cc["method"])
source = d[mode]
source: torch.Tensor = d[mode]
target: torch.Tensor = None
if "Straight" in method:
target = d[mode].detach().clone()
@ -175,4 +176,4 @@ def restore_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):
m = "img" if is_img else "txt"
m: str = "img" if is_img else "txt"
gr.Image(
WHEEL,
value=WHEEL,
interactive=False,
container=False,
elem_id=f"cc-colorwheel-{m}",
)
gr.Image(
DOT,
value=DOT,
interactive=False,
container=False,
elem_id=f"cc-temp-{m}",

View File

@ -11,7 +11,7 @@ EMPTY_STYLE = {"styles": {}, "deleted": {}}
class StyleManager:
def __init__(self):
self.STYLE_SHEET = None
self.STYLE_SHEET: dict = None
def load_styles(self):
if os.path.isfile(STYLE_FILE):
@ -27,10 +27,10 @@ class StyleManager:
return self.list_style()
def list_style(self):
def list_style(self) -> list[str]:
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)
if not style:

View File

@ -13,6 +13,7 @@ def grid_reference():
def xyz_support(cache: dict):
def apply_field(field):
def _(p, x, xs):
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
VERSION = "v2.2.3"
VERSION = "2.2.4"
style_manager = StyleManager()
@ -19,6 +19,7 @@ style_manager.load_styles()
class VectorscopeCC(scripts.Script):
def __init__(self):
self.xyzCache = {}
xyz_support(self.xyzCache)
@ -30,11 +31,11 @@ class VectorscopeCC(scripts.Script):
return scripts.AlwaysVisible
def ui(self, is_img2img):
mode = "img" if is_img2img else "txt"
m = f'"{mode}"'
mode: str = "img" if is_img2img else "txt"
m: str = f'"{mode}"'
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():
@ -151,13 +152,14 @@ class VectorscopeCC(scripts.Script):
label="Noise Settings",
value="Straight Abs.",
)
scaling = gr.Radio(
["Flat", "Cos", "Sin", "1 - Cos", "1 - Sin"],
label="Scaling Settings",
value="Flat",
)
comps = (
comps: tuple[gr.components.Component] = (
latent,
bri,
con,
@ -297,49 +299,40 @@ class VectorscopeCC(scripts.Script):
enable = self.xyzCache["Enable"].lower().strip() == "true"
if not enable:
if "Enable" not in self.xyzCache.keys():
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")
self.xyzCache.clear()
KDiffusionSampler.vec_cc = {"enable": False}
return p
if "Random" in self.xyzCache.keys():
print("[X/Y/Z Plot] x [Vec.CC] Randomize is Enabled.")
if len(self.xyzCache) > 1:
print(
"\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")
print("Some parameters will not apply!")
cc_seed = int(seeds[0]) if doRN else None
for k, v in self.xyzCache.items():
match k:
case "Alt":
if "Alt" in self.xyzCache.keys():
latent = self.xyzCache["Alt"].lower().strip() == "true"
case "Brightness":
bri = float(v)
case "Contrast":
con = float(v)
case "Saturation":
sat = float(v)
case "R":
r = float(v)
case "G":
g = float(v)
case "B":
b = float(v)
case "DoHR":
if "DoHR" in self.xyzCache.keys():
doHR = self.xyzCache["DoHR"].lower().strip() == "true"
case "Method":
method = str(v)
case "Scaling":
scaling = str(v)
case "Random":
cc_seed = int(v)
if "Random" in self.xyzCache.keys():
cc_seed = int(self.xyzCache["Random"])
bri = float(self.xyzCache.get("Brightness", bri))
con = float(self.xyzCache.get("Contrast", con))
sat = float(self.xyzCache.get("Saturation", sat))
r = float(self.xyzCache.get("R", r))
g = float(self.xyzCache.get("G", g))
b = float(self.xyzCache.get("B", b))
method = str(self.xyzCache.get("Method", method))
scaling = str(self.xyzCache.get("Scaling", scaling))
self.xyzCache.clear()
@ -347,11 +340,7 @@ class VectorscopeCC(scripts.Script):
KDiffusionSampler.vec_cc = {"enable": False}
return p
steps: int = 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)
steps: int = getattr(p, "firstpass_steps", None) or p.steps
if cc_seed:
seed(cc_seed)
@ -373,19 +362,24 @@ class VectorscopeCC(scripts.Script):
print(f"B:\t\t{b}\n")
if getattr(shared.opts, "cc_metadata", True):
p.extra_generation_params["Vec CC Enabled"] = enable
p.extra_generation_params["Vec CC Alt"] = latent
p.extra_generation_params["Vec CC Brightness"] = bri
p.extra_generation_params["Vec CC Contrast"] = con
p.extra_generation_params["Vec CC Saturation"] = sat
p.extra_generation_params["Vec CC R"] = r
p.extra_generation_params["Vec CC G"] = g
p.extra_generation_params["Vec CC B"] = b
p.extra_generation_params["Vec CC Noise"] = method
p.extra_generation_params["Vec CC Proc HrF"] = doHR
p.extra_generation_params["Vec CC Proc Ade"] = doAD
p.extra_generation_params["Vec CC Scaling"] = scaling
p.extra_generation_params["Vec CC Version"] = VERSION
p.extra_generation_params.update(
{
"Vec CC Enabled": enable,
"Vec CC Alt": latent,
"Vec CC Brightness": bri,
"Vec CC Contrast": con,
"Vec CC Saturation": sat,
"Vec CC R": r,
"Vec CC G": g,
"Vec CC B": b,
"Vec CC Noise": method,
"Vec CC Proc HrF": doHR,
"Vec CC Proc Ade": doAD,
"Vec CC Seed Randomize": doRN,
"Vec CC Scaling": scaling,
"Vec CC Version": VERSION,
}
)
bri /= steps
con /= steps
@ -394,7 +388,7 @@ class VectorscopeCC(scripts.Script):
g /= steps
b /= steps
mode = "x" if latent else "denoised"
mode: str = "x" if latent else "denoised"
KDiffusionSampler.vec_cc = {
"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
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 math
import os
output_folder = os.path.join(path, "hdr")
if not os.path.exists(output_folder):
os.makedirs(output_folder)
os.makedirs(output_folder, exist_ok=True)
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()
hdr = merge.process(imgs_np)
@ -39,8 +38,11 @@ def merge_HDR(imgs: list, path: str, depth: str, fmt: str, gamma: float):
rgb,
)
return ldr
class VectorHDR(scripts.Script):
def title(self):
return "High Dynamic Range"
@ -49,14 +51,14 @@ class VectorHDR(scripts.Script):
def ui(self, is_img2img):
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(
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(
"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,
):
auto = gr.Checkbox(label="Automatically Merge", value=True)
@ -85,16 +87,7 @@ class VectorHDR(scripts.Script):
center = count // 2
p.seed = get_fixed_seed(p.seed)
p.scripts.script("vectorscope cc").xyzCache.update(
{
"Enable": "True",
"Alt": "True",
"Brightness": 0,
"DoHR": "False",
"Method": "Ones",
"Scaling": "1 - Cos",
}
)
p.scripts.script("vectorscope cc").xyzCache.update({"Enable": "False"})
baseline = process_images(p)
pc = copy(p)
@ -109,7 +102,14 @@ class VectorHDR(scripts.Script):
continue
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)
@ -117,13 +117,12 @@ class VectorHDR(scripts.Script):
if not auto:
baseline.images = imgs
return baseline
else:
merge_HDR(imgs, p.outpath_samples, depth, fmt, gamma)
baseline.images = [merge_HDR(imgs, p.outpath_samples, depth, fmt, gamma)]
return baseline
def brightness_brackets(count, gap):
def brightness_brackets(count: int, gap: int) -> list[int]:
half = count // 2
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