ChristopherMarais commited on
Commit
f4a6ba2
·
verified ·
1 Parent(s): b8615bc

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +28 -21
app.py CHANGED
@@ -5,7 +5,7 @@ from PIL import Image, ImageDraw, ImageFont
5
  import matplotlib.pyplot as plt
6
  import io
7
 
8
- # --- Model Management (No changes in this section) ---
9
  MODEL_REGISTRY = {
10
  "Single-Class Detection": {
11
  "yolov10": "yolov10x_bb_detect_model",
@@ -41,13 +41,11 @@ def get_model(task, architecture):
41
  except Exception as e:
42
  raise gr.Error(f"Failed to load model. Please check the model name and your connection. Error: {e}")
43
 
44
- # --- Visualization and Drawing Functions (No changes in this section) ---
45
- try:
46
- font = ImageFont.truetype("arial.ttf", 60)
47
- except IOError:
48
- font = ImageFont.load_default()
49
 
50
- def draw_yolo_predictions(image, results, color="red"):
 
51
  img_copy = image.copy()
52
  draw = ImageDraw.Draw(img_copy)
53
  if not results or not results[0].boxes:
@@ -68,7 +66,8 @@ def draw_yolo_predictions(image, results, color="red"):
68
  draw.text((coords[0], text_bg_y1), label_text, fill="white", font=font)
69
  return img_copy
70
 
71
- def draw_dino_predictions(image, results, color="green"):
 
72
  img_copy = image.copy()
73
  draw = ImageDraw.Draw(img_copy)
74
  if not results: return img_copy
@@ -84,6 +83,7 @@ def draw_dino_predictions(image, results, color="green"):
84
  return img_copy
85
 
86
  def visualize_embedding(embedding):
 
87
  if embedding is None: return None
88
  if not hasattr(embedding, 'cpu'): return None
89
  if len(embedding.shape) == 1:
@@ -102,19 +102,27 @@ def visualize_embedding(embedding):
102
 
103
  # --- Main Processing Function ---
104
  def comprehensive_analysis(image, task, architecture, text_prompt, box_threshold, text_threshold):
 
105
  if image is None:
106
  raise gr.Error("Please upload an image first!")
107
-
 
 
 
 
 
 
 
 
108
  if task == "Zero-Shot Detection":
109
  architecture = "grounding_dino"
110
 
111
  model = get_model(task, architecture)
112
-
113
  outputs = {"annotated_image": None, "model_info": "", "classes_info": "", "embedding_plot": None}
114
 
115
  if task in ["Single-Class Detection", "Multi-Class Detection"]:
116
- results = model.predict(image) # Corrected line
117
- outputs["annotated_image"] = draw_yolo_predictions(image, results)
118
  features = model.extract_features(image)
119
  outputs["model_info"] = f"Architecture: {architecture.upper()}\nTask: {task}\nDevice: {model.device}"
120
  outputs["classes_info"] = f"Classes: {model.get_classes()}"
@@ -129,7 +137,7 @@ def comprehensive_analysis(image, task, architecture, text_prompt, box_threshold
129
  text_threshold=text_threshold
130
  )
131
 
132
- outputs["annotated_image"] = draw_dino_predictions(image, results)
133
  features = model.extract_features(image, text_prompt=text_prompt)
134
  outputs["model_info"] = f"Architecture: {architecture.upper()}\nTask: {task}\nDevice: {model.device}\nHF Model ID: {model.model.config._name_or_path}"
135
  outputs["classes_info"] = f"Prompt: '{text_prompt}'"
@@ -141,8 +149,9 @@ def comprehensive_analysis(image, task, architecture, text_prompt, box_threshold
141
 
142
  return outputs["annotated_image"], outputs["model_info"], outputs["classes_info"], outputs["embedding_plot"]
143
 
144
- # --- Gradio UI with Blocks and Dynamic UI Updates ---
145
  def update_ui_for_task(task):
 
146
  if task in ["Single-Class Detection", "Multi-Class Detection"]:
147
  arch_choices = list(MODEL_REGISTRY[task].keys())
148
  return {
@@ -160,16 +169,15 @@ def update_ui_for_task(task):
160
  text_threshold_slider: gr.update(visible=True)
161
  }
162
 
163
-
164
  with gr.Blocks(theme=gr.themes.Soft()) as demo:
165
- gr.Markdown("# IBBI - Intelligent Bark Beetle Identifier ")
166
  gr.Markdown("An all-in-one interface to analyze images using the `ibbi` library. Upload an image, select a task and model, and view the complete analysis.")
167
 
168
  with gr.Row():
169
  with gr.Column(scale=1):
170
  gr.Markdown("### 1. Inputs")
171
  image_input = gr.Image(type="pil", label="Upload Image")
172
- # ... all your other input components like task_selector, dropdowns, etc.
173
  task_selector = gr.Radio(
174
  choices=["Single-Class Detection", "Multi-Class Detection", "Zero-Shot Detection"],
175
  value="Single-Class Detection",
@@ -207,7 +215,7 @@ with gr.Blocks(theme=gr.themes.Soft()) as demo:
207
  classes_output = gr.Textbox(label="Classes / Prompt")
208
  embedding_output = gr.Image(label="Feature Embedding Visualization")
209
 
210
- # --- Event Handlers (No changes here) ---
211
  task_selector.change(
212
  fn=update_ui_for_task,
213
  inputs=task_selector,
@@ -220,7 +228,6 @@ with gr.Blocks(theme=gr.themes.Soft()) as demo:
220
  outputs=[output_image, model_details_output, classes_output, embedding_output]
221
  )
222
 
223
- # --- NEW: Use gr.Examples with just the image input ---
224
  gr.Markdown("---")
225
  gr.Markdown("### 3. Or Start with an Example Image")
226
 
@@ -234,8 +241,8 @@ with gr.Blocks(theme=gr.themes.Soft()) as demo:
234
 
235
  gr.Examples(
236
  examples=example_list,
237
- inputs=image_input, # This is the key change!
238
- label="Click an image to load it"
239
  )
240
 
241
  if __name__ == "__main__":
 
5
  import matplotlib.pyplot as plt
6
  import io
7
 
8
+ # --- Model Management ---
9
  MODEL_REGISTRY = {
10
  "Single-Class Detection": {
11
  "yolov10": "yolov10x_bb_detect_model",
 
41
  except Exception as e:
42
  raise gr.Error(f"Failed to load model. Please check the model name and your connection. Error: {e}")
43
 
44
+ # --- Visualization and Drawing Functions ---
45
+ # Note: The global font object has been removed from here.
 
 
 
46
 
47
+ def draw_yolo_predictions(image, results, font, color="red"):
48
+ """Draws YOLO predictions on an image with a dynamically sized font."""
49
  img_copy = image.copy()
50
  draw = ImageDraw.Draw(img_copy)
51
  if not results or not results[0].boxes:
 
66
  draw.text((coords[0], text_bg_y1), label_text, fill="white", font=font)
67
  return img_copy
68
 
69
+ def draw_dino_predictions(image, results, font, color="green"):
70
+ """Draws Grounding DINO predictions on an image with a dynamically sized font."""
71
  img_copy = image.copy()
72
  draw = ImageDraw.Draw(img_copy)
73
  if not results: return img_copy
 
83
  return img_copy
84
 
85
  def visualize_embedding(embedding):
86
+ """Visualizes a feature embedding as an image."""
87
  if embedding is None: return None
88
  if not hasattr(embedding, 'cpu'): return None
89
  if len(embedding.shape) == 1:
 
102
 
103
  # --- Main Processing Function ---
104
  def comprehensive_analysis(image, task, architecture, text_prompt, box_threshold, text_threshold):
105
+ """Performs the main analysis, including dynamic font calculation."""
106
  if image is None:
107
  raise gr.Error("Please upload an image first!")
108
+
109
+ # Calculate a dynamic font size based on image width.
110
+ # The font size will be 4% of the image width, with a minimum size of 15.
111
+ dynamic_font_size = max(15, int(image.width * 0.04))
112
+ try:
113
+ font = ImageFont.truetype("arial.ttf", dynamic_font_size)
114
+ except IOError:
115
+ font = ImageFont.load_default(size=dynamic_font_size)
116
+
117
  if task == "Zero-Shot Detection":
118
  architecture = "grounding_dino"
119
 
120
  model = get_model(task, architecture)
 
121
  outputs = {"annotated_image": None, "model_info": "", "classes_info": "", "embedding_plot": None}
122
 
123
  if task in ["Single-Class Detection", "Multi-Class Detection"]:
124
+ results = model.predict(image)
125
+ outputs["annotated_image"] = draw_yolo_predictions(image, results, font=font)
126
  features = model.extract_features(image)
127
  outputs["model_info"] = f"Architecture: {architecture.upper()}\nTask: {task}\nDevice: {model.device}"
128
  outputs["classes_info"] = f"Classes: {model.get_classes()}"
 
137
  text_threshold=text_threshold
138
  )
139
 
140
+ outputs["annotated_image"] = draw_dino_predictions(image, results, font=font)
141
  features = model.extract_features(image, text_prompt=text_prompt)
142
  outputs["model_info"] = f"Architecture: {architecture.upper()}\nTask: {task}\nDevice: {model.device}\nHF Model ID: {model.model.config._name_or_path}"
143
  outputs["classes_info"] = f"Prompt: '{text_prompt}'"
 
149
 
150
  return outputs["annotated_image"], outputs["model_info"], outputs["classes_info"], outputs["embedding_plot"]
151
 
152
+ # --- Gradio UI ---
153
  def update_ui_for_task(task):
154
+ """Updates the UI components based on the selected task."""
155
  if task in ["Single-Class Detection", "Multi-Class Detection"]:
156
  arch_choices = list(MODEL_REGISTRY[task].keys())
157
  return {
 
169
  text_threshold_slider: gr.update(visible=True)
170
  }
171
 
 
172
  with gr.Blocks(theme=gr.themes.Soft()) as demo:
173
+ gr.Markdown("# IBBI - Intelligent Bark Beetle Identifier")
174
  gr.Markdown("An all-in-one interface to analyze images using the `ibbi` library. Upload an image, select a task and model, and view the complete analysis.")
175
 
176
  with gr.Row():
177
  with gr.Column(scale=1):
178
  gr.Markdown("### 1. Inputs")
179
  image_input = gr.Image(type="pil", label="Upload Image")
180
+
181
  task_selector = gr.Radio(
182
  choices=["Single-Class Detection", "Multi-Class Detection", "Zero-Shot Detection"],
183
  value="Single-Class Detection",
 
215
  classes_output = gr.Textbox(label="Classes / Prompt")
216
  embedding_output = gr.Image(label="Feature Embedding Visualization")
217
 
218
+ # --- Event Handlers ---
219
  task_selector.change(
220
  fn=update_ui_for_task,
221
  inputs=task_selector,
 
228
  outputs=[output_image, model_details_output, classes_output, embedding_output]
229
  )
230
 
 
231
  gr.Markdown("---")
232
  gr.Markdown("### 3. Or Start with an Example Image")
233
 
 
241
 
242
  gr.Examples(
243
  examples=example_list,
244
+ inputs=image_input,
245
+ label="Select an image to load it"
246
  )
247
 
248
  if __name__ == "__main__":