File size: 5,535 Bytes
a2b5362
 
 
 
 
06c0743
 
a2b5362
 
06c0743
 
494daa2
06c0743
494daa2
 
 
 
 
 
 
 
 
 
06c0743
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
a2b5362
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
e78d7b4
 
 
 
 
a2b5362
 
 
 
 
 
 
 
 
 
 
 
 
 
e78d7b4
 
 
 
 
 
 
 
 
 
a2b5362
06c0743
 
e78d7b4
a2b5362
06c0743
 
 
 
 
 
494daa2
 
 
 
 
06c0743
a2b5362
e78d7b4
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
a2b5362
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
import streamlit as st
import cv2
import numpy as np
from PIL import Image
from yolo_inference import build_detector_from_env
from streamlit_webrtc import webrtc_streamer, VideoProcessorBase, RTCConfiguration
import av

# Configuração inicial da página do Streamlit (Título e Layout)
st.set_page_config(page_title="YOLO Detection - Streamlit", layout="wide", page_icon="🚀")

# Configuração RTC para STUN servers (mais robusta para evitar timeouts)
RTC_CONFIGURATION = RTCConfiguration(
    {
        "iceServers": [
            {"urls": ["stun:stun.l.google.com:19302"]},
            {"urls": ["stun:stun1.l.google.com:19302"]},
            {"urls": ["stun:stun2.l.google.com:19302"]},
            {"urls": ["stun:stun3.l.google.com:19302"]},
            {"urls": ["stun:stun4.l.google.com:19302"]},
            {"urls": ["stun:stun.services.mozilla.com"]},
        ]
    }
)

# Lista de classes do dataset personalizado para monitoramento especial
CUSTOM_CLASSES = {"car", "truck", "bus", "motorbike", "bicycle", "van", "threewheel"}

class YoloVideoProcessor(VideoProcessorBase):
    def __init__(self, detector):
        self.detector = detector

    def recv(self, frame):
        img = frame.to_ndarray(format="bgr24")
        
        # Realiza a detecção de objetos
        detections = self.detector.detect(img)
        
        # Desenha os resultados no frame
        img_out = self.detector.draw(img, detections)
        
        # Adiciona overlay de instrução
        cv2.putText(img_out, "YOLO Real-time Detection", (20, 40), 
                    cv2.FONT_HERSHEY_SIMPLEX, 0.7, (0, 255, 0), 2)
        
        return av.VideoFrame.from_ndarray(img_out, format="bgr24")

def main():
    """
    Função principal que gerencia a interface Streamlit.
    Permite alternar entre detecção em imagens estáticas e vídeo em tempo real via webcam.
    """
    st.title("🚀 YOLO Object Detection")
    st.markdown("---")
    st.markdown("### Interface interativa para detecção de objetos usando YOLOv3-tiny.")

    # Sidebar: Painel lateral para controle de parâmetros e seleção de modo
    st.sidebar.header("🛠️ Configurações do Modelo")
    
    # Sliders para ajuste dinâmico dos limiares de detecção
    conf_threshold = st.sidebar.slider("Confiança Mínima (Threshold)", 0.0, 1.0, 0.5, 0.05, 
                                     help="Nível mínimo de certeza para exibir uma detecção.")
    nms_threshold = st.sidebar.slider("NMS Threshold", 0.0, 1.0, 0.4, 0.05,
                                    help="Limiar para supressão de não-máximos (remove bboxes sobrepostas).")
    
    st.sidebar.markdown("---")
    # Seleção do modo de operação
    mode = st.sidebar.radio(
        "📡 Escolha o Modo de Entrada", 
        ["Imagem", "Câmera (Snapshot)", "Câmera (WebRTC)"],
        help="Snapshot: Mais estável em nuvem. WebRTC: Vídeo em tempo real (pode falhar em algumas redes)."
    )

    # Inicializa o detector YOLO
    try:
        detector = build_detector_from_env(conf_threshold=conf_threshold, nms_threshold=nms_threshold)
    except Exception as e:
        st.error(f"❌ Erro ao inicializar detector: {e}")
        return

    if mode == "Imagem":
        st.subheader("📁 Upload e Detecção em Imagem")
        uploaded_file = st.file_uploader("Arraste ou selecione uma imagem...", type=["jpg", "jpeg", "png"])

        if uploaded_file is not None:
            image = Image.open(uploaded_file)
            process_and_display_image(image, detector)

    elif mode == "Câmera (Snapshot)":
        st.subheader("📸 Detecção via Foto (Snapshot)")
        st.info("Este modo é o mais estável para uso em nuvem. Ele tira uma foto e processa a detecção.")
        img_file = st.camera_input("Tirar Foto")
        
        if img_file:
            image = Image.open(img_file)
            process_and_display_image(image, detector)

    elif mode == "Câmera (WebRTC)":
        st.subheader("🎥 Detecção via Webcam (WebRTC)")
        st.info("Vídeo em tempo real. Se a conexão demorar (timeout), use o modo 'Câmera (Snapshot)'.")
        
        webrtc_streamer(
            key="yolo-detection",
            video_processor_factory=lambda: YoloVideoProcessor(detector),
            rtc_configuration=RTC_CONFIGURATION,
            media_stream_constraints={"video": True, "audio": False},
            async_processing=True,
            video_html_attrs={
                "style": {"width": "100%"},
                "controls": False,
                "autoPlay": True,
            },
        )

def process_and_display_image(image, detector):
    """Função auxiliar para processar e exibir os resultados de uma imagem PIL"""
    image_np = np.array(image)
    frame_bgr = cv2.cvtColor(image_np, cv2.COLOR_RGB2BGR)

    with st.spinner('Processando...'):
        detections = detector.detect(frame_bgr)
    
    hits = sorted({d['class_name'] for d in detections if d['class_name'] in CUSTOM_CLASSES})
    
    col1, col2 = st.columns(2)
    with col1:
        st.image(image, caption="Entrada", use_column_width=True)
    with col2:
        result_bgr = detector.draw(frame_bgr, detections)
        result_rgb = cv2.cvtColor(result_bgr, cv2.COLOR_BGR2RGB)
        st.image(result_rgb, caption="Resultado da Detecção", use_column_width=True)

    if hits:
        st.success(f"✅ Objetos detectados: **{', '.join(hits)}**")
    else:
        st.info("ℹ️ Nenhuma classe de interesse detectada.")

if __name__ == "__main__":
    main()