Spaces:
Sleeping
Sleeping
TILE PATTERN EDIT
Browse files
app.py
CHANGED
|
@@ -135,28 +135,107 @@ def _process_saree_core(base_image: Image.Image, pattern_image: Image.Image):
|
|
| 135 |
l_clahe = clahe.apply(l_channel)
|
| 136 |
shading_map = l_clahe / 255.0
|
| 137 |
|
| 138 |
-
|
| 139 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 140 |
target_h, target_w = img_np.shape[:2]
|
| 141 |
-
|
| 142 |
-
|
| 143 |
-
|
| 144 |
-
|
| 145 |
-
|
| 146 |
-
|
| 147 |
-
|
| 148 |
-
|
| 149 |
-
|
| 150 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 151 |
shading_map_loaded = np.stack([shading_map] * 3, axis=-1)
|
|
|
|
|
|
|
| 152 |
|
| 153 |
-
|
| 154 |
-
|
| 155 |
-
|
| 156 |
-
pattern_folded = pattern_tiled.astype(np.float32) / 255.0 * blended_shading
|
| 157 |
-
normal_boost = 0.5 + 0.5 * normal_map_loaded[..., 2:3]
|
| 158 |
pattern_folded *= normal_boost
|
| 159 |
-
pattern_folded
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 160 |
|
| 161 |
# ==========================================================
|
| 162 |
# Background removal with post-processing (no duplicate blur)
|
|
|
|
| 135 |
l_clahe = clahe.apply(l_channel)
|
| 136 |
shading_map = l_clahe / 255.0
|
| 137 |
|
| 138 |
+
# ==========================================================
|
| 139 |
+
# [PATCHED] TILE PATTERN (soft crossfade) + BLEND
|
| 140 |
+
# Replace the block from "# Tile pattern" through
|
| 141 |
+
# "pattern_folded = np.clip(pattern_folded, 0, 1)"
|
| 142 |
+
# and keep everything below (BG removal etc.) unchanged.
|
| 143 |
+
# ==========================================================
|
| 144 |
+
|
| 145 |
+
# ----- ORIGINAL (hard tiling) — kept for reference -----
|
| 146 |
+
# # Tile pattern
|
| 147 |
+
# pattern_np = np.array(pattern_image.convert("RGB"))
|
| 148 |
+
# target_h, target_w = img_np.shape[:2]
|
| 149 |
+
# pattern_h, pattern_w = pattern_np.shape[:2]
|
| 150 |
+
# pattern_tiled = np.zeros((target_h, target_w, 3), dtype=np.uint8)
|
| 151 |
+
# for y in range(0, target_h, pattern_h):
|
| 152 |
+
# for x in range(0, target_w, pattern_w):
|
| 153 |
+
# end_y = min(y + pattern_h, target_h)
|
| 154 |
+
# end_x = min(x + pattern_w, target_w)
|
| 155 |
+
# pattern_tiled[y:end_y, x:end_x] = pattern_np[0:(end_y - y), 0:(end_x - x)]
|
| 156 |
+
#
|
| 157 |
+
# # Blend pattern
|
| 158 |
+
# normal_map_loaded = normal_map.astype(np.float32)
|
| 159 |
+
# shading_map_loaded = np.stack([shading_map] * 3, axis=-1)
|
| 160 |
+
# alpha = 0.7
|
| 161 |
+
# blended_shading = alpha * shading_map_loaded + (1 - alpha)
|
| 162 |
+
# pattern_folded = pattern_tiled.astype(np.float32) / 255.0 * blended_shading
|
| 163 |
+
# normal_boost = 0.5 + 0.5 * normal_map_loaded[..., 2:3]
|
| 164 |
+
# pattern_folded *= normal_boost
|
| 165 |
+
# pattern_folded = np.clip(pattern_folded, 0, 1)
|
| 166 |
+
# ----- END ORIGINAL -----
|
| 167 |
+
|
| 168 |
+
# ---------- NEW: seam‑free overlapped tiling ----------
|
| 169 |
+
eps = 1e-6
|
| 170 |
+
|
| 171 |
+
# 1) Clean the tile (unpremultiply RGBA to remove black fringe; optional 2px crop)
|
| 172 |
+
_tile_rgba = np.array(pattern_image.convert("RGBA")).astype(np.float32) / 255.0
|
| 173 |
+
_tile_rgb = _tile_rgba[..., :3]
|
| 174 |
+
_tile_a = _tile_rgba[..., 3:4]
|
| 175 |
+
_tile_rgb = np.where(_tile_a > eps, _tile_rgb / np.clip(_tile_a, eps, 1.0), _tile_rgb)
|
| 176 |
+
|
| 177 |
+
_crop = 2 # try 2–3 if fringe persists
|
| 178 |
+
if _tile_rgb.shape[0] > 2*_crop and _tile_rgb.shape[1] > 2*_crop:
|
| 179 |
+
_tile_rgb = _tile_rgb[_crop:-_crop, _crop:-_crop, :]
|
| 180 |
+
|
| 181 |
+
pattern_np = (np.clip(_tile_rgb, 0.0, 1.0) * 255).astype(np.uint8)
|
| 182 |
+
|
| 183 |
+
# 2) Overlapped tiling with cosine crossfade
|
| 184 |
target_h, target_w = img_np.shape[:2]
|
| 185 |
+
th, tw = pattern_np.shape[:2]
|
| 186 |
+
ov = 6 # overlap width in px (tune 4–12)
|
| 187 |
+
|
| 188 |
+
def _make_weight(h, w, ov_):
|
| 189 |
+
ovh = min(ov_, h // 2)
|
| 190 |
+
ovw = min(ov_, w // 2)
|
| 191 |
+
wy = np.ones((h,), dtype=np.float32)
|
| 192 |
+
wx = np.ones((w,), dtype=np.float32)
|
| 193 |
+
if ovh > 0:
|
| 194 |
+
t = np.linspace(0, np.pi, ovh, endpoint=False)
|
| 195 |
+
ramp = 0.5 - 0.5 * np.cos(t)
|
| 196 |
+
wy[:ovh] = np.minimum(wy[:ovh], ramp)
|
| 197 |
+
wy[-ovh:] = np.minimum(wy[-ovh:], ramp[::-1])
|
| 198 |
+
if ovw > 0:
|
| 199 |
+
t = np.linspace(0, np.pi, ovw, endpoint=False)
|
| 200 |
+
ramp = 0.5 - 0.5 * np.cos(t)
|
| 201 |
+
wx[:ovw] = np.minimum(wx[:ovw], ramp)
|
| 202 |
+
wx[-ovw:] = np.minimum(wx[-ovw:], ramp[::-1])
|
| 203 |
+
return np.outer(wy, wx).astype(np.float32)
|
| 204 |
+
|
| 205 |
+
acc = np.zeros((target_h, target_w, 3), dtype=np.float32)
|
| 206 |
+
wacc = np.zeros((target_h, target_w, 1), dtype=np.float32)
|
| 207 |
+
|
| 208 |
+
stride_y = max(1, th - ov)
|
| 209 |
+
stride_x = max(1, tw - ov)
|
| 210 |
+
|
| 211 |
+
for y in range(0, target_h, stride_y):
|
| 212 |
+
for x in range(0, target_w, stride_x):
|
| 213 |
+
h_crop = min(th, target_h - y)
|
| 214 |
+
w_crop = min(tw, target_w - x)
|
| 215 |
+
tile = pattern_np[:h_crop, :w_crop, :].astype(np.float32) / 255.0
|
| 216 |
+
wmask = _make_weight(h_crop, w_crop, ov)[..., None] # (h,w,1)
|
| 217 |
+
|
| 218 |
+
acc[y:y+h_crop, x:x+w_crop] += tile * wmask
|
| 219 |
+
wacc[y:y+h_crop, x:x+w_crop] += wmask
|
| 220 |
+
|
| 221 |
+
pattern_tiled = acc / np.clip(wacc, eps, None)
|
| 222 |
+
pattern_tiled = np.clip(pattern_tiled, 0.0, 1.0) # float32 in [0,1]
|
| 223 |
+
|
| 224 |
+
# 3) Continue with your shading/normal blending (unchanged)
|
| 225 |
+
normal_map_loaded = normal_map.astype(np.float32)
|
| 226 |
shading_map_loaded = np.stack([shading_map] * 3, axis=-1)
|
| 227 |
+
alpha = 0.7
|
| 228 |
+
blended_shading = alpha * shading_map_loaded + (1 - alpha)
|
| 229 |
|
| 230 |
+
pattern_folded = pattern_tiled * blended_shading
|
| 231 |
+
normal_boost = 0.5 + 0.5 * normal_map_loaded[..., 2:3]
|
|
|
|
|
|
|
|
|
|
| 232 |
pattern_folded *= normal_boost
|
| 233 |
+
pattern_folded = np.clip(pattern_folded, 0.0, 1.0)
|
| 234 |
+
|
| 235 |
+
# ==========================================================
|
| 236 |
+
# [END PATCHED]
|
| 237 |
+
# ==========================================================
|
| 238 |
+
|
| 239 |
|
| 240 |
# ==========================================================
|
| 241 |
# Background removal with post-processing (no duplicate blur)
|