Endless-Iterations
commited on
Commit
•
b094968
1
Parent(s):
a0bc898
Upload 43 files
Browse files- .gitattributes +7 -0
- sd-webui-vectorscope-cc/.gitattributes +2 -0
- sd-webui-vectorscope-cc/.github/FUNDING.yml +1 -0
- sd-webui-vectorscope-cc/CHANGELOG.md +76 -0
- sd-webui-vectorscope-cc/LICENSE +21 -0
- sd-webui-vectorscope-cc/README.md +250 -0
- sd-webui-vectorscope-cc/javascript/vec_cc.js +136 -0
- sd-webui-vectorscope-cc/samples/00.jpg +0 -0
- sd-webui-vectorscope-cc/samples/01.jpg +0 -0
- sd-webui-vectorscope-cc/samples/02.jpg +0 -0
- sd-webui-vectorscope-cc/samples/03.jpg +0 -0
- sd-webui-vectorscope-cc/samples/04.jpg +0 -0
- sd-webui-vectorscope-cc/samples/Bright.jpg +3 -0
- sd-webui-vectorscope-cc/samples/Dark.jpg +3 -0
- sd-webui-vectorscope-cc/samples/Random.jpg +3 -0
- sd-webui-vectorscope-cc/samples/Scaling.jpg +3 -0
- sd-webui-vectorscope-cc/samples/Scaling_alt.jpg +3 -0
- sd-webui-vectorscope-cc/samples/Skip.jpg +3 -0
- sd-webui-vectorscope-cc/samples/XYZ.jpg +3 -0
- sd-webui-vectorscope-cc/samples/api_example.json +29 -0
- sd-webui-vectorscope-cc/scripts/Vectorscope.png +0 -0
- sd-webui-vectorscope-cc/scripts/__pycache__/cc.cpython-310.pyc +0 -0
- sd-webui-vectorscope-cc/scripts/__pycache__/cc_colorpicker.cpython-310.pyc +0 -0
- sd-webui-vectorscope-cc/scripts/__pycache__/cc_const.cpython-310.pyc +0 -0
- sd-webui-vectorscope-cc/scripts/__pycache__/cc_hdr.cpython-310.pyc +0 -0
- sd-webui-vectorscope-cc/scripts/__pycache__/cc_noise.cpython-310.pyc +0 -0
- sd-webui-vectorscope-cc/scripts/__pycache__/cc_scaling.cpython-310.pyc +0 -0
- sd-webui-vectorscope-cc/scripts/__pycache__/cc_settings.cpython-310.pyc +0 -0
- sd-webui-vectorscope-cc/scripts/__pycache__/cc_style.cpython-310.pyc +0 -0
- sd-webui-vectorscope-cc/scripts/__pycache__/cc_version.cpython-310.pyc +0 -0
- sd-webui-vectorscope-cc/scripts/__pycache__/cc_xyz.cpython-310.pyc +0 -0
- sd-webui-vectorscope-cc/scripts/cc.py +294 -0
- sd-webui-vectorscope-cc/scripts/cc_colorpicker.py +23 -0
- sd-webui-vectorscope-cc/scripts/cc_const.py +12 -0
- sd-webui-vectorscope-cc/scripts/cc_hdr.py +107 -0
- sd-webui-vectorscope-cc/scripts/cc_noise.py +50 -0
- sd-webui-vectorscope-cc/scripts/cc_scaling.py +28 -0
- sd-webui-vectorscope-cc/scripts/cc_settings.py +6 -0
- sd-webui-vectorscope-cc/scripts/cc_style.py +76 -0
- sd-webui-vectorscope-cc/scripts/cc_version.py +20 -0
- sd-webui-vectorscope-cc/scripts/cc_xyz.py +40 -0
- sd-webui-vectorscope-cc/scripts/dot.png +0 -0
- sd-webui-vectorscope-cc/style.css +37 -0
- sd-webui-vectorscope-cc/styles.json +1 -0
.gitattributes
CHANGED
@@ -33,3 +33,10 @@ saved_model/**/* filter=lfs diff=lfs merge=lfs -text
|
|
33 |
*.zip filter=lfs diff=lfs merge=lfs -text
|
34 |
*.zst filter=lfs diff=lfs merge=lfs -text
|
35 |
*tfevents* filter=lfs diff=lfs merge=lfs -text
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
33 |
*.zip filter=lfs diff=lfs merge=lfs -text
|
34 |
*.zst filter=lfs diff=lfs merge=lfs -text
|
35 |
*tfevents* filter=lfs diff=lfs merge=lfs -text
|
36 |
+
sd-webui-vectorscope-cc/samples/Bright.jpg filter=lfs diff=lfs merge=lfs -text
|
37 |
+
sd-webui-vectorscope-cc/samples/Dark.jpg filter=lfs diff=lfs merge=lfs -text
|
38 |
+
sd-webui-vectorscope-cc/samples/Random.jpg filter=lfs diff=lfs merge=lfs -text
|
39 |
+
sd-webui-vectorscope-cc/samples/Scaling_alt.jpg filter=lfs diff=lfs merge=lfs -text
|
40 |
+
sd-webui-vectorscope-cc/samples/Scaling.jpg filter=lfs diff=lfs merge=lfs -text
|
41 |
+
sd-webui-vectorscope-cc/samples/Skip.jpg filter=lfs diff=lfs merge=lfs -text
|
42 |
+
sd-webui-vectorscope-cc/samples/XYZ.jpg filter=lfs diff=lfs merge=lfs -text
|
sd-webui-vectorscope-cc/.gitattributes
ADDED
@@ -0,0 +1,2 @@
|
|
|
|
|
|
|
1 |
+
*.png filter=lfs diff=lfs merge=lfs -text
|
2 |
+
*.jpg filter=lfs diff=lfs merge=lfs -text
|
sd-webui-vectorscope-cc/.github/FUNDING.yml
ADDED
@@ -0,0 +1 @@
|
|
|
|
|
1 |
+
ko_fi: haoming
|
sd-webui-vectorscope-cc/CHANGELOG.md
ADDED
@@ -0,0 +1,76 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
### v1.4.10 - 2023 Nov.01
|
2 |
+
- Better **Hires. fix** logic
|
3 |
+
|
4 |
+
### v1.4.9 - 2023 Nov.01
|
5 |
+
- Improve Sliders values refresh
|
6 |
+
|
7 |
+
### v1.4.8 - 2023 Nov.01
|
8 |
+
- Removed "**magic numbers**"
|
9 |
+
|
10 |
+
### v1.4.7 - 2023 Nov.01
|
11 |
+
- Removed **Skip** parameter
|
12 |
+
|
13 |
+
### v1.4.6 - 2023 Sep.19
|
14 |
+
- Add **HDR** Script
|
15 |
+
|
16 |
+
### v1.4.5 - 2023 Sep.13
|
17 |
+
- Bug Fix for Color Wheel in `img2img`
|
18 |
+
- Minor Formatting
|
19 |
+
|
20 |
+
### v1.4.4 - 2023 Sep.13
|
21 |
+
- Add **Infotext** Support by. **catboxanon**
|
22 |
+
|
23 |
+
### v1.4.3 - 2023 Sep.13
|
24 |
+
- Improve **Color Wheel** Functionality by. **catboxanon**
|
25 |
+
|
26 |
+
### v1.4.2 - 2023 Sep.11
|
27 |
+
- Fix the Reset and Randomize buttons for the new Contrast algorithm
|
28 |
+
|
29 |
+
### v1.4.1 - 2023 Sep.11
|
30 |
+
- New **Contrast** algorithm
|
31 |
+
|
32 |
+
### v1.4.0 - 2023 Jul.11
|
33 |
+
- Implement **Scaling** algorithm
|
34 |
+
|
35 |
+
### v1.3.5 - 2023 Jul.11
|
36 |
+
- Implement **Color Picker**
|
37 |
+
|
38 |
+
### v1.3.4 - 2023 Jul.08
|
39 |
+
- Implement **Metadata**
|
40 |
+
|
41 |
+
### v1.3.3 - 2023 Jul.07
|
42 |
+
- Color Wheel now works at (0, 0, 0)
|
43 |
+
- Style/Randomize/Reset now updates Color Wheel
|
44 |
+
|
45 |
+
### v1.3.2 - 2023 Jul.07
|
46 |
+
- Implement **Color Wheel**
|
47 |
+
- Finally added `changelog`
|
48 |
+
|
49 |
+
### v1.3.1 - 2023 Jul.06
|
50 |
+
- Bug Fix
|
51 |
+
|
52 |
+
### v1.3.0 - 2023 Jul.06
|
53 |
+
- Implement **Style Presets**
|
54 |
+
- Separate logics into different scripts
|
55 |
+
|
56 |
+
### v1.2.1 - 2023 Jul.05
|
57 |
+
- Add **Randomize** function
|
58 |
+
- Add **Reset** function
|
59 |
+
|
60 |
+
### v1.2.0 - 2023 Jul.03
|
61 |
+
- Implement multiple **Noise** algorithms
|
62 |
+
|
63 |
+
### v1.1.3 - 2023 Jun.26
|
64 |
+
- Automatically refresh outdated Sliders values
|
65 |
+
|
66 |
+
### v1.1.2 - 2023 Jun.23
|
67 |
+
- Bug Fix
|
68 |
+
|
69 |
+
### v1.1.1 - 2023 Jun.22
|
70 |
+
- **Batch** Support
|
71 |
+
|
72 |
+
### v1.1.0 - 2023 Jun.21
|
73 |
+
- **X/Y/Z Plot** Support
|
74 |
+
|
75 |
+
### v1.0.0 - 2023 Jun.20
|
76 |
+
- Extension **Released**!
|
sd-webui-vectorscope-cc/LICENSE
ADDED
@@ -0,0 +1,21 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
MIT License
|
2 |
+
|
3 |
+
Copyright (c) 2023 Haoming
|
4 |
+
|
5 |
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
6 |
+
of this software and associated documentation files (the "Software"), to deal
|
7 |
+
in the Software without restriction, including without limitation the rights
|
8 |
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
9 |
+
copies of the Software, and to permit persons to whom the Software is
|
10 |
+
furnished to do so, subject to the following conditions:
|
11 |
+
|
12 |
+
The above copyright notice and this permission notice shall be included in all
|
13 |
+
copies or substantial portions of the Software.
|
14 |
+
|
15 |
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
16 |
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
17 |
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
18 |
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
19 |
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
20 |
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
21 |
+
SOFTWARE.
|
sd-webui-vectorscope-cc/README.md
ADDED
@@ -0,0 +1,250 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
# SD Webui Vectorscope CC
|
2 |
+
This is an Extension for the [Automatic1111 Webui](https://github.com/AUTOMATIC1111/stable-diffusion-webui), which performs a kind of **Offset Noise**[*](#offset-noise-tldr) natively,
|
3 |
+
allowing you to adjust the brightness, contrast, and color of the generations.
|
4 |
+
|
5 |
+
> [Sample Images](#sample-images)
|
6 |
+
|
7 |
+
## How to Use
|
8 |
+
After installing this Extension, you will see a new section in both **txt2img** and **img2img** tabs.
|
9 |
+
Refer to the parameters and sample images below and play around with the values.
|
10 |
+
|
11 |
+
**Note:** Since this modifies the underlying latent noise, the composition may change drastically. Using the **Ones** scaling seems to reduce the variations.
|
12 |
+
|
13 |
+
#### Parameters
|
14 |
+
- **Enable:** Turn on/off this Extension
|
15 |
+
- **Alt:** Modify an alternative Tensor instead, causing the effects to be significantly stronger
|
16 |
+
- **Brightness:** Adjust the overall brightness of the image
|
17 |
+
- **Contrast:** Adjust the overall contrast of the image
|
18 |
+
- **Saturation:** Adjust the overall saturation of the image
|
19 |
+
|
20 |
+
#### Color Channels
|
21 |
+
- Comes with a Color Wheel for visualization
|
22 |
+
- You can also click and drag on the Color Wheel to select a color directly
|
23 |
+
|
24 |
+
<table>
|
25 |
+
<thead align="center">
|
26 |
+
<tr>
|
27 |
+
<td><b>Channel</b></td>
|
28 |
+
<td><b>Lower</b></td>
|
29 |
+
<td><b>Higher</b></td>
|
30 |
+
</tr>
|
31 |
+
</thead>
|
32 |
+
<tbody align="center">
|
33 |
+
<tr>
|
34 |
+
<td><b>R</b></td>
|
35 |
+
<td>Cyan</td>
|
36 |
+
<td>Red</td>
|
37 |
+
</tr>
|
38 |
+
<tr>
|
39 |
+
<td><b>G</b></td>
|
40 |
+
<td>Magenta</td>
|
41 |
+
<td>Green</td>
|
42 |
+
</tr>
|
43 |
+
<tr>
|
44 |
+
<td><b>B</b></td>
|
45 |
+
<td>Yellow</td>
|
46 |
+
<td>Blue</td>
|
47 |
+
</tr>
|
48 |
+
</tbody>
|
49 |
+
</table>
|
50 |
+
|
51 |
+
#### Buttons
|
52 |
+
- **Reset:** Reset all settings to the default values
|
53 |
+
- **Randomize:** Randomize `Brightness`, `Contrast`, `Saturation`, `R`, `G`, `B`
|
54 |
+
|
55 |
+
#### Style Presets
|
56 |
+
- Use the `Dropdown` to select a Style then click **Apply Style** to apply
|
57 |
+
- To save a Style, enter a name in the `Textbox` then click **Save Style**
|
58 |
+
- To delete a Style, enter the name in the `Textbox` then click **Delete Style**
|
59 |
+
- *Deleted Style is still in the `styles.json` in case you wish to retrieve it*
|
60 |
+
- Click **Refresh Style** to update the `Dropdown` if you edited the `styles.json` directly
|
61 |
+
|
62 |
+
#### Advanced Settings
|
63 |
+
- **Process Hires. fix:** By default, this Extension only functions during the **txt2img** phase, so that **Hires. fix** may "fix" the artifacts introduced during **txt2img**. Enable this to process **Hires. fix** phase too.
|
64 |
+
- This option does not affect **img2img**
|
65 |
+
|
66 |
+
##### Noise Settings
|
67 |
+
> let `x` denote the Tensor ; let `y` denote the operations
|
68 |
+
|
69 |
+
<!-- "Straight", "Straight Abs.", "Cross", "Cross Abs.", "Ones", "N.Random", "U.Random", "Multi-Res", "Multi-Res Abs." -->
|
70 |
+
|
71 |
+
- **Straight:** All operations are calculated on the same Tensor
|
72 |
+
- `x += x * y`
|
73 |
+
- **Cross:** All operations are calculated on the Tensor opposite of the `Alt.` setting
|
74 |
+
- `x += x' * y`
|
75 |
+
- **Ones:** All operations are calculated on a Tensor filled with ones
|
76 |
+
- `x += 1 * y`
|
77 |
+
- **N.Random:** All operations are calculated on a Tensor filled with random values from normal distribution
|
78 |
+
- `x += randn() * y`
|
79 |
+
- **U.Random:** All operations are calculated on a Tensor filled with random values from uniform distribution
|
80 |
+
- `x += rand() * y`
|
81 |
+
- **Multi-Res:** All operations are calculated on a Tensor generated with multi-res noise algorithm
|
82 |
+
- `x += multires() * y`
|
83 |
+
- **Abs:** Calculate using the absolute values of the chosen Tensors instead
|
84 |
+
- `x += abs(F) * y`
|
85 |
+
|
86 |
+
<p align="center"><img src="samples/Bright.jpg" width=768></p>
|
87 |
+
<p align="center"><img src="samples/Dark.jpg" width=768></p>
|
88 |
+
|
89 |
+
##### Scaling Settings
|
90 |
+
Previously, this Extension offsets the noise by the same amount each step.
|
91 |
+
But due to the denoising process, this may produce undesired outcomes such as blurriness at high **Brightness** or noises at low **Brightness**.
|
92 |
+
Thus, I added a scaling option to modify the offset amount.
|
93 |
+
|
94 |
+
> Essentially, the "magnitude" of the default Tensor gets smaller every step, so offsetting by the same amount will have stronger effects at later steps. This is reversed on the `Alt.` Tensor however.
|
95 |
+
|
96 |
+
- **Flat:** Default behavior. Same amount each step.
|
97 |
+
- **Cos:** Cosine scaling. *(High -> Low)*
|
98 |
+
- **Sin:** Sine scaling. *(Low -> High)*
|
99 |
+
- **1 - Cos:** *(Low -> High)*
|
100 |
+
- **1 - Sin:** *(High -> Low)*
|
101 |
+
|
102 |
+
> In my experience, **`1 - Sin`** works better for the **default** Tensor while **`1 - Cos`** works better for the **Alt.** Tensor
|
103 |
+
|
104 |
+
<p align="center">
|
105 |
+
<code>Alt. Disabled</code><br>
|
106 |
+
<img src="samples/Scaling.jpg" width=768>
|
107 |
+
</p>
|
108 |
+
|
109 |
+
<p align="center">
|
110 |
+
<code>Alt. Enabled</code><br>
|
111 |
+
<img src="samples/Scaling_alt.jpg" width=768>
|
112 |
+
</p>
|
113 |
+
|
114 |
+
<p align="center"><i>Notice the blurriness and the noises on <code>Flat</code> scaling</i></p>
|
115 |
+
|
116 |
+
## Sample Images
|
117 |
+
- **Checkpoint:** [UHD-23](https://civitai.com/models/22371/uhd-23)
|
118 |
+
- **Pos. Prompt:** `(masterpiece, best quality), 1girl, solo, night, street, city, neon_lights`
|
119 |
+
- **Neg. Prompt:** `(low quality, worst quality:1.2)`, [`EasyNegative`](https://huggingface.co/datasets/gsdf/EasyNegative/tree/main), [`EasyNegativeV2`](https://huggingface.co/gsdf/Counterfeit-V3.0/tree/main/embedding)
|
120 |
+
- `Euler a`; `20 steps`; `7.5 CFG`; `Hires. fix`; `Latent (nearest)`; `16 H.steps`; `0.6 D.Str.`; `Seed:`**`3814649974`**
|
121 |
+
- `Straight Abs.`
|
122 |
+
|
123 |
+
<p align="center">
|
124 |
+
<b>Base</b><br>
|
125 |
+
<code>Extension Disabled</code><br>
|
126 |
+
<img src="samples/00.jpg" width=512>
|
127 |
+
</p>
|
128 |
+
|
129 |
+
<p align="center">
|
130 |
+
<b>Dark</b><br>
|
131 |
+
<code><b>Brightness:</b> -3; <b>Contrast:</b> 1.5</code><br>
|
132 |
+
<img src="samples/01.jpg" width=512>
|
133 |
+
</p>
|
134 |
+
|
135 |
+
<p align="center">
|
136 |
+
<b>Bright</b><br>
|
137 |
+
<code><b>Brightness:</b> 2.5; <b>Contrast:</b> 0.5; <b>Alt:</b> Enabled</code><br>
|
138 |
+
<img src="samples/02.jpg" width=512>
|
139 |
+
</p>
|
140 |
+
|
141 |
+
<p align="center">
|
142 |
+
<b>Chill</b><br>
|
143 |
+
<code><b>Brightness:</b> -2.5; <b>Contrast:</b> 1.25</code><br>
|
144 |
+
<code><b>R:</b> -1.5; <b>B:</b> 2.5</code><br>
|
145 |
+
<img src="samples/03.jpg" width=512>
|
146 |
+
</p>
|
147 |
+
|
148 |
+
<p align="center">
|
149 |
+
<b><s>Mexican Movie</s></b><br>
|
150 |
+
<code><b>Brightness:</b> 3; <b>Saturation:</b> 1.5</code><br>
|
151 |
+
<code><b>R:</b> 2; <b>G:</b> 1; <b>B:</b> -2</code><br>
|
152 |
+
<img src="samples/04.jpg" width=512>
|
153 |
+
</p>
|
154 |
+
|
155 |
+
<p align="center"><i>Notice the significant differences even when using the same seed</i></p>
|
156 |
+
|
157 |
+
## Roadmap
|
158 |
+
- [X] Extension Released
|
159 |
+
- [X] Add Support for **X/Y/Z Plot**
|
160 |
+
- [X] Implement different **Noise** functions
|
161 |
+
- [X] Add **Randomize** functions
|
162 |
+
- [X] Append Parameters onto Metadata
|
163 |
+
- You can enable this in the **Infotext** section of the **Settings** tab
|
164 |
+
- [X] **Style** Presets
|
165 |
+
- [X] Implement **Color Wheel** & **Color Picker**
|
166 |
+
- [X] Implement better scaling algorithms
|
167 |
+
- [X] Fix the **Brightness** issues *~~kinda~~*
|
168 |
+
- [X] Add API Docs
|
169 |
+
- [X] Add Infotext Support *(by. [catboxanon](https://github.com/catboxanon))*
|
170 |
+
- [X] ADD **HDR** Script
|
171 |
+
- [ ] Add Gradient features
|
172 |
+
|
173 |
+
<p align="center"><code>X/Y/Z Plot Support</code><br><i>(Outdated Contrast Value)</i></p>
|
174 |
+
<p align="center"><img src="samples/XYZ.jpg" width=768></p>
|
175 |
+
|
176 |
+
<p align="center"><code>X/Y/Z Plot w/ Randomize</code></p>
|
177 |
+
<p align="center"><img src="samples/Random.jpg" width=768></p>
|
178 |
+
<p align="center">The value is used as the random seed<br>You can refer to the console to see the randomized values</p>
|
179 |
+
|
180 |
+
## API
|
181 |
+
You can use this Extension via [API](https://github.com/AUTOMATIC1111/stable-diffusion-webui/wiki/API) by adding an entry in the `alwayson_scripts` of your payload.
|
182 |
+
An [example](samples/api_example.json) is provided.
|
183 |
+
The `args` are sent in the following order:
|
184 |
+
|
185 |
+
- **[Enable, Alt, Brightness, Contrast, Saturation, R, G, B, Process Hires. Fix, Noise Settings, Scaling Settings]**
|
186 |
+
> `bool`, `bool`, `float`, `float`, `float`, `float`, `float`, `float`, `bool`, `str`, `str`
|
187 |
+
|
188 |
+
## Known Issues
|
189 |
+
- Does not work with `DDIM`, `UniPC` samplers
|
190 |
+
- Has little effect when used with certain **LoRA**s
|
191 |
+
|
192 |
+
## HDR
|
193 |
+
<p align="right"><i><b>BETA</b></i></p>
|
194 |
+
|
195 |
+
> [Discussion Thread](https://github.com/Haoming02/sd-webui-vectorscope-cc/issues/16)
|
196 |
+
|
197 |
+
- In the **Script** `Dropdown` at the bottom, there is now a new option: **`High Dynamic Range`**
|
198 |
+
- This script will generate multiple images *("Brackets")* of varying brightness, then merge them into 1 HDR image
|
199 |
+
- *Do provide feedback in the thread!*
|
200 |
+
- **Highly Recommended** to use a deterministic sampler and high enough steps. `Euler` *(**not** `Euler a`)* worked the best in my experience.
|
201 |
+
|
202 |
+
#### Settings
|
203 |
+
- **Brackets:** The numer of images to generate
|
204 |
+
- **Gaps:** The brightness difference between each image
|
205 |
+
- **Automatically Merge:** When enabled, this will merge the images using a `OpenCV` algorithm and save to the `HDR` folder in the `outputs` folder; When disabled, this will return all images to the result section, for when you have a more advanced program such as Photoshop to do the merging.
|
206 |
+
- All the images are still saved to the `outputs` folder regardless
|
207 |
+
|
208 |
+
<hr>
|
209 |
+
|
210 |
+
### Offset Noise TL;DR
|
211 |
+
The most common *version* of **Offset Noise** you may have heard of is from this [blog post](https://www.crosslabs.org/blog/diffusion-with-offset-noise),
|
212 |
+
where it was discovered that the noise functions used during **training** were flawed, causing `Stable Diffusion` to always generate images with an average of `0.5`.
|
213 |
+
|
214 |
+
> **ie.** Even if you prompt for dark/night or bright/snow, the overall image still looks "grey"
|
215 |
+
|
216 |
+
> [Technical Explanations](https://youtu.be/cVxQmbf3q7Q)
|
217 |
+
|
218 |
+
However, this Extension instead tries to offset the latent noise during the **inference** phase.
|
219 |
+
Therefore, you do not need to use models that were specially trained, as this can work on any model.
|
220 |
+
Though, the results may not be as good as using properly trained models.
|
221 |
+
|
222 |
+
<hr>
|
223 |
+
|
224 |
+
### What is Under the Hood
|
225 |
+
After reading through and messing around with the code,
|
226 |
+
I found out that it is possible to directly modify the Tensors
|
227 |
+
representing the latent noise used by the Stable Diffusion process.
|
228 |
+
|
229 |
+
The dimensions of the Tensors is `(X, 4, H / 8, W / 8)`, which can be thought of like this:
|
230 |
+
|
231 |
+
> **X** batch of noise images, with **4** channels, each with **(W / 8) x (H / 8)** values
|
232 |
+
|
233 |
+
> **eg.** Generating a single 512x768 image will create a Tensor of size (1, 4, 96, 64)
|
234 |
+
|
235 |
+
Then, I tried to play around with the values of each channel and ended up discovering these relationships.
|
236 |
+
Essentially, the 4 channels correspond to the **CMYK** color format,
|
237 |
+
hence why you can control the brightness as well as the colors.
|
238 |
+
|
239 |
+
<hr>
|
240 |
+
|
241 |
+
### Vectorscope?
|
242 |
+
The Extension is named this way because the color interactions remind me of the `Vectorscope` found in **Premiere Pro**'s **Lumetri Color**.
|
243 |
+
Those who are experienced in Color Correction should be rather familiar with this Extension.
|
244 |
+
|
245 |
+
<p align="center"><img src="scripts/Vectorscope.png" width=256></p>
|
246 |
+
|
247 |
+
<hr>
|
248 |
+
|
249 |
+
<sup>~~Yes. I'm aware that it's just how digital colors work in general.~~<br>
|
250 |
+
~~We've come full **circle** *(\*ba dum tss)* now that a Color Wheel is actually added.~~</sup>
|
sd-webui-vectorscope-cc/javascript/vec_cc.js
ADDED
@@ -0,0 +1,136 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
function registerPicker(wheel, sliders, mode) {
|
2 |
+
for (const event of ['mousemove', 'click']) {
|
3 |
+
wheel.addEventListener(event, (e) => {
|
4 |
+
e.preventDefault();
|
5 |
+
|
6 |
+
const rect = e.target.getBoundingClientRect();
|
7 |
+
|
8 |
+
if (e.type != 'click') {
|
9 |
+
if (e.buttons != 1) {
|
10 |
+
return;
|
11 |
+
}
|
12 |
+
|
13 |
+
const dot = e.target.parentElement.querySelector('#cc-dot-' + mode);
|
14 |
+
dot.style.position = 'fixed';
|
15 |
+
dot.style.left = e.x - (dot.width / 2) + 'px';
|
16 |
+
dot.style.top = e.y - (dot.height / 2) + 'px';
|
17 |
+
}
|
18 |
+
|
19 |
+
x = ((e.clientX - rect.left) - 100.0) / 25;
|
20 |
+
y = ((e.clientY - rect.top) - 100.0) / 25;
|
21 |
+
|
22 |
+
const zeta = Math.atan(y / x)
|
23 |
+
var degree = 0
|
24 |
+
|
25 |
+
if (x >= 0) {
|
26 |
+
if (y >= 0)
|
27 |
+
degree = zeta * 180 / Math.PI
|
28 |
+
else
|
29 |
+
degree = 360 + zeta * 180 / Math.PI
|
30 |
+
}
|
31 |
+
else if (x < 0) {
|
32 |
+
degree = 180 + zeta * 180 / Math.PI
|
33 |
+
}
|
34 |
+
|
35 |
+
// -0.5r - 0.5g + b = x
|
36 |
+
// -0.866r + 0.866g = y
|
37 |
+
// 240r + 120g = z * rgb
|
38 |
+
|
39 |
+
// g = (1 / 0.866)y + r
|
40 |
+
// -0.5r - 0.5((1 / 0.866)y + r) + b = x
|
41 |
+
// b = x + 0.5r + 0.5((1 / 0.866)y + r)
|
42 |
+
|
43 |
+
// 240r + 120(1 / 0.866)y + r = z * r((1 / 0.866)y + r)(x + 0.5r + 0.5((1 / 0.866)y + r))
|
44 |
+
|
45 |
+
var r = -(0.00077 * (433 * x * degree + 750 * y * degree) / degree)
|
46 |
+
var g = y / 0.866 + r
|
47 |
+
var b = x + 0.5 * r + 0.5 * g
|
48 |
+
|
49 |
+
const mag = Math.sqrt(r * r + g * g + b * b)
|
50 |
+
const len = Math.abs(r) + Math.abs(g) + Math.abs(b)
|
51 |
+
|
52 |
+
r = r / mag * len
|
53 |
+
g = g / mag * len
|
54 |
+
b = b / mag * len
|
55 |
+
|
56 |
+
sliders[0].value = r.toFixed(2)
|
57 |
+
sliders[0].closest('.gradio-slider').querySelector('input[type=range]').value = r.toFixed(2)
|
58 |
+
sliders[1].value = g.toFixed(2)
|
59 |
+
sliders[1].closest('.gradio-slider').querySelector('input[type=range]').value = g.toFixed(2)
|
60 |
+
sliders[2].value = b.toFixed(2)
|
61 |
+
sliders[2].closest('.gradio-slider').querySelector('input[type=range]').value = b.toFixed(2)
|
62 |
+
|
63 |
+
if (e.type == 'click') {
|
64 |
+
updateInput(sliders[0])
|
65 |
+
updateInput(sliders[1])
|
66 |
+
updateInput(sliders[2])
|
67 |
+
}
|
68 |
+
})
|
69 |
+
}
|
70 |
+
|
71 |
+
wheel.addEventListener('mouseup', (e) => {
|
72 |
+
const dot = e.target.parentElement.querySelector('#cc-dot-' + mode);
|
73 |
+
dot.style.position = 'absolute';
|
74 |
+
updateInput(sliders[0])
|
75 |
+
updateInput(sliders[1])
|
76 |
+
updateInput(sliders[2])
|
77 |
+
})
|
78 |
+
}
|
79 |
+
|
80 |
+
onUiLoaded(async () => {
|
81 |
+
|
82 |
+
['txt', 'img'].forEach((mode) => {
|
83 |
+
|
84 |
+
const container = document.getElementById('cc-colorwheel-' + mode)
|
85 |
+
container.style.height = '200px'
|
86 |
+
container.style.width = 'auto'
|
87 |
+
|
88 |
+
container.querySelector('.float')?.remove()
|
89 |
+
container.querySelector('.download')?.remove()
|
90 |
+
for (const downloadButton of container.querySelectorAll('[download]')) {
|
91 |
+
downloadButton.parentElement.remove()
|
92 |
+
}
|
93 |
+
|
94 |
+
const wheel = container.getElementsByTagName('img')[0]
|
95 |
+
wheel.style.height = '100%'
|
96 |
+
wheel.style.width = 'auto'
|
97 |
+
wheel.style.margin = 'auto'
|
98 |
+
wheel.id = 'cc-img-' + mode
|
99 |
+
|
100 |
+
wheel.ondragstart = (e) => { e.preventDefault(); }
|
101 |
+
|
102 |
+
sliders = [
|
103 |
+
document.getElementById('cc-r-' + mode).querySelector('input'),
|
104 |
+
document.getElementById('cc-g-' + mode).querySelector('input'),
|
105 |
+
document.getElementById('cc-b-' + mode).querySelector('input')
|
106 |
+
]
|
107 |
+
|
108 |
+
registerPicker(wheel, sliders, mode)
|
109 |
+
|
110 |
+
const temp = document.getElementById('cc-temp-' + mode)
|
111 |
+
|
112 |
+
const dot = temp.getElementsByTagName('img')[0]
|
113 |
+
dot.id = 'cc-dot-' + mode
|
114 |
+
|
115 |
+
container.appendChild(dot)
|
116 |
+
dot.style.left = 'calc(50% - 12px)'
|
117 |
+
dot.style.top = 'calc(50% - 12px)'
|
118 |
+
|
119 |
+
temp.remove()
|
120 |
+
|
121 |
+
const row1 = document.getElementById('cc-apply-' + mode).parentNode
|
122 |
+
const row2 = document.getElementById('cc-save-' + mode).parentNode
|
123 |
+
|
124 |
+
row1.style.alignItems = 'end'
|
125 |
+
row1.style.gap = '1em'
|
126 |
+
row2.style.alignItems = 'end'
|
127 |
+
row2.style.gap = '1em'
|
128 |
+
|
129 |
+
// ----- HDR UIs -----
|
130 |
+
const hdr_settings = document.getElementById('vec-hdr-' + mode)
|
131 |
+
const buttons = hdr_settings.getElementsByTagName('label')
|
132 |
+
|
133 |
+
for (let i = 0; i < buttons.length; i++)
|
134 |
+
buttons[i].style.borderRadius = '0.5em'
|
135 |
+
})
|
136 |
+
})
|
sd-webui-vectorscope-cc/samples/00.jpg
ADDED
sd-webui-vectorscope-cc/samples/01.jpg
ADDED
sd-webui-vectorscope-cc/samples/02.jpg
ADDED
sd-webui-vectorscope-cc/samples/03.jpg
ADDED
sd-webui-vectorscope-cc/samples/04.jpg
ADDED
sd-webui-vectorscope-cc/samples/Bright.jpg
ADDED
Git LFS Details
|
sd-webui-vectorscope-cc/samples/Dark.jpg
ADDED
Git LFS Details
|
sd-webui-vectorscope-cc/samples/Random.jpg
ADDED
Git LFS Details
|
sd-webui-vectorscope-cc/samples/Scaling.jpg
ADDED
Git LFS Details
|
sd-webui-vectorscope-cc/samples/Scaling_alt.jpg
ADDED
Git LFS Details
|
sd-webui-vectorscope-cc/samples/Skip.jpg
ADDED
Git LFS Details
|
sd-webui-vectorscope-cc/samples/XYZ.jpg
ADDED
Git LFS Details
|
sd-webui-vectorscope-cc/samples/api_example.json
ADDED
@@ -0,0 +1,29 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
{
|
2 |
+
"prompt": "(masterpiece, best quality), 1girl, solo, night",
|
3 |
+
"negative_prompt": "(low quality, worst quality:1.2)",
|
4 |
+
"seed": -1,
|
5 |
+
"sampler_name": "Euler a",
|
6 |
+
"sampler_index": "euler",
|
7 |
+
"batch_size": 1,
|
8 |
+
"steps": 24,
|
9 |
+
"cfg_scale": 8.5,
|
10 |
+
"width": 512,
|
11 |
+
"height": 512,
|
12 |
+
"alwayson_scripts": {
|
13 |
+
"Vectorscope CC": {
|
14 |
+
"args": [
|
15 |
+
true,
|
16 |
+
true,
|
17 |
+
-2.5,
|
18 |
+
0.5,
|
19 |
+
1.25,
|
20 |
+
0.0,
|
21 |
+
0.0,
|
22 |
+
0.0,
|
23 |
+
false,
|
24 |
+
"Straight Abs.",
|
25 |
+
"Flat"
|
26 |
+
]
|
27 |
+
}
|
28 |
+
}
|
29 |
+
}
|
sd-webui-vectorscope-cc/scripts/Vectorscope.png
ADDED
sd-webui-vectorscope-cc/scripts/__pycache__/cc.cpython-310.pyc
ADDED
Binary file (10.1 kB). View file
|
|
sd-webui-vectorscope-cc/scripts/__pycache__/cc_colorpicker.cpython-310.pyc
ADDED
Binary file (1.3 kB). View file
|
|
sd-webui-vectorscope-cc/scripts/__pycache__/cc_const.cpython-310.pyc
ADDED
Binary file (724 Bytes). View file
|
|
sd-webui-vectorscope-cc/scripts/__pycache__/cc_hdr.cpython-310.pyc
ADDED
Binary file (3.66 kB). View file
|
|
sd-webui-vectorscope-cc/scripts/__pycache__/cc_noise.cpython-310.pyc
ADDED
Binary file (1.85 kB). View file
|
|
sd-webui-vectorscope-cc/scripts/__pycache__/cc_scaling.cpython-310.pyc
ADDED
Binary file (801 Bytes). View file
|
|
sd-webui-vectorscope-cc/scripts/__pycache__/cc_settings.cpython-310.pyc
ADDED
Binary file (533 Bytes). View file
|
|
sd-webui-vectorscope-cc/scripts/__pycache__/cc_style.cpython-310.pyc
ADDED
Binary file (2.82 kB). View file
|
|
sd-webui-vectorscope-cc/scripts/__pycache__/cc_version.cpython-310.pyc
ADDED
Binary file (1.06 kB). View file
|
|
sd-webui-vectorscope-cc/scripts/__pycache__/cc_xyz.cpython-310.pyc
ADDED
Binary file (2.12 kB). View file
|
|
sd-webui-vectorscope-cc/scripts/cc.py
ADDED
@@ -0,0 +1,294 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
from modules.sd_samplers_kdiffusion import KDiffusionSampler
|
2 |
+
import modules.scripts as scripts
|
3 |
+
import scripts.cc_const as const
|
4 |
+
from modules import shared
|
5 |
+
import gradio as gr
|
6 |
+
import random
|
7 |
+
|
8 |
+
from scripts.cc_noise import *
|
9 |
+
|
10 |
+
from scripts.cc_xyz import xyz_support
|
11 |
+
|
12 |
+
from scripts.cc_scaling import apply_scaling
|
13 |
+
|
14 |
+
from scripts.cc_version import VERSION
|
15 |
+
|
16 |
+
from scripts.cc_colorpicker import create_colorpicker
|
17 |
+
from scripts.cc_colorpicker import horizontal_js
|
18 |
+
from scripts.cc_colorpicker import vertical_js
|
19 |
+
|
20 |
+
from scripts.cc_style import StyleManager
|
21 |
+
style_manager = StyleManager()
|
22 |
+
style_manager.load_styles()
|
23 |
+
|
24 |
+
og_callback = KDiffusionSampler.callback_state
|
25 |
+
|
26 |
+
class VectorscopeCC(scripts.Script):
|
27 |
+
def __init__(self):
|
28 |
+
self.xyzCache = {}
|
29 |
+
xyz_support(self.xyzCache)
|
30 |
+
|
31 |
+
def title(self):
|
32 |
+
return "Vectorscope CC"
|
33 |
+
|
34 |
+
def show(self, is_img2img):
|
35 |
+
return scripts.AlwaysVisible
|
36 |
+
|
37 |
+
def ui(self, is_img2img):
|
38 |
+
|
39 |
+
with gr.Accordion(f"Vectorscope CC {VERSION}", elem_id='vec-cc-' + ('img' if is_img2img else 'txt'), open=False):
|
40 |
+
|
41 |
+
with gr.Row():
|
42 |
+
enable = gr.Checkbox(label="Enable")
|
43 |
+
latent = gr.Checkbox(label="Alt. (Stronger Effects)")
|
44 |
+
|
45 |
+
with gr.Row():
|
46 |
+
bri = gr.Slider(label="Brightness", minimum=const.Brightness.minimum, maximum=const.Brightness.maximum, step=0.1, value=const.Brightness.default)
|
47 |
+
con = gr.Slider(label="Contrast", minimum=const.Contrast.minimum, maximum=const.Contrast.maximum, step=0.05, value=const.Contrast.default)
|
48 |
+
sat = gr.Slider(label="Saturation", minimum=const.Saturation.minimum, maximum=const.Saturation.maximum, step=0.05, value=const.Saturation.default)
|
49 |
+
|
50 |
+
with gr.Row():
|
51 |
+
with gr.Column():
|
52 |
+
r = gr.Slider(label="R", info='Cyan | Red', minimum=const.R.minimum, maximum=const.R.maximum, step=0.05, value=const.R.default, elem_id='cc-r-' + ('img' if is_img2img else 'txt'))
|
53 |
+
g = gr.Slider(label="G", info='Magenta | Green',minimum=const.G.minimum, maximum=const.G.maximum, step=0.05, value=const.G.default, elem_id='cc-g-' + ('img' if is_img2img else 'txt'))
|
54 |
+
b = gr.Slider(label="B", info='Yellow | Blue',minimum=const.B.minimum, maximum=const.B.maximum, step=0.05, value=const.B.default, elem_id='cc-b-' + ('img' if is_img2img else 'txt'))
|
55 |
+
|
56 |
+
create_colorpicker(is_img2img)
|
57 |
+
|
58 |
+
for component in [r, g, b]:
|
59 |
+
component.change(None, inputs=[r, g, b], outputs=[], _js=horizontal_js(is_img2img))
|
60 |
+
component.change(None, inputs=[r, g, b], outputs=[], _js=vertical_js(is_img2img))
|
61 |
+
|
62 |
+
with gr.Accordion("Styles", open=False):
|
63 |
+
|
64 |
+
with gr.Row():
|
65 |
+
style_choice = gr.Dropdown(label="Styles", choices=style_manager.list_style(), scale = 3)
|
66 |
+
apply_btn = gr.Button(value="Apply Style", elem_id='cc-apply-' + ('img' if is_img2img else 'txt'), scale = 2)
|
67 |
+
refresh_btn = gr.Button(value="Refresh Style", scale = 2)
|
68 |
+
with gr.Row():
|
69 |
+
style_name = gr.Textbox(label="Style Name", scale = 3)
|
70 |
+
save_btn = gr.Button(value="Save Style", elem_id='cc-save-' + ('img' if is_img2img else 'txt'), scale = 2)
|
71 |
+
delete_btn = gr.Button(value="Delete Style", scale = 2)
|
72 |
+
|
73 |
+
apply_btn.click(fn=style_manager.get_style, inputs=style_choice, outputs=[latent, bri, con, sat, r, g, b])
|
74 |
+
save_btn.click(fn=lambda *args: gr.update(choices=style_manager.save_style(*args)), inputs=[style_name, latent, bri, con, sat, r, g, b], outputs=style_choice)
|
75 |
+
delete_btn.click(fn=lambda name: gr.update(choices=style_manager.delete_style(name)), inputs=style_name, outputs=style_choice)
|
76 |
+
refresh_btn.click(fn=lambda _: gr.update(choices=style_manager.list_style()), outputs=style_choice)
|
77 |
+
|
78 |
+
with gr.Accordion("Advanced Settings", open=False):
|
79 |
+
doHR = gr.Checkbox(label="Process Hires. fix")
|
80 |
+
method = gr.Radio(["Straight", "Straight Abs.", "Cross", "Cross Abs.", "Ones", "N.Random", "U.Random", "Multi-Res", "Multi-Res Abs."], label="Noise Settings", value="Straight Abs.")
|
81 |
+
scaling = gr.Radio(["Flat", "Cos", "Sin", "1 - Cos", "1 - Sin"], label="Scaling Settings", value="Flat")
|
82 |
+
|
83 |
+
with gr.Row():
|
84 |
+
reset_btn = gr.Button(value="Reset")
|
85 |
+
self.register_reset(reset_btn, enable, latent, bri, con, sat, r, g, b, doHR, method, scaling)
|
86 |
+
|
87 |
+
random_btn = gr.Button(value="Randomize")
|
88 |
+
self.register_random(random_btn, bri, con, sat, r, g, b)
|
89 |
+
|
90 |
+
self.infotext_fields = []
|
91 |
+
self.paste_field_names = []
|
92 |
+
self.infotext_fields = [
|
93 |
+
(enable, lambda d: enable.update(value=("Vec CC Enabled" in d))),
|
94 |
+
(latent, "Vec CC Alt"),
|
95 |
+
(bri, "Vec CC Brightness"),
|
96 |
+
(con, "Vec CC Contrast"),
|
97 |
+
(sat, "Vec CC Saturation"),
|
98 |
+
(r, "Vec CC R"),
|
99 |
+
(g, "Vec CC G"),
|
100 |
+
(b, "Vec CC B"),
|
101 |
+
(method, "Vec CC Noise"),
|
102 |
+
(doHR, "Vec CC Proc HrF"),
|
103 |
+
(scaling, "Vec CC Scaling"),
|
104 |
+
]
|
105 |
+
|
106 |
+
for _, name in self.infotext_fields:
|
107 |
+
self.paste_field_names.append(name)
|
108 |
+
|
109 |
+
return [enable, latent, bri, con, sat, r, g, b, doHR, method, scaling]
|
110 |
+
|
111 |
+
def register_reset(self, reset_btn, enable, latent, bri, con, sat, r, g, b, doHR, method, scaling):
|
112 |
+
for component in [enable, latent, doHR]:
|
113 |
+
reset_btn.click(fn=lambda _: gr.update(value=False), outputs=component)
|
114 |
+
for component in [bri, con, r, g, b]:
|
115 |
+
reset_btn.click(fn=lambda _: gr.update(value=0.0), outputs=component)
|
116 |
+
for component in [sat]:
|
117 |
+
reset_btn.click(fn=lambda _: gr.update(value=const.Saturation.default), outputs=component)
|
118 |
+
|
119 |
+
reset_btn.click(fn=lambda _: gr.update(value='Straight Abs.'), outputs=method)
|
120 |
+
reset_btn.click(fn=lambda _: gr.update(value='Flat'), outputs=scaling)
|
121 |
+
|
122 |
+
def register_random(self, random_btn, bri, con, sat, r, g, b):
|
123 |
+
for component in [bri, con, r, g, b]:
|
124 |
+
random_btn.click(fn=lambda _: gr.update(value=round(random.uniform(const.R.minimum, const.R.maximum), 2)), outputs=component)
|
125 |
+
for component in [sat]:
|
126 |
+
random_btn.click(fn=lambda _: gr.update(value=round(random.uniform(const.Saturation.minimum, const.Saturation.maximum), 2)), outputs=component)
|
127 |
+
|
128 |
+
def parse_bool(self, string:str):
|
129 |
+
if string.lower() == "true":
|
130 |
+
return True
|
131 |
+
if string.lower() == "false":
|
132 |
+
return False
|
133 |
+
|
134 |
+
raise ValueError(f"Invalid Value: {string}")
|
135 |
+
|
136 |
+
def process(self, p, enable:bool, latent:bool, bri:float, con:float, sat:float, r:float, g:float, b:float, doHR:bool, method:str, scaling:str):
|
137 |
+
KDiffusionSampler.isHR_Pass = False
|
138 |
+
if 'Enable' in self.xyzCache.keys():
|
139 |
+
enable = self.parse_bool(self.xyzCache['Enable'])
|
140 |
+
|
141 |
+
if not enable:
|
142 |
+
if 'Enable' not in self.xyzCache.keys():
|
143 |
+
if len(self.xyzCache) > 0:
|
144 |
+
print('\n[X/Y/Z Plot] x [Vec.CC] Extension is not Enabled!\n')
|
145 |
+
self.xyzCache.clear()
|
146 |
+
|
147 |
+
KDiffusionSampler.callback_state = og_callback
|
148 |
+
return p
|
149 |
+
|
150 |
+
if 'Random' in self.xyzCache.keys():
|
151 |
+
if len(self.xyzCache) > 1:
|
152 |
+
print('\n[X/Y/Z Plot] x [Vec.CC] Randomize is Enabled!\nSome settings will not apply!\n')
|
153 |
+
else:
|
154 |
+
print('\n[X/Y/Z Plot] x [Vec.CC] Randomize is Enabled!\n')
|
155 |
+
|
156 |
+
cc_seed = None
|
157 |
+
|
158 |
+
for k, v in self.xyzCache.items():
|
159 |
+
match k:
|
160 |
+
case 'Alt':
|
161 |
+
latent = self.parse_bool(v)
|
162 |
+
case 'Brightness':
|
163 |
+
bri = v
|
164 |
+
case 'Contrast':
|
165 |
+
con = v
|
166 |
+
case 'Saturation':
|
167 |
+
sat = v
|
168 |
+
case 'R':
|
169 |
+
r = v
|
170 |
+
case 'G':
|
171 |
+
g = v
|
172 |
+
case 'B':
|
173 |
+
b = v
|
174 |
+
case 'DoHR':
|
175 |
+
doHR = self.parse_bool(v)
|
176 |
+
case 'Method':
|
177 |
+
method = v
|
178 |
+
case 'Scaling':
|
179 |
+
scaling = v
|
180 |
+
case 'Random':
|
181 |
+
cc_seed = v
|
182 |
+
|
183 |
+
self.xyzCache.clear()
|
184 |
+
|
185 |
+
if method == 'Disabled':
|
186 |
+
KDiffusionSampler.callback_state = og_callback
|
187 |
+
return p
|
188 |
+
|
189 |
+
steps = p.steps
|
190 |
+
if not hasattr(p, 'enable_hr') and hasattr(p, 'denoising_strength') and not shared.opts.img2img_fix_steps:
|
191 |
+
steps = int(steps * p.denoising_strength)
|
192 |
+
|
193 |
+
if cc_seed is not None:
|
194 |
+
random.seed(cc_seed)
|
195 |
+
|
196 |
+
bri = round(random.uniform(const.Contrast.minimum, const.Contrast.maximum), 2)
|
197 |
+
con = round(random.uniform(const.Contrast.minimum, const.Contrast.maximum), 2)
|
198 |
+
r = round(random.uniform(const.R.minimum, const.R.maximum), 2)
|
199 |
+
g = round(random.uniform(const.G.minimum, const.G.maximum), 2)
|
200 |
+
b = round(random.uniform(const.B.minimum, const.B.maximum), 2)
|
201 |
+
|
202 |
+
sat = round(random.uniform(const.Saturation.minimum, const.Saturation.maximum), 2)
|
203 |
+
|
204 |
+
print(f'-> Seed: {cc_seed}')
|
205 |
+
print(f'Brightness:\t{bri}')
|
206 |
+
print(f'Contrast:\t{con}')
|
207 |
+
print(f'Saturation:\t{sat}')
|
208 |
+
print(f'R:\t\t{r}')
|
209 |
+
print(f'G:\t\t{g}')
|
210 |
+
print(f'B:\t\t{b}\n')
|
211 |
+
|
212 |
+
if hasattr(shared.opts, 'cc_metadata') and shared.opts.cc_metadata is True:
|
213 |
+
p.extra_generation_params['Vec CC Enabled'] = enable
|
214 |
+
p.extra_generation_params['Vec CC Alt'] = latent
|
215 |
+
p.extra_generation_params['Vec CC Brightness'] = bri
|
216 |
+
p.extra_generation_params['Vec CC Contrast'] = con
|
217 |
+
p.extra_generation_params['Vec CC Saturation'] = sat
|
218 |
+
p.extra_generation_params['Vec CC R'] = r
|
219 |
+
p.extra_generation_params['Vec CC G'] = g
|
220 |
+
p.extra_generation_params['Vec CC B'] = b
|
221 |
+
p.extra_generation_params['Vec CC Noise'] = method
|
222 |
+
p.extra_generation_params['Vec CC Proc HrF'] = doHR
|
223 |
+
p.extra_generation_params['Vec CC Scaling'] = scaling
|
224 |
+
p.extra_generation_params['Vec CC Version'] = VERSION
|
225 |
+
|
226 |
+
bri /= steps
|
227 |
+
con /= steps
|
228 |
+
sat = pow(sat, 1.0 / steps)
|
229 |
+
r /= steps
|
230 |
+
g /= steps
|
231 |
+
b /= steps
|
232 |
+
|
233 |
+
mode = 'x' if latent else 'denoised'
|
234 |
+
|
235 |
+
# Channel 0: Dark | Bright
|
236 |
+
# Channel 1: Purple | Green
|
237 |
+
# Channel 2: Red | Cyan
|
238 |
+
# Channel 2: Violet | Yellow
|
239 |
+
|
240 |
+
def callback_state(self, d):
|
241 |
+
if not doHR and self.isHR_Pass is True:
|
242 |
+
return og_callback(self, d)
|
243 |
+
|
244 |
+
source = d[mode]
|
245 |
+
|
246 |
+
# "Straight", "Straight Abs.", "Cross", "Cross Abs.", "Ones", "N.Random", "U.Random", "Multi-Res", "Multi-Res Abs."
|
247 |
+
if 'Straight' in method:
|
248 |
+
target = d[mode]
|
249 |
+
elif 'Cross' in method:
|
250 |
+
cross = 'x' if mode == 'denoised' else 'denoised'
|
251 |
+
target = d[cross]
|
252 |
+
elif 'Multi-Res' in method:
|
253 |
+
target = multires_noise(d[mode], 'Abs' in method)
|
254 |
+
elif method == 'Ones':
|
255 |
+
target = ones(d[mode])
|
256 |
+
elif method == 'N.Random':
|
257 |
+
target = normal_noise(d[mode])
|
258 |
+
elif method == 'U.Random':
|
259 |
+
target = gaussian_noise(d[mode])
|
260 |
+
|
261 |
+
if 'Abs' in method:
|
262 |
+
target = to_abs(target)
|
263 |
+
|
264 |
+
batchSize = d[mode].size(0)
|
265 |
+
|
266 |
+
mods = apply_scaling(scaling, d["i"], steps, bri, con, sat, r, g, b)
|
267 |
+
|
268 |
+
for i in range(batchSize):
|
269 |
+
BRIGHTNESS = [source[i, 0], target[i, 0]]
|
270 |
+
R = [source[i, 2], target[i, 2]]
|
271 |
+
G = [source[i, 1], target[i, 1]]
|
272 |
+
B = [source[i, 3], target[i, 3]]
|
273 |
+
|
274 |
+
BRIGHTNESS[0] += BRIGHTNESS[1] * mods[0]
|
275 |
+
BRIGHTNESS[0] += get_delta(BRIGHTNESS[0]) * mods[1]
|
276 |
+
|
277 |
+
R[0] -= R[1] * mods[3]
|
278 |
+
G[0] += G[1] * mods[4]
|
279 |
+
B[0] -= B[1] * mods[5]
|
280 |
+
|
281 |
+
R[0] *= mods[2]
|
282 |
+
G[0] *= mods[2]
|
283 |
+
B[0] *= mods[2]
|
284 |
+
|
285 |
+
return og_callback(self, d)
|
286 |
+
|
287 |
+
KDiffusionSampler.callback_state = callback_state
|
288 |
+
return p
|
289 |
+
|
290 |
+
def before_hr(self, p, *args):
|
291 |
+
KDiffusionSampler.isHR_Pass = True
|
292 |
+
|
293 |
+
def postprocess(self, p, processed, *args):
|
294 |
+
KDiffusionSampler.callback_state = og_callback
|
sd-webui-vectorscope-cc/scripts/cc_colorpicker.py
ADDED
@@ -0,0 +1,23 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
import modules.scripts as scripts
|
2 |
+
import gradio as gr
|
3 |
+
|
4 |
+
WHEEL = scripts.basedir() + '/scripts/Vectorscope.png'
|
5 |
+
DOT = scripts.basedir() + '/scripts/dot.png'
|
6 |
+
|
7 |
+
def create_colorpicker(is_img):
|
8 |
+
gr.Image(WHEEL, type='filepath', interactive=False, container=False, elem_id='cc-colorwheel-' + ('img' if is_img else 'txt'))
|
9 |
+
gr.Image(DOT, type='filepath', interactive=False, container=False, elem_id='cc-temp-' + ('img' if is_img else 'txt'))
|
10 |
+
|
11 |
+
def horizontal_js(is_img):
|
12 |
+
mag = '(Math.abs(r) + Math.abs(g) + Math.abs(b))'
|
13 |
+
calc = '25 * Math.sqrt(r*r+g*g+b*b) * (r * -0.5 + g * -0.5 + b * 1.0) / ' + mag
|
14 |
+
cond = '(' + mag + ' === 0 ? 0 : ' + calc + ')'
|
15 |
+
|
16 |
+
return "(r, g, b) => {document.getElementById('cc-dot-" + ('img' if is_img else 'txt') + "').style.left = 'calc(50% + ' +(" + cond + "- 12) + 'px)'}"
|
17 |
+
|
18 |
+
def vertical_js(is_img):
|
19 |
+
mag = '(Math.abs(r) + Math.abs(g) + Math.abs(b))'
|
20 |
+
calc = '25 * Math.sqrt(r*r+g*g+b*b) * (r * -0.866 + g * 0.866 + b * 0.0) / ' + mag
|
21 |
+
cond = '(' + mag + ' === 0 ? 0 : ' + calc + ')'
|
22 |
+
|
23 |
+
return "(r, g, b) => {document.getElementById('cc-dot-" + ('img' if is_img else 'txt') + "').style.top = 'calc(50% + ' +(" + cond + "- 12) + 'px)'}"
|
sd-webui-vectorscope-cc/scripts/cc_const.py
ADDED
@@ -0,0 +1,12 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
class Param():
|
2 |
+
def __init__(self, minimum, maximum, default):
|
3 |
+
self.minimum = minimum
|
4 |
+
self.maximum = maximum
|
5 |
+
self.default = default
|
6 |
+
|
7 |
+
Brightness = Param(-7.5, 7.5, 0.0)
|
8 |
+
Contrast = Param(-5.0, 5.0, 0.0)
|
9 |
+
Saturation = Param(0.15, 1.85, 1.0)
|
10 |
+
R = Param(-4.0, 4.0, 0.0)
|
11 |
+
G = Param(-4.0, 4.0, 0.0)
|
12 |
+
B = Param(-4.0, 4.0, 0.0)
|
sd-webui-vectorscope-cc/scripts/cc_hdr.py
ADDED
@@ -0,0 +1,107 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
import modules.scripts as scripts
|
2 |
+
import gradio as gr
|
3 |
+
import numpy as np
|
4 |
+
import cv2 as cv
|
5 |
+
|
6 |
+
from modules.processing import process_images, get_fixed_seed
|
7 |
+
from copy import copy
|
8 |
+
|
9 |
+
# https://docs.opencv.org/4.8.0/d2/df0/tutorial_py_hdr.html
|
10 |
+
def merge_HDR(imgs:list, path:str, depth:str, fmt:str, gamma:float):
|
11 |
+
import datetime
|
12 |
+
import math
|
13 |
+
import os
|
14 |
+
|
15 |
+
output_folder = os.path.join(path, 'hdr')
|
16 |
+
if not os.path.exists(output_folder):
|
17 |
+
os.makedirs(output_folder)
|
18 |
+
|
19 |
+
imgs_np = [np.array(img, dtype=np.uint8) for img in imgs]
|
20 |
+
|
21 |
+
merge = cv.createMergeMertens()
|
22 |
+
hdr = merge.process(imgs_np)
|
23 |
+
hdr += math.ceil(0 - np.min(hdr) * 1000) / 1000
|
24 |
+
|
25 |
+
#print(f'{np.min(hdr)}, {np.max(hdr)}')
|
26 |
+
|
27 |
+
target = (65535 if depth == '16bpc' else 255)
|
28 |
+
precision = ('uint16' if depth == '16bpc' else 'uint8')
|
29 |
+
|
30 |
+
hdr = np.power(hdr, (1 / gamma))
|
31 |
+
|
32 |
+
ldr = np.clip(hdr * target, 0, target).astype(precision)
|
33 |
+
rgb = cv.cvtColor(ldr, cv.COLOR_BGR2RGB)
|
34 |
+
|
35 |
+
cv.imwrite(os.path.join(output_folder, f'{datetime.datetime.now().strftime("%H-%M-%S")}{fmt}'), rgb)
|
36 |
+
|
37 |
+
class VectorHDR(scripts.Script):
|
38 |
+
|
39 |
+
def title(self):
|
40 |
+
return "High Dynamic Range"
|
41 |
+
|
42 |
+
def show(self, is_img2img):
|
43 |
+
return True
|
44 |
+
|
45 |
+
def ui(self, is_img2img):
|
46 |
+
with gr.Row():
|
47 |
+
count = gr.Slider(label="Brackets", minimum=3, maximum=9, step=2, value=7)
|
48 |
+
gap = gr.Slider(label="Gaps", minimum=0.50, maximum=2.50, step=0.25, value=1.50)
|
49 |
+
|
50 |
+
with gr.Accordion("Merge Options", elem_id='vec-hdr-' + ('img' if is_img2img else 'txt'), open=False):
|
51 |
+
auto = gr.Checkbox(label="Automatically Merge", value=True)
|
52 |
+
|
53 |
+
with gr.Row():
|
54 |
+
depth = gr.Radio(['16bpc', '8bpc'], label="Bit Depth", value="16bpc")
|
55 |
+
fmt = gr.Radio(['.tiff', '.png'], label="Image Format", value=".tiff")
|
56 |
+
|
57 |
+
gamma = gr.Slider(label="Gamma", info='Lower: Darker | Higher: Brighter',minimum=0.2, maximum=2.2, step=0.2, value=1.2)
|
58 |
+
|
59 |
+
return [count, gap, auto, depth, fmt, gamma]
|
60 |
+
|
61 |
+
def run(self, p, count:int, gap:float, auto:bool, depth:str, fmt:str, gamma:float):
|
62 |
+
center = count // 2
|
63 |
+
|
64 |
+
p.seed = get_fixed_seed(p.seed)
|
65 |
+
p.scripts.script('vectorscope cc').xyzCache.update({
|
66 |
+
'Enable':'True',
|
67 |
+
'Alt':'True',
|
68 |
+
'Brightness': 0,
|
69 |
+
'DoHR': 'False',
|
70 |
+
'Method': 'Ones',
|
71 |
+
'Scaling': '1 - Cos'
|
72 |
+
})
|
73 |
+
|
74 |
+
baseline = process_images(p)
|
75 |
+
pc = copy(p)
|
76 |
+
|
77 |
+
imgs = [None] * count
|
78 |
+
imgs[center] = baseline.images[0]
|
79 |
+
|
80 |
+
brackets = brightness_brackets(count, gap)
|
81 |
+
|
82 |
+
for it in range(count):
|
83 |
+
if it == center:
|
84 |
+
continue
|
85 |
+
|
86 |
+
pc.scripts.script('vectorscope cc').xyzCache.update({
|
87 |
+
'Enable':'True',
|
88 |
+
'Alt':'True',
|
89 |
+
'Brightness': brackets[it],
|
90 |
+
'DoHR': 'False',
|
91 |
+
'Method': 'Ones',
|
92 |
+
'Scaling': '1 - Cos'
|
93 |
+
})
|
94 |
+
|
95 |
+
proc = process_images(pc)
|
96 |
+
imgs[it] = proc.images[0]
|
97 |
+
|
98 |
+
if not auto:
|
99 |
+
baseline.images = imgs
|
100 |
+
return baseline
|
101 |
+
else:
|
102 |
+
merge_HDR(imgs, p.outpath_samples, depth, fmt, gamma)
|
103 |
+
return baseline
|
104 |
+
|
105 |
+
def brightness_brackets(count, gap):
|
106 |
+
half = count // 2
|
107 |
+
return [gap * (i - half) for i in range(count)]
|
sd-webui-vectorscope-cc/scripts/cc_noise.py
ADDED
@@ -0,0 +1,50 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
from modules import devices
|
2 |
+
import torch
|
3 |
+
|
4 |
+
def get_delta(latent):
|
5 |
+
mean = torch.mean(latent)
|
6 |
+
return torch.sub(latent, mean)
|
7 |
+
|
8 |
+
def to_abs(latent):
|
9 |
+
return torch.abs(latent)
|
10 |
+
|
11 |
+
def zeros(latent):
|
12 |
+
return torch.zeros_like(latent)
|
13 |
+
|
14 |
+
def ones(latent):
|
15 |
+
return torch.ones_like(latent)
|
16 |
+
|
17 |
+
def gaussian_noise(latent):
|
18 |
+
return torch.rand_like(latent)
|
19 |
+
|
20 |
+
def normal_noise(latent):
|
21 |
+
return torch.randn_like(latent)
|
22 |
+
|
23 |
+
def multires_noise(latent, use_zero:bool, iterations=8, discount=0.4):
|
24 |
+
"""
|
25 |
+
Reference: https://wandb.ai/johnowhitaker/multires_noise/reports/Multi-Resolution-Noise-for-Diffusion-Model-Training--VmlldzozNjYyOTU2
|
26 |
+
Credit: Kohya_SS
|
27 |
+
"""
|
28 |
+
noise = zeros(latent) if use_zero else ones(latent)
|
29 |
+
|
30 |
+
batchSize = noise.size(0)
|
31 |
+
height = noise.size(2)
|
32 |
+
width = noise.size(3)
|
33 |
+
|
34 |
+
device = devices.get_optimal_device()
|
35 |
+
upsampler = torch.nn.Upsample(size=(height, width), mode="bilinear").to(device)
|
36 |
+
|
37 |
+
for b in range(batchSize):
|
38 |
+
for i in range(iterations):
|
39 |
+
r = torch.rand(1).item() * 2 + 2
|
40 |
+
|
41 |
+
wn = max(1, int(width / (r**i)))
|
42 |
+
hn = max(1, int(height / (r**i)))
|
43 |
+
|
44 |
+
for c in range(4):
|
45 |
+
noise[b, c] += upsampler(torch.randn(1, 1, hn, wn).to(device))[0, 0] * discount**i
|
46 |
+
|
47 |
+
if wn == 1 or hn == 1:
|
48 |
+
break
|
49 |
+
|
50 |
+
return noise / noise.std()
|
sd-webui-vectorscope-cc/scripts/cc_scaling.py
ADDED
@@ -0,0 +1,28 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
from math import cos
|
2 |
+
from math import sin
|
3 |
+
from math import pi
|
4 |
+
|
5 |
+
def apply_scaling(alg:str, current_step:int, total_steps:int, bri:float, con:float, sat:float, r:float, g:float, b:float):
|
6 |
+
ratio = float(current_step / total_steps)
|
7 |
+
rad = ratio * pi / 2
|
8 |
+
|
9 |
+
mod = 1.0
|
10 |
+
|
11 |
+
match alg:
|
12 |
+
case "Cos":
|
13 |
+
mod = cos(rad)
|
14 |
+
case "Sin":
|
15 |
+
mod = sin(rad)
|
16 |
+
case "1 - Cos":
|
17 |
+
mod = (1 - cos(rad))
|
18 |
+
case "1 - Sin":
|
19 |
+
mod = (1 - sin(rad))
|
20 |
+
|
21 |
+
return [
|
22 |
+
bri * mod,
|
23 |
+
con * mod,
|
24 |
+
(sat - 1) * mod + 1,
|
25 |
+
r * mod,
|
26 |
+
g * mod,
|
27 |
+
b * mod
|
28 |
+
]
|
sd-webui-vectorscope-cc/scripts/cc_settings.py
ADDED
@@ -0,0 +1,6 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
from modules import script_callbacks, shared
|
2 |
+
|
3 |
+
def on_ui_settings():
|
4 |
+
shared.opts.add_option("cc_metadata", shared.OptionInfo(False, "Add Vectorscope CC parameters to generation information", section=("infotext", "Infotext")))
|
5 |
+
|
6 |
+
script_callbacks.on_ui_settings(on_ui_settings)
|
sd-webui-vectorscope-cc/scripts/cc_style.py
ADDED
@@ -0,0 +1,76 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
import modules.scripts as scripts
|
2 |
+
import scripts.cc_const as const
|
3 |
+
import json
|
4 |
+
|
5 |
+
STYLE_FILE = scripts.basedir() + '/' + 'styles.json'
|
6 |
+
|
7 |
+
EMPTY_STYLE = {
|
8 |
+
'styles' : {},
|
9 |
+
'deleted' : {}
|
10 |
+
}
|
11 |
+
|
12 |
+
class StyleManager():
|
13 |
+
def __init__(self):
|
14 |
+
self.STYLE_SHEET = None
|
15 |
+
|
16 |
+
def load_styles(self):
|
17 |
+
if self.STYLE_SHEET is not None:
|
18 |
+
return
|
19 |
+
|
20 |
+
try:
|
21 |
+
with open(STYLE_FILE, 'r') as json_file:
|
22 |
+
self.STYLE_SHEET = json.loads(json_file.read())
|
23 |
+
print('[Vec. CC] Style Sheet Loaded...')
|
24 |
+
except IOError:
|
25 |
+
with open(STYLE_FILE, 'w+') as json_file:
|
26 |
+
self.STYLE_SHEET = EMPTY_STYLE
|
27 |
+
json_file.write(json.dumps(self.STYLE_SHEET))
|
28 |
+
print('[Vec. CC] Creating Empty Style Sheet...')
|
29 |
+
|
30 |
+
def list_style(self):
|
31 |
+
return list(self.STYLE_SHEET['styles'].keys())
|
32 |
+
|
33 |
+
def get_style(self, style_name):
|
34 |
+
try:
|
35 |
+
style = self.STYLE_SHEET['styles'][style_name]
|
36 |
+
return style['alt'], style['brightness'], style['contrast'], style['saturation'], style['rgb'][0], style['rgb'][1], style['rgb'][2]
|
37 |
+
except KeyError:
|
38 |
+
print(f'\n[Warning] No Style of Name "{style_name}" Found!\n')
|
39 |
+
return False, const.Brightness.default, const.Contrast.default, const.Saturation.default, const.R.default, const.G.default, const.B.default
|
40 |
+
|
41 |
+
def save_style(self, style_name, latent, bri, con, sat, r, g, b):
|
42 |
+
if style_name in self.STYLE_SHEET['styles'].keys():
|
43 |
+
print(f'\n[Warning] Duplicated Style Name "{style_name}" Detected! Values are not saved!\n')
|
44 |
+
return self.list_style()
|
45 |
+
|
46 |
+
style = {
|
47 |
+
'alt' : latent,
|
48 |
+
'brightness' : bri,
|
49 |
+
'contrast' : con,
|
50 |
+
'saturation' : sat,
|
51 |
+
'rgb' : [r, g, b]
|
52 |
+
}
|
53 |
+
|
54 |
+
self.STYLE_SHEET['styles'].update({style_name:style})
|
55 |
+
|
56 |
+
with open(STYLE_FILE, 'w+') as json_file:
|
57 |
+
json_file.write(json.dumps(self.STYLE_SHEET))
|
58 |
+
|
59 |
+
print(f'\nStyle of Name "{style_name}" Saved!\n')
|
60 |
+
return self.list_style()
|
61 |
+
|
62 |
+
def delete_style(self, style_name):
|
63 |
+
try:
|
64 |
+
style = self.STYLE_SHEET['styles'][style_name]
|
65 |
+
del self.STYLE_SHEET['styles'][style_name]
|
66 |
+
except KeyError:
|
67 |
+
print(f'\n[Warning] No Style of Name "{style_name}" Found!\n')
|
68 |
+
return self.list_style()
|
69 |
+
|
70 |
+
self.STYLE_SHEET['deleted'].update({style_name:style})
|
71 |
+
|
72 |
+
with open(STYLE_FILE, 'w+') as json_file:
|
73 |
+
json_file.write(json.dumps(self.STYLE_SHEET))
|
74 |
+
|
75 |
+
print(f'\nStyle of Name "{style_name}" Deleted!\n')
|
76 |
+
return self.list_style()
|
sd-webui-vectorscope-cc/scripts/cc_version.py
ADDED
@@ -0,0 +1,20 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
from modules import script_callbacks
|
2 |
+
import modules.scripts as scripts
|
3 |
+
import json
|
4 |
+
|
5 |
+
VERSION = 'v1.4.10'
|
6 |
+
|
7 |
+
def clean_outdated(EXT_NAME:str):
|
8 |
+
with open(scripts.basedir() + '/' + 'ui-config.json', 'r') as json_file:
|
9 |
+
configs = json.loads(json_file.read())
|
10 |
+
|
11 |
+
cleaned_configs = {key: value for key, value in configs.items() if EXT_NAME not in key}
|
12 |
+
|
13 |
+
with open(scripts.basedir() + '/' + 'ui-config.json', 'w') as json_file:
|
14 |
+
json.dump(cleaned_configs, json_file)
|
15 |
+
|
16 |
+
def refresh_sliders():
|
17 |
+
clean_outdated('cc.py')
|
18 |
+
clean_outdated('cc_hdr.py')
|
19 |
+
|
20 |
+
script_callbacks.on_before_ui(refresh_sliders)
|
sd-webui-vectorscope-cc/scripts/cc_xyz.py
ADDED
@@ -0,0 +1,40 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
import modules.scripts as scripts
|
2 |
+
|
3 |
+
def grid_reference():
|
4 |
+
for data in scripts.scripts_data:
|
5 |
+
if data.script_class.__module__ == 'xyz_grid.py' and hasattr(data, "module"):
|
6 |
+
return data.module
|
7 |
+
|
8 |
+
def xyz_support(cache):
|
9 |
+
def apply_field(field):
|
10 |
+
def _(p, x, xs):
|
11 |
+
cache.update({field : x})
|
12 |
+
return _
|
13 |
+
|
14 |
+
def choices_bool():
|
15 |
+
return ["False", "True"]
|
16 |
+
|
17 |
+
def choices_method():
|
18 |
+
return ["Disabled", "Straight", "Straight Abs.", "Cross", "Cross Abs.", "Ones", "N.Random", "U.Random", "Multi-Res", "Multi-Res Abs."]
|
19 |
+
|
20 |
+
def choices_scaling():
|
21 |
+
return ["Flat", "Cos", "Sin", "1 - Cos", "1 - Sin"]
|
22 |
+
|
23 |
+
xyz_grid = grid_reference()
|
24 |
+
|
25 |
+
extra_axis_options = [
|
26 |
+
xyz_grid.AxisOption("[Vec.CC] Enable", str, apply_field("Enable"), choices=choices_bool),
|
27 |
+
xyz_grid.AxisOption("[Vec.CC] Alt.", str, apply_field("Alt"), choices=choices_bool),
|
28 |
+
xyz_grid.AxisOption("[Vec.CC] Brightness", float, apply_field("Brightness")),
|
29 |
+
xyz_grid.AxisOption("[Vec.CC] Contrast", float, apply_field("Contrast")),
|
30 |
+
xyz_grid.AxisOption("[Vec.CC] Saturation", float, apply_field("Saturation")),
|
31 |
+
xyz_grid.AxisOption("[Vec.CC] R", float, apply_field("R")),
|
32 |
+
xyz_grid.AxisOption("[Vec.CC] G", float, apply_field("G")),
|
33 |
+
xyz_grid.AxisOption("[Vec.CC] B", float, apply_field("B")),
|
34 |
+
xyz_grid.AxisOption("[Adv.CC] Proc. H.Fix", str, apply_field("DoHR"), choices=choices_bool),
|
35 |
+
xyz_grid.AxisOption("[Adv.CC] Method", str, apply_field("Method"), choices=choices_method),
|
36 |
+
xyz_grid.AxisOption("[Adv.CC] Scaling", str, apply_field("Scaling"), choices=choices_scaling),
|
37 |
+
xyz_grid.AxisOption("[Adv.CC] Randomize", int, apply_field("Random"))
|
38 |
+
]
|
39 |
+
|
40 |
+
xyz_grid.axis_options.extend(extra_axis_options)
|
sd-webui-vectorscope-cc/scripts/dot.png
ADDED
sd-webui-vectorscope-cc/style.css
ADDED
@@ -0,0 +1,37 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
#cc-dot-txt {
|
2 |
+
position: absolute;
|
3 |
+
width: 24px;
|
4 |
+
height: 24px;
|
5 |
+
pointer-events: none;
|
6 |
+
}
|
7 |
+
|
8 |
+
#cc-dot-img {
|
9 |
+
position: absolute;
|
10 |
+
width: 24px;
|
11 |
+
height: 24px;
|
12 |
+
pointer-events: none;
|
13 |
+
}
|
14 |
+
|
15 |
+
#cc-img-txt {
|
16 |
+
cursor: pointer;
|
17 |
+
}
|
18 |
+
|
19 |
+
#cc-img-img {
|
20 |
+
cursor: pointer;
|
21 |
+
}
|
22 |
+
|
23 |
+
#vec-cc-txt button {
|
24 |
+
border-radius: 0.5em;
|
25 |
+
}
|
26 |
+
|
27 |
+
#vec-cc-txt label {
|
28 |
+
border-radius: 0.5em;
|
29 |
+
}
|
30 |
+
|
31 |
+
#vec-cc-img button {
|
32 |
+
border-radius: 0.5em;
|
33 |
+
}
|
34 |
+
|
35 |
+
#vec-cc-img label {
|
36 |
+
border-radius: 0.5em;
|
37 |
+
}
|
sd-webui-vectorscope-cc/styles.json
ADDED
@@ -0,0 +1 @@
|
|
|
|
|
1 |
+
{"styles": {}, "deleted": {}}
|