Matejstein commited on
Commit
d03592d
·
verified ·
1 Parent(s): 127ca08

Delete app.py

Browse files
Files changed (1) hide show
  1. app.py +0 -325
app.py DELETED
@@ -1,325 +0,0 @@
1
- import spaces # MUST be line 1 for ZeroGPU
2
-
3
- # ---------------------------------------------------------------------------
4
- # GRADIO SCHEMA BUG PATCH (Prevents TypeError on boolean schema definitions)
5
- # ---------------------------------------------------------------------------
6
- import gradio_client.utils as gc_utils
7
-
8
- _orig_get_type = gc_utils.get_type
9
- def _safe_get_type(schema):
10
- if not isinstance(schema, dict):
11
- return "Any"
12
- return _orig_get_type(schema)
13
- gc_utils.get_type = _safe_get_type
14
-
15
- _orig_json_schema_to_python_type = gc_utils._json_schema_to_python_type
16
- def _safe_json_schema_to_python_type(schema, defs=None):
17
- if not isinstance(schema, dict):
18
- return "Any"
19
- return _orig_json_schema_to_python_type(schema, defs)
20
- gc_utils._json_schema_to_python_type = _safe_json_schema_to_python_type
21
- # ---------------------------------------------------------------------------
22
-
23
- import tempfile
24
- import os
25
- import random
26
- import torch
27
- import numpy as np
28
- from PIL import Image, ImageFilter, ImageEnhance
29
- import gradio as gr
30
- from diffusers import StableDiffusionInpaintPipeline
31
-
32
- pipe_inpaint = None
33
-
34
- def get_inpaint_pipeline():
35
- global pipe_inpaint
36
- if pipe_inpaint is None:
37
- pipe_inpaint = StableDiffusionInpaintPipeline.from_pretrained(
38
- "runwayml/stable-diffusion-inpainting",
39
- torch_dtype=torch.float16,
40
- safety_checker=None
41
- )
42
- pipe_inpaint.enable_attention_slicing()
43
- return pipe_inpaint
44
-
45
- def shift_image_50(pil_img, mode):
46
- """Shifts image +50% so outer edge seams land directly in the canvas center."""
47
- arr = np.array(pil_img.convert("RGB"))
48
- h, w, _ = arr.shape
49
- if "Horizontal" in mode:
50
- shifted = np.roll(arr, w // 2, axis=1)
51
- else:
52
- shifted = np.roll(np.roll(arr, h // 2, axis=0), w // 2, axis=1)
53
- return Image.fromarray(shifted)
54
-
55
- def unshift_image_50(pil_img, mode):
56
- """Shifts image back -50% so inpainted continuous joins become outer borders."""
57
- arr = np.array(pil_img.convert("RGB"))
58
- h, w, _ = arr.shape
59
- if "Horizontal" in mode:
60
- unshifted = np.roll(arr, -(w // 2), axis=1)
61
- else:
62
- unshifted = np.roll(np.roll(arr, -(h // 2), axis=0), -(w // 2), axis=1)
63
- return Image.fromarray(unshifted)
64
-
65
- def create_seam_mask(width, height, seam_pct=0.20, mode="Horizontal Only (Landscapes/City Facades)"):
66
- """Creates a targeted center mask over the seam join."""
67
- mask_arr = np.zeros((height, width), dtype=np.uint8)
68
- if "Horizontal" in mode:
69
- w_seam = int(width * seam_pct)
70
- x_start = (width - w_seam) // 2
71
- mask_arr[:, x_start:x_start + w_seam] = 255
72
- else:
73
- # Full 2D Crosshair (+) Mask
74
- w_seam = int(width * seam_pct)
75
- h_seam = int(height * seam_pct)
76
- x_start = (width - w_seam) // 2
77
- y_start = (height - h_seam) // 2
78
- mask_arr[:, x_start:x_start + w_seam] = 255
79
- mask_arr[y_start:y_start + h_seam, :] = 255
80
- return Image.fromarray(mask_arr)
81
-
82
- def apply_2d_border_harmonization(pil_img, border_px=8):
83
- """
84
- Intelligent 2D border harmonization:
85
- Smooths micro-gradient color/texture transitions along extreme top/bottom
86
- and left/right boundaries to ensure 100% zero-seam 2D tiling.
87
- """
88
- img = np.array(pil_img.convert("RGB")).astype(np.float32)
89
- h, w, c = img.shape
90
-
91
- # Smooth Top and Bottom edges together
92
- alpha_y = np.linspace(0, 1, border_px)[:, np.newaxis, np.newaxis]
93
- top_strip = img[:border_px, :, :]
94
- bot_strip = img[-border_px:, :, :]
95
- avg_h = (top_strip + bot_strip) / 2.0
96
-
97
- img[:border_px, :, :] = top_strip * alpha_y + avg_h * (1.0 - alpha_y)
98
- img[-border_px:, :, :] = bot_strip * (1.0 - alpha_y) + avg_h * alpha_y
99
-
100
- # Smooth Left and Right edges together
101
- alpha_x = np.linspace(0, 1, border_px)[np.newaxis, :, np.newaxis]
102
- left_strip = img[:, :border_px, :]
103
- right_strip = img[:, -border_px:, :]
104
- avg_w = (left_strip + right_strip) / 2.0
105
-
106
- img[:, :border_px, :] = left_strip * alpha_x + avg_w * (1.0 - alpha_x)
107
- img[:, -border_px:, :] = right_strip * (1.0 - alpha_x) + avg_w * alpha_x
108
-
109
- return Image.fromarray(np.clip(img, 0, 255).astype(np.uint8))
110
-
111
- def create_tiled_preview(pil_img, mode="Horizontal Only (Landscapes/City Facades)"):
112
- """Generates a 1x3 horizontal panorama or 3x3 grid preview."""
113
- preview_img = pil_img.copy()
114
- if preview_img.width > 1024:
115
- preview_img = preview_img.resize((1024, 1024), Image.Resampling.LANCZOS)
116
-
117
- w, h = preview_img.size
118
-
119
- if "Horizontal" in mode:
120
- tiled = Image.new("RGB", (w * 3, h))
121
- for c in range(3):
122
- tiled.paste(preview_img, (c * w, 0))
123
- else:
124
- # Full 3x3 Grid Preview for 2D mode
125
- tiled = Image.new("RGB", (w * 3, h * 3))
126
- for r in range(3):
127
- for c in range(3):
128
- tiled.paste(preview_img, (c * w, r * h))
129
-
130
- return tiled
131
-
132
- @spaces.GPU
133
- def generate_photorealistic_seamless(
134
- input_image, prompt, negative_prompt, tiling_mode,
135
- seam_width_pct, steps, guidance_scale, seed_val,
136
- sharpness_boost, resolution_str, ut99_quantize
137
- ):
138
- if input_image is None:
139
- return None, None, None, None, "⚠️ Please upload a source photo first."
140
-
141
- # Seed Selection logic
142
- if seed_val == -1 or seed_val is None:
143
- actual_seed = random.randint(0, 2147483647)
144
- else:
145
- actual_seed = int(seed_val)
146
-
147
- res_val = int(resolution_str.split("x")[0])
148
-
149
- pipeline = get_inpaint_pipeline()
150
- pipeline.to("cuda")
151
- generator = torch.Generator("cuda").manual_seed(actual_seed)
152
-
153
- original_photo = input_image.convert("RGB")
154
- proc_photo = original_photo.resize((512, 512), Image.Resampling.LANCZOS)
155
-
156
- user_steps = max(10, int(steps))
157
- user_guidance = float(guidance_scale)
158
-
159
- photo_prompt = prompt + ", raw photo, ultra realistic, sharp photographic detail, DSLR 8k, crisp texture, natural lighting"
160
- strict_negative = negative_prompt + ", oil painting, painting, illustration, drawing, 3d render, anime, smooth, blurry, artistic, cartoon, canvas texture, digital art, vector"
161
-
162
- # =========================================================================
163
- # UNTOUCHED HORIZONTAL CODE (Landscapes / City Facades)
164
- # =========================================================================
165
- if "Horizontal" in tiling_mode:
166
- shifted_photo = shift_image_50(proc_photo, tiling_mode)
167
- seam_mask_sharp = create_seam_mask(512, 512, seam_pct=seam_width_pct / 100.0, mode=tiling_mode)
168
- seam_mask_feathered = seam_mask_sharp.filter(ImageFilter.GaussianBlur(radius=10))
169
-
170
- inpainted_zone = pipeline(
171
- prompt=photo_prompt,
172
- negative_prompt=strict_negative,
173
- image=shifted_photo,
174
- mask_image=seam_mask_sharp,
175
- num_inference_steps=user_steps,
176
- guidance_scale=user_guidance,
177
- generator=generator
178
- ).images[0]
179
-
180
- seamless_result = Image.composite(inpainted_zone, shifted_photo, seam_mask_feathered)
181
-
182
- # =========================================================================
183
- # ENHANCED INTELLIGENT FULL 2D ENGINE (Cube / Pattern Tiling)
184
- # =========================================================================
185
- else:
186
- # 1. Shift canvas 50% along both X and Y axes
187
- shifted_photo_2d = shift_image_50(proc_photo, tiling_mode)
188
-
189
- # 2. Build 2D crosshair mask with wide Gaussian alpha feathering
190
- seam_mask_2d_sharp = create_seam_mask(512, 512, seam_pct=seam_width_pct / 100.0, mode=tiling_mode)
191
- seam_mask_2d_feathered = seam_mask_2d_sharp.filter(ImageFilter.GaussianBlur(radius=14))
192
-
193
- # 3. AI Inpaints central 2D cross join
194
- inpainted_2d_zone = pipeline(
195
- prompt=photo_prompt,
196
- negative_prompt=strict_negative,
197
- image=shifted_photo_2d,
198
- mask_image=seam_mask_2d_sharp,
199
- num_inference_steps=user_steps,
200
- guidance_scale=user_guidance,
201
- generator=generator
202
- ).images[0]
203
-
204
- blended_2d = Image.composite(inpainted_2d_zone, shifted_photo_2d, seam_mask_2d_feathered)
205
-
206
- # 4. UN-SHIFT -50% X and -50% Y so the inpainted cross becomes the seamless outer borders
207
- unrolled_2d = unshift_image_50(blended_2d, tiling_mode)
208
-
209
- # 5. Apply 2D Border Harmonization for zero-seam 3x3 grid tiling
210
- seamless_result = apply_2d_border_harmonization(unrolled_2d, border_px=8)
211
-
212
- # High-resolution output scaling
213
- scaled_result = seamless_result.resize((res_val, res_val), Image.Resampling.LANCZOS)
214
-
215
- if sharpness_boost > 1.0:
216
- enhancer = ImageEnhance.Sharpness(scaled_result)
217
- scaled_result = enhancer.enhance(sharpness_boost)
218
-
219
- tiled_preview = create_tiled_preview(scaled_result, mode=tiling_mode)
220
-
221
- # Export formats (.PCX / .BMP)
222
- temp_dir = tempfile.mkdtemp()
223
- pcx_path = os.path.join(temp_dir, f"ut99_texture_{res_val}.pcx")
224
- bmp_path = os.path.join(temp_dir, f"ut99_texture_{res_val}.bmp")
225
-
226
- if ut99_quantize:
227
- quantized = scaled_result.convert("P", palette=Image.Palette.ADAPTIVE, colors=256)
228
- quantized.save(pcx_path, format="PCX")
229
- quantized.save(bmp_path, format="BMP")
230
- display_img = quantized.convert("RGB")
231
- else:
232
- scaled_result.save(pcx_path, format="PCX")
233
- scaled_result.save(bmp_path, format="BMP")
234
- display_img = scaled_result
235
-
236
- status_msg = f"✅ Photorealistic Seamless Complete | Mode: {tiling_mode} | Seed: {actual_seed} | Res: {res_val}x{res_val}"
237
- return display_img, tiled_preview, pcx_path, bmp_path, status_msg
238
-
239
- # Gradio Interface
240
- with gr.Blocks(title="UT99 ZeroGPU Photorealistic Texture Forge") as demo:
241
- gr.Markdown("# ⚡ UT99 ZeroGPU Photorealistic Texture Forge")
242
- gr.Markdown("Intelligent 2D and 1D seamless texture generation with seed selection and 8-bit UT99 exports.")
243
-
244
- with gr.Row():
245
- with gr.Column():
246
- input_img = gr.Image(type="pil", label="Upload Source Photo (Fabric / Stone / City Block)")
247
-
248
- tiling_mode = gr.Radio(
249
- choices=["Horizontal Only (Landscapes/City Facades)", "Full 2D (Both Axes)"],
250
- value="Full 2D (Both Axes)",
251
- label="Seamless Mode"
252
- )
253
-
254
- prompt = gr.Textbox(
255
- value="Detailed fabric curtain texture, sharp photographic pattern",
256
- label="AI Inpainting Prompt"
257
- )
258
-
259
- negative_prompt = gr.Textbox(
260
- value="seam line, border, frame, edge line, blur, watermark, repeating grid",
261
- label="Negative Prompt"
262
- )
263
-
264
- with gr.Row():
265
- seam_width_pct = gr.Slider(
266
- minimum=10, maximum=35, value=20, step=5,
267
- label="Seam Inpaint Width (% of canvas masked)"
268
- )
269
- sharpness_boost = gr.Slider(
270
- minimum=1.0, maximum=2.5, value=1.3, step=0.1,
271
- label="Photo Sharpness Restorer"
272
- )
273
-
274
- with gr.Row():
275
- steps = gr.Slider(minimum=10, maximum=50, value=25, step=1, label="Denoising Steps")
276
- guidance_scale = gr.Slider(minimum=1.0, maximum=15.0, value=7.5, step=0.5, label="Guidance Scale (CFG)")
277
-
278
- seed_val = gr.Number(
279
- value=-1, precision=0,
280
- label="Seed Selection (-1 = Random Integer)"
281
- )
282
-
283
- resolution = gr.Dropdown(
284
- choices=[
285
- "128x128",
286
- "256x256 (Default UT99)",
287
- "512x512 (HD UT99)",
288
- "1024x1024",
289
- "2048x2048 (2K)",
290
- "4096x4096 (4K)",
291
- "8192x8192 (8K)"
292
- ],
293
- value="1024x1024",
294
- label="Output Resolution"
295
- )
296
-
297
- ut99_quantize = gr.Checkbox(
298
- value=False,
299
- label="Convert to 8-Bit / 256 Colors (.PCX / .BMP)"
300
- )
301
-
302
- btn = gr.Button("🚀 Generate Photorealistic Seamless Texture", variant="primary")
303
-
304
- with gr.Column():
305
- output_status = gr.Textbox(label="Status / Applied Parameters", interactive=False)
306
- output_texture = gr.Image(type="pil", label="Photorealistic Seamless Output")
307
- output_preview = gr.Image(type="pil", label="Tiling Preview Test (3x3 Grid / Panorama)")
308
-
309
- with gr.Row():
310
- pcx_file = gr.File(label="Download .PCX")
311
- bmp_file = gr.File(label="Download .BMP")
312
-
313
- btn.click(
314
- fn=generate_photorealistic_seamless,
315
- inputs=[
316
- input_img, prompt, negative_prompt, tiling_mode,
317
- seam_width_pct, steps, guidance_scale, seed_val,
318
- sharpness_boost, resolution, ut99_quantize
319
- ],
320
- outputs=[output_texture, output_preview, pcx_file, bmp_file, output_status]
321
- )
322
-
323
- if __name__ == "__main__":
324
- demo.launch(show_api=False)
325
-