Implementação de Classificação de Imagens com YOLOv5 e ONNX no Raspberry Pi

Introdução ao Hardware e Ambiente

O Raspberry Pi 4B (4GB ou superior) é uma plataforma robusta para prototipagem de visão computacional. Para aplicações que envolvem Inteligência Artificial, como o uso de PyTorch e modelos de Deep Learning, é fundamental utilizar uma versão do sistema operacional Linux de 64 bits para garantir compatibilidade com as bibliotecas modernas.

A configuração básica envolve:

  • Placa Raspberry Pi 4B.
  • Cartão MicroSD de alta velocidade (Classe 10).
  • Módulo de câmera CSI ou câmera USB.
  • Fonte de alimentação estável (5V 3A).

Preparação do Sistema e Acesso Remoto

A gravação da imagem do sistema no cartão SD pode ser feita utilizando ferramentas como o Raspberry Pi Imager ou Win32DiskImager. Após o primeiro boot, recomenda-se configurar o acesso remoto para facilitar o desenvolvimento:

  1. VNC: Permite o acesso à interface gráfica de forma remota. Ative através do raspi-config.
  2. SSH: Essencial para transferência de arquivos via protocolos SFTP (utilizando ferramentas como WinSCP ou FileZilla) e execução de comandos via terminal.

Configuração de Visão Computacional com OpenCV

O primeiro passo para o processamento de imagem é a instalação do OpenCV e das dependências de suporte numérico. Execute os comandos abaixo no terminal do Raspberry Pi:

pip install opencv-python -i https://pypi.tuna.tsinghua.edu.cn/simple
pip install numpy --upgrade

Para validar o funcionaemnto da câmera, utilize o seguinte script Python:

import cv2

def test_camera_stream():
   # Inicializa a captura (0 para câmera padrão)
   video_capture = cv2.VideoCapture(0)
   
   # Define a resolução de captura
   video_capture.set(cv2.CAP_PROP_FRAME_WIDTH, 640)
   video_capture.set(cv2.CAP_PROP_FRAME_HEIGHT, 480)

   while True:
       success, img_frame = video_capture.read()
       if not success:
           break
           
       # Converte para tons de cinza para processamento simples
       gray_view = cv2.cvtColor(img_frame, cv2.COLOR_BGR2GRAY)
       
       cv2.imshow("Stream Original", img_frame)
       cv2.imshow("Stream Cinza", gray_view)

       # Sai do loop ao pressionar 'q'
       if cv2.waitKey(1) & 0xFF == ord('q'):
           break

   video_capture.release()
   cv2.destroyAllWindows()

if __name__ == "__main__":
   test_camera_stream()

Detecção de Objetos com YOLOv5

O deploy do modelo YOLOv5 no Raspberry Pi requer a instalação das dependências listadas no repositório oficial do YOLOv5. O processo de inferência pode ser executado diretamente com arquivos .pt (PyTorch), mas o desempenho em processadores ARM costuma ser limitado.

# Instalação de dependências
pip install -r requirements.txt

# Execução da detecção via terminal
python detect.py --weights best.pt --source 0

Otimização de Performance com ONNX Runtime

Para obter taxas de quadros por segundo (FPS) mais altas, recomenda-se a conversão do modelo PyTorch para o formato ONNX. O formato ONNX é otimizado para inferência em CPUs.

# Exportação para ONNX
python export.py --weights best.pt --include onnx

# Instalação do runtime
pip install onnx onnxruntime

Abaixo, um exemplo de implementação de um motor de inferência utilizando ONNX Runtime para procesamento em tempo real:

import cv2
import numpy as np
import onnxruntime
import time

class DetectorYolo:
   def __init__(self, path_model):
       self.session = onnxruntime.InferenceSession(path_model)
       self.input_layer = self.session.get_inputs()[0].name
       self.labels = ['classe_A', 'classe_B'] # Substituir pelas classes reais

   def transform_img(self, frame):
       blob = cv2.resize(frame, (640, 640))
       blob = blob[:, :, ::-1].transpose(2, 0, 1) # BGR para RGB e HWC para CHW
       blob = blob.astype(np.float32) / 255.0
       return np.expand_dims(blob, axis=0)

   def predict(self, frame):
       input_data = self.transform_img(frame)
       raw_results = self.session.run(None, {self.input_layer: input_data})[0]
       return raw_results

def calcular_nms(detections, threshold_iou):
   # Lógica de Non-Maximum Suppression para filtrar boxes sobrepostas
   x1 = detections[:, 0]
   y1 = detections[:, 1]
   x2 = detections[:, 2]
   y2 = detections[:, 3]
   scores = detections[:, 4]

   areas = (x2 - x1 + 1) * (y2 - y1 + 1)
   order = scores.argsort()[::-1]
   keep = []

   while order.size > 0:
       idx = order[0]
       keep.append(idx)
       xx1 = np.maximum(x1[idx], x1[order[1:]])
       yy1 = np.maximum(y1[idx], y1[order[1:]])
       xx2 = np.minimum(x2[idx], x2[order[1:]])
       yy2 = np.minimum(y2[idx], y2[order[1:]])

       w = np.maximum(0, xx2 - xx1 + 1)
       h = np.maximum(0, yy2 - yy1 + 1)
       inter = w * h
       iou = inter / (areas[idx] + areas[order[1:]] - inter)

       inds = np.where(iou <= threshold_iou)[0]
       order = order[inds + 1]
   return keep

def run_realtime_inference(model_path):
   engine = DetectorYolo(model_path)
   cam = cv2.VideoCapture(0)

   while cam.isOpened():
       ret, frame = cam.read()
       if not ret: break

       start = time.time()
       output = engine.predict(frame)
       
       # Processamento simplificado de desenho (exemplo)
       fps = 1.0 / (time.time() - start)
       cv2.putText(frame, f"FPS: {fps:.2f}", (20, 40), 
                   cv2.FONT_HERSHEY_DUPLEX, 1, (0, 255, 0), 2)
       
       cv2.imshow("Inferencia ONNX", frame)
       if cv2.waitKey(1) == ord('q'): break

   cam.release()
   cv2.destroyAllWindows()

if __name__ == "__main__":
   run_realtime_inference("best.onnx")

Ao utilizar o ONNX Runtime, o Raspberry Pi consegue gerenciar melhor os recursos da CPU, reduzindo a latência significativamente em comparação com a execução direta no framework de treinamento.

Tags: raspberry-pi YOLOv5 ONNX OpenCV Python

Publicado em 7-16 08:40