utkarsh-23 commited on
Commit
6f88fe0
Β·
1 Parent(s): ea89515

πŸš€ Update SAMADHAN app with enhanced UI and department classification

Browse files

- Enhanced UI with better text contrast and visibility
- Added comprehensive department classification system
- Improved upload area styling and readability
- Updated README with complete feature description
- Fixed text color issues for better accessibility
- Added professional gradient design and responsive layout

Files changed (3) hide show
  1. README.md +53 -3
  2. app.py +439 -41
  3. requirements.txt +1 -0
README.md CHANGED
@@ -1,12 +1,62 @@
1
  ---
2
- title: Garbage Pothole Detector App
3
- emoji: πŸ‘€
4
  colorFrom: blue
5
  colorTo: purple
6
  sdk: gradio
7
  sdk_version: 5.46.0
8
  app_file: app.py
9
  pinned: false
 
10
  ---
11
 
12
- Check out the configuration reference at https://huggingface.co/docs/hub/spaces-config-reference
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
  ---
2
+ title: SAMADHAN - Smart Infrastructure Detection
3
+ emoji: οΏ½
4
  colorFrom: blue
5
  colorTo: purple
6
  sdk: gradio
7
  sdk_version: 5.46.0
8
  app_file: app.py
9
  pinned: false
10
+ license: mit
11
  ---
12
 
13
+ # πŸ” SAMADHAN - Smart Infrastructure Detection System
14
+
15
+ AI-Powered Classification for Urban Infrastructure Management using YOLOv8
16
+
17
+ ## 🎯 Features
18
+
19
+ - **Image Detection**: Upload images to detect and classify infrastructure objects
20
+ - **Video Processing**: Process videos with real-time object detection
21
+ - **Department Classification**: Automatically categorizes detections into three main departments:
22
+ - πŸ—‘οΈ **Garbage Department**: Container, Garbage
23
+ - πŸ•³οΈ **Pothole Department**: Crocodile crack, Longitudinal crack, Pothole
24
+ - πŸ’‘ **Streetlight Department**: HV-switch, Crossarm, Streetlight, Traffic-light, Transformer
25
+
26
+ ## πŸš€ How to Use
27
+
28
+ 1. **Image Detection**:
29
+ - Upload an image using the file uploader
30
+ - The system automatically processes and shows detection results
31
+ - View classified department and detected objects with confidence scores
32
+
33
+ 2. **Video Detection**:
34
+ - Upload a video file (MP4, AVI, MOV)
35
+ - Click "Process Video" to analyze
36
+ - Download the processed video with detection annotations
37
+
38
+ ## πŸ› οΈ Technology Stack
39
+
40
+ - **AI Model**: YOLOv8 (Ultralytics)
41
+ - **Frontend**: Gradio
42
+ - **Backend**: Python, OpenCV
43
+ - **Deployment**: Hugging Face Spaces
44
+
45
+ ## πŸ“Š Supported Objects
46
+
47
+ The system can detect and classify 10 different types of infrastructure objects:
48
+ - Container, Garbage
49
+ - Crocodile crack, Longitudinal crack, Pothole
50
+ - HV-switch, Crossarm, Streetlight, Traffic-light, Transformer
51
+
52
+ ## 🎨 Interface
53
+
54
+ Modern, responsive web interface with:
55
+ - Professional gradient design
56
+ - Real-time processing indicators
57
+ - Clear department classification results
58
+ - Mobile-friendly layout
59
+
60
+ ---
61
+
62
+ Built with ❀️ using YOLOv8 and Gradio | Powered by AI for Smart City Management
app.py CHANGED
@@ -3,57 +3,455 @@ import gradio as gr
3
  from ultralytics import YOLO
4
  from huggingface_hub import hf_hub_download
5
  import cv2, tempfile
 
 
6
 
7
- # Load YOLO model from HF Hub
8
- model_path = hf_hub_download(repo_id="utkarsh-23/yolov8m-garbage-pothole-detector", filename="best.pt")
 
 
 
 
 
9
  model = YOLO(model_path)
10
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
11
  # Image detection
12
  def detect_image(image):
13
- results = model(image)
14
- return results[0].plot()
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
15
 
16
  # Video detection
17
  def detect_video(video_path):
18
- cap = cv2.VideoCapture(video_path)
19
- fourcc = cv2.VideoWriter_fourcc(*"mp4v")
20
- out_path = tempfile.mktemp(suffix=".mp4")
21
- out = cv2.VideoWriter(
22
- out_path, fourcc, cap.get(cv2.CAP_PROP_FPS),
23
- (int(cap.get(3)), int(cap.get(4)))
24
- )
 
 
 
 
 
 
 
 
 
 
25
 
26
- while cap.isOpened():
27
- ret, frame = cap.read()
28
- if not ret:
29
- break
30
- results = model(frame)
31
- annotated_frame = results[0].plot()
32
- out.write(annotated_frame)
33
-
34
- cap.release()
35
- out.release()
36
- return out_path
37
-
38
- # Interfaces
39
- image_interface = gr.Interface(
40
- fn=detect_image,
41
- inputs=gr.Image(type="numpy"),
42
- outputs=gr.Image(type="numpy"),
43
- title="Garbage & Pothole Detector (Image)"
44
- )
45
 
46
- video_interface = gr.Interface(
47
- fn=detect_video,
48
- inputs=gr.Video(),
49
- outputs=gr.Video(),
50
- title="Garbage & Pothole Detector (Video)"
51
- )
 
52
 
53
- demo = gr.TabbedInterface(
54
- [image_interface, video_interface],
55
- ["Image Detection", "Video Detection"]
56
- )
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
57
 
58
  if __name__ == "__main__":
59
- demo.launch()
 
 
 
 
 
 
 
 
 
3
  from ultralytics import YOLO
4
  from huggingface_hub import hf_hub_download
5
  import cv2, tempfile
6
+ import numpy as np
7
+ from PIL import Image
8
 
9
+ # Load YOLO model from HF Hub with token
10
+ # Replace 'your_token_here' with your actual HF token or use huggingface-cli login
11
+ model_path = hf_hub_download(
12
+ repo_id="utkarsh-23/yolov8m-garbage-pothole-detector",
13
+ filename="best.pt",
14
+ # token="your_token_here" # Uncomment and add your token if needed
15
+ )
16
  model = YOLO(model_path)
17
 
18
+ # Define class names
19
+ class_names = ['Container', 'Garbage', 'crocodile crack', 'longitudinal crack', 'pothole',
20
+ 'HV-switch', 'crossarm', 'streetlight', 'traffic-light', 'transformer']
21
+
22
+ # Define department mapping
23
+ department_mapping = {
24
+ 'Container': 'Garbage',
25
+ 'Garbage': 'Garbage',
26
+ 'crocodile crack': 'Pothole',
27
+ 'longitudinal crack': 'Pothole',
28
+ 'pothole': 'Pothole',
29
+ 'HV-switch': 'Streetlight',
30
+ 'crossarm': 'Streetlight',
31
+ 'streetlight': 'Streetlight',
32
+ 'traffic-light': 'Streetlight',
33
+ 'transformer': 'Streetlight'
34
+ }
35
+
36
  # Image detection
37
  def detect_image(image):
38
+ if image is None:
39
+ return None, "⚠️ Please upload an image first!"
40
+
41
+ try:
42
+ results = model(image)
43
+
44
+ # Get detected classes and departments
45
+ detected_objects = []
46
+ detected_departments = set()
47
+
48
+ if results[0].boxes is not None:
49
+ for box in results[0].boxes:
50
+ class_id = int(box.cls[0])
51
+ confidence = float(box.conf[0])
52
+ class_name = class_names[class_id] if class_id < len(class_names) else f"Class {class_id}"
53
+ department = department_mapping.get(class_name, "Unknown")
54
+
55
+ detected_objects.append(f"{class_name} ({confidence:.2f})")
56
+ detected_departments.add(department)
57
+
58
+ # Create classification text with emojis
59
+ if detected_departments:
60
+ if len(detected_departments) == 1:
61
+ department = list(detected_departments)[0]
62
+ dept_emoji = {"Garbage": "πŸ—‘οΈ", "Pothole": "πŸ•³οΈ", "Streetlight": "πŸ’‘"}.get(department, "πŸ“‹")
63
+ classification_text = f"{dept_emoji} **This image is classified under the {department} department**"
64
+ else:
65
+ departments_list = ", ".join(sorted(detected_departments))
66
+ classification_text = f"πŸ“Š **This image is classified under multiple departments:** {departments_list}"
67
+
68
+ # Add detailed detection info
69
+ classification_text += "\n\n### πŸ” Detected Objects:\n"
70
+ for obj in detected_objects:
71
+ classification_text += f"β€’ {obj}\n"
72
+ else:
73
+ classification_text = "❌ **No objects detected**\n\nPlease try with a different image containing garbage, potholes, or streetlight infrastructure."
74
+
75
+ annotated_image = results[0].plot()
76
+ return annotated_image, classification_text
77
+
78
+ except Exception as e:
79
+ return None, f"❌ **Error processing image:** {str(e)}"
80
 
81
  # Video detection
82
  def detect_video(video_path):
83
+ if video_path is None:
84
+ return None
85
+
86
+ try:
87
+ cap = cv2.VideoCapture(video_path)
88
+ if not cap.isOpened():
89
+ return None
90
+
91
+ fourcc = cv2.VideoWriter_fourcc(*"mp4v")
92
+ out_path = tempfile.mktemp(suffix=".mp4")
93
+
94
+ # Get video properties
95
+ fps = cap.get(cv2.CAP_PROP_FPS)
96
+ width = int(cap.get(cv2.CAP_PROP_FRAME_WIDTH))
97
+ height = int(cap.get(cv2.CAP_PROP_FRAME_HEIGHT))
98
+
99
+ out = cv2.VideoWriter(out_path, fourcc, fps, (width, height))
100
 
101
+ while cap.isOpened():
102
+ ret, frame = cap.read()
103
+ if not ret:
104
+ break
105
+ results = model(frame)
106
+ annotated_frame = results[0].plot()
107
+ out.write(annotated_frame)
 
 
 
 
 
 
 
 
 
 
 
 
108
 
109
+ cap.release()
110
+ out.release()
111
+ return out_path
112
+
113
+ except Exception as e:
114
+ print(f"Error processing video: {e}")
115
+ return None
116
 
117
+ # Custom CSS for better UI
118
+ custom_css = """
119
+ .gradio-container {
120
+ max-width: 1200px !important;
121
+ margin: auto !important;
122
+ }
123
+
124
+ .main-header {
125
+ text-align: center;
126
+ background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
127
+ color: white;
128
+ padding: 2rem;
129
+ border-radius: 10px;
130
+ margin-bottom: 2rem;
131
+ box-shadow: 0 4px 15px rgba(0,0,0,0.1);
132
+ }
133
+
134
+ .department-info {
135
+ background: #f8f9fa;
136
+ border-left: 4px solid #007bff;
137
+ padding: 1rem;
138
+ margin: 1rem 0;
139
+ border-radius: 5px;
140
+ color: #333 !important;
141
+ }
142
+
143
+ .department-info h3 {
144
+ color: #2c3e50 !important;
145
+ margin-bottom: 1rem !important;
146
+ font-weight: 600 !important;
147
+ }
148
+
149
+ .department-info div {
150
+ color: #333 !important;
151
+ }
152
+
153
+ .department-info strong {
154
+ color: #2c3e50 !important;
155
+ font-weight: 600 !important;
156
+ }
157
+
158
+ .upload-area {
159
+ border: 2px dashed #007bff;
160
+ border-radius: 10px;
161
+ padding: 2rem;
162
+ text-align: center;
163
+ background: #f8f9fa;
164
+ transition: all 0.3s ease;
165
+ color: #333 !important;
166
+ }
167
+
168
+ .upload-area:hover {
169
+ border-color: #0056b3;
170
+ background: #e3f2fd;
171
+ }
172
+
173
+ /* Upload area text styling */
174
+ .upload-area .upload-text {
175
+ color: #333 !important;
176
+ font-weight: 500 !important;
177
+ }
178
+
179
+ /* Fix for file upload component text */
180
+ .file-upload {
181
+ color: #333 !important;
182
+ }
183
+
184
+ .file-upload .upload-text {
185
+ color: #333 !important;
186
+ }
187
+
188
+ /* Gradio file upload specific styling */
189
+ .gr-file-upload {
190
+ color: #333 !important;
191
+ }
192
+
193
+ .gr-file-upload .upload-text,
194
+ .gr-file-upload .file-preview,
195
+ .gr-file-upload .file-name {
196
+ color: #333 !important;
197
+ }
198
+
199
+ /* Additional upload component fixes */
200
+ [data-testid="upload-button"] {
201
+ color: #333 !important;
202
+ }
203
+
204
+ .upload-container {
205
+ color: #333 !important;
206
+ }
207
+
208
+ .upload-container * {
209
+ color: #333 !important;
210
+ }
211
+
212
+ /* Specific targeting for upload text */
213
+ .svelte-1nausj1 {
214
+ color: #333 !important;
215
+ }
216
+
217
+ .svelte-1nausj1 * {
218
+ color: #333 !important;
219
+ }
220
+
221
+ .classification-result {
222
+ background: #ffffff !important;
223
+ border: 1px solid #e0e0e0 !important;
224
+ border-radius: 8px !important;
225
+ padding: 1.5rem !important;
226
+ color: #333333 !important;
227
+ font-size: 14px !important;
228
+ line-height: 1.6 !important;
229
+ box-shadow: 0 2px 4px rgba(0,0,0,0.1) !important;
230
+ }
231
+
232
+ .classification-result h3 {
233
+ color: #2c3e50 !important;
234
+ margin-top: 1rem !important;
235
+ margin-bottom: 0.5rem !important;
236
+ }
237
+
238
+ .classification-result p {
239
+ color: #333333 !important;
240
+ margin-bottom: 0.8rem !important;
241
+ }
242
+
243
+ .classification-result strong {
244
+ color: #2c3e50 !important;
245
+ font-weight: 600 !important;
246
+ }
247
+
248
+ .classification-result ul, .classification-result li {
249
+ color: #444444 !important;
250
+ }
251
+
252
+ /* Fix for markdown content */
253
+ .markdown {
254
+ background: #ffffff !important;
255
+ color: #333333 !important;
256
+ }
257
+
258
+ .markdown h1, .markdown h2, .markdown h3, .markdown h4, .markdown h5, .markdown h6 {
259
+ color: #2c3e50 !important;
260
+ }
261
+
262
+ .markdown p, .markdown li, .markdown span {
263
+ color: #333333 !important;
264
+ }
265
+
266
+ .markdown strong {
267
+ color: #2c3e50 !important;
268
+ }
269
+
270
+ footer {
271
+ text-align: center;
272
+ margin-top: 2rem;
273
+ padding: 1rem;
274
+ color: #666;
275
+ }
276
+
277
+ /* Additional text contrast fixes */
278
+ .block.svelte-90oupt {
279
+ background: #ffffff !important;
280
+ }
281
+
282
+ .prose {
283
+ color: #333333 !important;
284
+ }
285
+
286
+ .prose h1, .prose h2, .prose h3 {
287
+ color: #2c3e50 !important;
288
+ }
289
+
290
+ .prose p, .prose li {
291
+ color: #333333 !important;
292
+ }
293
+
294
+ /* Upload component text color fixes */
295
+ .image-container,
296
+ .video-container {
297
+ color: #333 !important;
298
+ }
299
+
300
+ .image-container *,
301
+ .video-container * {
302
+ color: #333 !important;
303
+ }
304
+
305
+ /* More specific upload text targeting */
306
+ div[data-testid*="upload"] {
307
+ color: #333 !important;
308
+ }
309
+
310
+ div[data-testid*="upload"] * {
311
+ color: #333 !important;
312
+ }
313
+
314
+ /* Force text visibility in upload areas */
315
+ .block.svelte-1t38q2d {
316
+ color: #333 !important;
317
+ }
318
+
319
+ .block.svelte-1t38q2d * {
320
+ color: #333 !important;
321
+ }
322
+
323
+ /* Additional upload text fixes */
324
+ .uploading,
325
+ .upload-instructions,
326
+ .drop-zone {
327
+ color: #333 !important;
328
+ }
329
+
330
+ .uploading *,
331
+ .upload-instructions *,
332
+ .drop-zone * {
333
+ color: #333 !important;
334
+ }
335
+ """
336
+
337
+ # Header HTML
338
+ header_html = """
339
+ <div class="main-header">
340
+ <h1>πŸ” SAMADHAN </h1>
341
+ <p>AI-Powered Classification for Urban Infrastructure Management</p>
342
+ <div class="department-info">
343
+ <h3 style="color: #2c3e50 !important; margin-bottom: 1rem;">πŸ“Š Detection Categories:</h3>
344
+ <div style="display: flex; justify-content: center; gap: 2rem; margin-top: 1rem; flex-wrap: wrap;">
345
+ <div style="color: #333 !important; font-weight: 500;"><strong style="color: #2c3e50 !important;">πŸ—‘οΈ Garbage Department:</strong> Container, Garbage</div>
346
+ <div style="color: #333 !important; font-weight: 500;"><strong style="color: #2c3e50 !important;">πŸ•³οΈ Pothole Department:</strong> Cracks, Potholes</div>
347
+ <div style="color: #333 !important; font-weight: 500;"><strong style="color: #2c3e50 !important;">πŸ’‘ Streetlight Department:</strong> Electrical Infrastructure</div>
348
+ </div>
349
+ </div>
350
+ </div>
351
+ """
352
+
353
+ # Footer HTML
354
+ footer_html = """
355
+ <div style="text-align: center; margin-top: 2rem; padding: 1rem; color: #666;">
356
+ <p>Built with ❀️ using YOLOv8 and Gradio | Powered by AI for Smart City Management</p>
357
+ </div>
358
+ """
359
+
360
+ # Interfaces with enhanced UI
361
+ with gr.Blocks(css=custom_css, title="Infrastructure Detection System", theme=gr.themes.Soft()) as demo:
362
+ gr.HTML(header_html)
363
+
364
+ with gr.Tabs() as tabs:
365
+ with gr.TabItem("πŸ“Έ Image Detection", elem_id="image-tab"):
366
+ with gr.Row():
367
+ with gr.Column(scale=1):
368
+ image_input = gr.Image(
369
+ label="Upload Image",
370
+ type="numpy",
371
+ elem_classes="upload-area"
372
+ )
373
+
374
+ gr.Examples(
375
+ examples=[], # Add example image paths here if you have any
376
+ inputs=image_input,
377
+ label="Example Images"
378
+ )
379
+
380
+ image_btn = gr.Button(
381
+ "πŸ” Analyze Image",
382
+ variant="primary",
383
+ size="lg"
384
+ )
385
+
386
+ with gr.Column(scale=1):
387
+ image_output = gr.Image(
388
+ label="Detection Results",
389
+ type="numpy"
390
+ )
391
+
392
+ classification_output = gr.Markdown(
393
+ label="Department Classification",
394
+ elem_classes="classification-result"
395
+ )
396
+
397
+ with gr.TabItem("πŸŽ₯ Video Detection", elem_id="video-tab"):
398
+ with gr.Row():
399
+ with gr.Column(scale=1):
400
+ video_input = gr.Video(
401
+ label="Upload Video",
402
+ elem_classes="upload-area"
403
+ )
404
+
405
+ video_btn = gr.Button(
406
+ "🎬 Process Video",
407
+ variant="primary",
408
+ size="lg"
409
+ )
410
+
411
+ gr.Markdown("""
412
+ ### πŸ“ Video Processing Notes:
413
+ - Supports common video formats (MP4, AVI, MOV)
414
+ - Processing time depends on video length
415
+ - Large videos may take several minutes
416
+ """)
417
+
418
+ with gr.Column(scale=1):
419
+ video_output = gr.Video(
420
+ label="Processed Video with Detections"
421
+ )
422
+
423
+ # Event handlers
424
+ image_btn.click(
425
+ fn=detect_image,
426
+ inputs=image_input,
427
+ outputs=[image_output, classification_output],
428
+ show_progress=True
429
+ )
430
+
431
+ video_btn.click(
432
+ fn=detect_video,
433
+ inputs=video_input,
434
+ outputs=video_output,
435
+ show_progress=True
436
+ )
437
+
438
+ # Auto-process when image is uploaded
439
+ image_input.change(
440
+ fn=detect_image,
441
+ inputs=image_input,
442
+ outputs=[image_output, classification_output],
443
+ show_progress=True
444
+ )
445
+
446
+ gr.HTML(footer_html)
447
 
448
  if __name__ == "__main__":
449
+ print("πŸš€ Starting Infrastructure Detection System...")
450
+ print("πŸ“Š Loading AI model...")
451
+ demo.launch(
452
+ share=False,
453
+ inbrowser=True,
454
+ show_error=True,
455
+ favicon_path=None,
456
+ app_kwargs={"docs_url": None}
457
+ )
requirements.txt CHANGED
@@ -2,3 +2,4 @@ ultralytics==8.3.202
2
  gradio==5.46.0
3
  huggingface_hub==0.35.0
4
  opencv-python==4.12.0.88
 
 
2
  gradio==5.46.0
3
  huggingface_hub==0.35.0
4
  opencv-python==4.12.0.88
5
+ Pillow>=9.0.0