Spaces:
Running
on
Zero
Running
on
Zero
HURA 0.2.0
Browse files- README.md +2 -0
- app.py +48 -18
- utils/hex_hura.py +359 -43
README.md
CHANGED
@@ -48,6 +48,7 @@ Welcome to HexaGrid Creator, the ultimate tool for transforming your images into
|
|
48 |
- **Pre-rendered Maps:** Access a library of ready-to-use hexagon maps for quick customization.
|
49 |
- **Add Margins:** Add customizable margins around your images for a polished print-ready look.
|
50 |
- **Sketch Pad Integration:** Directly sketch on images to modify or replace them before further processing.
|
|
|
51 |
|
52 |
|
53 |
### Why You'll Love It
|
@@ -68,6 +69,7 @@ Welcome to HexaGrid Creator, the ultimate tool for transforming your images into
|
|
68 |
- **TRELLIS Depth & 3D Model Generation:** Create detailed depth maps and 3D models, complete with GLB and Gaussian file extraction.
|
69 |
- **Add Margins:** Fine-tune image margins for a professional finish.
|
70 |
- **Sketch Pad Integration:** Use the built-in sketch pad to edit images on the fly before processing.
|
|
|
71 |
|
72 |
Join the hive and start creating with HexaGrid Creator today!
|
73 |
|
|
|
48 |
- **Pre-rendered Maps:** Access a library of ready-to-use hexagon maps for quick customization.
|
49 |
- **Add Margins:** Add customizable margins around your images for a polished print-ready look.
|
50 |
- **Sketch Pad Integration:** Directly sketch on images to modify or replace them before further processing.
|
51 |
+
- **HURA:** Generate HURA (Hexagonal Uniformly Redundant Arrays) patterns for sketches and masks
|
52 |
|
53 |
|
54 |
### Why You'll Love It
|
|
|
69 |
- **TRELLIS Depth & 3D Model Generation:** Create detailed depth maps and 3D models, complete with GLB and Gaussian file extraction.
|
70 |
- **Add Margins:** Fine-tune image margins for a professional finish.
|
71 |
- **Sketch Pad Integration:** Use the built-in sketch pad to edit images on the fly before processing.
|
72 |
+
- **HURA:** Generate HURA (Hexagonal Uniformly Redundant Arrays) patterns for sketches and masks
|
73 |
|
74 |
Join the hive and start creating with HexaGrid Creator today!
|
75 |
|
app.py
CHANGED
@@ -1,4 +1,4 @@
|
|
1 |
-
from ast import
|
2 |
from tokenize import String
|
3 |
import gradio as gr
|
4 |
from numba.core.types import string
|
@@ -25,6 +25,7 @@ from trellis.pipelines import TrellisImageTo3DPipeline
|
|
25 |
from trellis.representations import Gaussian, MeshExtractResult
|
26 |
from trellis.utils import render_utils, postprocessing_utils
|
27 |
from pathlib import Path
|
|
|
28 |
|
29 |
import logging
|
30 |
#logging.getLogger("transformers.modeling_utils").setLevel(logging.ERROR)
|
@@ -746,6 +747,7 @@ def on_input_image_change(image_path):
|
|
746 |
return None, gr.update()
|
747 |
img, img_path = convert_to_rgba_png(image_path)
|
748 |
width, height = img.size
|
|
|
749 |
return [img_path, gr.update(width=width, height=height)]
|
750 |
|
751 |
def update_sketch_dimensions(input_image, sketch_image):
|
@@ -761,18 +763,21 @@ def update_sketch_dimensions(input_image, sketch_image):
|
|
761 |
return [sk_img, gr.update()]
|
762 |
|
763 |
|
764 |
-
def composite_with_control_sync(input_image,
|
|
|
765 |
# Load the images using open_image() if they are provided as file paths.
|
766 |
-
|
767 |
-
|
768 |
-
|
|
|
|
|
769 |
|
770 |
-
# Resize
|
771 |
-
if in_img.size !=
|
772 |
-
|
773 |
|
774 |
# Now composite using the original alpha_composite_with_control function.
|
775 |
-
result_img = alpha_composite_with_control(in_img,
|
776 |
return result_img
|
777 |
|
778 |
def replace_with_sketch_image(sketch_image, replace_current_lut_example_img: bool = False):
|
@@ -1168,14 +1173,16 @@ with gr.Blocks(css_paths="style_20250314.css", title=title, theme='Surn/beeuty',
|
|
1168 |
HexaGrid Creator is a web-based application that allows you to apply a hexagon grid overlay to any image. You can customize the size, color, and opacity of the hexagons, as well as the background and border colors. The result is a visually striking image that looks like it was made from hexagonal tiles!
|
1169 |
|
1170 |
### What Can You Do?
|
1171 |
-
- **Generate Hexagon Grids:** Create
|
1172 |
-
- **AI-Powered Image Generation:** Use advanced AI models to generate images
|
1173 |
-
- **Color Exclusion:**
|
1174 |
-
- **Interactive Customization:** Adjust
|
1175 |
-
- **Depth
|
1176 |
-
- **Image Filter [
|
1177 |
-
- **Pre-rendered Maps:** Access a library of
|
1178 |
-
- **Add Margins:** Add customizable margins around your images for a polished
|
|
|
|
|
1179 |
|
1180 |
### Why You'll Love It
|
1181 |
- **Fun and Easy to Use:** With an intuitive interface and real-time previews, creating hexagon grids has never been this fun!
|
@@ -1194,6 +1201,8 @@ with gr.Blocks(css_paths="style_20250314.css", title=title, theme='Surn/beeuty',
|
|
1194 |
- **Image Filter [Look-Up Table (LUT)] Application:** Apply filters (LUTs) to your images for color grading and enhancement.
|
1195 |
- **Depth and 3D Model Generation:** Create depth maps and 3D models from your images for enhanced visualization.
|
1196 |
- **Add Margins:** Customize margins around your images for a polished finish.
|
|
|
|
|
1197 |
|
1198 |
Join the hive and start creating with HexaGrid Creator today!
|
1199 |
|
@@ -1300,11 +1309,32 @@ with gr.Blocks(css_paths="style_20250314.css", title=title, theme='Surn/beeuty',
|
|
1300 |
composite_button = gr.Button("Composite to Input Image", elem_classes="solid")
|
1301 |
composite_sketch_button = gr.Button("Composite to Sketh", elem_classes="solid")
|
1302 |
with gr.Accordion("Blur", open = False):
|
1303 |
-
with gr.Row():
|
1304 |
blur_amount = gr.Slider(label="Blur Amount", minimum=0, maximum=100, value=5, interactive=True)
|
1305 |
with gr.Row():
|
1306 |
blur_button = gr.Button("Blur Input Image", elem_classes="solid")
|
1307 |
blur_sketch_button = gr.Button("Blur Sketch", elem_classes="solid")
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1308 |
with gr.Tabs(selected="hex_gen") as input_tabs:
|
1309 |
with gr.Tab("HexaGrid Generation", id="hex_gen") as hexa_gen_tab:
|
1310 |
with gr.Column(elem_classes="outline-important"):
|
|
|
1 |
+
#from ast import Constant
|
2 |
from tokenize import String
|
3 |
import gradio as gr
|
4 |
from numba.core.types import string
|
|
|
25 |
from trellis.representations import Gaussian, MeshExtractResult
|
26 |
from trellis.utils import render_utils, postprocessing_utils
|
27 |
from pathlib import Path
|
28 |
+
import utils.hex_hura as hex_hura
|
29 |
|
30 |
import logging
|
31 |
#logging.getLogger("transformers.modeling_utils").setLevel(logging.ERROR)
|
|
|
747 |
return None, gr.update()
|
748 |
img, img_path = convert_to_rgba_png(image_path)
|
749 |
width, height = img.size
|
750 |
+
hex_components["set_height_width_hura_image"](width, height)
|
751 |
return [img_path, gr.update(width=width, height=height)]
|
752 |
|
753 |
def update_sketch_dimensions(input_image, sketch_image):
|
|
|
763 |
return [sk_img, gr.update()]
|
764 |
|
765 |
|
766 |
+
def composite_with_control_sync(input_image, new_image, slider_value):
|
767 |
+
|
768 |
# Load the images using open_image() if they are provided as file paths.
|
769 |
+
new_img_path, _ = get_image_from_dict(new_image)
|
770 |
+
if input_image is None:
|
771 |
+
return new_img_path
|
772 |
+
in_img = open_image(input_image) if isinstance(input_image, (dict,str)) else input_image
|
773 |
+
new_img = open_image(new_img_path)
|
774 |
|
775 |
+
# Resize new image if dimensions don't match input image.
|
776 |
+
if in_img.size != new_img.size:
|
777 |
+
new_img = new_img.resize(in_img.size, Image.LANCZOS)
|
778 |
|
779 |
# Now composite using the original alpha_composite_with_control function.
|
780 |
+
result_img = alpha_composite_with_control(in_img, new_img, slider_value)
|
781 |
return result_img
|
782 |
|
783 |
def replace_with_sketch_image(sketch_image, replace_current_lut_example_img: bool = False):
|
|
|
1173 |
HexaGrid Creator is a web-based application that allows you to apply a hexagon grid overlay to any image. You can customize the size, color, and opacity of the hexagons, as well as the background and border colors. The result is a visually striking image that looks like it was made from hexagonal tiles!
|
1174 |
|
1175 |
### What Can You Do?
|
1176 |
+
- **Generate Hexagon Grids:** Create stunning hexagon, square, or triangle grid overlays with fully customizable parameters.
|
1177 |
+
- **AI-Powered Image Generation:** Use advanced AI models and LoRA weights to generate images from your prompts and apply unique grid overlays.
|
1178 |
+
- **Color Exclusion:** Pick and exclude specific colors from your hexagon grid for improved clarity.
|
1179 |
+
- **Interactive Customization:** Adjust grid size, border size, rotation, background color, and more—all in real-time.
|
1180 |
+
- **Depth & 3D Model Generation:** Generate depth maps and interactive 3D models (with GLB and Gaussian extraction) for enhanced visualization.
|
1181 |
+
- **Image Filter [LUT] Application:** Apply advanced color grading filters with live previews using LUT files.
|
1182 |
+
- **Pre-rendered Maps:** Access a library of ready-to-use hexagon maps for quick customization.
|
1183 |
+
- **Add Margins:** Add customizable margins around your images for a polished print-ready look.
|
1184 |
+
- **Sketch Pad Integration:** Directly sketch on images to modify or replace them before further processing.
|
1185 |
+
- **HURA:** Generate HURA (Hexagonal Uniformly Redundant Arrays) patterns for sketches and masks
|
1186 |
|
1187 |
### Why You'll Love It
|
1188 |
- **Fun and Easy to Use:** With an intuitive interface and real-time previews, creating hexagon grids has never been this fun!
|
|
|
1201 |
- **Image Filter [Look-Up Table (LUT)] Application:** Apply filters (LUTs) to your images for color grading and enhancement.
|
1202 |
- **Depth and 3D Model Generation:** Create depth maps and 3D models from your images for enhanced visualization.
|
1203 |
- **Add Margins:** Customize margins around your images for a polished finish.
|
1204 |
+
- **Sketch Pad Integration:** Use the built-in sketch pad to edit images on the fly before processing.
|
1205 |
+
- **HURA:** Generate HURA (Hexagonal Uniformly Redundant Arrays) patterns for sketches and masks
|
1206 |
|
1207 |
Join the hive and start creating with HexaGrid Creator today!
|
1208 |
|
|
|
1309 |
composite_button = gr.Button("Composite to Input Image", elem_classes="solid")
|
1310 |
composite_sketch_button = gr.Button("Composite to Sketh", elem_classes="solid")
|
1311 |
with gr.Accordion("Blur", open = False):
|
1312 |
+
with gr.Row():
|
1313 |
blur_amount = gr.Slider(label="Blur Amount", minimum=0, maximum=100, value=5, interactive=True)
|
1314 |
with gr.Row():
|
1315 |
blur_button = gr.Button("Blur Input Image", elem_classes="solid")
|
1316 |
blur_sketch_button = gr.Button("Blur Sketch", elem_classes="solid")
|
1317 |
+
with gr.Accordion("Generate Hex Hura Background", open = False):
|
1318 |
+
hex_components = hex_hura.render()
|
1319 |
+
with gr.Row():
|
1320 |
+
hura_alpha_composite_slider = gr.Slider(0,100,50,0.5, label="HURA Transparancy", elem_id="hura_alpha_composite_slider", interactive=True)
|
1321 |
+
with gr.Row():
|
1322 |
+
hura_button = gr.Button("Composite Input Image", elem_classes="solid")
|
1323 |
+
hura_sketch_button = gr.Button("Composite Sketh Image", elem_classes="solid")
|
1324 |
+
|
1325 |
+
hura_sketch_button.click(
|
1326 |
+
fn=composite_with_control_sync,
|
1327 |
+
inputs=[sketch_image, hex_components["target_image"], hura_alpha_composite_slider],
|
1328 |
+
outputs=[sketch_image],
|
1329 |
+
scroll_to_output=True
|
1330 |
+
)
|
1331 |
+
hura_button.click(
|
1332 |
+
fn=composite_with_control_sync,
|
1333 |
+
inputs=[input_image, hex_components["target_image"], hura_alpha_composite_slider],
|
1334 |
+
outputs=[input_image],
|
1335 |
+
scroll_to_output=True
|
1336 |
+
)
|
1337 |
+
|
1338 |
with gr.Tabs(selected="hex_gen") as input_tabs:
|
1339 |
with gr.Tab("HexaGrid Generation", id="hex_gen") as hexa_gen_tab:
|
1340 |
with gr.Column(elem_classes="outline-important"):
|
utils/hex_hura.py
CHANGED
@@ -1,12 +1,109 @@
|
|
|
|
|
|
|
|
1 |
from PIL import Image
|
2 |
import math
|
|
|
|
|
3 |
|
4 |
-
|
5 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
6 |
|
7 |
-
# Define the smoothstep function for vignette effect
|
8 |
def smoothstep(edge0, edge1, x):
|
9 |
-
"""
|
|
|
|
|
|
|
10 |
if edge0 == edge1:
|
11 |
return 0.0 if x < edge0 else 1.0
|
12 |
t = min(max((x - edge0) / (edge1 - edge0), 0.0), 1.0)
|
@@ -15,16 +112,24 @@ def smoothstep(edge0, edge1, x):
|
|
15 |
# Define the hexagon function to compute coordinates
|
16 |
def hexagon(p):
|
17 |
"""
|
18 |
-
Compute hexagon coordinates and
|
19 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
20 |
"""
|
21 |
# Transform to hexagonal coordinate system
|
22 |
-
q = (p[0] * 2.0 *
|
23 |
pi = (math.floor(q[0]), math.floor(q[1]))
|
24 |
pf = (q[0] - pi[0], q[1] - pi[1])
|
25 |
-
|
26 |
-
ca = 1.0 if
|
27 |
-
cb = 1.0 if
|
28 |
ma = (1.0 if pf[1] >= pf[0] else 0.0, 1.0 if pf[0] >= pf[1] else 0.0)
|
29 |
temp = (
|
30 |
1.0 - pf[1] + ca * (pf[0] + pf[1] - 1.0) + cb * (pf[1] - 2.0 * pf[0]),
|
@@ -38,38 +143,41 @@ def hexagon(p):
|
|
38 |
h_xy = (pi[0] + ca - cb * ma[0], pi[1] + ca - cb * ma[1])
|
39 |
return (h_xy[0], h_xy[1], e, f)
|
40 |
|
41 |
-
|
|
|
42 |
"""
|
43 |
-
Generate
|
44 |
-
|
45 |
-
Parameters:
|
46 |
-
p (tuple): A 2-tuple (x, y) of coordinates.
|
47 |
-
r (float): Multiplier for p[0]. Default is 1.0.
|
48 |
-
v (float): Modulus value controlling the pattern frequency. Default is 10.0.
|
49 |
|
|
|
|
|
|
|
50 |
Returns:
|
51 |
-
float: 1.0
|
52 |
-
|
53 |
-
|
54 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
55 |
rz = 1.0
|
56 |
-
for i in range(1, int(v/2)):
|
57 |
if math.isclose(math.fmod(i * i, v), l, abs_tol=1e-6):
|
58 |
rz = 0.0
|
59 |
break
|
60 |
return rz
|
61 |
|
62 |
-
# Define the color palette
|
63 |
-
default_colors = [
|
64 |
-
(255, 0, 0), # Red
|
65 |
-
(0, 255, 0), # Green
|
66 |
-
(0, 0, 255) # Blue
|
67 |
-
]
|
68 |
-
|
69 |
# Generate the image with colorful_hexagonal pattern
|
70 |
-
def generate_image_color(width, height, colors=
|
71 |
"""Generate an RGB image with a colorful hexagonal pattern."""
|
72 |
img = Image.new('RGB', (width, height))
|
|
|
|
|
|
|
|
|
73 |
aspect = width / height
|
74 |
for j in range(height):
|
75 |
for i in range(width):
|
@@ -81,14 +189,15 @@ def generate_image_color(width, height, colors=default_colors):
|
|
81 |
p_y = q_y * 2.0 - 1.0
|
82 |
p = (p_x, p_y)
|
83 |
# Scale coordinates for pattern frequency
|
84 |
-
h = hexagon((p[0] *
|
85 |
h_xy = (int(h[0]), int(h[1]))
|
86 |
# Assign color based on hexagon coordinates
|
87 |
-
|
|
|
88 |
col = colors[color_index]
|
89 |
# Apply vignette effect
|
90 |
q = (q_x * 2.0 - 1.0, q_y * 2.0 - 1.0)
|
91 |
-
vignette = smoothstep(
|
92 |
col = tuple(int(c * vignette) for c in col)
|
93 |
# Set the pixel color
|
94 |
img.putpixel((i, j), col)
|
@@ -104,7 +213,7 @@ def generate_image_grayscale(width, height):
|
|
104 |
p_x = (q_x * 2.0 - 1.0) * aspect
|
105 |
p_y = q_y * 2.0 - 1.0
|
106 |
p = (p_x, p_y)
|
107 |
-
h = hexagon((p[0] *
|
108 |
rz = ura(h[:2])
|
109 |
smooth = smoothstep(-0.2, 0.13, h[2])
|
110 |
if rz > 0.5:
|
@@ -112,16 +221,223 @@ def generate_image_grayscale(width, height):
|
|
112 |
else:
|
113 |
col = 1.0 - smooth
|
114 |
q = (q_x * 2.0 - 1.0, q_y * 2.0 - 1.0)
|
115 |
-
vignette = smoothstep(
|
116 |
col *= vignette
|
117 |
-
color = int(col * 255)
|
118 |
img.putpixel((i, j), (color, color, color))
|
119 |
return img
|
120 |
|
121 |
-
|
122 |
-
|
123 |
-
|
124 |
-
|
125 |
-
|
126 |
-
|
127 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
# HURA (Hexagonal Uniformly Redundant Arrays) are used for aperture masks and imaging, and encoding.
|
2 |
+
# check it out https://ntrs.nasa.gov/citations/19850026627
|
3 |
+
# by Surn (Charles Fettinger) 4/5/2025
|
4 |
from PIL import Image
|
5 |
import math
|
6 |
+
import gradio as gr
|
7 |
+
from tempfile import NamedTemporaryFile
|
8 |
|
9 |
+
from transformers.models.deprecated.vit_hybrid import image_processing_vit_hybrid
|
10 |
+
import utils.constants as constants
|
11 |
+
import utils.color_utils as color_utils
|
12 |
+
|
13 |
+
|
14 |
+
class HuraConfig:
|
15 |
+
"""Configuration for Hexagonal Uniformly Redundant Array pattern generation."""
|
16 |
+
|
17 |
+
def __init__(self):
|
18 |
+
# Core parameters
|
19 |
+
self.v = 139 # Prime number parameter (affects pattern complexity)
|
20 |
+
self.r = 42 # Pattern frequency parameter
|
21 |
+
self.version = "0.2.0"
|
22 |
+
|
23 |
+
# Pattern generation constants
|
24 |
+
self.hex_ratio = 0.5773503 # sqrt(3)/3
|
25 |
+
self.pattern_scale = 21.0 # Controls pattern frequency
|
26 |
+
self.vignette_inner = 0.97
|
27 |
+
self.vignette_outer = 1.01
|
28 |
+
|
29 |
+
# Colors
|
30 |
+
self.default_colors = [
|
31 |
+
(255, 0, 0), # Red
|
32 |
+
(0, 255, 0), # Green
|
33 |
+
(0, 0, 255) # Blue
|
34 |
+
]
|
35 |
+
|
36 |
+
# Prime number calculation
|
37 |
+
self.prime_range_start = 1
|
38 |
+
self.prime_range_end = 5001
|
39 |
+
self._primes_cache = None # Will be lazily loaded
|
40 |
+
|
41 |
+
def get_v(self):
|
42 |
+
"""Get the current V parameter value."""
|
43 |
+
return self.v
|
44 |
+
|
45 |
+
def set_v(self, value):
|
46 |
+
"""Set the V parameter value."""
|
47 |
+
if not isinstance(value, (int, float)) or value < 1:
|
48 |
+
raise ValueError(f"V value must be a positive float, got {value}")
|
49 |
+
self.v = value
|
50 |
+
|
51 |
+
def get_r(self):
|
52 |
+
"""Get the current R parameter value."""
|
53 |
+
return self.r
|
54 |
+
|
55 |
+
def set_r(self, value):
|
56 |
+
"""Set the R parameter value."""
|
57 |
+
if not isinstance(value, (int, float)) or value < 1:
|
58 |
+
raise ValueError(f"R value must be a positive float, got {value}")
|
59 |
+
self.r = value
|
60 |
+
|
61 |
+
def get_primes(self):
|
62 |
+
"""Get or calculate the list of primes in the configured range."""
|
63 |
+
if self._primes_cache is None:
|
64 |
+
self._primes_cache = get_primes_in_range(self.prime_range_start, self.prime_range_end)
|
65 |
+
return self._primes_cache
|
66 |
+
|
67 |
+
def find_nearest_prime(self, value):
|
68 |
+
"""Find the nearest prime number to the given value."""
|
69 |
+
return min(self.get_primes(), key=lambda x: abs(x - value))
|
70 |
+
|
71 |
+
def reset_colors(self):
|
72 |
+
"""Reset default colors to original values."""
|
73 |
+
self.default_colors = [
|
74 |
+
(255, 0, 0), # Red
|
75 |
+
(0, 255, 0), # Green
|
76 |
+
(0, 0, 255) # Blue
|
77 |
+
]
|
78 |
+
return self.default_colors
|
79 |
+
|
80 |
+
# Initialize the HuraConfig instance
|
81 |
+
config = HuraConfig()
|
82 |
+
|
83 |
+
# For backwards compatibility - consider deprecating these
|
84 |
+
__version__ = config.version
|
85 |
+
_V = config.v
|
86 |
+
_R = config.r
|
87 |
+
|
88 |
+
def get_v():
|
89 |
+
return config.get_v()
|
90 |
+
|
91 |
+
def set_v(val):
|
92 |
+
config.set_v(val)
|
93 |
+
|
94 |
+
def get_r():
|
95 |
+
return config.get_r()
|
96 |
+
|
97 |
+
def set_r(val):
|
98 |
+
config.set_r(val)
|
99 |
+
|
100 |
+
state_colors = []
|
101 |
|
|
|
102 |
def smoothstep(edge0, edge1, x):
|
103 |
+
"""
|
104 |
+
Smoothstep function for vignette effect.
|
105 |
+
Smoothly interpolate between edge0 and edge1 based on x.
|
106 |
+
"""
|
107 |
if edge0 == edge1:
|
108 |
return 0.0 if x < edge0 else 1.0
|
109 |
t = min(max((x - edge0) / (edge1 - edge0), 0.0), 1.0)
|
|
|
112 |
# Define the hexagon function to compute coordinates
|
113 |
def hexagon(p):
|
114 |
"""
|
115 |
+
Compute hexagon coordinates and metrics for point p.
|
116 |
+
|
117 |
+
Args:
|
118 |
+
p (tuple): Normalized point (x,y) in [-aspect,aspect] � [-1,1] range
|
119 |
+
|
120 |
+
Returns:
|
121 |
+
tuple: (hex_x, hex_y, edge_distance, center_distance)
|
122 |
+
- hex_x, hex_y: Integer coordinates of the hexagon cell
|
123 |
+
- edge_distance: Distance to nearest edge (0-1)
|
124 |
+
- center_distance: Distance to cell center (0-1)
|
125 |
"""
|
126 |
# Transform to hexagonal coordinate system
|
127 |
+
q = (p[0] * 2.0 * config.hex_ratio, p[1] + p[0] * config.hex_ratio)
|
128 |
pi = (math.floor(q[0]), math.floor(q[1]))
|
129 |
pf = (q[0] - pi[0], q[1] - pi[1])
|
130 |
+
mod_val = (pi[0] + pi[1]) % 3.0 # renamed from v
|
131 |
+
ca = 1.0 if mod_val >= 1.0 else 0.0
|
132 |
+
cb = 1.0 if mod_val >= 2.0 else 0.0
|
133 |
ma = (1.0 if pf[1] >= pf[0] else 0.0, 1.0 if pf[0] >= pf[1] else 0.0)
|
134 |
temp = (
|
135 |
1.0 - pf[1] + ca * (pf[0] + pf[1] - 1.0) + cb * (pf[1] - 2.0 * pf[0]),
|
|
|
143 |
h_xy = (pi[0] + ca - cb * ma[0], pi[1] + ca - cb * ma[1])
|
144 |
return (h_xy[0], h_xy[1], e, f)
|
145 |
|
146 |
+
# important note: this is not a true hexagonal pattern, but a hexagonal grid
|
147 |
+
def ura(p):
|
148 |
"""
|
149 |
+
Generate binary pattern value based on Uniformly Redundant Array algorithm.
|
|
|
|
|
|
|
|
|
|
|
150 |
|
151 |
+
Args:
|
152 |
+
p (tuple): Hexagon coordinates (x,y)
|
153 |
+
|
154 |
Returns:
|
155 |
+
float: 1.0 for pattern, 0.0 for background
|
156 |
+
|
157 |
+
future consideration.. add animation
|
158 |
+
#ifdef INCREMENT_R
|
159 |
+
float l = mod(p.y + floor(time*1.5)*p.x, v);
|
160 |
+
#else
|
161 |
+
float l = mod(p.y + r*p.x, v);
|
162 |
+
"""
|
163 |
+
r = get_r()
|
164 |
+
v = get_v()
|
165 |
+
l = math.fmod(abs(p[1]) + r * abs(p[0]), v)
|
166 |
rz = 1.0
|
167 |
+
for i in range(1, int(v/2) + 1):
|
168 |
if math.isclose(math.fmod(i * i, v), l, abs_tol=1e-6):
|
169 |
rz = 0.0
|
170 |
break
|
171 |
return rz
|
172 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
173 |
# Generate the image with colorful_hexagonal pattern
|
174 |
+
def generate_image_color(width, height, colors=None):
|
175 |
"""Generate an RGB image with a colorful hexagonal pattern."""
|
176 |
img = Image.new('RGB', (width, height))
|
177 |
+
if colors is None or colors == []:
|
178 |
+
colors = config.default_colors
|
179 |
+
r = config.get_r()
|
180 |
+
v = config.get_v()
|
181 |
aspect = width / height
|
182 |
for j in range(height):
|
183 |
for i in range(width):
|
|
|
189 |
p_y = q_y * 2.0 - 1.0
|
190 |
p = (p_x, p_y)
|
191 |
# Scale coordinates for pattern frequency
|
192 |
+
h = hexagon((p[0] * config.pattern_scale, p[1] * config.pattern_scale))
|
193 |
h_xy = (int(h[0]), int(h[1]))
|
194 |
# Assign color based on hexagon coordinates
|
195 |
+
rz = math.fmod(abs(h_xy[0]) + r * abs(h_xy[1]),v)
|
196 |
+
color_index = int(rz % len(colors))
|
197 |
col = colors[color_index]
|
198 |
# Apply vignette effect
|
199 |
q = (q_x * 2.0 - 1.0, q_y * 2.0 - 1.0)
|
200 |
+
vignette = smoothstep(config.vignette_outer, config.vignette_inner, max(abs(q[0]), abs(q[1])))
|
201 |
col = tuple(int(c * vignette) for c in col)
|
202 |
# Set the pixel color
|
203 |
img.putpixel((i, j), col)
|
|
|
213 |
p_x = (q_x * 2.0 - 1.0) * aspect
|
214 |
p_y = q_y * 2.0 - 1.0
|
215 |
p = (p_x, p_y)
|
216 |
+
h = hexagon((p[0] * config.pattern_scale, p[1] * config.pattern_scale))
|
217 |
rz = ura(h[:2])
|
218 |
smooth = smoothstep(-0.2, 0.13, h[2])
|
219 |
if rz > 0.5:
|
|
|
221 |
else:
|
222 |
col = 1.0 - smooth
|
223 |
q = (q_x * 2.0 - 1.0, q_y * 2.0 - 1.0)
|
224 |
+
vignette = smoothstep(config.vignette_outer, config.vignette_inner, max(abs(q[0]), abs(q[1])))
|
225 |
col *= vignette
|
226 |
+
color = int(abs(col) * 255)
|
227 |
img.putpixel((i, j), (color, color, color))
|
228 |
return img
|
229 |
|
230 |
+
def get_primes_in_range(start: int, end: int) -> list:
|
231 |
+
"""
|
232 |
+
Return a list of prime numbers between start and end (inclusive).
|
233 |
+
|
234 |
+
Uses the Sieve of Eratosthenes for efficiency.
|
235 |
+
|
236 |
+
Parameters:
|
237 |
+
start (int): The starting number of the range.
|
238 |
+
end (int): The ending number of the range.
|
239 |
+
|
240 |
+
Returns:
|
241 |
+
list: A list of prime numbers between start and end.
|
242 |
+
"""
|
243 |
+
if end < 2:
|
244 |
+
return []
|
245 |
+
sieve = [True] * (end + 1)
|
246 |
+
sieve[0] = sieve[1] = False
|
247 |
+
for i in range(2, int(end ** 0.5) + 1):
|
248 |
+
if sieve[i]:
|
249 |
+
for j in range(i * i, end + 1, i):
|
250 |
+
sieve[j] = False
|
251 |
+
return [i for i in range(start, end + 1) if sieve[i]]
|
252 |
+
|
253 |
+
def find_nearest_prime(value):
|
254 |
+
"""Find the closest prime number to the given value."""
|
255 |
+
return config.find_nearest_prime(value)
|
256 |
+
|
257 |
+
def generate_pattern_background(pattern_type="color", width=1024, height=768, v_value=_V, r_value=_R, colors=None):
|
258 |
+
# Generate a hexagonal pattern image with the given parameters.
|
259 |
+
# Do not pass gr.State values here
|
260 |
+
# Set the parameters
|
261 |
+
set_v(v_value)
|
262 |
+
set_r(r_value)
|
263 |
+
print(f"Generating pattern with V: {v_value}, R: {r_value}, Colors: {colors}")
|
264 |
+
color_count = 3
|
265 |
+
|
266 |
+
if pattern_type == "color":
|
267 |
+
if colors is None:
|
268 |
+
img = generate_image_color(width, height)
|
269 |
+
else:
|
270 |
+
img = generate_image_color(width, height, colors)
|
271 |
+
color_count = len(colors)
|
272 |
+
else: # grayscale
|
273 |
+
img = generate_image_grayscale(width, height)
|
274 |
+
color_count = 1
|
275 |
+
|
276 |
+
# Save to temporary file and return path
|
277 |
+
with NamedTemporaryFile(delete=False,prefix=f"hura_{str(color_count)}_v{str(v_value)}_r{str(r_value)}_", suffix=".png") as tmp:
|
278 |
+
img.save(tmp.name, format="PNG")
|
279 |
+
constants.temp_files.append(tmp.name)
|
280 |
+
return tmp.name
|
281 |
+
|
282 |
+
|
283 |
+
def create_color_swatch_html(colors):
|
284 |
+
"""Create HTML for displaying color swatches"""
|
285 |
+
swatches = ''.join(
|
286 |
+
f'<div style="width: 50px; height: 50px; background-color: rgb{c}; '
|
287 |
+
f'border: 1px solid #ccc;"></div>'
|
288 |
+
for c in colors
|
289 |
+
)
|
290 |
+
return f'<div style="display: flex; gap: 10px;">{swatches}</div>'
|
291 |
+
|
292 |
+
def _add_color(color, color_list):
|
293 |
+
if color is None:
|
294 |
+
return color_list, color_list, ""
|
295 |
+
|
296 |
+
# Convert hex color to RGB
|
297 |
+
rgb_color = color_utils.hex_to_rgb(color)
|
298 |
+
color_list = color_list + [rgb_color]
|
299 |
+
|
300 |
+
# Create HTML to display color swatches
|
301 |
+
html = create_color_swatch_html(color_list)
|
302 |
+
return color_list, html
|
303 |
+
|
304 |
+
def _init_colors():
|
305 |
+
"""Initialize the color swatches HTML display based on config colors"""
|
306 |
+
updated_list = list(config.default_colors)
|
307 |
+
# Rebuild the HTML swatches from the updated list
|
308 |
+
html = create_color_swatch_html(updated_list)
|
309 |
+
return html
|
310 |
+
|
311 |
+
def reset_colors():
|
312 |
+
"""Reset the color list to the default colors."""
|
313 |
+
colors = config.reset_colors()
|
314 |
+
html = create_color_swatch_html(colors)
|
315 |
+
return colors, html
|
316 |
+
|
317 |
+
def _generate_pattern_from_state(pt, width, height, v_val, r_val, colors_list):
|
318 |
+
# colors_list is automatically the raw value from the gr.State input
|
319 |
+
return generate_pattern_background(pt, width, height, v_val, r_val, colors_list)
|
320 |
+
|
321 |
+
def render() -> dict:
|
322 |
+
"""
|
323 |
+
Renders a colorful or grayscale hexagonal pattern creation interface
|
324 |
+
|
325 |
+
Returns:
|
326 |
+
dict: A dictionary containing:
|
327 |
+
- target_image (gr.Image): The generated pattern image component
|
328 |
+
- run_generate_hex_pattern (function): Function to generate a pattern with given dimensions
|
329 |
+
- set_height_width_hura_image (function): Function to update the slider values
|
330 |
+
- width_slider (gr.Slider): The width slider component
|
331 |
+
- height_slider (gr.Slider): The height slider component
|
332 |
+
"""
|
333 |
+
|
334 |
+
# Initialize state
|
335 |
+
global state_colors
|
336 |
+
state_colors = gr.State(config.default_colors)
|
337 |
+
init_colors_html = _init_colors()
|
338 |
+
|
339 |
+
|
340 |
+
target_image = gr.Image(label="Generated Pattern", type="filepath")
|
341 |
+
with gr.Row():
|
342 |
+
pattern_type = gr.Radio(
|
343 |
+
label="Pattern Type",
|
344 |
+
choices=["color", "grayscale"],
|
345 |
+
value="grayscale",
|
346 |
+
type="value"
|
347 |
+
)
|
348 |
+
with gr.Column():
|
349 |
+
with gr.Row():
|
350 |
+
width_slider = gr.Slider(minimum=256, maximum=2560, value=1024, label="Width", step=8)
|
351 |
+
height_slider = gr.Slider(minimum=256, maximum=2560, value=768, label="Height", step=8)
|
352 |
+
v_value_slider = gr.Slider(minimum=config.prime_range_start, maximum=config.prime_range_end, value=config.v, label="V Value (Prime Number)", step=1)
|
353 |
+
r_value_slider = gr.Slider(minimum=1, maximum=100, value=config.r, label="R Value")
|
354 |
+
show_borders_chbox = gr.Checkbox(label="Show Borders", value=True)
|
355 |
+
|
356 |
+
with gr.Row(visible=False) as color_row:
|
357 |
+
color_picker = gr.ColorPicker(label="Pick a Color")
|
358 |
+
add_button = gr.Button("Add Color")
|
359 |
+
with gr.Column():
|
360 |
+
color_display = gr.HTML(label="Color Swatches", value=init_colors_html)
|
361 |
+
with gr.Row():
|
362 |
+
delete_colors_button = gr.Button("Delete Colors")
|
363 |
+
reset_colors_button = gr.Button("Reset Colors")
|
364 |
+
with gr.Row():
|
365 |
+
generate_button = gr.Button("Generate Pattern")
|
366 |
+
|
367 |
+
|
368 |
+
def run_generate_hex_pattern(width: int, height: int) -> str:
|
369 |
+
"""
|
370 |
+
Generate a colored hexagonal pattern image with the given width and height.
|
371 |
+
Uses default V and R values and the default color palette.
|
372 |
+
|
373 |
+
Returns:
|
374 |
+
str: The filepath of the generated image.
|
375 |
+
"""
|
376 |
+
global state_colors
|
377 |
+
width_slider.value=width
|
378 |
+
height_slider.value=height
|
379 |
+
gr.update()
|
380 |
+
# Use the current _V, _R, and default_colors
|
381 |
+
filepath = generate_pattern_background(
|
382 |
+
pattern_type="color",
|
383 |
+
width=width,
|
384 |
+
height=height,
|
385 |
+
v_value=get_v(),
|
386 |
+
r_value=get_r(),
|
387 |
+
colors=state_colors.value
|
388 |
+
)
|
389 |
+
return filepath
|
390 |
+
|
391 |
+
def set_height_width_hura_image(width, height) -> None:
|
392 |
+
"""
|
393 |
+
Set the height and width of the image.
|
394 |
+
"""
|
395 |
+
width_slider.value=width
|
396 |
+
height_slider.value=height
|
397 |
+
gr.update()
|
398 |
+
|
399 |
+
|
400 |
+
pattern_type.change(
|
401 |
+
fn=lambda x: gr.update(visible=(x == "color")),
|
402 |
+
inputs=pattern_type,
|
403 |
+
outputs=color_row
|
404 |
+
)
|
405 |
+
add_button.click(
|
406 |
+
fn=_add_color,
|
407 |
+
inputs=[color_picker, state_colors],
|
408 |
+
outputs=[state_colors, color_display]
|
409 |
+
)
|
410 |
+
delete_colors_button.click(
|
411 |
+
fn=lambda x: ([], "<div>Add Colors</div>"),
|
412 |
+
inputs=[],
|
413 |
+
outputs=[state_colors, color_display]
|
414 |
+
)
|
415 |
+
reset_colors_button.click(
|
416 |
+
fn=reset_colors,
|
417 |
+
inputs=[],
|
418 |
+
outputs=[state_colors,color_display]
|
419 |
+
)
|
420 |
+
generate_button.click(
|
421 |
+
fn=_generate_pattern_from_state,
|
422 |
+
inputs=[pattern_type, width_slider, height_slider, v_value_slider, r_value_slider, state_colors],
|
423 |
+
outputs=target_image
|
424 |
+
)
|
425 |
+
|
426 |
+
v_value_slider.input(
|
427 |
+
lambda x: config.find_nearest_prime(x),
|
428 |
+
inputs=v_value_slider,
|
429 |
+
outputs=v_value_slider
|
430 |
+
)
|
431 |
+
v_value_slider.change(
|
432 |
+
lambda x: config.find_nearest_prime(x),
|
433 |
+
inputs=v_value_slider,
|
434 |
+
outputs=v_value_slider
|
435 |
+
)
|
436 |
+
|
437 |
+
return {
|
438 |
+
"target_image": target_image,
|
439 |
+
"run_generate_hex_pattern": run_generate_hex_pattern,
|
440 |
+
"set_height_width_hura_image": set_height_width_hura_image,
|
441 |
+
"width_slider": width_slider,
|
442 |
+
"height_slider": height_slider
|
443 |
+
}
|