VietCat commited on
Commit
86b9261
·
1 Parent(s): d17b1c4

Simplify zoom implementation using global variables

Browse files

- Store original images as module-level variables after detection
- Zoom functions use simple cv2.resize on stored numpy arrays
- No intermediate State components
- Zoom sliders only take zoom_level as input, no image input
- More direct and reliable implementation

Files changed (1) hide show
  1. app.py +47 -51
app.py CHANGED
@@ -9,6 +9,10 @@ from PIL import Image
9
  # Load the detector
10
  detector = TrafficSignDetector('config.yaml')
11
 
 
 
 
 
12
  def detect_traffic_signs(image, confidence_threshold):
13
  """
14
  Process the uploaded image and return the image with detected signs.
@@ -16,6 +20,8 @@ def detect_traffic_signs(image, confidence_threshold):
16
  :param confidence_threshold: confidence threshold from slider
17
  :return: tuple of (detected image, preprocessed image)
18
  """
 
 
19
  # Redirect stdout to capture all logs
20
  print(f"Received image type: {type(image)}")
21
  # Convert PIL to numpy if necessary
@@ -34,44 +40,47 @@ def detect_traffic_signs(image, confidence_threshold):
34
  result_image = cv2.cvtColor(result_image, cv2.COLOR_BGR2RGB)
35
  preprocessed_image = cv2.cvtColor(preprocessed_image, cv2.COLOR_BGR2RGB)
36
 
 
 
 
 
37
  return result_image, preprocessed_image
38
 
39
- def apply_zoom(image, zoom_level):
40
- """
41
- Apply zoom to image by resizing it.
42
- :param image: numpy array or PIL Image
43
- :param zoom_level: zoom percentage (50-200, where 100 = 100%)
44
- :return: zoomed image as numpy array
45
- """
46
- if image is None:
47
  return None
48
 
49
- # Convert to PIL if needed
50
- if isinstance(image, np.ndarray):
51
- pil_image = Image.fromarray(image.astype('uint8'))
52
- else:
53
- pil_image = image
54
-
55
- # Calculate new size
56
  zoom_factor = zoom_level / 100.0
57
- new_width = int(pil_image.width * zoom_factor)
58
- new_height = int(pil_image.height * zoom_factor)
59
-
60
- # Resize image
61
- zoomed = pil_image.resize((new_width, new_height), Image.Resampling.LANCZOS)
 
 
 
 
 
 
 
 
62
 
63
- # Convert back to numpy
64
- return np.array(zoomed)
 
 
 
 
 
 
 
65
 
66
  # Create Gradio interface
67
- with gr.Blocks(title="Traffic Sign Detector", css=".zoom-info { font-size: 12px; color: #666; }") as demo:
68
  gr.Markdown("# Traffic Sign Detector")
69
  gr.Markdown("Upload an image to detect traffic signs using YOLOv8. Detection runs automatically when you upload or adjust the threshold.")
70
 
71
- # Store original images for zooming
72
- output_image_state = gr.State(None)
73
- preprocessed_image_state = gr.State(None)
74
-
75
  with gr.Row():
76
  input_image = gr.Image(label="Upload Image", type="pil")
77
  with gr.Column():
@@ -111,55 +120,42 @@ with gr.Blocks(title="Traffic Sign Detector", css=".zoom-info { font-size: 12px;
111
  detect_btn = gr.Button("Detect Traffic Signs", variant="primary")
112
  reset_btn = gr.Button("Clear")
113
 
114
- def detect_and_store(image, confidence_threshold):
115
- """Detect and store original images for zooming"""
116
- result_image, preprocessed_image = detect_traffic_signs(image, confidence_threshold)
117
- return result_image, preprocessed_image, result_image, preprocessed_image
118
-
119
- def apply_zoom_output(original_image, zoom_level):
120
- """Apply zoom to output image"""
121
- return apply_zoom(original_image, zoom_level)
122
-
123
- def apply_zoom_preprocessed(original_image, zoom_level):
124
- """Apply zoom to preprocessed image"""
125
- return apply_zoom(original_image, zoom_level)
126
-
127
  # Auto-detect when image is uploaded
128
  input_image.change(
129
- fn=detect_and_store,
130
  inputs=[input_image, confidence_threshold],
131
- outputs=[output_image, preprocessed_image, output_image_state, preprocessed_image_state],
132
  queue=True
133
  )
134
 
135
  # Auto-detect when threshold is changed
136
  confidence_threshold.change(
137
- fn=detect_and_store,
138
  inputs=[input_image, confidence_threshold],
139
- outputs=[output_image, preprocessed_image, output_image_state, preprocessed_image_state],
140
  queue=True
141
  )
142
 
143
  # Manual detection button
144
  detect_btn.click(
145
- fn=detect_and_store,
146
  inputs=[input_image, confidence_threshold],
147
- outputs=[output_image, preprocessed_image, output_image_state, preprocessed_image_state],
148
  queue=True
149
  )
150
 
151
- # Zoom output image - update the main display
152
  zoom_slider_output.change(
153
  fn=apply_zoom_output,
154
- inputs=[output_image_state, zoom_slider_output],
155
  outputs=[output_image],
156
  queue=False
157
  )
158
 
159
- # Zoom preprocessed image - update the main display
160
  zoom_slider_preprocessed.change(
161
  fn=apply_zoom_preprocessed,
162
- inputs=[preprocessed_image_state, zoom_slider_preprocessed],
163
  outputs=[preprocessed_image],
164
  queue=False
165
  )
@@ -167,7 +163,7 @@ with gr.Blocks(title="Traffic Sign Detector", css=".zoom-info { font-size: 12px;
167
  # Clear button
168
  reset_btn.click(
169
  fn=lambda: (None, None, None, None, 100, 100),
170
- outputs=[input_image, output_image, preprocessed_image, output_image_state, zoom_slider_output, zoom_slider_preprocessed]
171
  )
172
 
173
  if __name__ == "__main__":
 
9
  # Load the detector
10
  detector = TrafficSignDetector('config.yaml')
11
 
12
+ # Store original images in memory
13
+ original_output_image = None
14
+ original_preprocessed_image = None
15
+
16
  def detect_traffic_signs(image, confidence_threshold):
17
  """
18
  Process the uploaded image and return the image with detected signs.
 
20
  :param confidence_threshold: confidence threshold from slider
21
  :return: tuple of (detected image, preprocessed image)
22
  """
23
+ global original_output_image, original_preprocessed_image
24
+
25
  # Redirect stdout to capture all logs
26
  print(f"Received image type: {type(image)}")
27
  # Convert PIL to numpy if necessary
 
40
  result_image = cv2.cvtColor(result_image, cv2.COLOR_BGR2RGB)
41
  preprocessed_image = cv2.cvtColor(preprocessed_image, cv2.COLOR_BGR2RGB)
42
 
43
+ # Store originals as numpy arrays
44
+ original_output_image = result_image.copy()
45
+ original_preprocessed_image = preprocessed_image.copy()
46
+
47
  return result_image, preprocessed_image
48
 
49
+ def apply_zoom_output(zoom_level):
50
+ """Apply zoom to output image"""
51
+ if original_output_image is None:
 
 
 
 
 
52
  return None
53
 
 
 
 
 
 
 
 
54
  zoom_factor = zoom_level / 100.0
55
+ h, w = original_output_image.shape[:2]
56
+ new_w = int(w * zoom_factor)
57
+ new_h = int(h * zoom_factor)
58
+
59
+ if new_w > 0 and new_h > 0:
60
+ zoomed = cv2.resize(original_output_image, (new_w, new_h), interpolation=cv2.INTER_LINEAR)
61
+ return zoomed
62
+ return original_output_image
63
+
64
+ def apply_zoom_preprocessed(zoom_level):
65
+ """Apply zoom to preprocessed image"""
66
+ if original_preprocessed_image is None:
67
+ return None
68
 
69
+ zoom_factor = zoom_level / 100.0
70
+ h, w = original_preprocessed_image.shape[:2]
71
+ new_w = int(w * zoom_factor)
72
+ new_h = int(h * zoom_factor)
73
+
74
+ if new_w > 0 and new_h > 0:
75
+ zoomed = cv2.resize(original_preprocessed_image, (new_w, new_h), interpolation=cv2.INTER_LINEAR)
76
+ return zoomed
77
+ return original_preprocessed_image
78
 
79
  # Create Gradio interface
80
+ with gr.Blocks(title="Traffic Sign Detector") as demo:
81
  gr.Markdown("# Traffic Sign Detector")
82
  gr.Markdown("Upload an image to detect traffic signs using YOLOv8. Detection runs automatically when you upload or adjust the threshold.")
83
 
 
 
 
 
84
  with gr.Row():
85
  input_image = gr.Image(label="Upload Image", type="pil")
86
  with gr.Column():
 
120
  detect_btn = gr.Button("Detect Traffic Signs", variant="primary")
121
  reset_btn = gr.Button("Clear")
122
 
 
 
 
 
 
 
 
 
 
 
 
 
 
123
  # Auto-detect when image is uploaded
124
  input_image.change(
125
+ fn=detect_traffic_signs,
126
  inputs=[input_image, confidence_threshold],
127
+ outputs=[output_image, preprocessed_image],
128
  queue=True
129
  )
130
 
131
  # Auto-detect when threshold is changed
132
  confidence_threshold.change(
133
+ fn=detect_traffic_signs,
134
  inputs=[input_image, confidence_threshold],
135
+ outputs=[output_image, preprocessed_image],
136
  queue=True
137
  )
138
 
139
  # Manual detection button
140
  detect_btn.click(
141
+ fn=detect_traffic_signs,
142
  inputs=[input_image, confidence_threshold],
143
+ outputs=[output_image, preprocessed_image],
144
  queue=True
145
  )
146
 
147
+ # Zoom output image
148
  zoom_slider_output.change(
149
  fn=apply_zoom_output,
150
+ inputs=[zoom_slider_output],
151
  outputs=[output_image],
152
  queue=False
153
  )
154
 
155
+ # Zoom preprocessed image
156
  zoom_slider_preprocessed.change(
157
  fn=apply_zoom_preprocessed,
158
+ inputs=[zoom_slider_preprocessed],
159
  outputs=[preprocessed_image],
160
  queue=False
161
  )
 
163
  # Clear button
164
  reset_btn.click(
165
  fn=lambda: (None, None, None, None, 100, 100),
166
+ outputs=[input_image, output_image, preprocessed_image, None, zoom_slider_output, zoom_slider_preprocessed]
167
  )
168
 
169
  if __name__ == "__main__":