apilsp / main.py
Alex Vega
init
6c3f7aa
raw
history blame
2.92 kB
import pickle
import numpy as np
import io
import math
from fastapi import FastAPI, File, UploadFile, HTTPException
from PIL import Image
app = FastAPI(
title="Peruvian Sign Language (LSP) Recognition API",
description="Sube una imagen de una seña del alfabeto de la LSP para predecir la letra correspondiente usando un Mapa Autoorganizado (SOM).",
version="1.0.0"
)
try:
with open('lsp_som_model.pkl', 'rb') as f:
model_data = pickle.load(f)
som = model_data['som']
label_map = model_data['label_map']
CLASSES = model_data['classes'] # La lista ['A', 'B', 'C', ...]
IMG_SIZE = model_data['img_size'] # El tamaño de la imagen
print("✅ Modelo y activos cargados exitosamente.")
print(f" - Clases reconocidas: {CLASSES}")
print(f" - Tamaño de imagen esperado: {IMG_SIZE}x{IMG_SIZE}")
except FileNotFoundError:
print("❌ ERROR: No se encontró el archivo del modelo 'lsp_som_model.pkl'.")
som = None
def preprocess_image_from_bytes(image_bytes: bytes):
try:
img = Image.open(io.BytesIO(image_bytes)).convert('L') # 'L' para escala de grises
img = img.resize((IMG_SIZE, IMG_SIZE))
img_array = np.array(img)
img_normalized = img_array / 255.0
return img_normalized.flatten()
except Exception as e:
raise HTTPException(status_code=400, detail=f"Archivo de imagen inválido. Error: {e}")
@app.get("/", tags=["Status"])
def read_root():
return {"status": "ok", "message": "API de Reconocimiento de LSP!!"}
@app.post("/predict", tags=["Prediction"])
async def predict_sign(file: UploadFile = File(..., description="Un archivo de imagen de una seña de la LSP.")):
if not som:
raise HTTPException(status_code=503, detail="El modelo no está cargado.")
image_bytes = await file.read()
feature_vector = preprocess_image_from_bytes(image_bytes)
winner_neuron = som.winner(feature_vector)
predicted_index = label_map.get(winner_neuron, -1)
# Vecino mas cercano para prediccion
is_best_guess = False
if predicted_index == -1:
is_best_guess = True
min_dist = float('inf')
for mapped_pos, mapped_label in label_map.items():
dist = math.sqrt((winner_neuron[0] - mapped_pos[0])**2 + (winner_neuron[1] - mapped_pos[1])**2)
if dist < min_dist:
min_dist = dist
predicted_index = mapped_label
if predicted_index != -1:
predicted_letter = CLASSES[predicted_index]
prediction_type = "Nearest Neighbor" if is_best_guess else "Direct Match"
else:
predicted_letter = "Unknown"
prediction_type = "Error (No Mapped Neurons Found)"
return {
"filename": file.filename,
"predicted_letter": predicted_letter,
"prediction_type": prediction_type,
"winner_neuron_on_map": [int(coord) for coord in winner_neuron]
}