agrobot_base/Python/OAK/datasets/_12_check_percent_class.py

110 lines
3.5 KiB
Python
Raw Normal View History

2025-09-15 10:23:07 +00:00
#!/usr/bin/env python3
# -*- coding: utf-8 -*-
"""
Conta a porcentagem de pixels por CLASSE (segundo o labelmap) dentro da ROI,
para cada grupo em dataset/split/train/group.
- Usa utils.carregar_labelmap_completo(labelmap_path) para obter:
colormap_rgb, classes (id->nome) e ignore_rgb
- Ignora pixels com o valor de "ignore" do labelmap
- Normaliza a porcentagem SOMENTE sobre classes válidas (sem ignore)
Uso:
python _12_check_percent_class_labelmap.py
"""
import os, json
import numpy as np
from PIL import Image
from utils import carregar_labelmap_completo
# -------------- Config --------------
with open("config.json", "r", encoding="utf-8") as f:
config = json.load(f)
MODELO = config["camera"]
W, H = config["resolucao"][0], config["resolucao"][1]
ROI_INICIO = config["roi_inicio"]
ROI_TAMANHO = config["roi_tamanho"]
pasta_base = os.path.join(MODELO, "dataset")
labelmap_path = os.path.join(pasta_base, "labelmap.txt")
root = os.path.join(pasta_base, "split", "train", "group")
#root = os.path.join(pasta_base, "576x320", "group")
# Limite de amostras por grupo (para rodar rápido). Ajuste se quiser.
MAX_SAMPLES_PER_GROUP = 1000
# -------------- Utils --------------
def infer_ignore_id(ignore_rgb, default_id=255):
"""
Converte o 'ignore' do labelmap (que pode vir como [id] ou (R,G,B) ou int)
para um ID inteiro que devemos ignorar nas máscaras de IDs.
"""
# pode vir como lista/tupla com 1 elemento (id) ou 3 (cor)
if isinstance(ignore_rgb, (list, tuple)):
if len(ignore_rgb) == 1 and isinstance(ignore_rgb[0], (int, np.integer)):
return int(ignore_rgb[0])
if len(ignore_rgb) == 3:
return default_id
# pode vir como inteiro
if isinstance(ignore_rgb, (int, np.integer)):
return int(ignore_rgb)
return default_id
def roi_slice(h):
y_fim = int((1.0 - ROI_TAMANHO) * h)
y_ini = int(ROI_INICIO * h)
if y_ini <= y_fim:
y_fim, y_ini = max(0, h - int(ROI_TAMANHO * h)), h
return slice(y_fim, y_ini)
# -------------- Labelmap --------------
_, colormap_rgb, classes, ignore_rgb = carregar_labelmap_completo(labelmap_path)
ignore_id = infer_ignore_id(ignore_rgb, default_id=255)
# 'classes' esperado como dict: id -> nome
# Ordena por id para imprimir de forma estável
class_ids_sorted = sorted(classes.keys())
class_names_sorted = [classes[cid] for cid in class_ids_sorted]
# -------------- Coleta --------------
if not os.path.isdir(root):
raise SystemExit(f"Nenhum diretório encontrado em {root}")
grupos = [g for g in os.listdir(root) if os.path.isdir(os.path.join(root, g))]
for g in sorted(grupos):
mdir = os.path.join(root, g, "masks")
if not os.path.isdir(mdir):
continue
totals = {cid: 0 for cid in class_ids_sorted}
n = 0
for fname in os.listdir(mdir):
if not fname.lower().endswith(".png"):
continue
m = np.array(Image.open(os.path.join(mdir, fname)).convert("L"))
rs = roi_slice(m.shape[0])
roi = m[rs, :]
# Acumula só das classes válidas do labelmap (ignorando 'ignore' e outros valores)
for cid in class_ids_sorted:
totals[cid] += int((roi == cid).sum())
n += 1
if n >= MAX_SAMPLES_PER_GROUP:
break
s = sum(totals.values())
s = s if s > 0 else 1 # evita div/0
# Monta string dinâmica "nome=xx.xx%"
parts = []
for cid in class_ids_sorted:
name = classes[cid]
perc = totals[cid] / s
parts.append(f"{name}={perc:6.2%}")
print(f"{g:16s} " + " ".join(parts) + f" (amostras={n})")