Nos últimos tempos, comecei a experimentar soluções de automação que envolvem visão computacional aplicada ao controle de acesso.
Uma das áreas mais interessantes é o controle de estacionamento com leitura automática de placas (OCR).
E para validar alguns conceitos, eu decidi criar um protótipo completo, modular, organizado e pronto para evoluir para produção.
Neste artigo mostro como eu construí um app em Streamlit, com backend organizado em módulos, usando:
-
Python
-
Streamlit
-
PostgreSQL
-
SQLAlchemy
-
OpenCV
-
EasyOCR
-
PyTorch
-
Arquitetura modular escalável
Tecnologias utilizadas
| Tecnologia | Função |
|---|---|
| Python 3.10+ | Linguagem principal |
| Streamlit | Interface web |
| EasyOCR | Leitura da placa |
| OpenCV | Processamento da imagem |
| PyTorch | Dependência do EasyOCR |
| PostgreSQL | Banco relacional |
| SQLAlchemy | ORM |
| Pillow | Manipulação de imagens |
| Arquitetura modular | Manutenibilidade |
Instalação dos Pacotes (completa)
A seguir, deixo o passo a passo exato que utilizei para preparar o ambiente.
1. Criando o ambiente virtual (opcional, mas recomendado)
Ativar:
Windows:
Linux/Mac:
2. Instalando dependências principais
3. Instalando PyTorch (OBRIGATÓRIO para o EasyOCR funcionar)
Versão CPU (universal):
4. Criando um requirements.txt (opcional)
sqlalchemy
psycopg2-binary
easyocr
opencv-python
pillow
torch
torchvision
torchaudio
E instalo com:
Configuração do Banco PostgreSQL
Primeiro, criei o banco:
Depois, criei a tabela necessária:
id SERIAL PRIMARY KEY,
placa VARCHAR(20) NOT NULL,
horario_entrada TIMESTAMP NOT NULL DEFAULT NOW(),
horario_saida TIMESTAMP
);
Arquitetura do Projeto (Modular)
Organizei o projeto assim:
│
├── app.py # Interface Streamlit
│
├── modules/
│ ├── ocr.py # OCR da placa
│ ├── database.py # Conexão PostgreSQL
│ ├── models.py # Modelos ORM
│ ├── repositories.py # Acesso ao banco
│ └── services.py # Regras de negócio
│
└── README.md
Separar assim deixa tudo claro, limpo e escalável.
Módulos do Projeto
Agora mostro cada módulo com explicações.
modules/database.py — Conexão com Banco
from sqlalchemy.orm import sessionmaker, declarative_base
SessionLocal = sessionmaker(bind=engine, autocommit=False, autoflush=False)
Base = declarative_base()
db = SessionLocal()
try:
yield db
finally:
db.close()
modules/models.py — Modelos SQLAlchemy
from sqlalchemy.sql import func
from modules.database import Base
__tablename__ = "estacionamento"
placa = Column(String(20), nullable=False)
horario_entrada = Column(TIMESTAMP, server_default=func.now())
horario_saida = Column(TIMESTAMP, nullable=True)
modules/repositories.py — CRUD Completo
from sqlalchemy.orm import Session
from sqlalchemy import select, func
from modules.models import Movimentacao
def registrar_entrada(db: Session, placa: str):
mov = Movimentacao(placa=placa)
db.add(mov)
db.commit()
def registrar_saida(db: Session, placa: str):
stmt = (
select(Movimentacao)
.where(Movimentacao.placa == placa)
.where(Movimentacao.horario_saida.is_(None))
)
registro = db.execute(stmt).scalar_one_or_none()
registro.horario_saida = func.now()
db.commit()
def listar(db: Session):
stmt = select(Movimentacao).order_by(Movimentacao.id.desc())
return db.execute(stmt).scalars().all()
modules/ocr.py — Leitura da Placa
import easyocr
import cv2
import numpy as np
from PIL import Image
np_img = np.array(imagem)
np_img = cv2.cvtColor(np_img, cv2.COLOR_RGB2BGR)
textos = [r[1] for r in resultados]
return "NÃO IDENTIFICADA"
return placa.upper()
modules/services.py — Regras de Negócio
from sqlalchemy.orm import Session
from modules.repositories import EstacionamentoRepository
from modules.ocr import ler_placa
def registrar_entrada(db: Session, imagem):
placa = ler_placa(imagem)
EstacionamentoRepository.registrar_entrada(db, placa)
return placa
def registrar_saida(db: Session, imagem):
placa = ler_placa(imagem)
EstacionamentoRepository.registrar_saida(db, placa)
return placa
def listar_movs(db: Session):
return EstacionamentoRepository.listar(db)
app.py — Interface Streamlit Completa
import streamlit as st
from PIL import Image
from modules.database import SessionLocal
from modules.services import EstacionamentoService
st.write("Sistema modular utilizando Python, Streamlit, OCR e PostgreSQL")
img = Image.open(uploaded)
st.image(img, caption="Imagem enviada", width=350)
if acao == "Registrar entrada":
placa = EstacionamentoService.registrar_entrada(db, img)
st.success(f"Entrada registrada: {placa}")
else:
placa = EstacionamentoService.registrar_saida(db, img)
st.success(f"Saída registrada: {placa}")
st.write(
f"ID: {m.id} | Placa: {m.placa} | "
f"Entrada: {m.horario_entrada} | Saída: {m.horario_saida}"
)
Executando o sistema
Com tudo instalado e configurado:
streamlit run app.py
E pronto: sua aplicação de controle de estacionamento está funcionando.
Possíveis evoluções futuras
Como o sistema está modularizado, posso expandi-lo facilmente:
-
Reconhecimento de carro antes do OCR usando YOLOv8
-
Integração com câmera IP para captura automática
-
Painel administrativo completo
-
Cadastro de mensalistas
-
Integração com cancelas e totens
-
API REST consumida por mobile ou desktop
Criar um sistema profissional começa por uma boa arquitetura. Ao dividir o projeto em módulos (OCR, banco, repositórios, serviços e interface), o código fica limpo, reaproveitável e pronto para crescer.
Esse tutorial cobre:
• Instalação dos pacotes
• Setup do PostgreSQL
• Arquitetura modular
• Código organizado por camadas
• App Streamlit final funcionando