Update app.py
Browse files
app.py
CHANGED
@@ -4,10 +4,22 @@ import numpy as np
|
|
4 |
import os
|
5 |
import tempfile
|
6 |
from ultralytics import YOLO
|
|
|
|
|
|
|
|
|
|
|
7 |
|
8 |
# Load the Latex2Layout model
|
9 |
model_path = "latex2layout_object_detection_yolov8.pt"
|
10 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
11 |
|
12 |
def detect_and_visualize(image):
|
13 |
"""
|
@@ -20,45 +32,56 @@ def detect_and_visualize(image):
|
|
20 |
annotated_image: Image with detection boxes
|
21 |
layout_annotations: Annotations in YOLO format
|
22 |
"""
|
23 |
-
|
24 |
-
|
25 |
-
|
26 |
-
# Run detection using the Latex2Layout model
|
27 |
-
results = model(image)
|
28 |
-
result = results[0]
|
29 |
-
|
30 |
-
# Create a copy of the image for visualization
|
31 |
-
annotated_image = image.copy()
|
32 |
-
layout_annotations = []
|
33 |
-
|
34 |
-
# Get image dimensions
|
35 |
-
img_height, img_width = image.shape[:2]
|
36 |
-
|
37 |
-
# Draw detection results
|
38 |
-
for box in result.boxes:
|
39 |
-
x1, y1, x2, y2 = map(int, box.xyxy[0].cpu().numpy())
|
40 |
-
conf = float(box.conf[0])
|
41 |
-
cls_id = int(box.cls[0])
|
42 |
-
cls_name = result.names[cls_id]
|
43 |
|
44 |
-
#
|
45 |
-
|
|
|
46 |
|
47 |
-
|
48 |
-
|
49 |
-
label = f'{cls_name} {conf:.2f}'
|
50 |
-
(label_width, label_height), _ = cv2.getTextSize(label, cv2.FONT_HERSHEY_SIMPLEX, 0.5, 1)
|
51 |
-
cv2.rectangle(annotated_image, (x1, y1-label_height-5), (x1+label_width, y1), color, -1)
|
52 |
-
cv2.putText(annotated_image, label, (x1, y1-5), cv2.FONT_HERSHEY_SIMPLEX, 0.5, (255, 255, 255), 1)
|
53 |
|
54 |
-
#
|
55 |
-
|
56 |
-
|
57 |
-
|
58 |
-
|
59 |
-
|
60 |
-
|
61 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
62 |
|
63 |
def save_layout_annotations(layout_annotations_str):
|
64 |
"""
|
@@ -70,13 +93,34 @@ def save_layout_annotations(layout_annotations_str):
|
|
70 |
Returns:
|
71 |
file_path: Path to the saved annotation file
|
72 |
"""
|
73 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
74 |
return None
|
|
|
|
|
|
|
|
|
75 |
|
76 |
-
|
77 |
-
|
78 |
-
|
79 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
80 |
|
81 |
# Custom CSS for styling
|
82 |
custom_css = """
|
@@ -144,7 +188,7 @@ with gr.Blocks(
|
|
144 |
# Example image button (optional)
|
145 |
with gr.Row():
|
146 |
gr.Button("Load Example Image").click(
|
147 |
-
fn=
|
148 |
outputs=input_image
|
149 |
)
|
150 |
|
@@ -153,12 +197,7 @@ with gr.Blocks(
|
|
153 |
fn=detect_and_visualize,
|
154 |
inputs=input_image,
|
155 |
outputs=[output_image, layout_annotations],
|
156 |
-
_js="() => { document.querySelector('.button-primary').innerText = 'Processing...'; }",
|
157 |
show_progress=True
|
158 |
-
).then(
|
159 |
-
fn=lambda: gr.update(value="Start Detection"),
|
160 |
-
outputs=detect_btn,
|
161 |
-
_js="() => { document.querySelector('.button-primary').innerText = 'Start Detection'; }"
|
162 |
)
|
163 |
|
164 |
download_btn.click(
|
|
|
4 |
import os
|
5 |
import tempfile
|
6 |
from ultralytics import YOLO
|
7 |
+
import logging
|
8 |
+
|
9 |
+
# Configure logging
|
10 |
+
logging.basicConfig(level=logging.INFO)
|
11 |
+
logger = logging.getLogger(__name__)
|
12 |
|
13 |
# Load the Latex2Layout model
|
14 |
model_path = "latex2layout_object_detection_yolov8.pt"
|
15 |
+
try:
|
16 |
+
if not os.path.exists(model_path):
|
17 |
+
raise FileNotFoundError(f"Model file not found: {model_path}")
|
18 |
+
model = YOLO(model_path)
|
19 |
+
logger.info("Model loaded successfully")
|
20 |
+
except Exception as e:
|
21 |
+
logger.error(f"Error loading model: {str(e)}")
|
22 |
+
raise
|
23 |
|
24 |
def detect_and_visualize(image):
|
25 |
"""
|
|
|
32 |
annotated_image: Image with detection boxes
|
33 |
layout_annotations: Annotations in YOLO format
|
34 |
"""
|
35 |
+
try:
|
36 |
+
if image is None:
|
37 |
+
return None, "Error: No image uploaded."
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
38 |
|
39 |
+
# Validate image format and dimensions
|
40 |
+
if not isinstance(image, np.ndarray):
|
41 |
+
return None, "Error: Invalid image format."
|
42 |
|
43 |
+
if image.size == 0:
|
44 |
+
return None, "Error: Empty image."
|
|
|
|
|
|
|
|
|
45 |
|
46 |
+
# Run detection using the Latex2Layout model
|
47 |
+
results = model(image)
|
48 |
+
result = results[0]
|
49 |
+
|
50 |
+
# Create a copy of the image for visualization
|
51 |
+
annotated_image = image.copy()
|
52 |
+
layout_annotations = []
|
53 |
+
|
54 |
+
# Get image dimensions
|
55 |
+
img_height, img_width = image.shape[:2]
|
56 |
+
|
57 |
+
# Draw detection results
|
58 |
+
for box in result.boxes:
|
59 |
+
x1, y1, x2, y2 = map(int, box.xyxy[0].cpu().numpy())
|
60 |
+
conf = float(box.conf[0])
|
61 |
+
cls_id = int(box.cls[0])
|
62 |
+
cls_name = result.names[cls_id]
|
63 |
+
|
64 |
+
# Generate a color for each class
|
65 |
+
color = tuple(np.random.randint(0, 255, 3).tolist())
|
66 |
+
|
67 |
+
# Draw bounding box and label
|
68 |
+
cv2.rectangle(annotated_image, (x1, y1), (x2, y2), color, 2)
|
69 |
+
label = f'{cls_name} {conf:.2f}'
|
70 |
+
(label_width, label_height), _ = cv2.getTextSize(label, cv2.FONT_HERSHEY_SIMPLEX, 0.5, 1)
|
71 |
+
cv2.rectangle(annotated_image, (x1, y1-label_height-5), (x1+label_width, y1), color, -1)
|
72 |
+
cv2.putText(annotated_image, label, (x1, y1-5), cv2.FONT_HERSHEY_SIMPLEX, 0.5, (255, 255, 255), 1)
|
73 |
+
|
74 |
+
# Convert to YOLO format (normalized)
|
75 |
+
x_center = (x1 + x2) / (2 * img_width)
|
76 |
+
y_center = (y1 + y2) / (2 * img_height)
|
77 |
+
width = (x2 - x1) / img_width
|
78 |
+
height = (y2 - y1) / img_height
|
79 |
+
layout_annotations.append(f"{cls_id} {x_center:.6f} {y_center:.6f} {width:.6f} {height:.6f}")
|
80 |
+
|
81 |
+
return annotated_image, "\n".join(layout_annotations)
|
82 |
+
except Exception as e:
|
83 |
+
logger.error(f"Error in detect_and_visualize: {str(e)}")
|
84 |
+
return None, f"Error during detection: {str(e)}"
|
85 |
|
86 |
def save_layout_annotations(layout_annotations_str):
|
87 |
"""
|
|
|
93 |
Returns:
|
94 |
file_path: Path to the saved annotation file
|
95 |
"""
|
96 |
+
try:
|
97 |
+
if not layout_annotations_str:
|
98 |
+
return None
|
99 |
+
|
100 |
+
temp_file = tempfile.NamedTemporaryFile(delete=False, suffix=".txt")
|
101 |
+
with open(temp_file.name, "w") as f:
|
102 |
+
f.write(layout_annotations_str)
|
103 |
+
return temp_file.name
|
104 |
+
except Exception as e:
|
105 |
+
logger.error(f"Error in save_layout_annotations: {str(e)}")
|
106 |
return None
|
107 |
+
|
108 |
+
def load_example_image():
|
109 |
+
"""
|
110 |
+
Load an example image for demonstration.
|
111 |
|
112 |
+
Returns:
|
113 |
+
image: The loaded example image or None if loading fails
|
114 |
+
"""
|
115 |
+
try:
|
116 |
+
example_path = "example_image.jpg"
|
117 |
+
if not os.path.exists(example_path):
|
118 |
+
logger.error(f"Example image not found: {example_path}")
|
119 |
+
return None
|
120 |
+
return cv2.imread(example_path)
|
121 |
+
except Exception as e:
|
122 |
+
logger.error(f"Error loading example image: {str(e)}")
|
123 |
+
return None
|
124 |
|
125 |
# Custom CSS for styling
|
126 |
custom_css = """
|
|
|
188 |
# Example image button (optional)
|
189 |
with gr.Row():
|
190 |
gr.Button("Load Example Image").click(
|
191 |
+
fn=load_example_image,
|
192 |
outputs=input_image
|
193 |
)
|
194 |
|
|
|
197 |
fn=detect_and_visualize,
|
198 |
inputs=input_image,
|
199 |
outputs=[output_image, layout_annotations],
|
|
|
200 |
show_progress=True
|
|
|
|
|
|
|
|
|
201 |
)
|
202 |
|
203 |
download_btn.click(
|