herdnet-app / inference /postprocessing.py
jaimevera1107's picture
Versión final lista para Hugging Face Space
d04393d
import os
import pandas as pd
from PIL import Image
from animaloc.vizual import draw_points, draw_text
from inference.utils_io import mkdir, save_csv
def draw_detections_on_image(
image_path: str,
detections_df: pd.DataFrame,
output_path: str = None
) -> Image.Image:
"""
Dibuja puntos visibles sobre una imagen y añade una leyenda
con el total de detecciones y el desglose por especie.
Parámetros
----------
image_path : str
Ruta de la imagen original.
detections_df : pd.DataFrame
DataFrame con las detecciones (columnas: x, y, species, scores, etc.).
output_path : str, opcional
Ruta donde se guardará la imagen anotada.
Retorna
-------
Image.Image
Imagen con los puntos y leyenda dibujados.
"""
img = Image.open(image_path)
img_cpy = img.copy()
# Extraer coordenadas (y, x)
pts = list(detections_df[["y", "x"]].to_records(index=False))
pts = [(y, x) for y, x in pts]
# Dibujar puntos sobre la imagen
output = draw_points(img_cpy, pts, color=(255, 0, 0), size=60)
# Construir texto de leyenda
species_counts = detections_df["species"].value_counts().to_dict()
total = sum(species_counts.values())
legend = f"Detecciones: {total} | " + ", ".join(
[f"{sp}: {n}" for sp, n in species_counts.items()]
)
# Posicionar texto en parte inferior
overlay_y = img_cpy.height - int(0.08 * img_cpy.height)
output = draw_text(
output,
text=legend,
position=(20, overlay_y),
font_size=int(0.04 * img_cpy.height),
)
# Guardar imagen si se especifica ruta de salida
if output_path:
mkdir(os.path.dirname(output_path))
output.save(output_path, quality=95)
return output
def compute_species_counts(detections_df: pd.DataFrame) -> dict:
"""
Calcula el número de detecciones por especie.
Retorna
-------
dict
Diccionario con las especies y sus conteos.
Retorna un diccionario vacío si no hay detecciones.
"""
if detections_df.empty:
return {}
return detections_df["species"].value_counts().to_dict()
def generate_thumbnails(
image_path: str,
detections_df: pd.DataFrame,
output_dir: str,
thumb_size: int = 256
) -> None:
"""
Genera miniaturas recortadas alrededor de cada detección,
con el nombre de la especie y su puntaje de confianza.
Parámetros
----------
image_path : str
Ruta de la imagen original.
detections_df : pd.DataFrame
DataFrame con las detecciones.
output_dir : str
Directorio donde se guardarán las miniaturas.
thumb_size : int
Tamaño (en píxeles) de cada miniatura cuadrada.
"""
mkdir(output_dir)
img = Image.open(image_path)
img_cpy = img.copy()
sp_score = list(detections_df[["species", "scores"]].to_records(index=False))
pts = list(detections_df[["y", "x"]].to_records(index=False))
for i, ((y, x), (sp, score)) in enumerate(zip(pts, sp_score)):
off = thumb_size // 2
coords = (x - off, y - off, x + off, y + off)
# Recortar miniatura
thumbnail = img_cpy.crop(coords)
# Dibujar texto con especie y score
score = round(score * 100, 1)
thumbnail = draw_text(
thumbnail,
f"{sp} | {score}%",
position=(10, 5),
font_size=int(0.08 * thumb_size),
)
filename = os.path.basename(image_path)[:-4] + f"_{i}.JPG"
thumbnail.save(os.path.join(output_dir, filename))
def save_detections(
detections_df: pd.DataFrame,
output_dir: str,
logger=None
) -> str:
"""
Guarda las detecciones en formato CSV dentro del directorio de salida.
Parámetros
----------
detections_df : pd.DataFrame
DataFrame con las detecciones.
output_dir : str
Directorio de salida.
logger : logging.Logger, opcional
Logger para registrar el proceso.
Retorna
-------
str
Ruta del archivo CSV guardado.
"""
mkdir(output_dir)
csv_path = os.path.join(output_dir, "detections.csv")
save_csv(detections_df, csv_path, logger)
return csv_path