FrankFacundo commited on
Commit
d2f86ce
Β·
1 Parent(s): a0e7842
Files changed (1) hide show
  1. app.py +166 -11
app.py CHANGED
@@ -12,6 +12,9 @@ from huggingface_hub import login
12
  from diffusers import FluxControlNetPipeline, FluxControlNetModel
13
  from diffusers.models import FluxMultiControlNetModel
14
 
 
 
 
15
  """
16
  FLUX‑1 ControlNet demo
17
  ----------------------
@@ -64,39 +67,191 @@ pipe.set_progress_bar_config(disable=True)
64
  # --------------------------------------------------
65
  MODE_MAPPING = {
66
  "canny": 0,
67
- "depth": 1,
68
- "openpose": 2,
69
- "gray": 3,
70
- "blur": 4,
71
- "tile": 5,
72
  "low quality": 6,
73
  }
74
 
75
  MAX_SEED = 100
76
 
77
- # --------------------------------------------------
78
- # Helper: quick‑n‑dirty Canny preview (only for UI display)
79
- # --------------------------------------------------
80
 
81
 
82
  def _preview_canny(
83
  pil_img: Image.Image, canny_threshold_1: int, canny_threshold_2: int
84
  ) -> Image.Image:
 
 
85
  arr = np.array(pil_img.convert("RGB"))
86
  edges = cv2.Canny(arr, threshold1=canny_threshold_1, threshold2=canny_threshold_2)
87
  edges_rgb = cv2.cvtColor(edges, cv2.COLOR_GRAY2RGB)
88
  return Image.fromarray(edges_rgb)
89
 
90
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
91
  def _make_preview(
92
  control_image: Image.Image,
93
  mode: str,
94
- canny_threshold_1: int,
95
- canny_threshold_2: int,
96
  ) -> Image.Image:
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
97
  if mode == "canny":
98
  return _preview_canny(control_image, canny_threshold_1, canny_threshold_2)
99
- # For other modes you can plug in your own visualiser later
 
 
 
 
 
 
 
 
 
 
 
 
 
100
  return control_image
101
 
102
 
 
12
  from diffusers import FluxControlNetPipeline, FluxControlNetModel
13
  from diffusers.models import FluxMultiControlNetModel
14
 
15
+ import warnings
16
+ from typing import Tuple
17
+
18
  """
19
  FLUX‑1 ControlNet demo
20
  ----------------------
 
67
  # --------------------------------------------------
68
  MODE_MAPPING = {
69
  "canny": 0,
70
+ "tile": 1,
71
+ "depth": 2,
72
+ "blur": 3,
73
+ "pose": 4,
74
+ "gray": 5,
75
  "low quality": 6,
76
  }
77
 
78
  MAX_SEED = 100
79
 
80
+ # -----------------------------------------------------------------------------
81
+ # Preview helpers – one small, self‑contained function per mode
82
+ # -----------------------------------------------------------------------------
83
 
84
 
85
  def _preview_canny(
86
  pil_img: Image.Image, canny_threshold_1: int, canny_threshold_2: int
87
  ) -> Image.Image:
88
+ """Fast Canny‑edge preview (already implemented)."""
89
+
90
  arr = np.array(pil_img.convert("RGB"))
91
  edges = cv2.Canny(arr, threshold1=canny_threshold_1, threshold2=canny_threshold_2)
92
  edges_rgb = cv2.cvtColor(edges, cv2.COLOR_GRAY2RGB)
93
  return Image.fromarray(edges_rgb)
94
 
95
 
96
+ # ――― tile ―――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――― #
97
+
98
+
99
+ def _preview_tile(pil_img: Image.Image, grid: Tuple[int, int] = (2, 2)) -> Image.Image:
100
+ """Replicates *pil_img* into an *nΓ—m* tiled grid (default 2Γ—2).
101
+
102
+ This offers a quick visual hint of what a *tiling* control mode will do
103
+ (repeatable textures, etc.)."""
104
+
105
+ cols, rows = grid
106
+ img_rgb = pil_img.convert("RGB")
107
+ w, h = img_rgb.size
108
+ tiled = Image.new("RGB", (w * cols, h * rows))
109
+ for c in range(cols):
110
+ for r in range(rows):
111
+ tiled.paste(img_rgb, (c * w, r * h))
112
+ return tiled
113
+
114
+
115
+ # ――― depth ――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――― #
116
+
117
+
118
+ def _preview_depth(pil_img: Image.Image) -> Image.Image:
119
+ """Very rough *depth* proxy using the Laplacian and a colormap.
120
+
121
+ β–Έ Convert to gray
122
+ β–Έ Run Laplacian to highlight depth‑like gradients
123
+ β–Έ Apply a TURBO colormap to mimic depth heat‑map appearance"""
124
+
125
+ gray = cv2.cvtColor(np.array(pil_img), cv2.COLOR_RGB2GRAY)
126
+ lap = cv2.Laplacian(gray, cv2.CV_16S, ksize=3)
127
+ depth = cv2.convertScaleAbs(lap)
128
+ depth_color = cv2.applyColorMap(depth, cv2.COLORMAP_TURBO)
129
+ return Image.fromarray(depth_color)
130
+
131
+
132
+ # ――― blur ――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――― #
133
+
134
+
135
+ def _preview_blur(pil_img: Image.Image, ksize: int = 15) -> Image.Image:
136
+ """Gaussian blur preview.
137
+ A single, relatively large kernel is enough for UI illustration."""
138
+
139
+ if ksize % 2 == 0:
140
+ ksize += 1 # kernel must be odd
141
+ blurred = cv2.GaussianBlur(np.array(pil_img), (ksize, ksize), sigmaX=0)
142
+ return Image.fromarray(blurred)
143
+
144
+
145
+ # ――― pose ―――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――― #
146
+
147
+
148
+ def _preview_pose(pil_img: Image.Image) -> Image.Image:
149
+ """Attempt a lightweight 2‑D pose overlay using *mediapipe* if available.
150
+
151
+ If *mediapipe* is not installed (or CPU inference fails), we gracefully
152
+ fallback to an edge‑map preview so the UI never crashes."""
153
+
154
+ try:
155
+ import mediapipe as mp # type: ignore
156
+
157
+ mp_pose = mp.solutions.pose
158
+ mp_drawing = mp.solutions.drawing_utils
159
+
160
+ img_bgr = cv2.cvtColor(np.array(pil_img), cv2.COLOR_RGB2BGR)
161
+ with mp_pose.Pose(static_image_mode=True) as pose_estimator:
162
+ results = pose_estimator.process(
163
+ img_bgr[..., ::-1]
164
+ ) # Mediapipe expects RGB
165
+
166
+ annotated = img_bgr.copy()
167
+ if results.pose_landmarks:
168
+ mp_drawing.draw_landmarks(
169
+ annotated, results.pose_landmarks, mp_pose.POSE_CONNECTIONS
170
+ )
171
+ annotated_rgb = cv2.cvtColor(annotated, cv2.COLOR_BGR2RGB)
172
+ return Image.fromarray(annotated_rgb)
173
+
174
+ except Exception as exc: # pragma: no cover – any import / runtime error
175
+ warnings.warn(
176
+ f"Pose preview failed ({exc!s}); falling back to Canny.", RuntimeWarning
177
+ )
178
+ # Return an edge map as a sensible fallback rather than exploding the UI
179
+ return _preview_canny(pil_img, 100, 200)
180
+
181
+
182
+ # ――― gray ――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――― #
183
+
184
+
185
+ def _preview_gray(pil_img: Image.Image) -> Image.Image:
186
+ """Simple grayscale conversion, but keep a 3‑channel RGB image so the UI
187
+ widget pipeline stays consistent."""
188
+
189
+ gray = cv2.cvtColor(np.array(pil_img.convert("RGB")), cv2.COLOR_RGB2GRAY)
190
+ gray_rgb = cv2.cvtColor(gray, cv2.COLOR_GRAY2RGB)
191
+ return Image.fromarray(gray_rgb)
192
+
193
+
194
+ # ――― low quality ――――――――――――――――――――――――――――――――――――――――――――――――――――――――― #
195
+
196
+
197
+ def _preview_low_quality(pil_img: Image.Image, factor: int = 8) -> Image.Image:
198
+ """Mimic a low‑quality thumbnail: aggressively downsample then upscale.
199
+
200
+ The default *factor* (8Γ—) is chosen to make artefacts obvious."""
201
+
202
+ img_rgb = pil_img.convert("RGB")
203
+ w, h = img_rgb.size
204
+ small = img_rgb.resize((max(1, w // factor), max(1, h // factor)), Image.BILINEAR)
205
+ low_q = small.resize(
206
+ (w, h), Image.NEAREST
207
+ ) # upsample w/ Nearest to exaggerate blocks
208
+ return low_q
209
+
210
+
211
+ # -----------------------------------------------------------------------------
212
+ # Master dispatch
213
+ # -----------------------------------------------------------------------------
214
+
215
+
216
  def _make_preview(
217
  control_image: Image.Image,
218
  mode: str,
219
+ canny_threshold_1: int = 100,
220
+ canny_threshold_2: int = 200,
221
  ) -> Image.Image:
222
+ """Return a *quick‑n‑dirty* preview image for the requested *mode*.
223
+
224
+ Parameters
225
+ ----------
226
+ control_image : PIL.Image
227
+ The input image selected by the user.
228
+ mode : str
229
+ One of the keys of :data:`MODE_MAPPING`.
230
+ canny_threshold_1 / 2 : int, optional
231
+ Only used if *mode* is "canny" (passed straight to OpenCV Canny).
232
+ """
233
+
234
+ mode = mode.lower()
235
+ if mode not in MODE_MAPPING:
236
+ warnings.warn(f"Unknown preview mode '{mode}'. Returning untouched image.")
237
+ return control_image
238
+
239
  if mode == "canny":
240
  return _preview_canny(control_image, canny_threshold_1, canny_threshold_2)
241
+ if mode == "tile":
242
+ return _preview_tile(control_image)
243
+ if mode == "depth":
244
+ return _preview_depth(control_image)
245
+ if mode == "blur":
246
+ return _preview_blur(control_image)
247
+ if mode == "pose":
248
+ return _preview_pose(control_image)
249
+ if mode == "gray":
250
+ return _preview_gray(control_image)
251
+ if mode == "low quality":
252
+ return _preview_low_quality(control_image)
253
+
254
+ # Fallback – should never happen due to early mode check
255
  return control_image
256
 
257