Spaces:
Sleeping
Sleeping
Commit ·
df9d184
1
Parent(s): ef0824d
chore: initialize git repository and update project configuration files
Browse files
app.py
CHANGED
|
@@ -61,100 +61,15 @@ MODEL_FILENAME = "mambaeye_base_ft.pt"
|
|
| 61 |
_GLOBAL_MODEL = None
|
| 62 |
|
| 63 |
|
| 64 |
-
# ---
|
| 65 |
-
|
| 66 |
-
|
| 67 |
-
|
| 68 |
-
|
| 69 |
-
|
| 70 |
-
overlay.id = 'mamba-hover-overlay';
|
| 71 |
-
overlay.style.position = 'fixed';
|
| 72 |
-
overlay.style.pointerEvents = 'none';
|
| 73 |
-
overlay.style.border = '2px solid rgba(0, 102, 255, 0.8)';
|
| 74 |
-
overlay.style.backgroundColor = 'rgba(0, 102, 255, 0.2)';
|
| 75 |
-
overlay.style.zIndex = '99999';
|
| 76 |
-
overlay.style.display = 'none';
|
| 77 |
-
document.body.appendChild(overlay);
|
| 78 |
-
}
|
| 79 |
-
|
| 80 |
-
document.addEventListener('mousemove', (e) => {
|
| 81 |
-
let imgs = document.querySelectorAll('img');
|
| 82 |
-
let targetImg = null;
|
| 83 |
-
for (let img of imgs) {
|
| 84 |
-
if (img.closest('.gradio-image-hook')) {
|
| 85 |
-
if (img.src && !img.src.includes('data:image/svg')) {
|
| 86 |
-
targetImg = img;
|
| 87 |
-
}
|
| 88 |
-
}
|
| 89 |
-
}
|
| 90 |
-
if (!targetImg) { overlay.style.display = 'none'; return; }
|
| 91 |
-
|
| 92 |
-
let rect = targetImg.getBoundingClientRect();
|
| 93 |
-
if (e.clientX >= rect.left && e.clientX <= rect.right && e.clientY >= rect.top && e.clientY <= rect.bottom) {
|
| 94 |
-
let nw = targetImg.naturalWidth;
|
| 95 |
-
let nh = targetImg.naturalHeight;
|
| 96 |
-
if (nw === 0 || nh === 0) return;
|
| 97 |
-
|
| 98 |
-
let cw = rect.width;
|
| 99 |
-
let ch = rect.height;
|
| 100 |
-
let imgRatio = nw / nh;
|
| 101 |
-
let containerRatio = cw / ch;
|
| 102 |
-
|
| 103 |
-
let renderW, renderH, renderX, renderY;
|
| 104 |
-
if (imgRatio > containerRatio) {
|
| 105 |
-
renderW = cw;
|
| 106 |
-
renderH = cw / imgRatio;
|
| 107 |
-
renderX = 0;
|
| 108 |
-
renderY = (ch - renderH) / 2;
|
| 109 |
-
} else {
|
| 110 |
-
renderH = ch;
|
| 111 |
-
renderW = ch * imgRatio;
|
| 112 |
-
renderY = 0;
|
| 113 |
-
renderX = (cw - renderW) / 2;
|
| 114 |
-
}
|
| 115 |
-
|
| 116 |
-
let relX = e.clientX - rect.left - renderX;
|
| 117 |
-
let relY = e.clientY - rect.top - renderY;
|
| 118 |
-
|
| 119 |
-
if (relX >= 0 && relX <= renderW && relY >= 0 && relY <= renderH) {
|
| 120 |
-
let scale = renderW / nw;
|
| 121 |
-
let TARGET_CANVAS_SIZE = 512;
|
| 122 |
-
let ratio = Math.min(TARGET_CANVAS_SIZE / nw, TARGET_CANVAS_SIZE / nh);
|
| 123 |
-
|
| 124 |
-
let origX = relX / scale;
|
| 125 |
-
let origY = relY / scale;
|
| 126 |
-
|
| 127 |
-
let y_offset = (TARGET_CANVAS_SIZE - nw * ratio) / 2;
|
| 128 |
-
let x_offset = (TARGET_CANVAS_SIZE - nh * ratio) / 2;
|
| 129 |
-
|
| 130 |
-
let canvas_y = origX * ratio + y_offset;
|
| 131 |
-
let canvas_x = origY * ratio + x_offset;
|
| 132 |
-
|
| 133 |
-
let px = Math.floor(canvas_x / 16) * 16;
|
| 134 |
-
let py = Math.floor(canvas_y / 16) * 16;
|
| 135 |
-
|
| 136 |
-
let start_orig_y = (py - y_offset) / ratio;
|
| 137 |
-
let start_orig_x = (px - x_offset) / ratio;
|
| 138 |
-
|
| 139 |
-
let render_box_x = rect.left + renderX + start_orig_y * scale;
|
| 140 |
-
let render_box_y = rect.top + renderY + start_orig_x * scale;
|
| 141 |
-
|
| 142 |
-
let size_scale = (16 / ratio) * scale;
|
| 143 |
-
|
| 144 |
-
overlay.style.left = render_box_x + "px";
|
| 145 |
-
overlay.style.top = render_box_y + "px";
|
| 146 |
-
overlay.style.width = size_scale + "px";
|
| 147 |
-
overlay.style.height = size_scale + "px";
|
| 148 |
-
overlay.style.display = 'block';
|
| 149 |
-
} else {
|
| 150 |
-
overlay.style.display = 'none';
|
| 151 |
-
}
|
| 152 |
-
} else {
|
| 153 |
-
overlay.style.display = 'none';
|
| 154 |
-
}
|
| 155 |
-
});
|
| 156 |
}
|
| 157 |
"""
|
|
|
|
| 158 |
# -----------------------------
|
| 159 |
|
| 160 |
def get_model():
|
|
@@ -258,18 +173,6 @@ def draw_patches_on_image(image_arr, positions, x_offset, y_offset, h, w):
|
|
| 258 |
# Paste original color into the highlighted region
|
| 259 |
patch_crop = orig_pil.crop(box)
|
| 260 |
temp_img.paste(patch_crop, box)
|
| 261 |
-
|
| 262 |
-
color = "red" if i == len(positions) - 1 else "blue"
|
| 263 |
-
draw.rectangle(box, outline=color, width=2)
|
| 264 |
-
|
| 265 |
-
if i > 0:
|
| 266 |
-
prev_py, prev_px = positions[i-1]
|
| 267 |
-
prev_y = (prev_py - y_offset) / ratio
|
| 268 |
-
prev_x = (prev_px - x_offset) / ratio
|
| 269 |
-
|
| 270 |
-
center_prev = (prev_y + orig_px_size / 2, prev_x + orig_px_size / 2)
|
| 271 |
-
center_curr = (orig_y + orig_px_size / 2, orig_x + orig_px_size / 2)
|
| 272 |
-
draw.line([center_prev, center_curr], fill="blue", width=2)
|
| 273 |
|
| 274 |
return np.array(temp_img), positions
|
| 275 |
|
|
@@ -366,8 +269,9 @@ def process_click_inference(x_orig, y_orig, original_image, state):
|
|
| 366 |
canvas_y = int(x_orig * ratio) + state['y_offset']
|
| 367 |
canvas_x = int(y_orig * ratio) + state['x_offset']
|
| 368 |
|
| 369 |
-
|
| 370 |
-
|
|
|
|
| 371 |
|
| 372 |
cur_loc = state['cur_location'].to(device) if state['cur_location'] is not None else None
|
| 373 |
loc_tensor = torch.tensor([[px, py]], dtype=torch.long, device=device)
|
|
@@ -419,7 +323,7 @@ def on_clear(original_image):
|
|
| 419 |
|
| 420 |
return grey_base_np, {"Cleared": 1.0}, init_state_for_image(original_image), "Selections cleared. Ready for new patch sequence."
|
| 421 |
|
| 422 |
-
with gr.Blocks(title="MambaEye Interactive Demo") as demo:
|
| 423 |
gr.Markdown("# MambaEye Interactive Inference Demo")
|
| 424 |
gr.Markdown("This interface incorporates the full **MambaEye-base** model natively.")
|
| 425 |
|
|
@@ -471,7 +375,5 @@ with gr.Blocks(title="MambaEye Interactive Demo") as demo:
|
|
| 471 |
outputs=[input_image, model_output_label, state, status_text]
|
| 472 |
)
|
| 473 |
|
| 474 |
-
demo.load(js=JS_HOVER_SCRIPT)
|
| 475 |
-
|
| 476 |
if __name__ == "__main__":
|
| 477 |
demo.launch(theme=gr.themes.Soft(), ssr_mode=False)
|
|
|
|
| 61 |
_GLOBAL_MODEL = None
|
| 62 |
|
| 63 |
|
| 64 |
+
# --- FALLBACK CSS INJECTION ---
|
| 65 |
+
# We use a CSS override to display a precision crosshair since custom dynamic HTML div overlays
|
| 66 |
+
# are deeply rejected by Gradio's internal Canvas shadow properties.
|
| 67 |
+
CSS_STYLE = """
|
| 68 |
+
.gradio-image-hook, .gradio-image-hook * {
|
| 69 |
+
cursor: crosshair !important;
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 70 |
}
|
| 71 |
"""
|
| 72 |
+
|
| 73 |
# -----------------------------
|
| 74 |
|
| 75 |
def get_model():
|
|
|
|
| 173 |
# Paste original color into the highlighted region
|
| 174 |
patch_crop = orig_pil.crop(box)
|
| 175 |
temp_img.paste(patch_crop, box)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 176 |
|
| 177 |
return np.array(temp_img), positions
|
| 178 |
|
|
|
|
| 269 |
canvas_y = int(x_orig * ratio) + state['y_offset']
|
| 270 |
canvas_x = int(y_orig * ratio) + state['x_offset']
|
| 271 |
|
| 272 |
+
# 1px flexible precision anchoring the patch directly onto the exact center click
|
| 273 |
+
px = max(0, min(int(canvas_x - PATCH_SIZE / 2), TARGET_CANVAS_SIZE - PATCH_SIZE))
|
| 274 |
+
py = max(0, min(int(canvas_y - PATCH_SIZE / 2), TARGET_CANVAS_SIZE - PATCH_SIZE))
|
| 275 |
|
| 276 |
cur_loc = state['cur_location'].to(device) if state['cur_location'] is not None else None
|
| 277 |
loc_tensor = torch.tensor([[px, py]], dtype=torch.long, device=device)
|
|
|
|
| 323 |
|
| 324 |
return grey_base_np, {"Cleared": 1.0}, init_state_for_image(original_image), "Selections cleared. Ready for new patch sequence."
|
| 325 |
|
| 326 |
+
with gr.Blocks(title="MambaEye Interactive Demo", css=CSS_STYLE) as demo:
|
| 327 |
gr.Markdown("# MambaEye Interactive Inference Demo")
|
| 328 |
gr.Markdown("This interface incorporates the full **MambaEye-base** model natively.")
|
| 329 |
|
|
|
|
| 375 |
outputs=[input_image, model_output_label, state, status_text]
|
| 376 |
)
|
| 377 |
|
|
|
|
|
|
|
| 378 |
if __name__ == "__main__":
|
| 379 |
demo.launch(theme=gr.themes.Soft(), ssr_mode=False)
|