VIXI, O ROBÔ GANHOU OLHO, PIÁ!

👁️ Visão Computacional

"O robô de olho: detectando mãos e lendo QR codes" — implementando MediaPipe Hands e OpenCV para criar um robô que enxerga.

Duração: 100 min (2 aulas)
MediaPipe + OpenCV + QR Code
BNCC: EM13CNT101 | EM13CNT303
👁️👄👁️
⬇️⬇️⬇️
"TO DE OLHO EM TU!"
🎬

Abertura · 10min

Mostrar exemplos de visão computacional (filtros do Instagram, Snapchat, Google Lens).

🧠

Conceituação · 15min

Explicar detecção de mãos (pontos de referência) e QR codes (matrizes de dados).

💻

Codificação · 40min

Implementar captura de imagem + detecção de mão + leitura de QR code.

🧪

Teste · 20min

Alunos testam com mãos na webcam e QR codes impressos (ou no celular).

⚖️

Fechamento · 15min

Gerar QR code personalizado do robô e discutir aplicações para acessibilidade.

Adaptações inclusivas

Alunos sem webcam usam imagens fornecidas. Versão simulada com upload de fotos disponível.

Pontos da Mão (Landmarks) — "Os 21 pontos que o robô aprendeu a vigiar" 🤚 MediaPipe Hands
📍 0-4: Polegar
Base até ponta do polegar
📍 5-8: Indicador
Base até ponta do dedo indicador
📍 9-12: Médio
Base até ponta do dedo médio
📍 13-16: Anelar
Base até ponta do dedo anelar
📍 17-20: Mínimo
Base até ponta do dedo mínimo
🤖 Contagem de dedos
Compara Y da ponta com Y da base
robo_fofoqueiro_visao.py — Código completo da aula download disponível
# ===================================================================
#                Robô Fofoqueiro - Visão Computacional
# ===================================================================
# Objetivo: Utilizar visão computacional para detectar mãos, contar
#           dedos levantados e ler QR codes através da webcam.
#           Inclui modo simulado para ambientes sem câmera e
#           gerador de QR codes personalizados.
# Alunos: [A SER PREENCHIDO]
# Orientadora: Gisele Nunes
# Data  : 2026
# ===================================================================

# -*- coding: utf-8 -*-

# Importa o módulo sys para acessar funcionalidades do sistema e
# verificar se está rodando no Google Colab.
import sys

# Importa o módulo os para manipular caminhos e arquivos do sistema.
import os

# Importa a biblioteca OpenCV (cv2) para processamento de imagens,
# captura de webcam, detecção de QR codes e exibição de vídeo.
import cv2

# Importa a biblioteca MediaPipe para detecção de landmarks (pontos)
# da mão e reconhecimento de gestos.
import mediapipe as mp

# Importa numpy para operações matemáticas com arrays (imagens, matrizes).
import numpy as np

# Importa a biblioteca qrcode para gerar QR codes a partir de strings.
import qrcode

# Importa a biblioteca PIL (Pillow) para manipulação de imagens.
from PIL import Image

# Importa time para medir intervalos e gerar timestamps.
import time

# Importa ferramentas do IPython para exibir imagens diretamente no notebook.
from IPython.display import display, Image as IPImage

# ============================================================
# VERIFICAÇÃO DO AMBIENTE (Colab ou local)
# ============================================================

def verifica_ambiente():
    """
    Verifica se o código está sendo executado no Google Colab ou em ambiente local.
    Retorna 'colab' se estiver no Colab, 'local' caso contrário.
    Isso é importante porque a instalação de bibliotecas difere entre os ambientes.
    """
    
    # Verifica se o módulo 'google.colab' está presente nos módulos carregados.
    if 'google.colab' in sys.modules:
        # Se estiver no Colab, exibe mensagem e retorna "colab".
        print("✅ Tamo no Colab! Vamos instalar as paradas com !pip.")
        return "colab"
    else:
        # Se estiver em ambiente local, exibe mensagem e retorna "local".
        print("✅ Ambiente local detectado!")
        return "local"

# Chama a função para detectar o ambiente e armazena o resultado.
AMBIENTE = verifica_ambiente()

# ============================================================
# INSTALAÇÃO DAS BIBLIOTECAS (SÓ NO COLAB)
# ============================================================

print("\n📦 Verificando/Instalando as bibliotecas de visão...")

# Se o ambiente for o Google Colab, instala as bibliotecas necessárias.
if AMBIENTE == "colab":
    # Atualiza a lista de pacotes do sistema (apt-get).
    !apt-get update -qq
    
    # Instala a biblioteca libgl1-mesa-glx (necessária para OpenCV no Linux).
    !apt-get install -y libgl1-mesa-glx -qq
    
    # Instala as bibliotecas Python: OpenCV (sem interface gráfica), MediaPipe,
    # qrcode com suporte a PIL/Pillow.
    !pip install opencv-python-headless mediapipe qrcode[pil] pillow -q
    
    print("✅ Bibliotecas instaladas (OpenCV, MediaPipe, QRCode).")
else:
    # Se for ambiente local, apenas avisa que o usuário precisa instalar manualmente.
    print("⚠️ Ambiente local: pip install opencv-python mediapipe qrcode[pil] pillow")

# ============================================================
# ARTE ASCII DO ROBÔ (VISÃO)
# ============================================================

# String com arte ASCII representando o robô no modo de visão computacional.
# Inclui olhos (👁️👄👁️) para simbolizar o "modo vidente" e gírias paranaenses.
ascii_robo_visao = r"""
╔══════════════════════════════════════════════════════╗
║ 👁️👄👁️                                              ║
║ 🤖 ROBÔ FOFOQUEIRO - MODO VIDENTE 🤖                ║
║ "To de olho em tu, piá!"                            ║
║ "Levantou a mão? Já sei quantos dedo tem!"         ║
╚══════════════════════════════════════════════════════╝
"""

# Exibe a arte ASCII na tela.
print(ascii_robo_visao)

# ============================================================
# DETECTOR DE MÃOS (MEDIAPIPE)
# ============================================================

# Cria um atalho para o módulo de soluções de mãos do MediaPipe.
mp_hands = mp.solutions.hands

# Cria um atalho para o módulo de desenho de landmarks do MediaPipe.
mp_drawing = mp.solutions.drawing_utils

# Inicializa o detector de mãos com os seguintes parâmetros:
# - static_image_mode=False: otimizado para vídeo (detecta continuamente).
# - max_num_hands=2: detecta no máximo 2 mãos simultaneamente.
# - min_detection_confidence=0.7: confiança mínima para detectar uma mão (70%).
# - min_tracking_confidence=0.5: confiança mínima para rastrear (50%).
hands = mp_hands.Hands(
    static_image_mode=False,
    max_num_hands=2,
    min_detection_confidence=0.7,
    min_tracking_confidence=0.5
)

def contar_dedos(landmarks, lado):
    """
    Conta quantos dedos estão levantados com base nos landmarks (pontos de referência)
    da mão fornecidos pelo MediaPipe.
    
    Parâmetros:
    landmarks: lista de pontos 3D (x, y, z) de cada articulação da mão.
    lado: string indicando se é "Right" (mão direita) ou "Left" (mão esquerda).
    
    Retorna:
    int: número total de dedos levantados (0 a 5).
    """
    
    # Lista para armazenar se cada dedo está levantado (1) ou não (0).
    dedos = []
    
    # POLEGAR - Lógica diferente: compara posição X (horizontal)
    # Para mão direita: polegar levantado se ponta (landmark 4) estiver à direita
    # da base (landmark 3).
    if lado == "Right":
        if landmarks[4].x > landmarks[3].x:
            dedos.append(1)  # Levantado
        else:
            dedos.append(0)  # Abaixado
    else:
        # Para mão esquerda: polegar levantado se ponta estiver à esquerda da base.
        if landmarks[4].x < landmarks[3].x:
            dedos.append(1)
        else:
            dedos.append(0)
    
    # OUTROS DEDOS (indicador, médio, anel, mínimo)
    # Índices dos landmarks das pontas dos dedos.
    pontas = [8, 12, 16, 20]
    
    # Índices dos landmarks das bases dos dedos (articulação proximal).
    bases = [6, 10, 14, 18]
    
    # Percorre os pares (ponta, base) para cada dedo.
    for ponta, base in zip(pontas, bases):
        # Um dedo está levantado se a ponta estiver acima (menor Y) da base.
        # Lembrando: no OpenCV, Y=0 é o topo da imagem, Y aumenta para baixo.
        if landmarks[ponta].y < landmarks[base].y:
            dedos.append(1)  # Levantado
        else:
            dedos.append(0)  # Abaixado
    
    # Retorna a soma total de dedos levantados.
    return sum(dedos)

def detectar_maos(frame):
    """
    Detecta mãos em um frame de vídeo e desenha os landmarks.
    
    Parâmetros:
    frame: imagem BGR (formato do OpenCV).
    
    Retorna:
    tuple: (frame_modificado, total_dedos)
        - frame_modificado: imagem com landmarks e texto desenhados.
        - total_dedos: soma de todos os dedos levantados (ambas as mãos).
    """
    
    # Converte o frame de BGR (padrão OpenCV) para RGB (padrão MediaPipe).
    rgb = cv2.cvtColor(frame, cv2.COLOR_BGR2RGB)
    
    # Processa o frame para detectar landmarks das mãos.
    resultado = hands.process(rgb)
    
    # Inicializa o contador total de dedos.
    dedos_total = 0
    
    # Se pelo menos uma mão foi detectada...
    if resultado.multi_hand_landmarks:
        # Itera sobre cada mão detectada e sua classificação (direita/esquerda).
        for hand_landmarks, handedness in zip(resultado.multi_hand_landmarks, resultado.multi_handedness):
            # Desenha os landmarks (pontos) e as conexões (linhas) da mão no frame.
            mp_drawing.draw_landmarks(frame, hand_landmarks, mp_hands.HAND_CONNECTIONS)
            
            # Obtém o lado da mão ("Right" ou "Left").
            lado = handedness.classification[0].label
            
            # Conta quantos dedos estão levantados nesta mão.
            dedos = contar_dedos(hand_landmarks.landmark, lado)
            
            # Acumula no total geral.
            dedos_total += dedos
            
            # Escreve no frame qual lado e quantos dedos foram detectados.
            cv2.putText(frame, f"{lado}: {dedos} dedos",
                        (10, 50),                    # Posição (x, y)
                        cv2.FONT_HERSHEY_SIMPLEX,    # Fonte
                        1,                           # Escala
                        (0,255,0),                   # Cor verde (BGR)
                        2)                           # Espessura da linha
    
    # Retorna o frame modificado e o total de dedos.
    return frame, dedos_total

# ============================================================
# LEITOR DE QR CODE
# ============================================================

def ler_qr_code(frame):
    """
    Lê QR code em um frame de vídeo e retorna o texto decodificado.
    
    Parâmetros:
    frame: imagem BGR (formato do OpenCV).
    
    Retorna:
    str or None: o texto decodificado do QR code, ou None se não encontrado.
    """
    
    # Cria um detector de QR code do OpenCV.
    detector = cv2.QRCodeDetector()
    
    # Tenta detectar e decodificar o QR code no frame.
    # Retorna: texto, pontos do quadrado, matriz de correção (ignorada).
    texto, pontos, _ = detector.detectAndDecode(frame)
    
    # Se um texto foi encontrado (QR code válido)...
    if texto:
        # Escreve o texto decodificado no frame (posição (10,100), cor amarela).
        cv2.putText(frame, f"QR: {texto}", (10, 100),
                    cv2.FONT_HERSHEY_SIMPLEX, 0.7, (0,255,255), 2)
        # Retorna o texto.
        return texto
    
    # Se nenhum QR code foi encontrado, retorna None.
    return None

# ============================================================
# MODO SIMULADO (PARA QUEM NÃO TEM WEBCAM)
# ============================================================

def modo_simulado():
    """
    Versão simulada do robô para usuários que não possuem webcam.
    Cria uma imagem artificial com textos simulando a detecção de mãos e QR codes.
    Útil para testar o código no Google Colab sem hardware.
    """
    
    print("\n🎭 MODO SIMULADO - Robô testando com imagens falsas.\n")
    
    # Cria uma imagem preta (todos os pixels zero) de tamanho 480x640 com 3 canais (BGR).
    img = np.zeros((480, 640, 3), dtype=np.uint8)
    
    # Adiciona texto simulando detecção de uma mão com 5 dedos.
    cv2.putText(img, "SIMULACAO: Mao com 5 dedos", (50, 100),
                cv2.FONT_HERSHEY_SIMPLEX, 1, (0,255,0), 2)
    
    # Adiciona texto com a contagem simulada de dedos.
    cv2.putText(img, "Total dedos (simulado): 5", (50, 200),
                cv2.FONT_HERSHEY_SIMPLEX, 1, (0,255,0), 2)
    
    # Define um QR code falso para simular a leitura.
    qr_falso = "https://forms.gle/fofoca-do-robô"
    
    # Adiciona texto simulando a leitura do QR code.
    cv2.putText(img, f"QR Simulado: {qr_falso}", (50, 300),
                cv2.FONT_HERSHEY_SIMPLEX, 0.7, (0,255,255), 2)
    
    # Converte a imagem para formato JPEG em memória.
    ret, buffer = cv2.imencode('.jpg', img)
    
    # Exibe a imagem no notebook Colab.
    from IPython.display import display, Image
    display(Image(data=buffer.tobytes()))
    
    # Exibe o QR code simulado que teria sido lido.
    print(f"📲 QR code simulado lido: {qr_falso}")
    print("✅ Simulação concluída.")

# ============================================================
# GERADOR DE QR CODE
# ============================================================

def gerar_qr_code(dados="https://github.com/robofofoqueiro", nome_arquivo="qr_robofofoqueiro.png"):
    """
    Gera um QR code a partir de uma string (URL, texto, etc.) e salva como imagem PNG.
    
    Parâmetros:
    dados: str - o conteúdo a ser codificado no QR code.
    nome_arquivo: str - nome do arquivo de saída (padrão: qr_robofofoqueiro.png).
    """
    
    print(f"\n📱 Gerando QR code com os dados: {dados}")
    
    # Cria um objeto QRCode com as configurações:
    # - version=1: tamanho básico (21x21 módulos).
    # - box_size=10: cada módulo terá 10 pixels.
    # - border=5: borda de 5 módulos.
    qr = qrcode.QRCode(version=1, box_size=10, border=5)
    
    # Adiciona os dados ao QR code.
    qr.add_data(dados)
    
    # Ajusta o tamanho automaticamente para caber os dados.
    qr.make(fit=True)
    
    # Cria a imagem do QR code com cor preta e fundo branco.
    img_qr = qr.make_image(fill_color="black", back_color="white")
    
    # Salva a imagem no arquivo especificado.
    img_qr.save(nome_arquivo)
    
    # Exibe a imagem no notebook Colab.
    display(IPImage(nome_arquivo))
    
    print(f"✅ QR code salvo como {nome_arquivo}")

# ============================================================
# FUNÇÃO PRINCIPAL (WEBCAM)
# ============================================================

def modo_visao_robo():
    """
    Função principal que ativa a webcam e detecta mãos e QR codes em tempo real.
    Executa um loop contínuo até o usuário pressionar a tecla 'q'.
    """
    
    print("\n🎥 Iniciando a visão do Robô Fofoqueiro...")
    print("👉 Mostre a mão pra eu contar os dedos!")
    print("👉 Mostre um QR code pra eu ler a fofoca!")
    print("👉 Pressione 'q' para sair do modo visão.")
    
    # Tenta abrir a webcam padrão (índice 0).
    cap = cv2.VideoCapture(0)
    
    # Se não conseguiu abrir a webcam...
    if not cap.isOpened():
        print("❌ Webcam não encontrada! Usando modo SIMULADO.")
        modo_simulado()
        return
    
    print("✅ Webcam ligada!")
    
    # Loop principal de captura de frames.
    while True:
        # Captura um frame da webcam.
        # ret: booleano indicando sucesso.
        # frame: imagem capturada.
        ret, frame = cap.read()
        
        # Se falhou ao capturar, interrompe o loop.
        if not ret:
            print("❌ Falha ao capturar frame.")
            break
        
        # Espelha o frame horizontalmente (efeito espelho, mais natural para o usuário).
        frame = cv2.flip(frame, 1)
        
        # Detecta mãos e conta dedos.
        frame, dedos = detectar_maos(frame)
        
        # Tenta ler QR code no frame.
        qr_texto = ler_qr_code(frame)
        
        # Se um QR code foi detectado...
        if qr_texto:
            print(f"📲 QR Code detectado: {qr_texto}")
            # Salva o QR code lido em um arquivo de log.
            with open("fofocas_qr.txt", "a", encoding="utf-8") as f:
                f.write(f"{time.ctime()} - QR: {qr_texto}\n")
        
        # Escreve o total de dedos detectados no canto superior esquerdo.
        cv2.putText(frame, f"Total dedos: {dedos}", (10, 30),
                    cv2.FONT_HERSHEY_SIMPLEX, 1, (0,255,0), 2)
        
        # Exibe a janela com o vídeo processado.
        cv2.imshow("Robô Fofoqueiro - Visão Computacional", frame)
        
        # Aguarda 1 milissegundo pela tecla 'q' (ASCII 113) para sair.
        # Se 'q' for pressionado, interrompe o loop.
        if cv2.waitKey(1) & 0xFF == ord('q'):
            break
    
    # Libera a webcam (encerra a captura).
    cap.release()
    
    # Fecha todas as janelas abertas pelo OpenCV.
    cv2.destroyAllWindows()
    
    print("\n👋 Modo visão desligado.")

# ============================================================
# CHECKLIST
# ============================================================

def checklist_visao():
    """
    Verifica se as bibliotecas necessárias estão instaladas corretamente.
    Exibe um relatório de status para cada biblioteca.
    """
    
    print("\n📋 CHECKLIST DO MODO VISÃO:")
    print("="*40)
    
    # Verifica MediaPipe.
    try:
        import mediapipe
        print("✅ MediaPipe instalado")
    except:
        print("❌ MediaPipe faltando")
    
    # Verifica OpenCV.
    try:
        import cv2
        print("✅ OpenCV funcionando")
    except:
        print("❌ OpenCV faltando")
    
    # Verifica QRCode.
    try:
        import qrcode
        print("✅ QRCode funcionando")
    except:
        print("❌ QRCode faltando")
    
    print("="*40)

# ============================================================
# MENU PRINCIPAL
# ============================================================

def main():
    """
    Função principal que exibe o menu de opções e executa a funcionalidade escolhida.
    Opções: webcam real, modo simulado, gerar QR code, checklist ou sair.
    """
    
    # Exibe o menu de opções.
    print("\n🤖 ROBÔ FOFOQUEIRO - AULA 4: VISÃO COMPUTACIONAL")
    print("1 - Testar detecção de mãos e QR code (webcam real)")
    print("2 - Modo simulado (sem webcam)")
    print("3 - Gerar QR code do robô")
    print("4 - Verificar checklist das bibliotecas")
    print("5 - Sair")
    
    # Solicita a opção do usuário.
    opcao = input("\n👉 Escolha uma opção (1/2/3/4/5): ")
    
    # Executa a opção escolhida.
    if opcao == '1':
        # Modo com webcam real.
        modo_visao_robo()
    elif opcao == '2':
        # Modo simulado (sem hardware).
        modo_simulado()
    elif opcao == '3':
        # Gera um QR code personalizado.
        texto_qr = input("Digite o texto ou URL para gerar o QR code: ")
        if not texto_qr:
            texto_qr = "https://github.com/robofofoqueiro"
        gerar_qr_code(texto_qr)
    elif opcao == '4':
        # Exibe checklist de bibliotecas.
        checklist_visao()
    else:
        # Sai do programa (opção 5 ou qualquer outra).
        print("👋 Até a próxima fofoca visual!")

# Verifica se o script está sendo executado diretamente (não importado como módulo).
if __name__ == "__main__":
    # Chama a função principal.
    main()

# Mensagem final de encerramento da aula.
print("\n🎉 Fim da Aula 4 - Robô Fofoqueiro agora é vidente!")
print("(Mas não guarda rancor, só fofoca mesmo)")

Checklist de avaliação - Aluno

  • Conseguiu implementar a detecção de mãos funcional?
  • O robô conta os dedos corretamente?
  • Leitura de QR code está funcionando?
  • Conseguiu gerar um QR code personalizado?
  • Testou com webcam real ou modo simulado?
  • Participou da discussão sobre acessibilidade com visão computacional?
Prazos & alertas

Entrega do projeto: 30/04/2026

Validar visão computacional antes do próximo encontro.


Dica: "Se a webcam não funcionar no Colab, use o modo simulado!"

Plano de Aula - Docente

Códigos BNCC: EM13CNT101, EM13CNT303 | RCP - Paraná: Matemática - Geometria, Programação - Bibliotecas

Materiais: Chromebooks com webcam, QR codes impressos, celulares para teste.


Dicas de mediação
  • Comece mostrando exemplos de visão computacional do dia a dia (filtros do Instagram, Snapchat, Google Lens).
  • Explique os pontos de referência da mão (landmarks) como "os 21 pontos que o robô aprendeu a vigiar".
  • Use QR codes impressos para teste - alunos adoram escanear com o celular.
  • Para alunos sem webcam, use o modo simulado com imagens estáticas.
  • Debata aplicações reais: leitura de QR code em cardápios, catracas de metrô, etc.
  • Organize um "Caça ao QR Code" pela escola usando o robô.
👩‍🏫🧑‍🏫

Kit do Professor

Simulador de QR Code - Robô Fofoqueiro

📱🤖 "GERA UM QR CODE AÍ, PIÁ!"
QR Code Gerado

Clique em "Gerar QR Code" para criar seu código!


Simulador de Detecção de Mãos

🤖 Clique no botão para simular a detecção de uma mão!

Privacidade: Os QR codes são gerados localmente usando a API pública do QR Server. Nenhum dado é armazenado permanentemente.