marrtinagg's picture
add gradio interface with preprocessing and model prediction
4b80d99
import cv2
import numpy as np
import math
def _leer_mask(mask):
"""Lee una máscara que puede venir como ruta o como array."""
if isinstance(mask, str): # si es ruta
mask = cv2.imread(mask, cv2.IMREAD_GRAYSCALE)
elif mask.ndim == 3: # si es RGB/BGR
mask = cv2.cvtColor(mask, cv2.COLOR_BGR2GRAY)
if mask is None:
raise ValueError("No se pudo leer la máscara.")
return mask
def calcular_area(mask):
mask = _leer_mask(mask)
_, mask_bin = cv2.threshold(mask, 127, 255, cv2.THRESH_BINARY)
contours, _ = cv2.findContours(mask_bin, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE)
if not contours:
return 0.0
cnt = max(contours, key=cv2.contourArea)
area = cv2.contourArea(cnt)
if not np.isfinite(area):
area = 0.0
return round(float(area), 2)
def calcular_perimetro(mask):
mask = _leer_mask(mask)
_, mask_bin = cv2.threshold(mask, 127, 255, cv2.THRESH_BINARY)
contours, _ = cv2.findContours(mask_bin, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE)
if not contours:
return 0.0
cnt = max(contours, key=cv2.contourArea)
perimetro = cv2.arcLength(cnt, True)
if not np.isfinite(perimetro):
perimetro = 0.0
return round(float(perimetro), 2)
def calcular_circularidad(mask):
mask = _leer_mask(mask)
_, mask_bin = cv2.threshold(mask, 127, 255, cv2.THRESH_BINARY)
contours, _ = cv2.findContours(mask_bin, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE)
if not contours:
return 0.0
cnt = max(contours, key=cv2.contourArea)
area = cv2.contourArea(cnt)
perimetro = cv2.arcLength(cnt, True)
if perimetro == 0 or area == 0:
return 0.0
circ = (4 * math.pi * area) / (perimetro ** 2)
if not np.isfinite(circ):
circ = 0.0
circ = np.clip(circ, 0, 1)
return round(float(circ), 4)
def calcular_simetria(mask):
mask = _leer_mask(mask)
_, mask_bin = cv2.threshold(mask, 127, 1, cv2.THRESH_BINARY)
if np.sum(mask_bin) == 0:
return 0.0, 0.0
y, x = np.where(mask_bin > 0)
y_min, y_max = y.min(), y.max()
x_min, x_max = x.min(), x.max()
roi = mask_bin[y_min:y_max+1, x_min:x_max+1]
h, w = roi.shape
size = max(h, w)
canvas = np.zeros((size, size), dtype=np.uint8)
y_off, x_off = (size - h)//2, (size - w)//2
canvas[y_off:y_off+h, x_off:x_off+w] = roi
mask_centered = canvas
cy, cx = np.mean(np.column_stack(np.where(mask_centered > 0)), axis=0).astype(int)
area_total = np.sum(mask_centered)
if area_total == 0:
return 0.0, 0.0
# --- simetría vertical ---
left = mask_centered[:, :cx]
right = mask_centered[:, cx:]
right_flipped = np.fliplr(right)
min_width = min(left.shape[1], right_flipped.shape[1])
xor_v = np.logical_xor(left[:, :min_width], right_flipped[:, :min_width])
sim_v = 1 - (np.sum(xor_v) / area_total)
# --- simetría horizontal ---
top = mask_centered[:cy, :]
bottom = mask_centered[cy:, :]
bottom_flipped = np.flipud(bottom)
min_height = min(top.shape[0], bottom_flipped.shape[0])
xor_h = np.logical_xor(top[:min_height, :], bottom_flipped[:min_height, :])
sim_h = 1 - (np.sum(xor_h) / area_total)
sim_v = max(0.0, min(1.0, sim_v))
sim_h = max(0.0, min(1.0, sim_h))
return round(sim_v, 3), round(sim_h, 3)