Marcus Vinicius Zerbini Canhaço commited on
Commit
d78970a
·
1 Parent(s): eb1a752

feat: atualização do detector com otimizações para GPU T4

Browse files
README.md CHANGED
@@ -1,29 +1,28 @@
1
- ---
2
- title: Weapon Detection App
3
- emoji: 🚨
4
- colorFrom: red
5
- colorTo: yellow
6
- sdk: gradio
7
- sdk_version: 5.15.0
8
- app_file: app.py
9
- pinned: false
10
- license: mit
11
- hardware: true
12
- resources:
13
- accelerator: T4
14
- gpu: true
15
- ---
16
-
17
- Sistema de detecção de objetos de risco em vídeos usando OWL-ViT e processamento
18
  GPU/CPU otimizado.
19
 
20
  [![Open in Hugging Face][hf-badge]][hf-space]
21
  [![GitHub][gh-badge]][gh-repo]
22
 
23
  [hf-badge]: https://img.shields.io/badge/Hugging%20Face-Spaces-yellow
24
- [hf-space]: https://huggingface.co/spaces/seu-usuario/seu-espaco
25
  [gh-badge]: https://img.shields.io/badge/GitHub-Repo-blue
26
- [gh-repo]: https://github.com/seu-usuario/hackatoon-1iadt
27
 
28
  ## Funcionalidades
29
 
 
1
+ # Detecção de Armas - FIAP Vision Guard - Hackatoon 1IADT
2
+
3
+ ## Sobre o Projeto
4
+
5
+ A FIAP VisionGuard é uma empresa especializada em monitoramento de câmeras de segurança que busca inovar através da implementação de tecnologias avançadas de detecção de riscos. Este projeto demonstra a viabilidade de uma nova funcionalidade que utiliza Inteligência Artificial para identificar objetos potencialmente perigosos em tempo real, como armas brancas (facas, tesouras e similares) e outros objetos de risco.
6
+
7
+ ### Objetivo
8
+
9
+ O sistema visa otimizar a segurança de estabelecimentos e comércios através de:
10
+
11
+ - Detecção automática de objetos perigosos
12
+ - Emissão de alertas em tempo real para centrais de segurança
13
+ - Análise contínua de feeds de vídeo
14
+ - Redução do tempo de resposta a incidentes
15
+
16
+ Sistema de detecção de objetos de risco em vídeos usando OWLV2-ViT e processamento
 
17
  GPU/CPU otimizado.
18
 
19
  [![Open in Hugging Face][hf-badge]][hf-space]
20
  [![GitHub][gh-badge]][gh-repo]
21
 
22
  [hf-badge]: https://img.shields.io/badge/Hugging%20Face-Spaces-yellow
23
+ [hf-space]: https://huggingface.co/spaces/marcuscanhaco/weapon-detection-app
24
  [gh-badge]: https://img.shields.io/badge/GitHub-Repo-blue
25
+ [gh-repo]: https://github.com/mvzcanhaco/hackatoon-1IADT-fiap
26
 
27
  ## Funcionalidades
28
 
src/application/use_cases/process_video.py CHANGED
@@ -144,10 +144,11 @@ Tempo de análise: {result.analysis_time:.2f}s"""
144
  # Adicionar detalhes das detecções se houver
145
  if result.detections:
146
  message += "\n\nDetecções encontradas:"
147
- for i, det in enumerate(result.detections[:3], 1): # Mostrar até 3 detecções
148
- message += f"\n{i}. {det.label} (Confiança: {det.confidence:.1%}, Frame: {det.frame})"
149
- if len(result.detections) > 3:
150
- message += f"\n... e mais {len(result.detections) - 3} detecção(ões)"
 
151
 
152
  return message
153
 
 
144
  # Adicionar detalhes das detecções se houver
145
  if result.detections:
146
  message += "\n\nDetecções encontradas:"
147
+ for i, det in enumerate(result.detections[:5], 1): # Mostrar até 5 detecções
148
+ confidence_pct = det.confidence * 100 if det.confidence <= 1.0 else det.confidence
149
+ message += f"\n{i}. {det.label} (Confiança: {confidence_pct:.1f}%, Frame: {det.frame})"
150
+ if len(result.detections) > 5:
151
+ message += f"\n... e mais {len(result.detections) - 5} detecção(ões)"
152
 
153
  return message
154
 
src/domain/detectors/gpu.py CHANGED
@@ -163,35 +163,82 @@ class WeaponDetectorGPU(BaseDetector):
163
  # Calcular duração do vídeo
164
  metrics["video_duration"] = len(frames) / (fps or 2)
165
 
166
- # Processar frames
167
  t0 = time.time()
168
- for i, frame in enumerate(frames):
169
- frame_rgb = cv2.cvtColor(frame, cv2.COLOR_BGR2RGB)
170
- frame_pil = Image.fromarray(frame_rgb)
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
171
 
172
- detections = self.detect_objects(frame_pil, threshold)
 
 
 
 
 
 
 
 
 
 
 
 
 
173
 
174
- # Filtrar apenas detecções válidas (sem filtrar unknown)
175
- valid_detections = [
176
- {
177
- "confidence": d["confidence"],
178
- "box": d["box"],
179
- "label": d["label"],
180
- "timestamp": i / (fps or 2)
181
- }
182
- for d in detections
183
- if d["confidence"] > threshold
184
- ]
 
 
 
 
 
 
 
 
 
 
 
 
 
 
185
 
186
- if valid_detections:
187
- metrics["detections"].append({
188
- "frame": i,
189
- "detections": valid_detections
190
- })
191
 
192
  # Atualizar métricas finais
193
  metrics["analysis_time"] = time.time() - t0
194
  metrics["total_time"] = time.time() - start_time
 
195
 
196
  return video_path, metrics
197
 
 
163
  # Calcular duração do vídeo
164
  metrics["video_duration"] = len(frames) / (fps or 2)
165
 
166
+ # Processar frames em batch
167
  t0 = time.time()
168
+ batch_size = 16 # Aumentado para T4 dedicada
169
+ detections_by_frame = []
170
+
171
+ for i in range(0, len(frames), batch_size):
172
+ batch_frames = frames[i:i + batch_size]
173
+ batch_pil_frames = []
174
+
175
+ # Preparar batch
176
+ for frame in batch_frames:
177
+ frame_rgb = cv2.cvtColor(frame, cv2.COLOR_BGR2RGB)
178
+ frame_pil = Image.fromarray(frame_rgb)
179
+ frame_pil = self._preprocess_image(frame_pil)
180
+ batch_pil_frames.append(frame_pil)
181
+
182
+ # Processar batch
183
+ batch_inputs = self.owlv2_processor(
184
+ images=batch_pil_frames,
185
+ return_tensors="pt",
186
+ padding=True
187
+ )
188
+ batch_inputs = {
189
+ key: val.to(self.device)
190
+ for key, val in batch_inputs.items()
191
+ }
192
 
193
+ # Inferência em batch
194
+ with torch.no_grad():
195
+ inputs = {**batch_inputs, **self.processed_text}
196
+ outputs = self.owlv2_model(**inputs)
197
+
198
+ target_sizes = torch.tensor(
199
+ [frame.size[::-1] for frame in batch_pil_frames],
200
+ device=self.device
201
+ )
202
+ results = self.owlv2_processor.post_process_grounded_object_detection(
203
+ outputs=outputs,
204
+ target_sizes=target_sizes,
205
+ threshold=threshold
206
+ )
207
 
208
+ # Processar resultados do batch
209
+ for frame_idx, frame_results in enumerate(results):
210
+ if len(frame_results["scores"]) > 0:
211
+ scores = frame_results["scores"]
212
+ boxes = frame_results["boxes"]
213
+ labels = frame_results["labels"]
214
+
215
+ frame_detections = []
216
+ for score, box, label in zip(scores, boxes, labels):
217
+ score_val = score.item()
218
+ if score_val >= threshold:
219
+ label_idx = min(label.item(), len(self.text_queries) - 1)
220
+ label_text = self.text_queries[label_idx]
221
+ frame_detections.append({
222
+ "confidence": round(score_val * 100, 2),
223
+ "box": [int(x) for x in box.tolist()],
224
+ "label": label_text
225
+ })
226
+
227
+ if frame_detections:
228
+ frame_detections = self._apply_nms(frame_detections)
229
+ detections_by_frame.append({
230
+ "frame": i + frame_idx,
231
+ "detections": frame_detections
232
+ })
233
 
234
+ # Liberar memória do batch
235
+ del batch_inputs, outputs
236
+ torch.cuda.empty_cache()
 
 
237
 
238
  # Atualizar métricas finais
239
  metrics["analysis_time"] = time.time() - t0
240
  metrics["total_time"] = time.time() - start_time
241
+ metrics["detections"] = detections_by_frame
242
 
243
  return video_path, metrics
244
 
src/infrastructure/services/weapon_detector.py CHANGED
@@ -70,17 +70,19 @@ class WeaponDetectorService(DetectorInterface):
70
 
71
  # Converter detecções para entidades do domínio
72
  detections = []
73
- for d in metrics.get('detections', []):
74
- try:
75
- detections.append(Detection(
76
- frame=d.get('frame', 0),
77
- confidence=d.get('confidence', 0.0),
78
- label=d.get('label', 'unknown'),
79
- box=d.get('box', [0, 0, 0, 0]),
80
- timestamp=d.get('frame', 0) / fps if fps else 0
81
- ))
82
- except Exception as e:
83
- logger.error(f"Erro ao processar detecção: {str(e)}")
 
 
84
 
85
  result = DetectionResult(
86
  video_path=output_path or video_path,
 
70
 
71
  # Converter detecções para entidades do domínio
72
  detections = []
73
+ for detection_group in metrics.get('detections', []):
74
+ frame = detection_group.get('frame', 0)
75
+ for det in detection_group.get('detections', []):
76
+ try:
77
+ detections.append(Detection(
78
+ frame=frame,
79
+ confidence=det.get('confidence', 0.0),
80
+ label=det.get('label', 'objeto perigoso'), # Valor padrão mais informativo
81
+ box=det.get('box', [0, 0, 0, 0]),
82
+ timestamp=frame / fps if fps else 0
83
+ ))
84
+ except Exception as e:
85
+ logger.error(f"Erro ao processar detecção: {str(e)}")
86
 
87
  result = DetectionResult(
88
  video_path=output_path or video_path,
src/main.py CHANGED
@@ -61,19 +61,22 @@ def setup_gpu_environment(gpu_type: str) -> bool:
61
  gc.collect()
62
 
63
  if gpu_type == "t4_dedicated":
64
- # Configurações para T4 dedicada
65
  logger.info("Configurando para T4 dedicada")
66
  torch.backends.cuda.matmul.allow_tf32 = True
67
  torch.backends.cudnn.benchmark = True
68
  torch.backends.cudnn.allow_tf32 = True
69
- # Usar mais memória pois temos GPU dedicada
70
- torch.cuda.set_per_process_memory_fraction(0.9)
71
- os.environ['PYTORCH_CUDA_ALLOC_CONF'] = 'max_split_size_mb:512'
 
 
72
 
73
  elif gpu_type == "zero_gpu_shared":
74
  # Configurações para Zero-GPU compartilhada
75
  logger.info("Configurando para Zero-GPU compartilhada")
76
  torch.backends.cudnn.benchmark = False
 
77
  # Limitar uso de memória
78
  torch.cuda.set_per_process_memory_fraction(0.6)
79
  os.environ['PYTORCH_CUDA_ALLOC_CONF'] = 'max_split_size_mb:128'
 
61
  gc.collect()
62
 
63
  if gpu_type == "t4_dedicated":
64
+ # Configurações otimizadas para T4 dedicada
65
  logger.info("Configurando para T4 dedicada")
66
  torch.backends.cuda.matmul.allow_tf32 = True
67
  torch.backends.cudnn.benchmark = True
68
  torch.backends.cudnn.allow_tf32 = True
69
+ torch.backends.cudnn.enabled = True
70
+ torch.backends.cudnn.deterministic = False
71
+ # Aumentar fração de memória e tamanho do split
72
+ torch.cuda.set_per_process_memory_fraction(0.95) # Aumentado para 95%
73
+ os.environ['PYTORCH_CUDA_ALLOC_CONF'] = 'max_split_size_mb:1024' # Aumentado para 1GB
74
 
75
  elif gpu_type == "zero_gpu_shared":
76
  # Configurações para Zero-GPU compartilhada
77
  logger.info("Configurando para Zero-GPU compartilhada")
78
  torch.backends.cudnn.benchmark = False
79
+ torch.backends.cudnn.deterministic = True
80
  # Limitar uso de memória
81
  torch.cuda.set_per_process_memory_fraction(0.6)
82
  os.environ['PYTORCH_CUDA_ALLOC_CONF'] = 'max_split_size_mb:128'
src/presentation/web/gradio_interface.py CHANGED
@@ -279,7 +279,37 @@ class GradioInterface:
279
 
280
  response = self.use_case.execute(request)
281
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
282
  return (
283
  response.status_message,
284
- response.detection_result.__dict__
285
  )
 
279
 
280
  response = self.use_case.execute(request)
281
 
282
+ # Formatar saída para o Gradio
283
+ status_color = "#ff0000" if response.detections else "#00ff00"
284
+ status_html = f"""
285
+ <div style='padding: 1em; background: {status_color}20; border-radius: 8px;'>
286
+ <h3 style='color: {status_color}; margin: 0;'>
287
+ {"⚠️ RISCO DETECTADO" if response.detections else "✅ SEGURO"}
288
+ </h3>
289
+ <p style='margin: 0.5em 0;'>
290
+ Processado em: {response.device_type}<br>
291
+ Total de detecções: {len(response.detections)}<br>
292
+ Frames analisados: {response.frames_analyzed}<br>
293
+ Tempo total: {response.total_time:.2f}s
294
+ </p>
295
+ </div>
296
+ """
297
+
298
+ if response.detections:
299
+ status_html += "<div style='margin-top: 1em;'><h4>Detecções:</h4><ul>"
300
+ for det in response.detections[:5]: # Mostrar até 5 detecções
301
+ confidence_pct = det.confidence * 100 if det.confidence <= 1.0 else det.confidence
302
+ status_html += f"""
303
+ <li style='margin: 0.5em 0;'>
304
+ <strong>{det.label}</strong><br>
305
+ Confiança: {confidence_pct:.1f}%<br>
306
+ Frame: {det.frame}
307
+ </li>"""
308
+ if len(response.detections) > 5:
309
+ status_html += f"<li>... e mais {len(response.detections) - 5} detecção(ões)</li>"
310
+ status_html += "</ul></div>"
311
+
312
  return (
313
  response.status_message,
314
+ status_html
315
  )