Reconhecimento de Sinais em Libras com MediaPipe e Redes Neurais: Um Guia Completo | by Tulio Castro | Jul, 2024


A comunicação em Libras é vital para milhões de brasileiros surdos, mas a barreira entre surdos e ouvintes ainda é significativa. Este projeto de Reconhecimento de Sinais em Libras com MediaPipe e Redes Neurais foi motivado pelo desejo de promover inclusão e acessibilidade. Usando tecnologias de IA, podemos criar sistemas que interpretam Libras em tempo real, facilitando uma comunicação mais fluida e eficaz. Este guia completo mostra como desenvolvi essa solução e destaca a importância dessas tecnologias para a inclusão social.

Para desenvolver o projeto de Reconhecimento de Sinais em Libras, utilizei um conjunto robusto de ferramentas e bibliotecas. Cada uma desempenhou um papel crucial no processo, desde a coleta de dados até o treinamento da rede neural e a implementação do sistema de reconhecimento em tempo real.

TensorFlow

TensorFlow é uma das bibliotecas mais populares para machine learning e deep learning. Utilizei o TensorFlow para construir e treinar a rede neural artificial responsável pelo reconhecimento dos sinais em Libras. Sua flexibilidade e eficiência permitem o desenvolvimento de modelos complexos de maneira intuitiva e eficaz.

Scikit-Learn

scikit-learn é uma biblioteca essencial para machine learning em Python. Embora seja mais conhecida por algoritmos de aprendizado supervisionado, utilizei o scikit-learn principalmente para a normalização dos dados e a avaliação do desempenho do modelo.

MediaPipe

MediaPipe é uma biblioteca desenvolvida pelo Google que facilita a implementação de pipelines de processamento multimodal. Utilizei o MediaPipe para a detecção e extração de pontos-chave das mãos em imagens.

OpenCV (cv2)

OpenCV é uma biblioteca de visão computacional de código aberto. Utilizei o OpenCV para manipulação de imagens e vídeos, incluindo a captura de frames e a pré-processamento das imagens antes de passá-las para o MediaPipe.

Captura dos vídeos

Utilize a biblioteca OpenCV para coletar imagens de uma webcam da seguinte maneira

import cv2

cap = cv2.VideoCapture(0)

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

# Inverter o vídeo horizontelmente
frame = cv2.flip(frame, 1)

# Converter a imagem de BRG para RGB
rgb_frame = cv2.cvtColor(frame, cv2.COLOR_BGR2RGB)

# Mostrar a imagem capturada em tempo real
cv2.imshow('WebCam', frame)

Extração de Pontos-Chave

Após a captura dos vídeos, utilizei o MediaPipe para extrair os pontos-chave das mãos de cada frame do vídeo. o MediaPipe fornece coordenadas dos pontos principais das mãos, como articulações dos dedos e punho.

Este processo foi feito da seguinte forma

import cv2
import mediapipe as mp
import csv

cap = cv2.VideoCapture(0)
csv_header = ['y'] + [f'keypoint_{i}_{axis}' for i in range(21) for axis in ['x', 'y', 'z']]
csv_path = "dataset.csv"

# Iniciando o mediapipe
mp_hands = mp.solutions.hands
hands = mp_hands.Hands(min_detection_confidence=0.7, min_tracking_confidence=0.5)

# Iniciando as ferramentas para desenhar os pontos-chave
mp_drawing = mp.solutions.drawing_utils

with open(csv_path, mode='w', newline='') as file:

writer = csv.writer(file)
writer.writerow(csv_header)

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

# Inverter o vídeo horizontelmente
frame = cv2.flip(frame, 1)

# Converter a imagem de BRG para RGB
rgb_frame = cv2.cvtColor(frame, cv2.COLOR_BGR2RGB)

# Processando a imagem obtida com mediapipe
result = hands.process(rgb_frame)

# Checando se alguma mão foi detectada
if result.multi_hand_landmarks:
for hand_landmarks in result.multi_hand_landmarks:

# Desenhando os pontos-chave detectados
mp_drawing.draw_landmarks(frame, hand_landmarks, mp_hands.HAND_CONNECTIONS)

# Coletando qual o sinal esta sendo sinalizado
key = cv2.waitKey(1) & 0xFF

] # Checando se é uma letra valida
if key != 255:

key_str = chr(key)
keypoints = [key_str]

# Guardando os pontos-chave da mão detectada em um csv
for landmark in hand_landmarks.landmark:
keypoints.extend([landmark.x,landmark.y,landmark.z])

writer.writerow(keypoints)

# Mostrar a imagem capturada em tempo real
cv2.imshow('WebCam', frame)

# Liberar a WebCam e fechar as janelas criadas
cap.release()
cv2.destroyAllWindows()

A arquitetura da rede neural utilizada para o reconhecimento de sinais em Libras é projetada para processar e interpretar os dados das coordenadas dos pontos-chave das mãos, extraídos com MediaPipe. A arquitetura selecionada utiliza camadas densas (fully connected) para criar um modelo eficiente e preciso.

Representação da Rede Neural Utilizada

MediaPipe é capaz de identificar 21 pontos distintos na mão, cada um com coordenadas x, y e z. Isso resulta em 63 entradas para a rede neural. A rede neural conta também com 3 camadas escondidas com 36,39 e 26 neurônios respectivamente. A camada de saida utiliza a função de ativação SoftMax para transformar a camada de saida em uma distribuição de probabilidades de cada classe, todas as outras camadas utilizam a função de ativação ReLU, o modelo foi compilado com o otimizador Adam

Você pode construir um modelo similar em python da seguinte forma

import tensorflow as tf
from keras import layers, models, callbacks
import pandas as pd

# Importando os dados
data_frame = pd.read_csv("dataset.csv",sep=",",decimal=".")

# Coletando o numero de classes diferentes
labels = data_frame["y"].unique()

# Criando um modelo
model = models.Sequential()

# Adicionando a camada de entrada
model.add(layers.Dense(63,activation="relu",input_dim = 63))

# Adicionando as camadas escondidas
model.add(layers.Dense(26,activation="relu"))
model.add(layers.Dense(39,activation="relu"))
model.add(layers.Dense(26,activation="relu"))

# Adicionando a camada de saida
model.add(layers.Dense(len(labels),activation="softmax"))

# Compilando o modelo
model.compile(loss = "sparse_categorical_crossentropy", optimizer = "adam", metrics=["accuracy"])

Preparação dos dados

Os dados foram normalizados utilizando LabelEncoder e StandartScaler, em seguida divididos em conjuntos de treinamento e validação da seguinte forma

import tensorflow as tf
import pandas as pd
from sklearn.preprocessing import LabelEncoder,StandardScaler

path = "dataset.csv"

#Crir o dataframe
data_frame = pd.read_csv(path,sep=",",decimal=".")

labels = data_frame["y"].unique() #Colhendo os diferentes labels do data frame
encoder = LabelEncoder() #Criando o codificador
encoder.fit(labels) #Ajustando o codificador
data_frame["target"] = encoder.transform(data_frame["y"]) #Criando uma nova coluna no data frame

#Ajustando o data frame
scaler = StandardScaler()
scaler.fit(data_frame.iloc[:,1:64])
data_frame.iloc[:,1:64] = pd.DataFrame(scaler.fit_transform(data_frame.iloc[:,1:64])) #Normalizando os valores

#Criando os valores de treino, teste e validacao

train = data_frame.sample(frac=0.8,random_state=seed) #Separando 80% do data frame para o treino
data_frame = data_frame.drop(train.index) #Removendo os valores de treino do data frame
valid = data_frame.sample(frac=0.5,random_state=seed) #Separando 50% dos valores para a validacao
data_frame = data_frame.drop(valid.index) #Removendo os valores de validacao do data frame
test = data_frame.sample(frac=1,random_state=seed) #Separando o resto dos valores para o teste

X_train = train.iloc[:,1:64]
y_train = train.iloc[:,64]
X_valid = valid.iloc[:,1:64]
y_valid = valid.iloc[:,64]
X_test = test.iloc[:,1:64]
y_test = test.iloc[:,64]

Treinamento do modelo

Apos criado e compilado o modelo, o processo de treinamento seguiu da seguinte forma

# Adicionando callbacks para medir o treinamento do modelo

callback = callbacks.ModelCheckpoint("best.keras",save_best_only=True)

reduce_lr_callback = callbacks.ReduceLROnPlateau(monitor='accuracy', factor=0.2, patience=3, min_lr=1e-6)

#Criando uma condicao para que a rede pare de treinar se nao houver melhoras, ajuda a evitar overfitting
early_stopping_callback = callbacks.EarlyStopping(monitor="accuracy",patience=10,restore_best_weights=True)

#Treinamento
history = model.fit(X_train, y_train,
epochs=epocas,
batch_size=64,
validation_data=(X_valid, y_valid),
shuffle=True,
callbacks=[early_stopping_callback, callback, reduce_lr_callback],
verbose=1)

#Plotando o grafico de acuracia
plt.plot(history.history['accuracy'],color='red',label='training accuracy')
plt.plot(history.history['val_accuracy'],color='blue',label='validation accuracy')
plt.legend()
plt.show()

#Plotando o grafico de loss
plt.plot(history.history['loss'],color='red',label='training loss')
plt.plot(history.history['val_loss'],color='blue',label='validation loss')
plt.legend()
plt.show()

Avaliação do Modelo

Após o treinamento, o modelo é avaliado para verificar seu desempenho e ajustar hiperparâmetros, se necessário.

Acurácia durante o treinamento
Perda durante o treinamento

Os gráficos de desempenho do modelo indicam resultados muito positivos durante o treinamento. O gráfico de acurácia mostra um rápido crescimento no valor da métrica, alcançando e mantendo uma precisão entre 0,99 e 1. Isso sugere que o modelo aprendeu a identificar com alta precisão os sinais em Libras, conseguindo classificar corretamente a maioria dos exemplos.

Simultaneamente, o gráfico de perda (loss) revela uma rápida diminuição na função de perda, que estabilizou em um valor próximo a 0. Isso indica que a rede neural foi eficaz em minimizar a diferença entre as previsões e os sinais verdadeiros durante o treinamento. A perda próxima de 0 reflete uma excelente capacidade do modelo em ajustar seus pesos e melhorar a qualidade das previsões.

Esses resultados demonstram que o modelo está bem treinado e possui uma alta capacidade de generalização, uma vez que a acurácia elevada e a perda baixa indicam uma performance robusta tanto em termos de precisão quanto de capacidade de previsão. A constância nos altos valores de acurácia e baixos valores de perda sugere que o modelo não está apenas se ajustando bem aos dados de treinamento, mas também está mantendo um desempenho sólido e consistente.

Matriz de confusão

Uma matriz de confusão é uma ferramenta essencial para avaliar o desempenho de um modelo de classificação. Ela mostra o número de previsões corretas e incorretas do modelo em relação às classes reais. Ela é capaz de identificar verdadeiros positivos, verdadeiros negativos,falsos positivos, falsos negativos. A matriz de confusão revelou um desempenho impecável, sem erros de classificação, o que demonstra a eficácia do modelo.

Impacto potencial

A aplicação desta tecnologia pode transformar a comunicação para surdos e deficientes auditivos, facilitando a interação em tempo real e promovendo uma inclusão mais eficaz em diversos contextos.

Proximos passos

Para aprimorar ainda mais o sistema, planejo implementar novos sinais, expandir o reconhecimento para sinais feitos com ambas as mãos, e integrar a detecção de expressões faciais e posturas do sinalizador.

MediaPipe : https://mediapipe.dev

TensorFlow: https://www.tensorflow.org/guide

OpenCV : https://docs.opencv.org/

Libras: https://www.libras.org



Source link

Be the first to comment

Leave a Reply

Your email address will not be published.


*