ovi054 commited on
Commit
b4d3000
·
verified ·
1 Parent(s): 42816ac

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +46 -30
app.py CHANGED
@@ -42,16 +42,39 @@ _VAE_IMAGE_SIZE = 1024 * 1024
42
 
43
 
44
  def calculate_vae_gen_size(image: Image.Image) -> tuple:
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
45
  W, H = image.size
46
  ratio = W / H
47
  gen_w = math.sqrt(_VAE_IMAGE_SIZE * ratio)
48
  gen_h = gen_w / ratio
 
49
  gen_w = round(gen_w / 32) * 32
50
  gen_h = round(gen_h / 32) * 32
51
  return int(gen_w), int(gen_h)
52
 
53
 
 
54
  def update_dimensions_on_upload(image: Optional[Image.Image]) -> Image.Image:
 
 
 
 
 
55
  if image is None:
56
  return image
57
 
@@ -60,6 +83,7 @@ def update_dimensions_on_upload(image: Optional[Image.Image]) -> Image.Image:
60
  original_width, original_height = image.size
61
  scale = min(MAX_SIDE / original_width, MAX_SIDE / original_height, 1.0)
62
 
 
63
  new_width = (int(original_width * scale) // 16) * 16
64
  new_height = (int(original_height * scale) // 16) * 16
65
 
@@ -78,7 +102,10 @@ def infer(
78
  true_guidance_scale: float = 1.0,
79
  num_inference_steps: int = 4,
80
  progress=gr.Progress(track_tqdm=True)
81
- ):
 
 
 
82
  if source_image is None:
83
  raise gr.Error("Please upload a source image (Image 1).")
84
  if reference_image is None:
@@ -91,8 +118,16 @@ def infer(
91
  src_img = source_image.convert("RGB")
92
  ref_img = reference_image.convert("RGB")
93
 
 
94
  out_w, out_h = src_img.size
95
 
 
 
 
 
 
 
 
96
  gen_w, gen_h = calculate_vae_gen_size(src_img)
97
 
98
  result = pipe(
@@ -106,19 +141,11 @@ def infer(
106
  num_images_per_prompt=1,
107
  ).images[0]
108
 
109
- # Return updates: Show single image by default, update slider in the background
110
- return (
111
- gr.update(value=result, visible=True),
112
- gr.update(value=(src_img, result), visible=False),
113
- seed,
114
- gr.update(visible=True, value="🔍 Compare Before & After")
115
- )
116
 
117
- def toggle_compare_view(btn_text):
118
- if "Compare" in btn_text:
119
- return gr.update(visible=False), gr.update(visible=True), gr.update(value="🖼️ Show Only Result")
120
- else:
121
- return gr.update(visible=True), gr.update(visible=False), gr.update(value="🔍 Compare Before & After")
122
 
123
 
124
  # --- UI ---
@@ -181,14 +208,7 @@ with gr.Blocks() as demo:
181
  )
182
 
183
  with gr.Column():
184
- # Clean single image layout as the default output view
185
- result_image = gr.Image(label="Final Color-Graded Output", interactive=False)
186
-
187
- # Using the core native gr.ImageSlider component (hidden initially)
188
- compare_slider = gr.ImageSlider(label="Before & After Comparison", interactive=False, visible=False)
189
-
190
- # Subtle secondary toggle button
191
- compare_btn = gr.Button("🔍 Compare Before & After", visible=False, variant="secondary")
192
 
193
  gr.Examples(
194
  examples=[
@@ -196,9 +216,10 @@ with gr.Blocks() as demo:
196
  ["images/image2.jpeg","images/image1.jpg"],
197
  ],
198
  inputs=[source_image, reference_image],
199
- outputs=[result_image, compare_slider, seed, compare_btn],
200
  fn=infer,
201
- cache_examples=False,
 
202
  elem_id="examples"
203
  )
204
 
@@ -207,14 +228,9 @@ with gr.Blocks() as demo:
207
  seed, randomize_seed, true_guidance_scale,
208
  num_inference_steps,
209
  ]
210
- outputs = [result_image, compare_slider, seed, compare_btn]
211
- run_btn.click(fn=infer, inputs=inputs, outputs=outputs)
212
 
213
- compare_btn.click(
214
- fn=toggle_compare_view,
215
- inputs=[compare_btn],
216
- outputs=[result_image, compare_slider, compare_btn]
217
- )
218
 
219
  source_image.upload(
220
  fn=update_dimensions_on_upload,
 
42
 
43
 
44
  def calculate_vae_gen_size(image: Image.Image) -> tuple:
45
+ """
46
+ Return (gen_w, gen_h) that exactly matches the pipeline's internal VAE
47
+ conditioning scale for this image.
48
+
49
+ The pipeline always resizes every input image to VAE_IMAGE_SIZE (~1MP) before
50
+ VAE-encoding it into image_latents, using:
51
+ vae_width, vae_height = calculate_dimensions(VAE_IMAGE_SIZE, w / h)
52
+
53
+ img_shapes (used for 2-D RoPE) is built from BOTH the output size (height/width)
54
+ AND the conditioning sizes (vae_width, vae_height). When they differ, the RoPE
55
+ coordinate systems are misaligned → huge pixel shift.
56
+
57
+ Passing gen_h/gen_w = the same 1MP-equivalent makes the output tokens and Image 1
58
+ conditioning tokens share an identical coordinate system → no shift.
59
+ This is exactly what ComfyUI’s ImageScaleToTotalPixels (megapixels=1.0) achieves.
60
+ """
61
  W, H = image.size
62
  ratio = W / H
63
  gen_w = math.sqrt(_VAE_IMAGE_SIZE * ratio)
64
  gen_h = gen_w / ratio
65
+ # pipeline rounds to multiples of 32 (also satisfies the ÷16 divisibility requirement)
66
  gen_w = round(gen_w / 32) * 32
67
  gen_h = round(gen_h / 32) * 32
68
  return int(gen_w), int(gen_h)
69
 
70
 
71
+
72
  def update_dimensions_on_upload(image: Optional[Image.Image]) -> Image.Image:
73
+ """
74
+ Cap longest side to 1328px, snap to multiples of 16.
75
+ Pipeline requires divisibility by vae_scale_factor * 2 = 8 * 2 = 16.
76
+ Never upscales.
77
+ """
78
  if image is None:
79
  return image
80
 
 
83
  original_width, original_height = image.size
84
  scale = min(MAX_SIDE / original_width, MAX_SIDE / original_height, 1.0)
85
 
86
+ # Must be multiples of 16 (vae_scale_factor * 2)
87
  new_width = (int(original_width * scale) // 16) * 16
88
  new_height = (int(original_height * scale) // 16) * 16
89
 
 
102
  true_guidance_scale: float = 1.0,
103
  num_inference_steps: int = 4,
104
  progress=gr.Progress(track_tqdm=True)
105
+ ) -> Tuple[Image.Image, int]:
106
+ """
107
+ Transfer color grading from a reference image onto a source image.
108
+ """
109
  if source_image is None:
110
  raise gr.Error("Please upload a source image (Image 1).")
111
  if reference_image is None:
 
118
  src_img = source_image.convert("RGB")
119
  ref_img = reference_image.convert("RGB")
120
 
121
+ # Original size — used to resize the output back at the end
122
  out_w, out_h = src_img.size
123
 
124
+ # Generate at the 1MP-equivalent of Image 1’s aspect ratio.
125
+ # The pipeline internally scales ALL input images to VAE_IMAGE_SIZE (~1MP) before
126
+ # VAE-encoding them as conditioning latents. img_shapes (for 2-D RoPE) combines
127
+ # the output size (height/width) with those conditioning sizes. If they differ,
128
+ # the RoPE coordinate systems are misaligned → huge pixel shift.
129
+ # Using the same 1MP formula as the pipeline eliminates the mismatch.
130
+ # (ComfyUI achieves this via ImageScaleToTotalPixels at megapixels=1.0.)
131
  gen_w, gen_h = calculate_vae_gen_size(src_img)
132
 
133
  result = pipe(
 
141
  num_images_per_prompt=1,
142
  ).images[0]
143
 
144
+ # Resize output back to the original image dimensions
145
+ # if result.size != (out_w, out_h):
146
+ # result = result.resize((out_w, out_h), Image.LANCZOS)
 
 
 
 
147
 
148
+ return (src_img, result), seed
 
 
 
 
149
 
150
 
151
  # --- UI ---
 
208
  )
209
 
210
  with gr.Column():
211
+ result = gr.ImageSlider(label="Color Graded Output", interactive=False)
 
 
 
 
 
 
 
212
 
213
  gr.Examples(
214
  examples=[
 
216
  ["images/image2.jpeg","images/image1.jpg"],
217
  ],
218
  inputs=[source_image, reference_image],
219
+ outputs=[result, seed],
220
  fn=infer,
221
+ cache_examples=True,
222
+ cache_mode="lazy",
223
  elem_id="examples"
224
  )
225
 
 
228
  seed, randomize_seed, true_guidance_scale,
229
  num_inference_steps,
230
  ]
231
+ outputs = [result, seed]
 
232
 
233
+ run_btn.click(fn=infer, inputs=inputs, outputs=outputs)
 
 
 
 
234
 
235
  source_image.upload(
236
  fn=update_dimensions_on_upload,