Spaces:
Sleeping
Sleeping
Update main.py
Browse files
main.py
CHANGED
|
@@ -144,6 +144,43 @@ def generate_shadow(car_rgba, bg, paste_pos, actual_tyre_y, v_type="low"):
|
|
| 144 |
shadow_rgba = np.zeros((bg_h, bg_w, 4), dtype=np.uint8)
|
| 145 |
shadow_rgba[..., 3] = (np.clip(shadow_canvas, 0, 1) * 220).astype(np.uint8)
|
| 146 |
return Image.fromarray(shadow_rgba, "RGBA")
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 147 |
|
| 148 |
# ββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
|
| 149 |
# CORE PIPELINE & POSITIONING
|
|
@@ -203,51 +240,48 @@ def auto_position_car(car_rgba: Image.Image, bg: Image.Image):
|
|
| 203 |
return car_res, (px, py), tyre_y
|
| 204 |
|
| 205 |
def run_pipeline(car_pil, bg_pil):
|
| 206 |
-
#
|
| 207 |
car_pil = car_pil.resize((1024, int(1024 * car_pil.height/car_pil.width)), Image.LANCZOS)
|
| 208 |
bg_pil = bg_pil.resize((1600, int(1600 * bg_pil.height/bg_pil.width)), Image.LANCZOS)
|
| 209 |
|
| 210 |
-
# 1. Classification (New)
|
| 211 |
v_type = classify_vehicle(car_pil)
|
| 212 |
-
|
| 213 |
-
|
| 214 |
# 2. Segmentation
|
| 215 |
-
import torch
|
| 216 |
bundle = get_model("birefnet")
|
| 217 |
-
orig_w, orig_h = car_pil.size
|
| 218 |
inp = bundle["transform"](car_pil.convert("RGB")).unsqueeze(0).to(bundle["device"]).float()
|
| 219 |
with torch.no_grad():
|
| 220 |
bundle["model"].float()
|
| 221 |
-
# inp = inp.float()
|
| 222 |
preds = bundle["model"](inp)
|
| 223 |
mask = torch.sigmoid(preds[-1]).squeeze().cpu().numpy()
|
| 224 |
-
mask = cv2.resize(mask,
|
| 225 |
|
| 226 |
-
|
| 227 |
-
|
| 228 |
-
|
| 229 |
-
#
|
| 230 |
-
|
|
|
|
| 231 |
|
| 232 |
-
#
|
| 233 |
c_arr = np.array(car_positioned)
|
| 234 |
rgb_fixed = harmonize_color(c_arr[..., :3], c_arr[..., 3]/255.0, np.array(bg_pil))
|
| 235 |
car_final = Image.fromarray(np.dstack([rgb_fixed, c_arr[..., 3]]), "RGBA")
|
|
|
|
|
|
|
|
|
|
| 236 |
|
| 237 |
-
#
|
| 238 |
-
|
|
|
|
| 239 |
|
| 240 |
-
#
|
| 241 |
-
|
| 242 |
-
|
| 243 |
-
sh_alpha = (sh_np[..., 3] / 255.0)[..., None]
|
| 244 |
|
| 245 |
-
#
|
| 246 |
-
|
| 247 |
-
output_img = Image.fromarray(darkened_bg.astype(np.uint8))
|
| 248 |
-
output_img.paste(car_final, pos, car_final)
|
| 249 |
|
| 250 |
-
return
|
| 251 |
|
| 252 |
@app.post("/composite")
|
| 253 |
async def composite(car_image: UploadFile = File(...), background_image: UploadFile = File(...)):
|
|
|
|
| 144 |
shadow_rgba = np.zeros((bg_h, bg_w, 4), dtype=np.uint8)
|
| 145 |
shadow_rgba[..., 3] = (np.clip(shadow_canvas, 0, 1) * 220).astype(np.uint8)
|
| 146 |
return Image.fromarray(shadow_rgba, "RGBA")
|
| 147 |
+
# ββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
|
| 148 |
+
# NEW: SPYNE-GRADE SHADOW & REFLECTION LOGIC
|
| 149 |
+
# ββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
|
| 150 |
+
|
| 151 |
+
def extract_original_shadow(car_pil, mask_np):
|
| 152 |
+
"""Original photo se asli shadow nikalne ka logic."""
|
| 153 |
+
orig_np = np.array(car_pil.convert("L")) # Grayscale
|
| 154 |
+
# Mask ko thora phailao (dilate) taake tires ke niche ka area mil jaye
|
| 155 |
+
kernel = np.ones((20,20), np.uint8)
|
| 156 |
+
dilated_mask = cv2.dilate(mask_np, kernel, iterations=2)
|
| 157 |
+
shadow_area_mask = dilated_mask - mask_np
|
| 158 |
+
|
| 159 |
+
# Shadow map: Light areas ko white aur dark areas (shadow) ko black/gray karo
|
| 160 |
+
# Original ground agar whiteish hai toh ye bohot acha kaam karta hai
|
| 161 |
+
shadow_map = orig_np.astype(float) / 255.0
|
| 162 |
+
shadow_map = np.clip(shadow_map * 1.2, 0, 1) # Contrast barhao
|
| 163 |
+
return shadow_map, shadow_area_mask
|
| 164 |
+
|
| 165 |
+
def generate_reflection(car_rgba, bg_size, pos):
|
| 166 |
+
"""Car ki halki si perchaayi (reflection) floor par."""
|
| 167 |
+
bg_w, bg_h = bg_size
|
| 168 |
+
cw, ch = car_rgba.size
|
| 169 |
+
px, py = pos
|
| 170 |
+
|
| 171 |
+
# Car ko flip karo aur blur kardo
|
| 172 |
+
reflection = car_rgba.transpose(Image.FLIP_TOP_BOTTOM)
|
| 173 |
+
reflection = reflection.resize((cw, int(ch * 0.3)), Image.LANCZOS)
|
| 174 |
+
|
| 175 |
+
# Reflection Canvas
|
| 176 |
+
refl_canvas = Image.new("RGBA", (bg_w, bg_h), (0,0,0,0))
|
| 177 |
+
# Car ke bilkul niche paste karo (tyre line par)
|
| 178 |
+
refl_canvas.paste(reflection, (px, py + ch - 5))
|
| 179 |
+
|
| 180 |
+
# Bohat halki opacity (Spyne level is 5-10%)
|
| 181 |
+
refl_np = np.array(refl_canvas).astype(np.float32)
|
| 182 |
+
refl_np[..., 3] *= 0.08
|
| 183 |
+
return Image.fromarray(refl_np.astype(np.uint8), "RGBA")
|
| 184 |
|
| 185 |
# ββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
|
| 186 |
# CORE PIPELINE & POSITIONING
|
|
|
|
| 240 |
return car_res, (px, py), tyre_y
|
| 241 |
|
| 242 |
def run_pipeline(car_pil, bg_pil):
|
| 243 |
+
# 1. Standardize
|
| 244 |
car_pil = car_pil.resize((1024, int(1024 * car_pil.height/car_pil.width)), Image.LANCZOS)
|
| 245 |
bg_pil = bg_pil.resize((1600, int(1600 * bg_pil.height/bg_pil.width)), Image.LANCZOS)
|
| 246 |
|
|
|
|
| 247 |
v_type = classify_vehicle(car_pil)
|
| 248 |
+
|
|
|
|
| 249 |
# 2. Segmentation
|
|
|
|
| 250 |
bundle = get_model("birefnet")
|
|
|
|
| 251 |
inp = bundle["transform"](car_pil.convert("RGB")).unsqueeze(0).to(bundle["device"]).float()
|
| 252 |
with torch.no_grad():
|
| 253 |
bundle["model"].float()
|
|
|
|
| 254 |
preds = bundle["model"](inp)
|
| 255 |
mask = torch.sigmoid(preds[-1]).squeeze().cpu().numpy()
|
| 256 |
+
mask = cv2.resize(mask, car_pil.size)
|
| 257 |
|
| 258 |
+
# 3. Extract Original Shadow (Secret Sauce)
|
| 259 |
+
orig_shadow_map, shadow_mask = extract_original_shadow(car_pil, mask)
|
| 260 |
+
|
| 261 |
+
# 4. Positioning
|
| 262 |
+
car_rgba_temp = Image.fromarray(np.dstack([np.array(car_pil), (mask*255).astype(np.uint8)]), "RGBA")
|
| 263 |
+
car_positioned, pos, actual_tyre_y = auto_position_car(car_rgba_temp, bg_pil)
|
| 264 |
|
| 265 |
+
# 5. Color Matching
|
| 266 |
c_arr = np.array(car_positioned)
|
| 267 |
rgb_fixed = harmonize_color(c_arr[..., :3], c_arr[..., 3]/255.0, np.array(bg_pil))
|
| 268 |
car_final = Image.fromarray(np.dstack([rgb_fixed, c_arr[..., 3]]), "RGBA")
|
| 269 |
+
|
| 270 |
+
# 6. COMPOSITING LAYERS (Spyne Style)
|
| 271 |
+
bg_final = bg_pil.convert("RGBA")
|
| 272 |
|
| 273 |
+
# Layer A: Ambient Shadow (Jo humne pehle banayi thi)
|
| 274 |
+
ambient_layer = generate_shadow(car_final, bg_pil, pos, actual_tyre_y, v_type=v_type)
|
| 275 |
+
bg_final = Image.alpha_composite(bg_final, ambient_layer)
|
| 276 |
|
| 277 |
+
# Layer B: Reflection (New)
|
| 278 |
+
reflection_layer = generate_reflection(car_final, bg_pil.size, pos)
|
| 279 |
+
bg_final = Image.alpha_composite(bg_final, reflection_layer)
|
|
|
|
| 280 |
|
| 281 |
+
# Layer C: The Car
|
| 282 |
+
bg_final.paste(car_final, pos, car_final)
|
|
|
|
|
|
|
| 283 |
|
| 284 |
+
return bg_final.convert("RGB")
|
| 285 |
|
| 286 |
@app.post("/composite")
|
| 287 |
async def composite(car_image: UploadFile = File(...), background_image: UploadFile = File(...)):
|