Spaces:
Sleeping
Sleeping
Update app.py
Browse files
app.py
CHANGED
|
@@ -13,7 +13,6 @@ from transformers import AutoModelForImageSegmentation
|
|
| 13 |
import cv2
|
| 14 |
import ezdxf
|
| 15 |
import gradio as gr
|
| 16 |
-
from MODNet.src.models.modnet import MODNet
|
| 17 |
import gc
|
| 18 |
# from scalingtestupdated import calculate_scaling_factor
|
| 19 |
from scalingtestupdated import calculate_scaling_factor_with_units, calculate_paper_scaling_factor, convert_units
|
|
@@ -42,21 +41,6 @@ PAPER_SIZES = {
|
|
| 42 |
"A3": {"width": 297, "height": 420},
|
| 43 |
"US Letter": {"width": 215.9, "height": 279.4}
|
| 44 |
}
|
| 45 |
-
|
| 46 |
-
def get_modnet():
|
| 47 |
-
"""Lazy load MODNet model"""
|
| 48 |
-
global modnet_global
|
| 49 |
-
if modnet_global is None:
|
| 50 |
-
logger.info("Loading MODNet model...")
|
| 51 |
-
modnet_global = MODNet(backbone_pretrained=False)
|
| 52 |
-
modnet_global.load_state_dict(torch.load('modnet_photographic_portrait_matting.ckpt', map_location='cpu'))
|
| 53 |
-
modnet_global.to(device).eval()
|
| 54 |
-
return modnet_global
|
| 55 |
-
|
| 56 |
-
def get_yolo_world():
|
| 57 |
-
"""Lazy load YOLO-World model"""
|
| 58 |
-
yolo_world = YOLOWorld('yolov8s-world.pt') # Smaller model for efficiency
|
| 59 |
-
return yolo_world
|
| 60 |
|
| 61 |
# Custom Exception Classes
|
| 62 |
class TimeoutReachedError(Exception):
|
|
@@ -536,34 +520,6 @@ def remove_bg_u2netp(image: np.ndarray) -> np.ndarray:
|
|
| 536 |
logger.error(f"Error in U2NETP background removal: {e}")
|
| 537 |
raise
|
| 538 |
|
| 539 |
-
def remove_bg_modnet(image: np.ndarray) -> np.ndarray:
|
| 540 |
-
"""Remove background using MODNet"""
|
| 541 |
-
try:
|
| 542 |
-
model = get_modnet()
|
| 543 |
-
|
| 544 |
-
# Preprocess
|
| 545 |
-
transform = transforms.Compose([
|
| 546 |
-
transforms.ToTensor(),
|
| 547 |
-
transforms.Normalize((0.5, 0.5, 0.5), (0.5, 0.5, 0.5))
|
| 548 |
-
])
|
| 549 |
-
|
| 550 |
-
image_pil = Image.fromarray(image)
|
| 551 |
-
image_tensor = transform(image_pil).unsqueeze(0).to(device)
|
| 552 |
-
|
| 553 |
-
# Predict
|
| 554 |
-
with torch.no_grad():
|
| 555 |
-
_, _, matte = model(image_tensor, True)
|
| 556 |
-
|
| 557 |
-
# Post-process
|
| 558 |
-
matte = matte.squeeze().cpu().numpy()
|
| 559 |
-
matte = (matte * 255).astype(np.uint8)
|
| 560 |
-
matte = cv2.resize(matte, (image.shape[1], image.shape[0]))
|
| 561 |
-
|
| 562 |
-
return matte
|
| 563 |
-
|
| 564 |
-
except Exception as e:
|
| 565 |
-
logger.error(f"MODNet failed: {e}")
|
| 566 |
-
return remove_bg_u2netp(image) # Fallback to U2Net
|
| 567 |
|
| 568 |
def remove_bg(image: np.ndarray) -> np.ndarray:
|
| 569 |
"""Remove background using BiRefNet model for main objects"""
|
|
@@ -1103,143 +1059,6 @@ def make_square(img: np.ndarray):
|
|
| 1103 |
|
| 1104 |
return padded
|
| 1105 |
|
| 1106 |
-
# def predict_with_paper(image, paper_size, offset,offset_unit, finger_clearance=False):
|
| 1107 |
-
# """Main prediction function using paper as reference"""
|
| 1108 |
-
|
| 1109 |
-
# logger.info(f"Starting prediction with image shape: {image.shape}")
|
| 1110 |
-
# logger.info(f"Paper size: {paper_size}")
|
| 1111 |
-
|
| 1112 |
-
# if offset_unit == "inches":
|
| 1113 |
-
# offset_mm = offset * 25.4 # Convert to mm for internal calculations
|
| 1114 |
-
# else:
|
| 1115 |
-
# offset_mm = offset
|
| 1116 |
-
|
| 1117 |
-
# edge_radius = None
|
| 1118 |
-
# if edge_radius is None or edge_radius == 0:
|
| 1119 |
-
# edge_radius = 0.0001
|
| 1120 |
-
|
| 1121 |
-
# if offset < 0:
|
| 1122 |
-
# raise gr.Error("Offset Value Can't be negative")
|
| 1123 |
-
|
| 1124 |
-
# try:
|
| 1125 |
-
# # Detect paper bounds and calculate scaling factor
|
| 1126 |
-
# logger.info("Starting paper detection...")
|
| 1127 |
-
# paper_contour, scaling_factor = detect_paper_bounds(image, paper_size)
|
| 1128 |
-
# logger.info(f"Paper detected successfully with scaling factor: {scaling_factor:.4f} mm/px")
|
| 1129 |
-
|
| 1130 |
-
# except ReferenceBoxNotDetectedError as e:
|
| 1131 |
-
# logger.error(f"Paper detection failed: {e}")
|
| 1132 |
-
# return (
|
| 1133 |
-
# None, None, None, None,
|
| 1134 |
-
# f"Error: {str(e)}"
|
| 1135 |
-
# )
|
| 1136 |
-
# except Exception as e:
|
| 1137 |
-
# logger.error(f"Unexpected error in paper detection: {e}")
|
| 1138 |
-
# raise gr.Error(f"Error processing image: {str(e)}")
|
| 1139 |
-
|
| 1140 |
-
# try:
|
| 1141 |
-
# # Remove background from main objects
|
| 1142 |
-
# # orig_size = image.shape[:2]
|
| 1143 |
-
# # objects_mask = remove_bg(image)
|
| 1144 |
-
|
| 1145 |
-
# # Mask paper area in input image first
|
| 1146 |
-
# masked_input_image = mask_paper_area_in_image(image, paper_contour)
|
| 1147 |
-
|
| 1148 |
-
# # Remove background from main objects
|
| 1149 |
-
# orig_size = image.shape[:2]
|
| 1150 |
-
# objects_mask = remove_bg(image)
|
| 1151 |
-
# processed_size = objects_mask.shape[:2]
|
| 1152 |
-
|
| 1153 |
-
# # Resize mask to match original image
|
| 1154 |
-
# objects_mask = cv2.resize(objects_mask, (image.shape[1], image.shape[0]))
|
| 1155 |
-
|
| 1156 |
-
# # Remove paper area from mask to focus only on objects
|
| 1157 |
-
# objects_mask = exclude_paper_area(objects_mask, paper_contour)
|
| 1158 |
-
|
| 1159 |
-
# # Check if we actually have object pixels after paper exclusion
|
| 1160 |
-
# object_pixels = np.count_nonzero(objects_mask)
|
| 1161 |
-
# if object_pixels < 1000: # Minimum threshold
|
| 1162 |
-
# raise NoObjectDetectedError("No significant object detected after excluding paper area")
|
| 1163 |
-
|
| 1164 |
-
# # Validate single object
|
| 1165 |
-
# validate_single_object(objects_mask, paper_contour)
|
| 1166 |
-
|
| 1167 |
-
# except (MultipleObjectsError, NoObjectDetectedError) as e:
|
| 1168 |
-
# return (
|
| 1169 |
-
# None, None, None, None,
|
| 1170 |
-
# f"Error: {str(e)}"
|
| 1171 |
-
# )
|
| 1172 |
-
# except Exception as e:
|
| 1173 |
-
# raise gr.Error(f"Error in object detection: {str(e)}")
|
| 1174 |
-
|
| 1175 |
-
# # Apply edge rounding if specified
|
| 1176 |
-
# rounded_mask = objects_mask.copy()
|
| 1177 |
-
|
| 1178 |
-
# # Apply dilation for offset - more precise calculation
|
| 1179 |
-
# if offset_mm > 0:
|
| 1180 |
-
# offset_pixels = int(round(float(offset_mm) / scaling_factor))
|
| 1181 |
-
# if offset_pixels > 0:
|
| 1182 |
-
# kernel = cv2.getStructuringElement(cv2.MORPH_ELLIPSE, (offset_pixels*2+1, offset_pixels*2+1))
|
| 1183 |
-
# dilated_mask = cv2.dilate(rounded_mask, kernel, iterations=1)
|
| 1184 |
-
# else:
|
| 1185 |
-
# dilated_mask = rounded_mask.copy()
|
| 1186 |
-
|
| 1187 |
-
# # Save original dilated mask for output
|
| 1188 |
-
# Image.fromarray(dilated_mask).save("./outputs/scaled_mask_original.jpg")
|
| 1189 |
-
# dilated_mask_orig = dilated_mask.copy()
|
| 1190 |
-
|
| 1191 |
-
# # Extract contours
|
| 1192 |
-
# outlines, contours = extract_outlines(dilated_mask)
|
| 1193 |
-
|
| 1194 |
-
# try:
|
| 1195 |
-
# # Generate DXF
|
| 1196 |
-
# dxf, finger_polygons, original_polygons = save_dxf_spline(
|
| 1197 |
-
# contours,
|
| 1198 |
-
# scaling_factor,
|
| 1199 |
-
# processed_size[0],
|
| 1200 |
-
# finger_clearance=(finger_clearance == "On")
|
| 1201 |
-
# )
|
| 1202 |
-
# except FingerCutOverlapError as e:
|
| 1203 |
-
# raise gr.Error(str(e))
|
| 1204 |
-
|
| 1205 |
-
# # Create annotated image
|
| 1206 |
-
# shrunked_img_contours = image.copy()
|
| 1207 |
-
|
| 1208 |
-
# if finger_clearance == "On":
|
| 1209 |
-
# outlines = np.full_like(dilated_mask, 255)
|
| 1210 |
-
# for poly in finger_polygons:
|
| 1211 |
-
# try:
|
| 1212 |
-
# coords = np.array([
|
| 1213 |
-
# (int(x / scaling_factor), int(processed_size[0] - y / scaling_factor))
|
| 1214 |
-
# for x, y in poly.exterior.coords
|
| 1215 |
-
# ], np.int32).reshape((-1, 1, 2))
|
| 1216 |
-
|
| 1217 |
-
# cv2.drawContours(shrunked_img_contours, [coords], -1, (0, 255, 0), thickness=2)
|
| 1218 |
-
# cv2.drawContours(outlines, [coords], -1, 0, thickness=2)
|
| 1219 |
-
# except Exception as e:
|
| 1220 |
-
# logger.warning(f"Failed to draw finger cut: {e}")
|
| 1221 |
-
# continue
|
| 1222 |
-
# else:
|
| 1223 |
-
# outlines = np.full_like(dilated_mask, 255)
|
| 1224 |
-
# cv2.drawContours(shrunked_img_contours, contours, -1, (0, 255, 0), thickness=2)
|
| 1225 |
-
# cv2.drawContours(outlines, contours, -1, 0, thickness=2)
|
| 1226 |
-
|
| 1227 |
-
# # # Draw paper bounds on annotated image
|
| 1228 |
-
# # cv2.drawContours(shrunked_img_contours, [paper_contour], -1, (255, 0, 0), thickness=3)
|
| 1229 |
-
|
| 1230 |
-
# # # Add paper size text
|
| 1231 |
-
# # paper_text = f"Paper: {paper_size}"
|
| 1232 |
-
# # cv2.putText(shrunked_img_contours, paper_text, (10, 30), cv2.FONT_HERSHEY_SIMPLEX, 1, (255, 0, 0), 2)
|
| 1233 |
-
|
| 1234 |
-
# cleanup_models()
|
| 1235 |
-
|
| 1236 |
-
# return (
|
| 1237 |
-
# shrunked_img_contours,
|
| 1238 |
-
# outlines,
|
| 1239 |
-
# dxf,
|
| 1240 |
-
# dilated_mask_orig,
|
| 1241 |
-
# f"Scale: {scaling_factor:.4f} mm/px | Paper: {paper_size}"
|
| 1242 |
-
# )
|
| 1243 |
def predict_with_paper(image, paper_size, offset, offset_unit, finger_clearance=False):
|
| 1244 |
"""Main prediction function using paper as reference"""
|
| 1245 |
|
|
@@ -1286,7 +1105,7 @@ def predict_with_paper(image, paper_size, offset, offset_unit, finger_clearance=
|
|
| 1286 |
orig_size = image.shape[:2]
|
| 1287 |
# objects_mask = remove_bg(image)
|
| 1288 |
# objects_mask = remove_bg(image)
|
| 1289 |
-
objects_mask =
|
| 1290 |
processed_size = objects_mask.shape[:2]
|
| 1291 |
|
| 1292 |
# Resize mask to match original image
|
|
|
|
| 13 |
import cv2
|
| 14 |
import ezdxf
|
| 15 |
import gradio as gr
|
|
|
|
| 16 |
import gc
|
| 17 |
# from scalingtestupdated import calculate_scaling_factor
|
| 18 |
from scalingtestupdated import calculate_scaling_factor_with_units, calculate_paper_scaling_factor, convert_units
|
|
|
|
| 41 |
"A3": {"width": 297, "height": 420},
|
| 42 |
"US Letter": {"width": 215.9, "height": 279.4}
|
| 43 |
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 44 |
|
| 45 |
# Custom Exception Classes
|
| 46 |
class TimeoutReachedError(Exception):
|
|
|
|
| 520 |
logger.error(f"Error in U2NETP background removal: {e}")
|
| 521 |
raise
|
| 522 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 523 |
|
| 524 |
def remove_bg(image: np.ndarray) -> np.ndarray:
|
| 525 |
"""Remove background using BiRefNet model for main objects"""
|
|
|
|
| 1059 |
|
| 1060 |
return padded
|
| 1061 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1062 |
def predict_with_paper(image, paper_size, offset, offset_unit, finger_clearance=False):
|
| 1063 |
"""Main prediction function using paper as reference"""
|
| 1064 |
|
|
|
|
| 1105 |
orig_size = image.shape[:2]
|
| 1106 |
# objects_mask = remove_bg(image)
|
| 1107 |
# objects_mask = remove_bg(image)
|
| 1108 |
+
objects_mask = remove_bg_u2netp(image)
|
| 1109 |
processed_size = objects_mask.shape[:2]
|
| 1110 |
|
| 1111 |
# Resize mask to match original image
|