Neste tutorial, vais aprender a detetar e classificar objetos usando o módulo ESP32-CAM e o YOLO, um sistema de deep learning para deteção de objetos.
Vou guiar-te na construção de um projeto onde o ESP32-CAM captura imagens, funciona como servidor web e envia as imagens para um computador para análise. O computador usará o YOLO para detetar e classificar objetos. Vais aprender a montar o hardware, configurar a câmara e servir imagens JPEG via HTTP.
No final, terás uma interface web funcional para ver as fotos capturadas pelo teu ESP32-CAM e um sistema de deteção de objetos para 80 tipos diferentes de objetos.
Peças Necessárias
A seguir encontras os componentes necessários para construir o projeto. Em vez do Programador FTDI, também podes usar um Programming Shield para o ESP32-CAM, mas recomendo o primeiro.

ESP32-CAM

Adaptador FTDI USB-TTL

Cabo USB de Dados

Arduino IDE
Makerguides is a participant in affiliate advertising programs designed to provide a means for sites to earn advertising fees by linking to Amazon, AliExpress, Elecrow, and other sites. As an Affiliate we may earn from qualifying purchases.
Arquitetura do Sistema
O sistema que vamos construir é composto por dois componentes principais: 1) um módulo ESP32-CAM que captura imagens e funciona como servidor web que envia as imagens via WiFi; 2) um PC onde o YOLO sistema de deteção de objetos está a correr. Ele analisa as imagens e anota os objetos detetados. O diagrama abaixo dá uma visão geral da arquitetura do sistema:

A imagem seguinte mostra um exemplo de deteção do sistema. Na minha secretária desarrumada, o YOLO conseguiu detetar uma chávena com 88% de confiança, um par de tesouras com 68% e um portátil com 59%. Podes ver as caixas delimitadoras em volta dos objetos com os seus nomes e a confiança da deteção anotados no canto superior esquerdo:

Nas próximas secções vais aprender a programar o servidor web no ESP32-CAM e a configurar o sistema de deteção YOLO num PC.
Placa de Desenvolvimento ESP32-CAM
A Placa de Desenvolvimento ESP32-CAM é um módulo compacto que combina um chip ESP32-S, uma câmara, um flash incorporado e um slot para cartão microSD. A placa tem Wi-Fi e Bluetooth integrados e suporta uma câmara OV2640 ou OV7670 com até 2 megapixels de resolução.

No tutorial vamos referir-nos ao AI-Thinker model original da placa ESP32-CAM, mas existem muitos clones com exatamente as mesmas especificações. São programados e usados da mesma forma – incluindo o que listámos em Peças Necessárias.
Ligação do programador FTDI
Podes programar o ESP32-CAM via um Programming Shield ou via um FTDI Programmer. Este último é mais fácil de usar e mais flexível. Converte sinais USB em sinais seriais e permite programar microcontroladores como o Arduino e o ESP32 via interface UART. A imagem seguinte mostra como ligar o Programador FTDI ao módulo ESP32-CAM.

As ligações são simples. Começa por ligar o GND do Programador ao GND do módulo ESP32-CAM (fio azul). Depois faz o mesmo com a alimentação de 5V (fio vermelho). Nota que alguns Programadores FTDI têm jumpers ou interruptores para mudar de 3.3V para 5V. Atenção a isso e usa 5V, se possível.
De seguida ligamos o pino U0T (U0TXD) do ESP32-CAM ao pino RXD do Programador (fio amarelo). De forma semelhante, o U0R liga-se ao TXD (fio verde). Com isso, a comunicação serial fica estabelecida.
Para colocar o ESP32-CAM em modo de programação, o pino IO0 precisa de ser ligado ao terra (GND). Mas para executar o programa, o pino IO0 deve ficar desconectado. Por isso, adicionei um interruptor entre IO0 e GND (fio roxo) que me permite alternar entre modo de programação e modo de execução. A foto abaixo mostra a minha ligação do ESP32-CAM com o interruptor e o Programador FTDI:

Instalar o Core ESP32
Se este é o teu primeiro projeto com qualquer placa da série ESP32, precisas primeiro de instalar a placa. Se já tens as placas ESP32 instaladas no Arduino IDE, podes saltar esta secção.
Começa por abrir o diálogo de Preferências selecionando “Preferences…” no menu “File”. Isto abrirá o diálogo de Preferências mostrado abaixo.
Na aba Settings encontrarás uma caixa de edição na parte inferior do diálogo rotulada “Additional boards manager URLs”:

Neste campo de entrada copia a seguinte URL: “https://espressif.github.io/arduino-esp32/package_esp32_dev_index.json“
Isto permite ao Arduino IDE saber onde encontrar as bibliotecas core do ESP32. A seguir vamos instalar as bibliotecas core do ESP32 usando o Boards Manager.
Abre o Boards Manager via “Tools -> Boards -> Board Manager”. Vais ver o Boards Manager aparecer na barra lateral esquerda. Escreve “ESP32” no campo de pesquisa no topo e deverás ver dois tipos de placas ESP32; as “Arduino ESP32 Boards” e as placas “esp32 by Espressif”. Queremos as bibliotecas esp32 da Espressif. Clica no botão INSTALL e espera até o download e instalação terminarem.

Selecionar a placa ESP32-CAM
Clica no menu drop-down e depois em “Select other board and port…”:

Isto abrirá um diálogo onde escreves “ESP32-CAM” na barra de pesquisa. Vais ver a placa “AI Thinker ESP32-CAM” em Boards. Clica nela, seleciona a porta COM para ativá-la e depois clica OK:

Se não conseguires selecionar uma PORTA apesar do ESP32-CAM estar ligado a uma porta USB via programador FTDI, então falta o driver CP210X. Vai a SILICON LABS Software Downloads e descarrega o driver CP210x para o teu sistema operativo, por exemplo, para Windows é “CP210x VCP Windows”:

Isto vai descarregar um ficheiro ZIP. Descompacta-o e executa o instalador. Depois disso, o teu ESP32-CAM deverá aparecer como ligado a uma porta USB. Se ainda tiveres problemas, pode ser necessário instalar também um FTDI Driver.
Instalar a biblioteca ESP32-CAM
Para o nosso Servidor Web vamos usar a esp32cam library. Vai ao github repo, clica no botão verde CODE e depois em “Download ZIP” para descarregar a biblioteca:

Depois clica em “Sketch->Include Library->Add .Zip Library”:

e seleciona o caminho para o ficheiro ZIP que acabaste de descarregar para instalar a biblioteca. Na próxima secção vamos escrever e explicar o código para correr um Servidor Web no ESP32-CAM.
Código para Servidor Web ESP32-CAM
O código seguinte configura um módulo ESP32-CAM para enviar imagens através de uma rede Wi-Fi. Ele captura imagens e serve-as como ficheiros JPEG aos clientes que as solicitam. O servidor corre na porta 80, que é a porta HTTP padrão.
#include "WebServer.h"
#include "WiFi.h"
#include "esp32cam.h"
const char* WIFI_SSID = "SSID";
const char* WIFI_PASS = "PASSWORD";
const char* URL = "/cam.jpg";
static auto RES = esp32cam::Resolution::find(800, 600);
WebServer server(80);
void serveJpg() {
auto frame = esp32cam::capture();
if (frame == nullptr) {
Serial.println("CAPTURE FAILED!");
server.send(503, "", "");
return;
}
Serial.printf("CAPTURE OK %dx%d %db\n",
frame->getWidth(), frame->getHeight(),
static_cast<int>(frame->size()));
server.setContentLength(frame->size());
server.send(200, "image/jpeg");
WiFiClient client = server.client();
frame->writeTo(client);
}
void handleJpg() {
if (!esp32cam::Camera.changeResolution(RES)) {
Serial.println("CAN'T SET RESOLUTION!");
}
serveJpg();
}
void initCamera() {
{
using namespace esp32cam;
Config cfg;
cfg.setPins(pins::AiThinker);
cfg.setResolution(RES);
cfg.setBufferCount(2);
cfg.setJpeg(80);
bool ok = Camera.begin(cfg);
Serial.println(ok ? "CAMERA OK" : "CAMERA FAIL");
}
}
void initWifi() {
WiFi.persistent(false);
WiFi.mode(WIFI_STA);
WiFi.begin(WIFI_SSID, WIFI_PASS);
while (WiFi.status() != WL_CONNECTED)
;
Serial.printf("http://%s%s\n",
WiFi.localIP().toString().c_str(), URL);
}
void initServer() {
server.on(URL, handleJpg);
server.begin();
}
void setup() {
Serial.begin(115200);
initWifi();
initCamera();
initServer();
}
void loop() {
server.handleClient();
}
Vamos decompor o código em componentes para entender como funciona.
Bibliotecas e Constantes
No início do código, incluímos as bibliotecas necessárias para o servidor web, funcionalidade Wi-Fi e controlo da câmara.
#include "WebServer.h" #include "WiFi.h" #include "esp32cam.h"
Também definimos constantes para as credenciais Wi-Fi e o endpoint URL para aceder à imagem da câmara.
const char* WIFI_SSID = "SSID"; const char* WIFI_PASS = "PASSWORD"; const char* URL = "/cam.jpg";
Obviamente, terás de substituir as credenciais pelo SSID e password da tua rede Wi-Fi.
Resolução da Câmara
Definimos a resolução desejada para a câmara. Neste caso, procuramos uma resolução de 800×600 pixels.
static auto RES = esp32cam::Resolution::find(800, 600);
Inicialização do Servidor Web
De seguida, criamos uma instância do servidor web que escuta na porta 80.
WebServer server(80);
Função Serve JPEG
A função serveJpg() captura uma imagem da câmara e envia-a ao cliente como ficheiro JPEG. Se a captura falhar, envia uma resposta “503 Service Unavailable”.
void serveJpg() {
auto frame = esp32cam::capture();
if (frame == nullptr) {
Serial.println("CAPTURE FAILED!");
server.send(503, "", "");
return;
}
Serial.printf("CAPTURE OK %dx%d %db\n",
frame->getWidth(), frame->getHeight(),
static_cast<int>(frame->size()));
server.setContentLength(frame->size());
server.send(200, "image/jpeg");
WiFiClient client = server.client();
frame->writeTo(client);
}
Aqui, tentamos primeiro capturar um frame. Se for bem-sucedido, registamos as dimensões e o tamanho da imagem, definimos o comprimento do conteúdo e enviamos a imagem ao cliente.
Função Handle JPEG
A função handleJpg() altera a resolução da câmara e chama serveJpg() para servir a imagem.
void handleJpg() {
if (!esp32cam::Camera.changeResolution(RES)) {
Serial.println("CAN'T SET RESOLUTION!");
}
serveJpg();
}
Esta função garante que a câmara está configurada para a resolução desejada antes de servir a imagem.
Inicialização da Câmara
A função initCamera() configura as definições da câmara, incluindo atribuição de pinos, resolução, número de buffers e qualidade JPEG.
void initCamera() {
{
using namespace esp32cam;
Config cfg;
cfg.setPins(pins::AiThinker);
cfg.setResolution(RES);
cfg.setBufferCount(2);
cfg.setJpeg(80);
bool ok = Camera.begin(cfg);
Serial.println(ok ? "CAMERA OK" : "CAMERA FAIL");
}
}
Criamos um objeto de configuração, definimos os parâmetros necessários e inicializamos a câmara. Uma mensagem é impressa no monitor serial indicando se a inicialização da câmara foi bem-sucedida.
Inicialização do Wi-Fi
A função initWifi() liga o ESP32 à rede Wi-Fi especificada.
void initWifi() {
WiFi.persistent(false);
WiFi.mode(WIFI_STA);
WiFi.begin(WIFI_SSID, WIFI_PASS);
while (WiFi.status() != WL_CONNECTED)
;
Serial.printf("http://%s%s\n",
WiFi.localIP().toString().c_str(), URL);
}
Desativamos conexões Wi-Fi persistentes, definimos o modo para estação e tentamos conectar à rede Wi-Fi. Uma vez conectado, imprimimos a URL para aceder à imagem da câmara.
Inicialização do Servidor
A função initServer() configura o servidor para tratar pedidos da imagem da câmara.
void initServer() {
server.on(URL, handleJpg);
server.begin();
}
Definimos o endpoint URL e associamo-lo à função handleJpg(), depois iniciamos o servidor.
Função Setup
A função setup() inicializa a comunicação serial, Wi-Fi, câmara e servidor.
void setup() {
Serial.begin(115200);
initWifi();
initCamera();
initServer();
}
Função Loop
Finalmente, a função loop() trata continuamente os pedidos dos clientes.
void loop() {
server.handleClient();
}
Esta função garante que o servidor responde aos pedidos dos clientes, permitindo-lhes obter imagens capturadas pela câmara.
Testar o Servidor Web ESP32-CAM
Agora, vamos testar o Servidor Web. Compila e carrega o código acima. Para carregar código no ESP32-CAM, coloca a placa em modo de programação acionando o interruptor, depois pressiona brevemente o botão Reset na placa e clica no botão Upload no Arduino IDE.
Se precisares de mais ajuda para carregar código no ESP32-CAM, consulta o tutorial Programming the ESP32-CAM que fornece mais detalhes.
Após um upload bem-sucedido, verás a URL para as imagens da câmara impressa no Monitor Serial e também deverás ver o texto “CAMERA OK”:
http://192.168.1.146/cam.jpg CAMERA OK
Copia esta URL para a barra de endereços do navegador e deverás ver a imagem capturada pela câmara:

Cada vez que clicas no botão de recarregar no teu navegador, o Servidor Web recebe o pedido, pede ao ESP32-CAM para tirar uma nova foto e envia essa nova foto para o navegador. Abaixo uma foto da minha secretária, tirada desta forma:

Na próxima secção, vamos enviar as fotos para o Modelo de Deteção de Objetos YOLO para reconhecer os objetos na cena.
Deteção de Objetos YOLO
YOLO(You Only Look Once) é um modelo de deep learning para deteção de objetos conhecido pela sua rapidez e precisão. Foi introduzido pela primeira vez por Joseph Redmon et al. in 2016. Desde então, houve muitas versões melhoradas, sendo YOLO11 by Ultralytics a mais recente (em fevereiro de 2025).
No entanto, vamos usar um modelo mais antigo YOLOv3v, pois é mais pequeno e fácil de usar, embora a sua precisão não seja tão alta como os modelos mais recentes.

O Modelo YOLO é uma rede convolucional profunda que recebe uma imagem RGB com dimensões 448x448x3 como entrada e produz as caixas delimitadoras e as pontuações de confiança para os objetos detetados num tensor 7×7×30. Vamos usar uma versão do modelo treinada para detetar 80 different objects, tais como:
- pessoa
- bicicleta
- carro
- mota
- …
- tesouras
- urso de peluche
- secador de cabelo
- escova de dentes
Não vamos entrar em detalhes do modelo aqui, mas se quiseres aprender mais, aqui estão os links para a publicação original do YOLO, uma descrição das melhorias na Versão 3 do YOLO e um artigo de aplicação com informações úteis:
- YOLOv3: An Incremental Improvement
- You Only Look Once: Unified, Real-Time Object Detection
- YOLO v3: Visual and Real-Time Object Detection Model for Smart Surveillance Systems(3s)
Estrutura da Pasta do Projeto
Para correr o sistema de deteção de objetos YOLO num PC, precisamos criar uma pasta de projeto, digamos “esp32-cam-yolo-object-detection”. Dentro desta pasta, cria uma subpasta chamada “YOLO” e um ficheiro python chamado “detect.py”. A estrutura da tua pasta deve ficar assim:

Descarregar ficheiros YOLO
De seguida, tens de descarregar os ficheiros necessários do YOLO (pesos, configuração da arquitetura, nomes das classes) e colocá-los na pasta “YOLO” do projeto. Aqui estão os links para esses ficheiros:
- https://pjreddie.com/media/files/yolov3.weights
- https://github.com/pjreddie/darknet/blob/master/cfg/yolov3.cfg
- https://github.com/pjreddie/darknet/blob/master/data/coco.names
O conteúdo da tua pasta “YOLO” deverá ficar assim:

Criar Ambiente Virtual
Também temos de instalar algumas bibliotecas Python e vamos instalá-las num Ambiente Virtual usando venv. Abre uma shell de comandos e executa os seguintes comandos:
cd esp32-cam-object-detection python -m venv venv venv\Scripts\activate.bat pip install opencv-python opencv-python-headless numpy torch torchvision
O comando cdleva-nos para a pasta do projeto. O comando venv cria o ambiente virtual e dentro dele instalamos as bibliotecas necessárias via pip install. Isto vai criar uma pasta “venv” na pasta do projeto que contém as bibliotecas:

Código de Deteção de Objetos
Finalmente, como último passo, copia o seguinte código para o ficheiro detect.py na pasta do teu projeto.
import cv2
import numpy as np
import urllib.request
# Camera URL
url = "http://192.168.1.146/cam.jpg"
# YOLO model files
weights_path = r"./YOLO/yolov3.weights"
config_path = r"./YOLO/yolov3.cfg"
names_path = r"./YOLO/coco.names"
# Load the YOLO model and COCO class names
net = cv2.dnn.readNet(weights_path, config_path)
with open(names_path, "r") as f:
classes = [line.strip() for line in f.readlines()]
layer_names = net.getLayerNames()
# Handling the return value of getUnconnectedOutLayers()
out_layers = net.getUnconnectedOutLayers()
if isinstance(out_layers[0], list):
output_layers = [layer_names[i[0] - 1] for i in out_layers]
else:
output_layers = [layer_names[i - 1] for i in out_layers]
# Generate random colors for each class
colors = np.random.uniform(0, 255, size=(len(classes), 3))
def detect_objects(frame):
height, width, _ = frame.shape
blob = cv2.dnn.blobFromImage(frame, 1 / 255.0, (416, 416), swapRB=True, crop=False)
net.setInput(blob)
layer_outputs = net.forward(output_layers)
boxes = []
confidences = []
class_ids = []
for output in layer_outputs:
for detection in output:
scores = detection[5:]
class_id = np.argmax(scores)
confidence = scores[class_id]
if confidence > 0.3:
center_x = int(detection[0] * width)
center_y = int(detection[1] * height)
w = int(detection[2] * width)
h = int(detection[3] * height)
x = int(center_x - w / 2)
y = int(center_y - h / 2)
boxes.append([x, y, w, h])
confidences.append(float(confidence))
class_ids.append(class_id)
indexes = cv2.dnn.NMSBoxes(boxes, confidences, 0.3, 0.4)
# Draw detections on the frame
if len(indexes) > 0 and isinstance(indexes, np.ndarray):
indexes = indexes.flatten()
for i in indexes:
x, y, w, h = boxes[i]
label = str(classes[class_ids[i]])
confidence = confidences[i]
color = colors[class_ids[i]]
print(f"Detected: {label} with confidence {confidence:.2f}")
cv2.rectangle(frame, (x, y), (x + w, y + h), color, 2)
cv2.putText(
frame,
f"{label} {confidence:.2f}",
(x, y - 10),
cv2.FONT_HERSHEY_SIMPLEX,
0.5,
color,
2,
)
return frame
def main():
cv2.namedWindow("Object Detection", cv2.WINDOW_AUTOSIZE)
while True:
try:
img_resp = urllib.request.urlopen(url)
imgnp = np.array(bytearray(img_resp.read()), dtype=np.uint8)
frame = cv2.imdecode(imgnp, -1)
frame = detect_objects(frame)
cv2.imshow("Object Detection", frame)
if cv2.waitKey(1) & 0xFF == ord("q"):
break
except Exception as e:
print(f"Error occurred: {e}")
break
cv2.destroyAllWindows()
if __name__ == "__main__":
main()
O código acima implementa um sistema de deteção de objetos usando o modelo YOLO com OpenCV. Captura imagens de um feed de câmara e deteta objetos em tempo real, mostrando os resultados no ecrã.
Importar Bibliotecas
Começamos por importar as bibliotecas necessárias: cv2 para tarefas de visão computacional, numpy para operações numéricas, e urllib.request para lidar com pedidos URL.
import cv2 import numpy as np import urllib.request
URL da Câmara
Aqui definimos a URL do feed da câmara de onde vamos capturar imagens. Terás de substituir esta constante pela URL que o teu Servidor Web está a fornecer:
url = "http://192.168.1.146/cam.jpg"
Ficheiros do Modelo YOLO
De seguida, especificamos os caminhos para os ficheiros do modelo YOLO: o ficheiro de pesos, o ficheiro de configuração e os nomes dos objetos que o modelo pode detetar.
weights_path = r"./YOLO/yolov3.weights" config_path = r"./YOLO/yolov3.cfg" names_path = r"./YOLO/coco.names"
Carregar o Modelo YOLO
Carregamos o modelo YOLO usando o módulo dnn do OpenCV e lemos os nomes das classes do ficheiro especificado. Os nomes das camadas também são obtidos para uso posterior.
net = cv2.dnn.readNet(weights_path, config_path)
with open(names_path, "r") as f:
classes = [line.strip() for line in f.readlines()]
layer_names = net.getLayerNames()
Camadas de Saída
Determinamos as camadas de saída da rede. Isto é crucial para saber quais camadas fornecem as deteções finais.
out_layers = net.getUnconnectedOutLayers()
if isinstance(out_layers[0], list):
output_layers = [layer_names[i[0] - 1] for i in out_layers]
else:
output_layers = [layer_names[i - 1] for i in out_layers]
Gerar Cores para as Classes
Para visualizar e distinguir os objetos detetados, geramos cores aleatórias para as caixas delimitadoras.
colors = np.random.uniform(0, 255, size=(len(classes), 3))
Função de Deteção de Objetos
A função detect_objects() recebe um frame de imagem como entrada, processa-o e deteta objetos usando o modelo YOLO. Retorna o frame com caixas delimitadoras e etiquetas desenhadas.
def detect_objects(frame):
height, width, _ = frame.shape
blob = cv2.dnn.blobFromImage(frame, 1 / 255.0, (416, 416), swapRB=True, crop=False)
net.setInput(blob)
layer_outputs = net.forward(output_layers)
boxes = []
confidences = []
class_ids = []
Nesta função, primeiro criamos um blob a partir do frame de entrada, que é uma versão pré-processada da imagem adequada para o modelo. Depois fazemos uma passagem forward para obter a saída do modelo.
Processar Deteções
Percorremos as saídas para extrair caixas delimitadoras, pontuações de confiança e IDs de classe para os objetos detetados. Apenas deteções com confiança superior a 0.3 são consideradas válidas. Sente-te à vontade para alterar este parâmetro (0…1) para mostrar deteções menos ou mais confiantes.
for output in layer_outputs:
for detection in output:
scores = detection[5:]
class_id = np.argmax(scores)
confidence = scores[class_id]
if confidence > 0.3:
center_x = int(detection[0] * width)
center_y = int(detection[1] * height)
w = int(detection[2] * width)
h = int(detection[3] * height)
x = int(center_x - w / 2)
y = int(center_y - h / 2)
boxes.append([x, y, w, h])
confidences.append(float(confidence))
class_ids.append(class_id)
Supressão de Não-Máximos
Para eliminar caixas sobrepostas redundantes, aplicamos Non-Maximum Suppressio (NMS) para manter apenas as melhores caixas delimitadoras.
indexes = cv2.dnn.NMSBoxes(boxes, confidences, 0.3, 0.4)
Desenhar Deteções
Desenhamos as caixas delimitadoras e etiquetas no frame para cada objeto detetado. O nome da classe/objeto detetado e a pontuação de confiança são exibidos.
if len(indexes) > 0 and isinstance(indexes, np.ndarray):
indexes = indexes.flatten()
for i in indexes:
x, y, w, h = boxes[i]
label = str(classes[class_ids[i]])
confidence = confidences[i]
color = colors[class_ids[i]]
print(f"Detected: {label} with confidence {confidence:.2f}")
cv2.rectangle(frame, (x, y), (x + w, y + h), color, 2)
cv2.putText(
frame,
f"{label} {confidence:.2f}",
(x, y - 10),
cv2.FONT_HERSHEY_SIMPLEX,
0.5,
color,
2,
)
Função Principal
A função main() configura uma janela para mostrar as deteções e captura continuamente frames do feed da câmara. Processa cada frame através da função detect_objects() e mostra o resultado.
def main():
cv2.namedWindow("Object Detection", cv2.WINDOW_AUTOSIZE)
while True:
try:
img_resp = urllib.request.urlopen(url)
imgnp = np.array(bytearray(img_resp.read()), dtype=np.uint8)
frame = cv2.imdecode(imgnp, -1)
frame = detect_objects(frame)
cv2.imshow("Object Detection", frame)
if cv2.waitKey(1) & 0xFF == ord("q"):
break
except Exception as e:
print(f"Error occurred: {e}")
break
cv2.destroyAllWindows()
Abrirá uma janela e, se pressionares “q” enquanto a janela estiver ativa, a aplicação terminará.
Ponto de Entrada da Execução
Finalmente, verificamos se o script está a ser executado diretamente e chamamos a função main() para iniciar o programa.
if __name__ == "__main__":
main()
Na próxima secção juntamos tudo e corremos o nosso sistema de deteção de objetos.
Executar o Deteção de Objetos
Primeiro, liga o teu módulo ESP32-CAM com o código do Servidor Web e certifica-te que o ESP32-CAM captura imagens e as mostra num navegador web na URL impressa no Monitor Serial. Também certifica-te que esta URL é usada no detect.py, por exemplo, no meu caso esta URL é:
url = "http://192.168.1.146/cam.jpg"
De seguida, inicia o detector de objetos YOLO. Vai para a pasta do projeto (“esp32-cam-object-detection”), ativa o ambiente virtual e executa o código do detector detect.py:
cd esp32-cam-object-detection venv\Scripts\activate.bat python detect.py
Nota que podes desativar o ambiente virtual chamando:
venv\Scripts\deactivate.bat
Se o código estiver a correr, deverás ver os nomes dos objetos detetados com a pontuação de confiança impressa no console:
Detected: cup with confidence 0.76 Detected: laptop with confidence 0.39 Detected: cup with confidence 0.51 Detected: laptop with confidence 0.33 Detected: cup with confidence 0.44 Detected: cup with confidence 0.65 Detected: cup with confidence 0.63
Também abrirá uma janela chamada “Object Detection” que mostra a imagem atual que a câmara vê com caixas delimitadoras em volta dos objetos que o sistema conseguiu detetar. Abaixo um exemplo onde o sistema detetou corretamente uma chávena, um comando e um portátil:

Se quiseres ver mais exemplos das capacidades de deteção do modelo YOLO, vai ao seguinte YOLO Demo Video.
Conclusões
Neste tutorial aprendeste a construir um sistema de deteção de objetos. O módulo ESP32-CAM foi usado para capturar imagens e correr um Servidor Web para essas imagens. As imagens foram depois enviadas via Wi-Fi para um PC que corre um software de deteção de objetos baseado no modelo de deep learning YOLO.
Compilar e carregar código para o ESP32-CAM pode ser complicado. Se encontrares problemas, consulta o tutorial Programming the ESP32-CAM que fornece instruções mais detalhadas.
Note que o nosso pequeno sistema de deteção de objetos está limitado a 80 objetos (ou classes) predefinidos. No entanto, podes treinar o modelo YOLO com os teus próprios objetos. O tutorial How to Train YOLOv3 to Detect Custom Objects? pode ajudar se quiseres fazer isso.
Se tiveres mais perguntas, não hesites em deixá-las na secção de comentários.
Boas construções ; )


