LiangLabUMB commited on
Commit
9ff4f8e
Β·
verified Β·
1 Parent(s): 94b36d9

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +78 -42
app.py CHANGED
@@ -18,54 +18,90 @@ MODEL_OPTIONS = {
18
  loaded_models = {}
19
 
20
  def extract_region_from_editor(editor_data):
21
- """Extract the selected region from ImageEditor data"""
22
  if editor_data is None:
23
  return None, None
24
-
 
 
 
 
 
 
 
 
 
25
  if isinstance(editor_data, dict):
26
- background = editor_data.get('background')
27
- layers = editor_data.get('layers', [])
28
-
29
- if background is None:
 
30
  return None, None
31
-
32
- background_np = np.array(background)
33
-
34
- if layers and len(layers) > 0:
35
- selection_layer = layers[0]
36
- selection_np = np.array(selection_layer)
37
-
38
- if len(selection_np.shape) == 3:
39
- if selection_np.shape[2] == 4: # RGBA
40
- mask = selection_np[:, :, 3] > 0
41
- else: # RGB
42
- mask = np.any(selection_np > 0, axis=2)
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
43
  else:
44
- mask = selection_np > 0
45
-
46
- coords = np.where(mask)
47
- if len(coords[0]) > 0:
48
- y_min, y_max = coords[0].min(), coords[0].max()
49
- x_min, x_max = coords[1].min(), coords[1].max()
50
-
51
- pad = 5
52
- h, w = background_np.shape[:2]
53
- y_min = max(0, y_min - pad)
54
- y_max = min(h, y_max + pad)
55
- x_min = max(0, x_min - pad)
56
- x_max = min(w, x_max + pad)
57
-
58
- region = background_np[y_min:y_max+1, x_min:x_max+1]
59
- return region, (x_min, y_min, x_max, y_max)
60
-
 
 
 
 
 
61
  return background_np, None
62
-
63
- else:
64
- if hasattr(editor_data, 'size'):
65
- image_np = np.array(editor_data)
66
- return image_np, None
67
- else:
68
- return None, None
69
 
70
  def classify_cells_by_blueness(image_np, masks, blue_threshold):
71
  """
 
18
  loaded_models = {}
19
 
20
  def extract_region_from_editor(editor_data):
21
+ """Extract selected region from ImageEditor data (mobile-safe)."""
22
  if editor_data is None:
23
  return None, None
24
+
25
+ # CASE 1 β€” Editor returns a PIL Image directly
26
+ if isinstance(editor_data, Image.Image):
27
+ return np.array(editor_data), None
28
+
29
+ # CASE 2 β€” Editor returns a NumPy array
30
+ if isinstance(editor_data, np.ndarray):
31
+ return editor_data, None
32
+
33
+ # CASE 3 β€” Mobile browser returns dict structure
34
  if isinstance(editor_data, dict):
35
+
36
+ # --- Get background from multiple possible formats ---
37
+ bg = editor_data.get("background")
38
+
39
+ if bg is None:
40
  return None, None
41
+
42
+ # Mobile ImageEditor sometimes wraps image like: {'image': base64, 'mask': None}
43
+ if isinstance(bg, dict) and "image" in bg:
44
+ try:
45
+ # Decode base64 β†’ PIL β†’ NumPy
46
+ img_bytes = io.BytesIO(base64.b64decode(bg["image"].split(",")[-1]))
47
+ bg_img = Image.open(img_bytes).convert("RGB")
48
+ background_np = np.array(bg_img)
49
+ except Exception:
50
+ return None, None
51
+
52
+ # Desktop / some mobile: bg is a PIL image
53
+ elif isinstance(bg, Image.Image):
54
+ background_np = np.array(bg)
55
+
56
+ # Final fallback
57
+ else:
58
+ try:
59
+ background_np = np.array(bg)
60
+ except Exception:
61
+ return None, None
62
+
63
+ # --- Layers (selection mask) ---
64
+ layers = editor_data.get("layers", [])
65
+ if layers:
66
+ sel = layers[0]
67
+
68
+ # Convert to NumPy if needed
69
+ if isinstance(sel, Image.Image):
70
+ sel_np = np.array(sel)
71
+ elif isinstance(sel, dict) and "image" in sel:
72
+ try:
73
+ sel_bytes = io.BytesIO(base64.b64decode(sel["image"].split(",")[-1]))
74
+ sel_np = np.array(Image.open(sel_bytes).convert("RGBA"))
75
+ except Exception:
76
+ sel_np = None
77
  else:
78
+ try:
79
+ sel_np = np.array(sel)
80
+ except:
81
+ sel_np = None
82
+
83
+ # If selection exists: compute bounding box
84
+ if sel_np is not None:
85
+ if sel_np.ndim == 3:
86
+ if sel_np.shape[2] == 4:
87
+ mask = sel_np[:, :, 3] > 0
88
+ else:
89
+ mask = np.any(sel_np > 0, axis=2)
90
+ else:
91
+ mask = sel_np > 0
92
+
93
+ coords = np.where(mask)
94
+ if coords[0].size > 0:
95
+ y0, y1 = coords[0].min(), coords[0].max()
96
+ x0, x1 = coords[1].min(), coords[1].max()
97
+ return background_np[y0:y1+1, x0:x1+1], (x0, y0, x1, y1)
98
+
99
+ # No selection β†’ return full image
100
  return background_np, None
101
+
102
+ # CASE 4 β€” Unknown structure
103
+ return None, None
104
+
 
 
 
105
 
106
  def classify_cells_by_blueness(image_np, masks, blue_threshold):
107
  """