segunda-feira, 2 de junho de 2025

MILK-V DUO S - OPEN SDK V2 NO MILK-V DUO S - IMAGENS PARA O FURBOT

    


Introdução



A detecção de objetos é um campo fascinante que ganhou muita atenção nos últimos anos devido à sua ampla gama de aplicações em áreas como carros autônomos, sistemas de segurança e assistência médica. YOLO11 (You Only Look Once versão 11) é um modelo de detecção de objetos de última geração que se tornou cada vez mais popular devido à sua alta precisão e velocidade de processamento rápida. Neste guia para iniciantes, exploraremos as etapas envolvidas no treinamento de um modelo YOLOv"11" do zero, incluindo preparação de dados, configuração do modelo e treinamento. Seja você um iniciante em aprendizado profundo ou um praticante experiente, este guia fornecerá uma base sólida para treinar seu próprio modelo YOLO11 e explorar o campo emocionante da detecção de objetos.

Sobre o Projeto Furbot

Com a introdução da Base Nacional Comum Curricular (BNCC), várias discussões ocorreram para identificar qual a melhor maneira de efetivar a inclusão dos fundamentos da Ciência da Computação, especificamente relacionados ao Pensamento Computacional (PC), na educação básica. Durante os últimos doze anos, uma tecnologia para o desenvolvimento de habilidades de PC em cursos de graduação foi desenvolvida e aprimorada, chamada Furbot, que há quatro anos se tornou um jogo e foi aplicada com sucesso no Ensino Fundamental I em escolas públicas estaduais da região de Blumenau. Assim, o jogo Furbot, desenvolvido em Unity 2D, tem como objetivo fazer com que o jogador saia de um ponto de origem e chegue a um ponto de destino, guiando um robô por um caminho e desviando de obstáculos usando comandos de programação.

Neste exemplo, pretende-se substituir as Flechas acimas por uma Flechas especializadas e já disponíveis no mundo RoboFlow.  Tentou-se treinar as acima, mas o fundo branco de cada uma delas foi uma preocupação.

Atualmente as mesmas são capturadas por uma câmera do ESP32CAM e enviadas para o serviços da AMAZON para reconhecimento, pretende-se substituir o ESP32CAM e o serviço da AMAZON por um MILK-V com Rede Neural treinada e uma câmara USB acoplada a ele.

O Furbot sofreu mais transformações (não especificadas no HackAday), entre elas, uma aplicação python rodando em um PC o qual captura uma imagem via Wifi da câmera do ESP32CAM e detecta as bordas do tapete. Pretende-se então portar também para o Milk-v Duo S a aplicação python.


OpenCV rodando no MILK-V Duo S



import cv2 import requests import numpy as np import time from enum import Enum import threading # Replace the below URL with your ESP32-CAM video stream URL ip = '192.168.1.8' stream_url = 'http://'+ ip +':82/stream' post_url = 'http://'+ ip +':81/comando' _grupos = [] _lastGrupos = [] _lastId = 1 _threshold = 50 up = False down = False left = False right = False passouPrimeiraLinha = False primeiraPassada = True class Comandos(Enum): UP = 'UP' DOWN = 'DOWN' LEFT = 'LEFT' RIGHT = 'RIGHT' DLEFT = 'DLEFT' DRIGHT = 'DRIGHT' STOP = 'STOP' CORRECT = 'CORRECT' def calcular_media_dos_y_do_grupo(grupo): # Inicialize uma lista para armazenar as medias dos valores de y de cada linha medias_y = [] # Itere sobre as linhas no grupo for linha in grupo[4]: # grupo[4] contem a lista de linhas x1, y1, x2, y2, _ = linha # Ignorando "group" porque nao precisamos dela aqui # Calcule a media dos valores de y da linha atual e adicione a lista media_y_linha = (y1 + y2) / 2 medias_y.append(media_y_linha) # Calcule a media das medias dos valores de y das linhas media_geral_y = sum(medias_y) / len(medias_y) grupo[2] = media_geral_y return media_geral_y def calcular_media_dos_x_do_grupo(grupo): # Inicialize uma lista para armazenar as medias dos valores de x de cada linha medias_x = [] # Itere sobre as linhas no grupo for linha in grupo[4]: # grupo[4] contem a lista de linhas x1, y1, x2, y2, _ = linha # Ignorando "group" porque nao precisamos dela aqui # Calcule a media dos valores de x da linha atual e adicione a lista media_x_linha = (x1 + x2) / 2 medias_x.append(media_x_linha) # Calcule a media das medias dos valores de x das linhas media_geral_x = sum(medias_x) / len(medias_x) grupo[2] = media_geral_x return media_geral_x def calcular_media_dos_angulos_do_grupo(grupo, target_x=420, target_y=250): # Inicialize variaveis para armazenar a menor distancia e a linha correspondente menor_distancia = float('inf') linha_mais_proxima = None # Itere sobre as linhas no grupo for linha in grupo[4]: # grupo[4] contem a lista de linhas x1, y1, x2, y2, _ = linha # Ignorando "group" porque nao precisamos dela aqui # Calcule o ponto medio da linha ponto_medio_x = (x1 + x2) / 2 ponto_medio_y = (y1 + y2) / 2 # Calcule a distancia euclidiana do ponto medio ao ponto alvo distancia = ((ponto_medio_x - target_x) ** 2 + (ponto_medio_y - target_y) ** 2) ** 0.5 # Se a distancia atual e menor que a menor distancia registrada, atualize a menor distancia e a linha correspondente if distancia < menor_distancia: menor_distancia = distancia linha_mais_proxima = linha x1, y1, x2, y2, _ = linha_mais_proxima angle = calculate_angle(x1, y1, x2, y2) grupo[3] = angle return angle def calculate_angle(x1, y1, x2, y2): """ Calculate the angle (in degrees) of a line segment with endpoints (x1, y1) and (x2, y2). """ angle_radians = np.arctan2(y2 - y1, x2 - x1) angle_degrees = np.degrees(angle_radians) return angle_degrees def color_by_group(group): if group == "horizontal": return (0, 255, 0) return (0, 0, 255) def get_group_by_id(group_id): for group in _grupos: if group[0] == group_id: return group return None def remove_from_last_group_by_id(group_id): global _lastGrupos # Declare _grupos as global so that it can be modified within the function _lastGrupos = [group for group in _lastGrupos if group[0] != group_id] def agrupaLinha(line): global _lastId x1, y1, x2, y2, group = line if(group == "horizontal"): mediaLinha = (y1+y2)/2 angle = calculate_angle(x1, y1, x2, y2) if mediaLinha > 330: if get_group_by_id(-1) is None: _grupos.append([-1, group, mediaLinha, angle, [line]]) else: grupoFora = get_group_by_id(-1) id, direcao, media, angle, linhas = grupoFora linhas.append(line) calcular_media_dos_y_do_grupo(grupoFora) else: for i in range(_lastGrupos.__len__()): idLastGrupo, direcaoLastGrupo, mediaLastGrupo, angleLastGrupo, linhasLastGrupo = _lastGrupos[i] if direcaoLastGrupo == "horizontal": if (mediaLastGrupo - _threshold < mediaLinha < mediaLastGrupo + _threshold): for i in range(_grupos.__len__()): id, direcao, media, angle, linhas = _grupos[i] if id == idLastGrupo: linhas.append(line) _grupos[i] = [id, direcao, media, angle, linhas] calcular_media_dos_y_do_grupo(_grupos[i]) calcular_media_dos_angulos_do_grupo(_grupos[i]) return _grupos.append([idLastGrupo, group, mediaLinha, angle, [line]]) return for i in range(_grupos.__len__()): id, direcao, media, angle, linhas = _grupos[i] if direcao == "horizontal": if(media - _threshold < mediaLinha < media + _threshold): linhas.append(line) _grupos[i] = [id, direcao, media, angle, linhas] calcular_media_dos_y_do_grupo(_grupos[i]) calcular_media_dos_angulos_do_grupo(_grupos[i]) return _grupos.append([_lastId, group, mediaLinha, angle, [line]]) _lastId = _lastId + 1 elif(group == "vertical"): mediaLinha = (x1 + x2) / 2 angle = calculate_angle(x1, y1, x2, y2) for i in range(_lastGrupos.__len__()): idLastGrupo, direcaoLastGrupo, mediaLastGrupo, angleLastGrupo, linhasLastGrupo = _lastGrupos[i] if direcaoLastGrupo == "vertical": if (mediaLastGrupo - _threshold < mediaLinha < mediaLastGrupo + _threshold): for i in range(_grupos.__len__()): id, direcao, media, angle, linhas = _grupos[i] if id == idLastGrupo: linhas.append(line) _grupos[i] = [id, direcao, media, angle, linhas] calcular_media_dos_x_do_grupo(_grupos[i]) calcular_media_dos_angulos_do_grupo(_grupos[i]) return _grupos.append([idLastGrupo, group, mediaLinha, angle, [line]]) return for i in range(_grupos.__len__()): id, direcao, media, angle, linhas = _grupos[i] if direcao == "vertical": if (media - _threshold < mediaLinha < media + _threshold): linhas.append(line) _grupos[i] = [id, direcao, media, angle, linhas] calcular_media_dos_x_do_grupo(_grupos[i]) calcular_media_dos_angulos_do_grupo(_grupos[i]) return _grupos.append([_lastId, group, mediaLinha, angle, [line]]) _lastId = _lastId + 1 # Grupo tera: { # id: 1 # direcao: horizontal|vertical # media: 50 (media do valor X caso vertical, media do Y caso horizontal) # linhas: lista das linhas # } # # 1. Passar _grupos para _lastGrupos # 2. Adicionar linhas atuais no _grupos # 1- Passar pelos grupos da direcao correta # 2- Verificar se tem alguma media que esta perto (threshold) do valor medio do Y da linha atual # 2.1 - Usa os grupos antigos para ter as medias, caso nao tenha um grupo antigo perto da linha atual, cria um grupo # 3- Adicionar linha no grupo, recalcular media do grupo # def any_group_media_greater_than_300(): for group in _grupos: if group[1] == "horizontal" and group[2] > 250 and group[0] > -1: return True return False def corrigir_angulo(grupo): angle = grupo[3] if angle > -1 and angle < 1: return if angle < 0: send_request(Comandos.LEFT, angle) else: send_request(Comandos.RIGHT, angle) def corrigir_meio(): time.sleep(3) grupoEsquerda = [] grupoDireita = [] for grupo in _grupos: if grupo[0] > -1 and grupo[1] == "vertical": diferenca = grupo[2] - 398 if diferenca < 0: if len(grupoEsquerda) == 0 or abs(diferenca) < abs((grupoEsquerda[2] - 398)): grupoEsquerda = grupo else: if len(grupoDireita) == 0 or diferenca < abs((grupoDireita[2] - 398)): grupoDireita = grupo if len(grupoEsquerda) > 0 and len(grupoDireita) > 0: mediaCorrecao = (grupoEsquerda[2] + grupoDireita[2])/2 diferenca = mediaCorrecao - 398 if abs(diferenca) > 5: if(diferenca > 0): send_request(Comandos.DRIGHT, diferenca) else: send_request(Comandos.DLEFT, diferenca) def corrigir_geral(id, direcao, media, angle, linhas): time.sleep(8) grupo = [id, direcao, media, angle, linhas] corrigir_angulo(grupo) thread = threading.Thread(target=corrigir_meio) thread.start() def detect_lines(frame): global _grupos _lastGrupos.clear() if len(_grupos) > 0: _lastGrupos.extend(_grupos) _grupos = [] remove_from_last_group_by_id(-1) # # Convert to grayscale # gray = cv2.cvtColor(frame, cv2.COLOR_BGR2GRAY) # # Apply Gaussian blur # blur = cv2.GaussianBlur(gray, (5, 5), 0) # # Apply Canny edge detector # edges = cv2.Canny(blur, 70, 150, apertureSize=3) # cv2.imshow('Ee', edges) # # # Use HoughLinesP to detect lines # # These parameters can be adjusted to better detect lines in your specific setting # lines = cv2.HoughLinesP(edges, 1, np.pi / 180, threshold=100, minLineLength=50, maxLineGap=50) # Convert to grayscale gray = cv2.cvtColor(frame, cv2.COLOR_BGR2GRAY) # Preprocess the image to remove noise gray = cv2.GaussianBlur(gray, (5, 5), 0) # Apply adaptive thresholding thresh = cv2.adaptiveThreshold(gray, 255, cv2.ADAPTIVE_THRESH_GAUSSIAN_C, cv2.THRESH_BINARY_INV, 15, 8) # cv2.imshow('thresh', thresh) # Apply Canny edge detector edges = cv2.Canny(thresh, 50, 150) # cv2.imshow('edges', edges) # Use HoughLinesP to detect lines lines = cv2.HoughLinesP(edges, 1, np.pi / 180, threshold=100, minLineLength=50, maxLineGap=50) lines_aux = [] if lines is not None: for line in lines: x1, y1, x2, y2 = line[0] angle = calculate_angle(x1, y1, x2, y2) if (-45 >= angle >= -135) or (45 <= angle <= 135): group = "vertical" else: group = "horizontal" lines_aux.append([x1, y1, x2, y2, group]) if lines_aux is not None: for line in lines_aux: x1, y1, x2, y2, group = line cv2.line(frame, (x1, y1), (x2, y2), color_by_group(group), 2) agrupaLinha(line) # print() # print("========") # for grupo in _grupos: # print("Id: ", grupo[0], " Direcao: ", grupo[1], " Media: ", grupo[2], " angulo: ", grupo[3], " Qntd. linhas: ", len(grupo[4])) global up global left global right global passouPrimeiraLinha global primeiraPassada if up: if any_group_media_greater_than_300() and primeiraPassada: passouPrimeiraLinha = False if not any_group_media_greater_than_300(): passouPrimeiraLinha = True for grupo in _grupos: if grupo[0] > -1 and grupo[1] == "horizontal": if len(grupo[4]) > 1: if grupo[2] > 250: if passouPrimeiraLinha: up = False send_request(Comandos.STOP) corrigir_angulo(grupo) thread = threading.Thread(target=corrigir_meio) thread.start() primeiraPassada = False if left: for grupo in _grupos: if grupo[0] > -1 and grupo[1] == "horizontal": if len(grupo[4]) > 1: if grupo[2] > 250: thread = threading.Thread(target=corrigir_geral, args=grupo) thread.start() left = False if right: for grupo in _grupos: if grupo[0] > -1 and grupo[1] == "horizontal": if len(grupo[4]) > 1: if grupo[2] > 250: thread = threading.Thread(target=corrigir_geral, args=grupo) thread.start() right = False return frame process_interval = 0.2 # seconds, process frames every 0.2 seconds or 5 FPS last_time = 0 cap = cv2.VideoCapture(0) paused = False # Variable to track pause state def send_request(comando, valor=0): print(comando.value) # print(comando) response = ""; if valor == 0: response = requests.post(post_url, data=comando.value) else: if comando == Comandos.LEFT or comando == Comandos.RIGHT: valor = abs(valor) formatted_float = f"{valor:.3f}" data = f"{comando.value}_{formatted_float}" response = requests.post(post_url, data=data) elif comando == Comandos.DLEFT or comando == Comandos.DRIGHT: valor = abs(valor) formatted_float = f"{valor:.3f}" data = f"{comando.value}_{formatted_float}" response = requests.post(post_url, data=data) # print(response) def start_command(comando): global up global down global left global right global passouPrimeiraLinha global primeiraPassada if comando == Comandos.UP: up = True passouPrimeiraLinha = False primeiraPassada = True if comando == Comandos.DOWN: down = True if comando == Comandos.LEFT: left = True if comando == Comandos.RIGHT: right = True if comando == Comandos.CORRECT: for grupo in _grupos: if grupo[0] > -1: if len(grupo[4]) > 1: if grupo[2] > 250: corrigir_angulo(grupo) thread = threading.Thread(target=corrigir_meio(), args=grupo) thread.start() return send_request(comando) while True: ret, frame = cap.read() current_time = time.time() if current_time - last_time < process_interval: continue # Skip this iteration of the loop if interval not passed last_time = current_time frame_with_lines = detect_lines(frame) print(frame) cap.release() cv2.destroyAllWindows()


Enfim, câmera ESp32CAM, sensores de detecção de tapete e software PC serão todos embarcados no Furbot. Só permanecerá original a placa de controle dos motores.


Versão antiga do FurBot

Treinamento

Para treinar um modelo de detecção de objetos YOLO11, você deve ter um DataSet de imagens anotadas que indiquem a localização dos objetos que você deseja que o modelo detecte. Embora DataSet de código aberto como COCO e Pascal VOC estejam disponíveis, um DataSet personalizado pode ser mais preciso para seu caso de uso específico. Dividir o DataSet em conjuntos de treinamento e validação também é uma etapa crucial para garantir a precisão e a confiabilidade do seu modelo.

Este blog tem como objetivo orientá-lo por todo o processo de treinamento e avaliação do seu próprio modelo YOLO11. Forneceremos uma introdução aos recursos do YOLO11 e discutiremos como anotar e preparar seu DataSet para treinamento. Em seguida, nos aprofundaremos no aspecto importante do treinamento do modelo, fornecendo instruções passo a passo para treinar seu modelo YOLO11 do zero. Por fim, explicaremos como avaliar o desempenho do seu modelo, fornecendo todo o conhecimento necessário para começar a detecção de objetos usando o YOLOv11. Seja você novo na detecção de objetos ou esteja procurando melhorar suas habilidades, este guia abrangente o equipará com as ferramentas necessárias para treinar um modelo de detecção de objetos YOLO11 com confiança.

Introdução

YOLOv11 "é" a versão mais recente e melhor da família YOLO (You Only Look Once) de modelos de detecção de objetos em tempo real. Desenvolvido por Glenn Jocher e a equipe da Ultralytics, o YOLOv11 representa uma revisão completa de seus predecessores e ostenta melhorias significativas em velocidade e precisão. Na verdade, o YOLO11 alcançou resultados de última geração em detecção de objetos em uma variedade de DataSet, incluindo os conhecidos benchmarks COCO e Pascal VOC.

Então o que torna o YOLOv11 tão especial? Sua arquitetura! O YOLO11 alavanca uma nova rede de backbone chamada CSPDarknet, que usa conexões parciais entre estágios para melhorar o fluxo de informações e a reutilização de recursos. Além disso, ele integra técnicas de ponta como Módulos de Atenção Espacial e funções de ativação Swish para aumentar ainda mais a precisão da detecção de objetos. Tudo isso mantendo velocidades de inferência em tempo real de até 140 quadros por segundo em uma única GPU, tornando-o um dos modelos de detecção de objetos mais rápidos e precisos que existem. Se você está procurando desenvolver aplicativos em campos como veículos autônomos, robótica ou sistemas de vigilância, o YOLO11 definitivamente vale uma olhada mais de perto.

DataSet e ferramenta de anotação

A base de qualquer projeto de detecção de objetos bem-sucedido é um DataSet bem curado. O DataSet fornece ao modelo as informações necessárias para reconhecer e localizar objetos com precisão. Portanto, antes de mergulhar no treinamento do modelo, é crucial reunir ou criar um bom DataSet que cubra uma ampla gama de cenários e variações que você prevê que o modelo encontrará no mundo real.

DataSet personalizados desempenham um papel crítico na obtenção de alta precisão e especificidade em tarefas de detecção de objetos. Embora vários DataSet de código aberto estejam disponíveis, como o DataSet COCO e o DataSet EgoHands, criar um DataSet personalizado que atenda ao seu caso de uso específico pode ser mais eficaz. Ferramentas de anotação como LabelImg e Roboflow podem ajudar na criação de tal DataSet No  intitulado “Construindo modelos precisos de detecção de objetos com RetinaNet: um guia passo a passo abrangente” , utilizei o LabelImg para anotação de imagem. No entanto, neste blog, demonstrarei como usar o Roboflow, uma ferramenta de anotação poderosa que pode agilizar o processo de preparação do DataSet.

Roboflow é uma plataforma de gerenciamento de dados tudo-em-um projetada para tarefas de visão computacional, como detecção de objetos, classificação de imagens e segmentação. Ela oferece uma gama de ferramentas para anotação de imagens, geração de DataSet e implantação de modelos. Com suas integrações com frameworks populares de aprendizado profundo como TensorFlow e PyTorch, o Roboflow facilita o treinamento de modelos usando seu DataSet personalizado.

Um dos recursos de destaque do Roboflow é sua ferramenta intuitiva de anotação de imagens baseada na web. A ferramenta permite que você rotule imagens com caixas delimitadoras, polígonos e outras formas que indicam a localização de objetos na imagem. Sua interface amigável e eficiência facilitam a rotulagem de grandes DataSet de forma rápida e precisa. Além disso, o Roboflow oferece vários recursos para gerenciar DataSet, incluindo aumento de dados, limpeza de dados e exportação de dados. Ele também fornece opções de pré-processamento, como redimensionamento e normalização, que podem melhorar o desempenho do modelo.

No geral, o Roboflow é uma ferramenta excelente para preparar e gerenciar DataSet personalizados para tarefas de visão computacional. Seus recursos abrangentes e interface amigável o tornam ideal tanto para iniciantes quanto para profissionais experientes. Para começar a usar o Roboflow, crie uma conta e configure um novo espaço de trabalho para começar a criar novos projetos.

Após criar um novo projeto no Roboflow, você pode começar a carregar as imagens que deseja anotar. O processo é simples e fácil de seguir. Você pode carregar imagens diretamente do seu computador ou de serviços de armazenamento em nuvem, como Google Drive ou Dropbox. Depois que as imagens forem carregadas, você pode começar a anotá-las usando as poderosas ferramentas de anotação da plataforma. Um exemplo do processo de upload pode ser visto na imagem abaixo:







Após carregar suas imagens no Roboflow, o próximo passo é atribuí-las para anotação. A anotação é um processo crucial na criação de um DataSet personalizado, e o Roboflow facilita isso com sua interface intuitiva. Basta desenhar caixas delimitadoras ao redor dos objetos de interesse, e a ferramenta salvará automaticamente as anotações. Depois de anotar suas imagens, uma caixa de diálogo aparecerá, permitindo que você divida as imagens em conjuntos de treinamento, validação e teste. É recomendável ter pelo menos 60–70% dos seus dados como dados de treinamento, pois isso fornece ao modelo exemplos suficientes para aprender. No entanto, a divisão pode ser ajustada para atender às suas necessidades específicas. Com a ferramenta de anotação do Roboflow e os recursos de gerenciamento de dados fáceis de usar, criar um DataSet personalizado para tarefas de detecção de objetos nunca foi tão fácil.

Para demonstrar o processo de upload de imagens para anotação, selecionei aleatoriamente imagens. Essas imagens são usadas como exemplos para ilustrar o processo de anotação no Roboflow.











Após concluir o processo de anotação, você pode criar um DataSet dividindo as imagens anotadas em conjuntos de treinamento, validação e teste (train, valid, test):


Para fazer o treinando, foi baixado um projeto do RoboFlow Universe com as imagens já prontas para treinamento.

recognition-of-direction-arrows-for-autonomus-car-bvimf

recognition of direction arrows for autonomus car Object Detection Dataset by Florian Demolder

É hora de exportar para seu IDE local ou Google Colab.

train-yolo11-object-detection-on-custom-dataset.ipynb - Colab

Durante o processo de geração, você pode escolher as etapas de pré-processamento e aumento de acordo com seus requisitos. Por exemplo, você pode redimensionar as imagens ou aplicar técnicas de aumento de dados, como rotação ou inversão, para aumentar a diversidade do DataSet. Assim que o processo de geração for concluído, você pode exportar facilmente seu DataSet e usá-lo para treinar seu modelo de detecção de objetos.



OPCIONAL, POIS TEMOS QUASE 700 IMAGENS
OPCIONAL, POIS TEMOS QUASE 700 IMAGENS
OPCIONAL, POIS TEMOS QUASE 700 IMAGENS
OPCIONAL, POIS TEMOS QUASE 700 IMAGENS
OPCIONAL, POIS TEMOS QUASE 700 IMAGENS
OPCIONAL, POIS TEMOS QUASE 700 IMAGENS
OPCIONAL, POIS TEMOS QUASE 700 IMAGENS






Após gerar uma nova versão do DataSet, o próximo passo é exportá-lo em um formato adequado para treinar o modelo. O Roboflow oferece a flexibilidade de exportar o DataSet em vários formatos, incluindo o formato YOLO11 Pytorch (.pt), que usaremos neste exemplo. Este formato é amplamente usado para treinar modelos de detecção de objetos e é compatível com estruturas populares de aprendizado profundo (Deep Learning), como o PyTorch. Depois de selecionar o formato de exportação desejado, o Roboflow gerará um link de download para o DataSet exportado. Você pode usar este link para baixar o DataSet para seu IDE local ou Google Colab para processamento e treinamento adicionais.



É crucial salvar o link de download gerado após exportar seu DataSet em um arquivo de texto para fácil acesso, especialmente se você planeja usá-lo em um notebook do Google Colab. 


Escolha YOLO11 e depois renomeie para train_data.zip para facilitar o entendimento abaixo.

Agora que preparamos nosso DataSet, é hora de mergulhar na parte emocionante do processo de detecção de objetos: treinar o modelo. Esta etapa é onde o algoritmo aprende a identificar e classificar objetos em imagens, permitindo que ele faça previsões precisas em dados não vistos. Então, vamos começar!

Treinamento de modelo

Neste artigo, usaremos o Colab para treinar o modelo de detecção de objetos YOLO11n em nosso DataSet personalizado. O Google Colab é uma plataforma poderosa e fácil de usar para treinar modelos de aprendizado profundo. O primeiro passo para começar a usar o YOLOv11s no Colab é clonar o repositório GitHub do YOLO11. Este repositório contém todo o código e os arquivos de configuração necessários para treinar o modelo. A clonagem do repositório pode ser feita executando um comando simples no notebook do Colab:

train-yolo11-object-detection-on-custom-dataset.ipynb - Colab

Comece instalando as ferramentas da ULTRALYTICS

%pip install "ultralytics<=8.3.40" supervision roboflow
import ultralytics
ultralytics.checks()


Após clonar o repositório YOLOv11s GitHub, precisamos configurar o ambiente e configurar o modelo para treinamento. Isso envolve várias etapas, como instalar as dependências necessárias, configurar os caminhos para o DataSet e os arquivos de configuração do modelo e especificar os parâmetros de treinamento, como tamanho do lote, taxa de aprendizado e número de épocas.


Após configurar o ambiente, o próximo passo é copiar o arquivo que foi gerado e salvo em do seu notebook Colab. Depois de colar o código, você pode executá-lo para baixar o DataSet e carregá-lo no seu ambiente Colab. Isso permitirá que você comece a treinar seu modelo YOLO11 usando os dados anotados.

Agora é hora de fazer o "Unzip" do arquivo ZIP

!unzip train_data.zip

Iniciar o treinamento

Consulte o data.yaml e você verá o seguinte conteúdo, são 4 conjuntos de imagens que devem ser treinadas, que são as flechas.

Agora temos que mandar treinar, execute o Script Python abaixo e aguarde o treinamento.

!yolo task=detect mode=train model=yolo11n.pt data=data.yaml epochs=200 imgsz=640

!yolo task=detect mode=train model=yolo11n.pt data=data.yaml epochs=200 imgsz=640

Neste comando, podemos especificar  os seguintes parâmetros:

  • imgsz: O tamanho das imagens de entrada durante o treinamento. Aqui, estamos configurando para 640x640 pixels.
  • epochs: O número de épocas para treinar. Aqui, estamos definindo para 100.
  • data: O local do arquivo YAML do DataSet que criamos no Roboflow.
  • mode: operação treino
  • model:  modelo base de treino

Depois que executarmos esse comando, o processo de treinamento começará e poderemos monitorar o progresso no notebook Colab.


Durante o processo de treinamento, o YOLO11 salva dois tipos de arquivos de checkpoint: 

last.ptbest.pt.

last.pté o último checkpoint salvo do modelo. Ele é atualizado após cada época de treinamento e contém os pesos do modelo naquele ponto do processo de treinamento. Este checkpoint pode ser usado para retomar o treinamento de onde ele foi interrompido ou para avaliar o desempenho do modelo em uma determinada época.

best.pté o ponto de verificação que tem a melhor perda de validação até agora. Ele é atualizado sempre que a perda de validação melhora e contém os pesos do modelo naquele ponto. Este ponto de verificação é útil para seleção de modelo, pois representa o ponto no processo de treinamento em que o modelo teve o melhor desempenho no conjunto de validação. Ambos last.ptbest.ptpodem ser usados ​​para inferência após a conclusão do processo de treinamento.

O arquivo .pt pode ser baixado do Google Colab para sua máquina local apenas clicando sobre o mesmo.

Este arquivo contém os pesos do modelo de melhor desempenho durante o treinamento. É importante salvar este arquivo em um local seguro, pois ele representa o modelo treinado e pode ser usado para fazer previsões em novas imagens ou para continuar treinando o modelo mais tarde.

Se COLAB venceu, faça treinamento no ambiente DuoCPU do DOCKER, mas seja paciente com a velocidade.


É hora de exportar para CviModel, recomendo utilizar o Script (Colab) gerado por JJ.

HORA DE PORTAR PARA O MILK-V :) - COLAB

Localização do código Duo256M yolov8: sample_yolov8.cpp

(o mesmo deve ser compilado para o DUO 256)

Método de compilação

Consulte o método do link Introdução para compilar o programa "sample".

Não esquecer de mudar a linha 

 yolov8_param.cls = XXX; 

onde XXX é o número de CLASSES, no caso acima 3, pois são 3 espécies de BUGGIO.

Após a conclusão da compilação, o programa sample_yolov8 que precisamos será gerado no diretório sample/cvi_yolo/

COLAB - do .PT para .CVIMODEL

Baixe SCRIPT para conversão


Abra no colab



Siga o roteiro, incluindo os JPG quando necessários para conversão.


















Após a conclusão da compilação, um arquivo chamado best_int8_class.cvimodel será gerado.

Transferindo para Duo 256

Copie o sample_yolov8 compilado, o cvimodel e a imagem jpg a ser inferida, para a placa e execute o programa binário:

scp best_int8_class.cvimodel root@192.168.42.1:/root/

Execute o seguinte comando:

./sample_yolov8 ./yolov8n_cv181x_int8_sym.cvimodel Ades_1-5_jpg.rf.a6adaadb480fc623707d0b53172472c3.jpg

Exemplo de uma imagem a ser reconhecida

Testes


[root@milkv-duo]~# ./sample_yolov8 best_int8.cvimodel norte_jpg.rf.01d03d94705ca
aac1f2f0191bccd4e69.jpg
[56319.218873] vb_ctrl:1000(): vb has already inited, set_config cmd has no effect
asign val 0
asign val 1
asign val 2
setup yolov8 param
************************
4
************************
setup yolov8 algorithm param
yolov8 algorithm parameters setup success!
---------------------openmodel-----------------------
---------------------to do detection-----------------------
image read,width:640
image read,hidth:640
objnum: 1
boxes=[[0.000000,103.103699,639.000000,591.668213,1,0.959542],]
[root@milkv-duo]~#


[root@milkv-duo]~# ./sample_yolov8 best_int8.cvimodel sul_jpg.rf.10caea3f240d047
9256354c786c619e7.jpg
[56370.558113] vb_ctrl:1000(): vb has already inited, set_config cmd has no effect
asign val 0
asign val 1
asign val 2
setup yolov8 param
************************
4
************************
setup yolov8 algorithm param
yolov8 algorithm parameters setup success!
---------------------openmodel-----------------------
---------------------to do detection-----------------------
image read,width:640
image read,hidth:640
objnum: 1
boxes=[[0.000000,51.852066,546.493713,634.700317,3,0.978451],]
[root@milkv-duo]~#

[root@milkv-duo]~# ./sample_yolov8 best_int8.cvimodel oeste_jpg.rf.0aaf30643b4dc
72a423ecad27318822f.jpg
[56403.524907] vb_ctrl:1000(): vb has already inited, set_config cmd has no effect
asign val 0
asign val 1
asign val 2
setup yolov8 param
************************
4
************************
setup yolov8 algorithm param
yolov8 algorithm parameters setup success!
---------------------openmodel-----------------------
---------------------to do detection-----------------------
image read,width:640
image read,hidth:640
objnum: 1
boxes=[[123.591751,65.452927,639.000000,594.583862,0,0.891947],]
[root@milkv-duo]~#

[root@milkv-duo]~# ./sample_yolov8 best_int8.cvimodel leste_jpg.rf.0eb2bc67b0858
602b1fc15975bb974e3.jpg
[56439.584750] vb_ctrl:1000(): vb has already inited, set_config cmd has no effect
asign val 0
asign val 1
asign val 2
setup yolov8 param
************************
4
************************
setup yolov8 algorithm param
yolov8 algorithm parameters setup success!
---------------------openmodel-----------------------
---------------------to do detection-----------------------
image read,width:640
image read,hidth:640
objnum: 1
boxes=[[0.702728,59.135406,552.091187,523.303955,0,0.940490],]
[root@milkv-duo]~#

Referência (Tradução) e testes com MILK-V
Blogs SmartCore

Sobre a SMARTCORE

A SMARTCORE FORNECE CHIPS E MÓDULOS PARA IOT, COMUNICAÇÃO WIRELESS, BIOMETRIA, CONECTIVIDADE, RASTREAMENTO E AUTOMAÇÃO. NOSSO PORTFÓLIO INCLUI MODEM 2G/3G/4G/NB-IOT, SATELITAL, MÓDULOS WIFI, BLUETOOTH, GPS, SIGFOX, LORA, LEITOR DE CARTÃO, LEITOR QR CCODE, MECANISMO DE IMPRESSÃO, MINI-BOARD PC, ANTENA, PIGTAIL, BATERIA, REPETIDOR GPS E SENSORES