O LibrIA reconhece Libras a partir da webcam usando landmarks de mão do MediaPipe. O repositório cobre o ciclo completo: coleta de dataset, treino, inferência em tempo real e export de um bundle quantizado com pacote C/C++ pronto para o Raspberry Pi Pico.
O sistema reconhece sinais isolados — o alfabeto manual e sinais dinâmicos. A composição em palavras e frases é o trabalho em andamento; veja o plano arquitetural e as fases já implementadas em docs/FASE1_RECONHECIMENTO.md e docs/FASE2_TEMPORAL.md.
git clone https://github.com/Gabryel-lima/LibrIA.git
cd LibrIA
make setup # cria o venv e instala as dependências
make verify # confere se o ambiente está utilizável
make report # o que já existe e o que falta por classe
make sources # bases públicas de Libras que cobrem as lacunas
# Ingestão de base externa — cobre classes inteiras sem gravar nada
make ingest SOURCE_DIR=data/archives/minds-libras MODALITY=temporal
# Coleta — só o que sobrou, e sempre identifique quem está sinalizando
make collect SUBJECT=ana ENVIRONMENT=sala_luz_natural CAMERA_ID=c920 DOMINANT_HAND=right
make train # treina os modelos estático e temporal
make infer # inferência híbrida em tempo real ('q' para sair)make help lista todos os comandos. Pré-requisitos: Python 3.11+, webcam e uma
CPU com suporte a AVX (necessário para o MediaPipe — veja
docs/AVX_COMPATIBILITY.md se a sua não tiver).
Cada alvo do Makefile tem um comando de mesmo nome no main.py:
make train-temporal é idêntico a python main.py train-temporal. Use o
Makefile no dia a dia; o main.py existe para quem não usa make.
| Comando | O que faz |
|---|---|
make sources |
Catálogo de bases públicas de Libras que podem alimentar o dataset |
make fetch SOURCE=<chave> |
Baixa uma base com download automatizável |
make ingest SOURCE_DIR=<dir> |
Converte a base baixada em amostras do dataset (sem webcam) |
make collect |
Dataset mínimo: alfabeto estático (24 letras) + J/Z |
make collect-static |
Só o alfabeto manual estático |
make collect-temporal |
Só as letras temporais (J, Z) |
make collect-words |
Palavras e gestos funcionais do vocabulário lexical |
make collect-unknown |
Amostras fora do vocabulário (classe de rejeição) |
make report |
Cobertura do dataset: vocabulário, metadados, divisão por pessoa |
make train |
Treina os modelos estático e temporal |
make train-static |
Só o Random Forest estático |
make train-temporal |
Só a LSTM temporal |
make infer |
Inferência híbrida (recomendado) |
make infer-static |
Só o modelo estático |
make infer-temporal |
Só o modelo temporal |
make all |
Pipeline completo: coletar → treinar → inferir |
| Variável | Padrão | Para quê |
|---|---|---|
SUBJECT |
desconhecido |
Quem está sinalizando — sem isso não há divisão por pessoa |
CAMERA_ID |
desconhecido |
Modelo/apelido da câmera |
ENVIRONMENT |
desconhecido |
Ambiente da captura (ex.: sala_luz_natural) |
DOMINANT_HAND |
desconhecido |
left ou right |
CAMERA |
0 |
Índice da webcam |
SAMPLES |
30 |
Amostras estáticas por classe |
SEQUENCES |
30 |
Sequências temporais por classe |
make collect-words SUBJECT=bruno ENVIRONMENT=escritorio SEQUENCES=40A coleta é dirigida por lacunas: classes que já atingiram a meta (SAMPLES /
SEQUENCES) são puladas, venham elas da webcam ou de uma base externa. O plano
é impresso antes de a câmera abrir. Para regravar mesmo assim, use
python main.py collect-static --all-labels.
| Variável | Para quê |
|---|---|
SOURCE |
Chave da base em make fetch (ex.: minds-libras) |
SOURCE_DIR |
Diretório da base já baixada, uma pasta por sinal |
SOURCE_NAME |
Vira source_dataset nos metadados de cada amostra |
MODALITY |
temporal (padrão) ou static |
LABEL_MAP |
JSON {termo_da_base: LABEL_LIBRIA} para casar o vocabulário |
Detalhes e as bases catalogadas em docs/DATASETS.md.
| Comando | O que faz |
|---|---|
make setup / make verify |
Cria o ambiente / valida as dependências |
make install-cpu / make install-gpu |
Instala dependências (CUDA detectado automaticamente) |
make embedded-train |
Treina as CNNs quantizadas INT8 e exporta o bundle |
make embedded-export |
Empacota modelos, manifesto e pacote C/C++ do Pico |
make embedded-check |
Valida o bundle sobre os datasets .npy |
make checkerboard / make calibrate-capture / make calibrate |
Calibração de câmera com tabuleiro 9x6 |
make test |
Roda a suíte de testes |
make lint / make format |
flake8 / black (requer make install-dev) |
make clean / make clean-all |
Limpa caches / remove venv, dataset e modelos |
- Percepção visual — webcam → MediaPipe → landmarks normalizados.
- Reconhecimento de sinais — classificação estática e temporal, com detecção de início e fim de cada sinal.
- Composição linguística — tokens → palavras → português. (em aberto)
- Apresentação — texto em tempo real, histórico e confiança.
webcam → MediaPipe → features → buffer → movimento → segmentação
↓ ↓
fallback estático modelo temporal
↓ ↓
└──→ suavização → dedup → SignToken
O modelo temporal só é consultado quando há um sinal delimitado por movimento; o modelo estático responde enquanto a mão está parada formando uma letra. Detalhes em docs/FASE2_TEMPORAL.md.
Toda saída é um SignToken padronizado:
{
'label': 'OI', 'token': 'oi', 'confidence': 0.91,
'start_time': 12.4, 'end_time': 13.1, 'duration_seconds': 0.7,
'source': 'temporal', # temporal | static
'state': 'final', # partial | final | rejected
'sign_type': 'lexical', # alphabet | lexical | functional
}state: rejected é o que evita apresentar tradução errada como certeza: abaixo
do limiar de confiança, o sinal vira DESCONHECIDO em vez de virar palavra.
| Modelo | Papel | Artefato |
|---|---|---|
| Random Forest | Letras estáticas | model/model.pickle |
| LSTM | Sinais dinâmicos (30 quadros × 63 features) | model/libras_lstm.keras |
| CNN estática INT8 | Deployment embarcado | model/libria_embedded_cnn_int8.tflite |
| CNN temporal INT8 | Deployment embarcado | model/libria_embedded_temporal_cnn_int8.tflite |
Todos os modelos recebem os mesmos landmarks; o FEATURE_MODE
(wrist_relative, 63 features, ou bounding_box, 42) define o formato.
config/vocabulary.py é a fonte única de verdade do
vocabulário, dividido em três famílias:
| Família | Modalidade | Conteúdo |
|---|---|---|
alphabet |
estática (24) + temporal (J, Z) | Alfabeto manual |
lexical |
temporal | Palavras (OI, OBRIGADO, AJUDA, …) |
functional |
temporal | ESPACO, PAUSA, APAGAR, CONFIRMAR |
Mais DESCONHECIDO, a classe explícita de fora do vocabulário.
dataset/
├── static/<LABEL>/ sample_XXX.npy · sample_XXX_mirror.npy
│ sample_XXX.json · frame_XXX.png
└── temporal/<LABEL>/ seq_XXX.npy · seq_XXX_mirror.npy · seq_XXX.json
Cada .npy tem um .json irmão com pessoa, câmera, ambiente, mão dominante,
duração e qualidade da captura. São esses metadados que permitem dividir
treino/validação/teste por pessoa — dividir por amostra faz a mesma pessoa
aparecer nos três conjuntos e infla a acurácia. Detalhes em
docs/FASE1_RECONHECIMENTO.md e
docs/DATASETS.md.
Toda amostra é gravada junto com sua versão espelhada, o que dá suporte a mão esquerda e direita sem coletar duas vezes.
LibrIA/
├── main.py CLI (mesmos nomes dos alvos do Makefile)
├── Makefile setup, coleta, treino, inferência
├── config/
│ ├── settings.py configuração central
│ └── vocabulary.py vocabulário (fonte de verdade)
├── scripts/
│ ├── collect_dataset.py coleta estática e temporal
│ ├── dataset_report.py relatório de cobertura
│ ├── calibrate_camera.py calibração de câmera
│ └── generate_checkerboard.py
├── src/
│ ├── dataset/ metadados por amostra
│ ├── evaluation/ divisão por pessoa e métricas
│ ├── model_training/ Random Forest, LSTM e CNNs quantizadas
│ ├── inference/ pipeline temporal e classificadores
│ ├── models/transformer-gpt/ experimental, ainda não integrado
│ └── utils/
├── utils/helpers.py landmarks, calibração e logging
├── tests/ suíte de testes (make test)
├── dataset/ · model/ · output/ · training_plots/
└── docs/
Tudo em config/settings.py:
FEATURE_MODE = 'wrist_relative' # ou 'bounding_box'
COLLECTION_CONFIG = {'static_samples_per_label': 30, ...}
LSTM_CONFIG = {'sequence_length': 30, 'confidence_threshold': 0.85, ...}
TEMPORAL_PIPELINE_CONFIG = { # segmentação e suavização
'motion_start_threshold': 0.012,
'motion_end_threshold': 0.006,
'duplicate_window_seconds': 1.0, ...
}
EVALUATION_CONFIG = {'split_ratios': {...}, 'rejection_threshold': 0.75, ...}Os limiares de movimento estão em unidades de deslocamento médio de landmark por quadro e precisam ser calibrados na sua câmera — o padrão é um ponto de partida, não uma medição.
- Acrescente entradas em
_LEXICAL_ENTRIES(config/vocabulary.py). - Veja se uma base pública já cobre o sinal (
make sources) e ingira (make ingest ... LABEL_MAP=...). Só grave commake collect-words SUBJECT=...o que sobrar. - Aponte
LSTM_CONFIG['allowed_classes']paraTEMPORAL_VOCABULARY_LABELSe deixerequire_all_allowed_classes = False, para treinar com as classes já coletadas em vez de falhar nas que ainda faltam. make train-temporal.
| Problema | Solução |
|---|---|
illegal hardware instruction (core dumped) |
CPU sem AVX — veja docs/AVX_COMPATIBILITY.md |
Ambiente virtual não encontrado |
make setup |
| Webcam não detectada | Confira permissões e tente make infer CAMERA=1 |
| Baixa acurácia | Colete mais pessoas e ambientes; confira make report |
| Sinal não é detectado | Ajuste motion_start_threshold (veja a seção de configuração) |
| Um sinal vira vários tokens repetidos | Aumente duplicate_window_seconds |
| Módulo não encontrado | Rode os comandos a partir da raiz do projeto |
Logs em libras.log (configurável em LOGGING_CONFIG).
- docs/FASE1_RECONHECIMENTO.md — vocabulário, metadados, divisão por pessoa e métricas
- docs/FASE2_TEMPORAL.md — pipeline temporal, segmentação e
SignToken - docs/ARCHITECTURE.md — arquitetura e diagramas
- docs/DATASETS.md — formatos, artefatos e datasets externos
- docs/DEVELOPMENT.md — setup de desenvolvimento
- docs/AVX_COMPATIBILITY.md — CPUs sem AVX
- docs/latex/model_architecture_equations.pdf — fórmulas da arquitetura
Comunidade: CONTRIBUTING.md · CODE_OF_CONDUCT.md · GOVERNANCE.md · ROADMAP.md · CHANGELOG.md · CONTRIBUTORS.md
Contribuições são bem-vindas. Leia o CONTRIBUTING.md e o guia de Pull Requests. Áreas com maior impacto agora:
- Coleta com mais pessoas — o gargalo real do projeto hoje
- Vocabulário lexical de Libras (palavras e variações regionais)
- Camada de composição linguística (tokens → português)
- Validação com pessoas surdas e intérpretes
MIT — veja LICENSE.
Gabryel Lima — GitHub
Construído com MediaPipe, OpenCV, scikit-learn e TensorFlow.