Projeto de Visão Computacional para detectar, localizar, segmentar e contar peixes em imagens subaquáticas. O repositório mantém dois caminhos de experimento: um pipeline clássico, baseado em OpenCV/NumPy/SciPy, e um pipeline com U-Net para segmentação semântica.
Os dados de entrada e os resultados gerados ficam fora das pastas de código. As
pastas de dados locais são ignoradas pelo Git; portanto, os comandos abaixo
devem receber a pasta de entrada por DATA_DIR quando você quiser usar um
dataset específico.
.
├── documentation/ # relatório e apresentações do projeto
├── pipeline-classic/ # pipeline clássico, sem deep learning
├── pipeline-UNet/ # pipeline de segmentação e tracking com U-Net
├── scripts/ # preparação dos datasets e divisão por vídeo
├── data-localization/ # DeepFish Localization (não versionado)
├── data-segmentation/ # DeepFish Segmentation (não versionado)
├── data-results/ # resultados gerados (não versionados)
│ ├── classic/
│ └── unet/
├── best_model.pt # checkpoint do melhor modelo treinado da U-Net (obtido via make download-model; não versionado)
├── Makefile # atalhos principais de execução
├── requirements.txt # dependências compartilhadas
└── README.md
Os documentos finais estão disponíveis em:
As pastas data-localization/, data-segmentation/ e data-results/ são
locais e ignoradas pelo Git.
- Baixe o dataset DeepFish no Queensland Government Open Data Portal. A página oficial do projeto também mantém o link e a descrição do dataset.
- Extraia as tarefas
LocalizationeSegmentationna raiz deste repositório, usando estes nomes:
data-localization/ # conteúdo da pasta Localization do DeepFish
data-segmentation/ # conteúdo da pasta Segmentation do DeepFish
- Reconstrua os splits antes de executar os pipelines:
make split-datasetsEsse passo é necessário porque os splits originais podem colocar frames do
mesmo vídeo em subconjuntos diferentes. O script scripts/split_by_video.py
reorganiza imagens, máscaras e CSVs em train, valid e test, garantindo
que cada vídeo pertença a apenas um split. Isso evita vazamento temporal entre
treino, validação e teste e preserva as sequências exigidas pelo tracking.
Também é possível preparar apenas uma tarefa:
make split-localization
make split-segmentationOs alvos split-* reconstroem o dataset no próprio diretório e guardam a
organização anterior em <dataset>.before-video-split. Novas execuções criam
backups numerados (-2, -3, etc.), que podem ocupar bastante espaço.
Depois da preparação, a estrutura esperada é:
<dataset>/
├── train/
│ ├── train.csv
│ ├── images/{valid,empty}
│ └── masks/{valid,empty}
├── valid/
│ ├── val.csv
│ ├── images/{valid,empty}
│ └── masks/{valid,empty}
└── test/
├── test.csv
├── images/{valid,empty}
└── masks/{valid,empty}
Os CSVs devem conter ao menos o identificador da imagem e a coluna counts, com
a quantidade de peixes observados. Para métricas espaciais, as máscaras podem
representar pontos de localização ou máscaras reais de segmentação; cada
pipeline interpreta isso conforme descrito em seu README interno.
Os splits devem manter todos os frames de um mesmo vídeo no mesmo subconjunto,
evitando vazamento entre treino, validação e teste. O identificador de vídeo é
derivado do prefixo do arquivo antes do primeiro _.
- (Opcional, mas recomendado) Baixe o checkpoint do melhor modelo treinado da U-Net:
make download-modelEsse comando faz o download do arquivo best_model.pt para a raiz do projeto.
Ele corresponde ao melhor modelo treinado utilizado nos experimentos deste
trabalho e permite executar todo o pipeline U-Net sem necessidade de realizar o
treinamento novamente.
Depois de baixar e preparar os datasets, rode pela raiz:
# Pipeline clássico completo sobre Localization
make classic-run DATA_DIR=data-localization NUM_WORKERS=0
# Pipeline U-Net completo sobre Segmentation
make unet-all DATA_DIR=data-segmentation NUM_WORKERS=0
# Baixar o checkpoint do melhor modelo treinado (apenas uma vez)
make download-model
# Pipeline U-Net completo usando o checkpoint baixado
make unet-all-existing-model DATA_DIR=data-segmentation NUM_WORKERS=0Por padrão, todos os alvos de avaliação, segmentação, tracking e execução com
modelo existente utilizam o arquivo best_model.pt localizado na raiz do
projeto. Caso deseje utilizar outro checkpoint, basta informar:
make unet-all-existing-model \
DATA_DIR=data-segmentation \
MODEL=/caminho/para/outro_model.pt
`NUM_WORKERS=0` usa todos os núcleos lógicos disponíveis. Os alvos criam a
venv compartilhada e instalam as dependências quando necessário. Use `make` ou
`make help` para consultar todas as opções.
Os resultados são salvos automaticamente fora das pastas de código:
```text
data-results/classic/<nome-do-dataset>/
data-results/unet/<nome-do-dataset>/| Alvo | O que faz |
|---|---|
help |
Mostra os alvos principais e exemplos de variáveis. |
split-segmentation |
Reconstrói o dataset de segmentação por vídeo, mantendo imagens, máscaras e CSVs sincronizados. |
split-localization |
Reconstrói o dataset de localização por vídeo, preservando sequências para o clássico. |
split-datasets |
Executa split-segmentation e split-localization. |
download-model |
Baixa para a raiz do projeto o checkpoint (best_model.pt) correspondente ao melhor modelo treinado da U-Net. |
classic-run |
Instala dependências se necessário, executa o pipeline clássico e salva métricas ao final. |
classic-metrics |
Recalcula as métricas do clássico usando resultados já gerados. |
classic-clean |
Remove os resultados clássicos associados ao DATA_DIR. |
classic-paths |
Mostra os caminhos resolvidos para o clássico. |
classic-install |
Cria/atualiza a venv e instala dependências sem executar o pipeline. |
unet-sanity |
Executa somente a checagem de dados e augmentations. |
unet-train |
Executa somente o treinamento da U-Net. |
unet-evaluate |
Avalia o best_model.pt no split de teste. |
unet-segment |
Calibra threshold em validação e gera instâncias/contagens U-Net por frame. |
unet-track |
Associa instâncias U-Net no tempo e consolida contagens por frame/vídeo. |
unet-compare |
Compara U-Net e clássico quando existirem frames equivalentes. |
unet-all |
Executa sanity, treinamento, avaliação, segmentação e tracking. |
unet-all-existing-model |
Executa tudo exceto treinamento, incluindo tracking. |
unet-run |
Alias de unet-all. |
unet-clean |
Remove os resultados U-Net associados ao DATA_DIR. |
unet-paths |
Mostra os caminhos resolvidos para a U-Net. |
unet-install |
Cria/atualiza a venv e instala dependências sem executar o pipeline. |
Comandos úteis:
make help
make download-model
make split-segmentation
make split-localization
make classic-metrics DATA_DIR=CAMINHO_DO_DATASET
make classic-paths DATA_DIR=CAMINHO_DO_DATASET
make unet-paths DATA_DIR=CAMINHO_DO_DATASET
make unet-segment DATA_DIR=CAMINHO_DO_DATASET
make unet-track DATA_DIR=CAMINHO_DO_DATASET
make unet-compare DATA_DIR=CAMINHO_DO_DATASET
make unet-all-existing-model DATA_DIR=CAMINHO_DO_DATASET
make classic-clean DATA_DIR=CAMINHO_DO_DATASET
make unet-clean DATA_DIR=CAMINHO_DO_DATASETDetalhes das etapas, parâmetros e arquivos gerados ficam em:
Resultados obtidos sobre a pasta Localization do dataset
DeepFish, usando contagem por imagem e
localização por ponto. Os splits foram reconstruídos por vídeo/habitat, sem
compartilhar frames do mesmo vídeo entre treino, validação e teste. A Etapa 3
corresponde aos candidatos rotulados por componentes/contornos; a Etapa 4
corresponde aos resultados após consolidação temporal.
| Split | Etapa | N | MAE | RMSE | F1 contagem | Exato | Pontos pareados | Dist. média | Dist. mediana | Hit@25 | Hit@50 | Hit@100 | Frame recall |
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| train | 3 | 2236 | 0.979 | 1.906 | 0.394 | 55.8% | 1741/2890 | 265.990 px | 155.301 px | 8.5% | 16.1% | 24.3% | 42.7% |
| train | 4 | 2236 | 0.932 | 1.833 | 0.440 | 56.9% | 1822/2890 | 239.660 px | 137.305 px | 8.9% | 17.3% | 26.7% | 45.6% |
| valid | 3 | 488 | 0.486 | 0.785 | 0.394 | 57.2% | 99/302 | 256.238 px | 125.620 px | 7.0% | 11.3% | 14.6% | 25.9% |
| valid | 4 | 488 | 0.473 | 0.778 | 0.418 | 58.4% | 102/302 | 242.415 px | 113.438 px | 7.9% | 12.9% | 15.9% | 27.2% |
| test | 3 | 476 | 1.071 | 2.004 | 0.419 | 58.2% | 448/689 | 327.052 px | 156.925 px | 9.6% | 20.8% | 28.2% | 52.3% |
| test | 4 | 476 | 1.013 | 1.881 | 0.470 | 58.0% | 500/689 | 305.109 px | 149.373 px | 10.0% | 22.6% | 31.6% | 57.7% |
A consolidação temporal da Etapa 4 melhora de forma consistente o pipeline:
reduz MAE e RMSE nos três splits e aumenta o F1 de contagem em treino,
validação e teste. A localização também melhora, com mais pontos pareados,
menores distâncias médias/medianas e aumento de hit@100, especialmente no
teste. Ainda assim, os acertos espaciais em raios curtos continuam limitados,
indicando que o clássico captura bem parte do sinal temporal, mas tem
dificuldade em posicionar detecções com precisão em cenários subaquáticos
complexos.
Resultados obtidos sobre a pasta Segmentation do dataset DeepFish, com os
splits reconstruídos por vídeo/habitat. O treinamento executou 32 épocas, e o
melhor checkpoint foi selecionado pelo Dice de validação, atingindo Dice
0.908 e IoU 0.832 na época 22. A tabela abaixo usa o threshold 0.15,
selecionado automaticamente no split de validação.
| Split | Dice | IoU | Precision | Recall | MAE contagem | RMSE contagem | Acurácia exata |
|---|---|---|---|---|---|---|---|
| valid | 0.910 | 0.835 | 0.941 | 0.881 | 0.239 | 0.511 | 77.2% |
| test | 0.688 | 0.524 | 0.871 | 0.569 | 0.256 | 0.548 | 76.7% |
Após a segmentação por frame, a consolidação temporal reduziu o erro de
contagem: no teste, o MAE caiu de 0.256 para 0.244, e o RMSE caiu de
0.548 para 0.494. A acurácia exata temporal no teste ficou em 75.6%.
Os resultados indicam boa capacidade de contagem e baixa ocorrência de falsos
positivos em frames vazios, mas também mostram queda relevante entre validação e
teste nas métricas de pixel. Isso sugere que a U-Net aprendeu bem o conjunto de
validação, porém ainda tem dificuldade de generalizar a segmentação para vídeos
visualmente distintos no split de teste.