Spaces:
Running on CPU Upgrade
Running on CPU Upgrade
Upload app.py
Browse files
app.py
CHANGED
|
@@ -68,6 +68,14 @@ def compute_homography(kp1, kp2, matches, ransac_reproj_thresh=8.0, confidence=0
|
|
| 68 |
return H, mask
|
| 69 |
|
| 70 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 71 |
def create_inlier_mask(keypoints, matches, inlier_mask, image_shape, radius=50):
|
| 72 |
h, w = image_shape[:2]
|
| 73 |
mask_img = np.zeros((h, w), dtype=np.uint8)
|
|
@@ -444,26 +452,35 @@ def align_image(source_img, target_img, pp_level=2, paste_back=True):
|
|
| 444 |
matches = match_features(desc_src, desc_tgt)
|
| 445 |
|
| 446 |
color_mask = None
|
|
|
|
|
|
|
| 447 |
if len(matches) >= 4:
|
| 448 |
H, mask = compute_homography(kp_src, kp_tgt, matches)
|
| 449 |
if H is not None and mask is not None:
|
| 450 |
-
|
| 451 |
-
|
| 452 |
-
|
| 453 |
-
|
| 454 |
-
|
| 455 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 456 |
else:
|
|
|
|
| 457 |
aligned = source_resized
|
| 458 |
else:
|
|
|
|
| 459 |
aligned = source_resized
|
| 460 |
|
| 461 |
result = fast_color_transfer(aligned, target_img, mask=color_mask)
|
| 462 |
|
| 463 |
-
#
|
| 464 |
pre_paste = result.copy()
|
| 465 |
unedited_mask = None
|
| 466 |
-
if paste_back:
|
| 467 |
unedited_mask = detect_unedited_mask(result, target_img)
|
| 468 |
result = paste_unedited_regions(result, target_img, unedited_mask)
|
| 469 |
|
|
@@ -471,7 +488,7 @@ def align_image(source_img, target_img, pp_level=2, paste_back=True):
|
|
| 471 |
pp_result = None
|
| 472 |
if pp_level > 0:
|
| 473 |
pp_result = postprocess_foreground(result, target_img, level=pp_level)
|
| 474 |
-
if paste_back and unedited_mask is not None:
|
| 475 |
pp_result = paste_unedited_regions(pp_result, target_img, unedited_mask)
|
| 476 |
|
| 477 |
final = pp_result if pp_result is not None else result
|
|
|
|
| 68 |
return H, mask
|
| 69 |
|
| 70 |
|
| 71 |
+
def homography_deviation(H, width, height):
|
| 72 |
+
H_norm = H / H[2, 2]
|
| 73 |
+
corners = np.float32([[0, 0], [width, 0], [width, height], [0, height]]).reshape(-1, 1, 2)
|
| 74 |
+
warped = cv2.perspectiveTransform(corners, H_norm)
|
| 75 |
+
displacement = np.sqrt(np.sum((warped.reshape(-1, 2) - corners.reshape(-1, 2)) ** 2, axis=1))
|
| 76 |
+
return float(np.mean(displacement))
|
| 77 |
+
|
| 78 |
+
|
| 79 |
def create_inlier_mask(keypoints, matches, inlier_mask, image_shape, radius=50):
|
| 80 |
h, w = image_shape[:2]
|
| 81 |
mask_img = np.zeros((h, w), dtype=np.uint8)
|
|
|
|
| 452 |
matches = match_features(desc_src, desc_tgt)
|
| 453 |
|
| 454 |
color_mask = None
|
| 455 |
+
skip_warp = False
|
| 456 |
+
max_deviation_px = 100
|
| 457 |
if len(matches) >= 4:
|
| 458 |
H, mask = compute_homography(kp_src, kp_tgt, matches)
|
| 459 |
if H is not None and mask is not None:
|
| 460 |
+
deviation = homography_deviation(H, target_w, target_h)
|
| 461 |
+
if deviation > max_deviation_px:
|
| 462 |
+
skip_warp = True
|
| 463 |
+
aligned = source_resized
|
| 464 |
+
else:
|
| 465 |
+
inlier_mask = mask.ravel()
|
| 466 |
+
aligned = cv2.warpPerspective(source_resized, H, target_size,
|
| 467 |
+
flags=cv2.INTER_LANCZOS4,
|
| 468 |
+
borderMode=cv2.BORDER_REPLICATE)
|
| 469 |
+
color_mask = create_inlier_mask(kp_tgt, matches, inlier_mask,
|
| 470 |
+
target_img.shape, radius=50)
|
| 471 |
else:
|
| 472 |
+
skip_warp = True
|
| 473 |
aligned = source_resized
|
| 474 |
else:
|
| 475 |
+
skip_warp = True
|
| 476 |
aligned = source_resized
|
| 477 |
|
| 478 |
result = fast_color_transfer(aligned, target_img, mask=color_mask)
|
| 479 |
|
| 480 |
+
# Paste back unedited regions from target (skip if warp was skipped)
|
| 481 |
pre_paste = result.copy()
|
| 482 |
unedited_mask = None
|
| 483 |
+
if paste_back and not skip_warp:
|
| 484 |
unedited_mask = detect_unedited_mask(result, target_img)
|
| 485 |
result = paste_unedited_regions(result, target_img, unedited_mask)
|
| 486 |
|
|
|
|
| 488 |
pp_result = None
|
| 489 |
if pp_level > 0:
|
| 490 |
pp_result = postprocess_foreground(result, target_img, level=pp_level)
|
| 491 |
+
if paste_back and not skip_warp and unedited_mask is not None:
|
| 492 |
pp_result = paste_unedited_regions(pp_result, target_img, unedited_mask)
|
| 493 |
|
| 494 |
final = pp_result if pp_result is not None else result
|