Introdução
Na primeira parte deste artigo, exploramos os princípios fundamentais da visão computacional e apresentamos bibliotecas e algoritmos utilizadas na área. Nessa segunda parte, iremos utilizar uma abordagem prática com o YOLOv11, algoritmo de detecção de objetos, desenvolvido pela Ultralytics. Mostraremos como configurar o ambiente, carregar um modelo YOLOv11 pré-treinado, detectar objetos em imagens e vídeos, e interpretar os resultados.
Detecção de objetos
Utilizaremos um notebook Python no ambiente Google Colab, como exemplo, porém o passo a passo pode ser seguido em qualquer outro ambiente.
Com sua conta Google, acesso o Google Colab: https://colab.research.google.com e crie um novo notebook, clicando em 'New notebook'.
Instalação de bibliotecas
Primeiramente, instalaremos a biblioteca da Ultralytics com o gerenciador de pacotes do Python, pip:
! pip install ultralytics
Utilização
Em seguida, iremos carregar um modelo YOLO versão 11 pré-treinado. Ao executar o seguinte trecho de código, um modelo será baixado do GitHub da Ultralytics para o ambiente do notebook.
from ultralytics import YOLO
model = YOLO("yolo11n.pt") # ou YOLO("yolo11n.yaml") para criar um modelo do zero
Treinamento
Treinaremos o modelo com o dataset de Common Objects in Context (ou COCO) versão 8, utilizando 5 epochs.
COCO é um conjunto de dados de detecção, segmentação e legendagem de objetos em larga escala. Em sua versão completa, ele possui mais de 200 mil imagens rotuladas, 80 categorias de objetos e 91 categorias de "coisas". Para fins de teste, utilizaremos um versão menor, composto das primeiras 128 imagens do COCO Train 2017.
Já epoch, se refere a uma passagem completa por todo o conjunto de dados de treinamento. Imagine que você tem um conjunto de imagens com rótulos, usado para treinar um modelo para detectar objetos. Durante uma epoch, o modelo "vê" todas essas imagens uma vez, ajustando seus pesos internos para aprender a fazer previsões mais precisas. Portanto, se você treinar um modelo com 50 epochs, isso significa que ele passará 50 vezes por todo o conjunto de dados. Escolher um número baixo de epochs pode causar o que chamamos de underfitting, onde o modelo aprende pouco. O oposto disso também pode ser prejudicial, pois o modelo aprende demais os dados de treino e perde capacidade de generalização, chamado de overfitting.
results = model.train(data="coco128.yaml", epochs=5)
Depois de treinado, note que foram criados diretórios para o dataset e para o resultado dos treinamentos (métricas e pesos), em runs > detect > train
. No diretório de weights
, estão os pesos treinados do modelo. O arquivo best.pt
representa o modelo com o melhor desempenho obtido durante o treinamento, medido com base em alguma métrica de validação, geralmente mAP (mean Average Precision). Já o last.pt
, é o modelo salvo ao final do treinamento, independentemente de seu desempenho. De modo geral, podemos escolher o best.pt
para detectar os objetos pós treinamento, e last.pt
quando quisermos continuar o treinamento de onde parou.
Para sabermos se o modelo está desempenhando bem, podemos consultar as métricas disponíveis na imagem runs/detect/train/results.png
. Nela, podemos ver a evolução do desempenho do modelo a cada epoch.
- Precision é a proporção de previsões corretas entre todas as previsões positivas feitas. Alta precisão significa que o modelo não comete muitos falsos positivos
- Recall é a proporção de objetos verdadeiros que o modelo conseguiu identificar corretamente. Alto recall significa que o modelo não deixa escapar muitos objetos reais.
- mAP_0.5 e mAP_0.5:0.95 são métrica de mean Average Precision. mAP_0.5 é a média da precisão com IoU ≥ 0.5, idealmente deve ficar acima de 0.5 (ou 50%) para tarefas gerais. Enquanto mAP_0.5:0.95 é a média da precisão com múltiplos limiares de IoU (de 0.5 a 0.95, com passo 0.05), idealmente ficando acima de 0.75 (ou 75%) em contextos profissionais mais exigentes.
Na imagem abaixo, podemos ver que a precisão está aumentando, porém o recall está instável. Além disso, pela baixa quantidade de epochs, os gráficos encontram-se muito instáveis.
Testando com 20 epochs, podemos notar que as curvas de loss de caem de forma consistente, o que indica que o modelo está conseguindo aprender com os dados. A precisão, apesar das oscilações, aparente estar aumentando. indicando que o modelo está acertando mais quando prevê a presença de objetos, e o recall está crescendo constantemente, o que indica que o modelo está detectando mais objetos verdadeiros ao longo do tempo.
Mas agora você pode estar se perguntando qual é o número ideal de epochs, e a resposta é: depende. Para datasets menores, como o COCO 128, de 50 e 100 epochs pode ser o suficiente, mas para grandes volumes de imagens, pode ser necessário mais de 300 epochs.
Para minimizar a tentativa e erro ao escolher o número de epochs, podemos utilizar o parâmetro patience
, que serve para interromper automaticamente o treino quando não há melhora nas métricas por várias épocas consecutivas. Continuando nossa análise, agora podemos definir, por exemplo, epochs=100
e patience=15
, que gera o resultado da figura a seguir.
Podemos notar que nos logs, foi mostrado que o treinamento parou mais cedo pois nenhuma melhora foi observada nas últimas 15 epochs, e os melhores resultados foram observados na epoch de número 73.
Sobre as métricas, observamos que a precisão cresceu e se estabilizou por volta de 0.90, o recall atingiu aproximadamente 0.85 e mAP50 chegou a 0.91, o que são bons resultados para o dataset.
Predição
Agora que temos o nosso modelo treinado, podemos utilizá-lo da seguinte forma:
model = YOLO("./runs/detect/train/weights/best.pt")
Note que, nós fizemos diferentes treinamentos, portanto várias versões do diretório "train". Então, certifique-se que você ajustou o caminho do arquivo para o último treinamento.
Então, podemos utilizar o modelo para fazer uma predição com:
results = model("https://ultralytics.com/images/bus.jpg", save=True)
O resultado da predição será salvo em 'runs/detect/predict'.
Detecção de objetos em vídeos
Para detectar objetos em vídeos, precisaremos primeiramente instalar a biblioteca OpenCV para Python, com:
! pip install opencv-python
Então, com o trecho de código abaixo, recebemos um arquivo de vídeo no formato .mp4 (input.mp4
), processamos cada frame, utilizando o modelo para predizer o resultado e escrevemos em um novo frame, que fará parte de um novo arquivo de vídeo, output.mp4
.
import cv2
input_path = "input.mp4"
output_path = "output.mp4"
cap = cv2.VideoCapture(input_path)
width = int(cap.get(cv2.CAP_PROP_FRAME_WIDTH))
height = int(cap.get(cv2.CAP_PROP_FRAME_HEIGHT))
fps = cap.get(cv2.CAP_PROP_FPS)
fourcc = cv2.VideoWriter_fourcc(*'mp4v')
out = cv2.VideoWriter(output_path, fourcc, fps, (width, height))
while cap.isOpened():
ret, frame = cap.read()
if not ret:
break
results = model(frame)
annotated_frame = results[0].plot()
out.write(annotated_frame)
cap.release()
out.release()
cv2.destroyAllWindows()
O resultado pode ser visto abaixo.
Top comments (1)
Muito bom seu tutorial. Parabéns. Onde posso encontrar a parte 1? Obrigado.