Damanger commited on
Commit
f16d0cc
·
1 Parent(s): 5d99b0b

corrigiendo app

Browse files
Files changed (2) hide show
  1. app.py +35 -16
  2. requirements.txt +2 -0
app.py CHANGED
@@ -3,11 +3,14 @@ from typing import Optional, List
3
  import numpy as np, cv2, torch
4
  from ultralytics import YOLO
5
  import easyocr
 
 
6
 
7
  from fastapi import FastAPI, HTTPException, File, UploadFile, Form
8
  from fastapi.middleware.cors import CORSMiddleware
9
  from pydantic import BaseModel, Field
10
 
 
11
  TMP_DIR = "/tmp"
12
  paths = [
13
  f"{TMP_DIR}/Ultralytics",
@@ -119,25 +122,42 @@ def bgr_to_jpeg_base64(bgr):
119
  return None
120
  return base64.b64encode(buf.tobytes()).decode("ascii")
121
 
122
- def load_image_from_url(url: str):
123
- ssl._create_default_https_context = ssl._create_unverified_context
124
- data = urllib.request.urlopen(url).read()
 
 
 
 
 
 
 
 
 
125
  arr = np.frombuffer(data, np.uint8)
126
  bgr = cv2.imdecode(arr, cv2.IMREAD_COLOR)
127
- if bgr is None:
128
- raise ValueError("No pude decodificar la imagen desde URL.")
129
- return bgr
 
 
 
 
 
130
 
131
- def load_image_from_b64(b64_or_data_url: str):
 
 
 
 
 
 
 
132
  s = b64_or_data_url
133
  if s.startswith("data:"):
134
  s = s.split(",", 1)[1]
135
  raw = base64.b64decode(s)
136
- arr = np.frombuffer(raw, np.uint8)
137
- bgr = cv2.imdecode(arr, cv2.IMREAD_COLOR)
138
- if bgr is None:
139
- raise ValueError("No pude decodificar la imagen desde base64.")
140
- return bgr
141
 
142
  # --- FastAPI ---
143
  app = FastAPI(title="Plates API (HF Space)")
@@ -192,6 +212,7 @@ def detect(req: DetectRequest):
192
  try:
193
  if not req.image_url and not req.image_b64:
194
  raise HTTPException(400, "Proporciona 'image_url' o 'image_b64'.")
 
195
  bgr = load_image_from_url(req.image_url) if req.image_url else load_image_from_b64(req.image_b64)
196
  vis, dets, (w, h), dt_ms = run_on_image_bgr(
197
  bgr, conf=req.conf, iou=req.iou, with_ocr=req.ocr, annotate=req.return_image
@@ -219,10 +240,9 @@ async def detect_upload(
219
  if not data:
220
  raise HTTPException(400, "Archivo vacío.")
221
 
222
- arr = np.frombuffer(data, np.uint8)
223
- bgr = cv2.imdecode(arr, cv2.IMREAD_COLOR)
224
  if bgr is None:
225
- # mejor devolver 415 que 500 si no se puede decodificar (HEIC, dañada, etc.)
226
  raise HTTPException(415, f"Formato no soportado: {image.content_type or image.filename}")
227
 
228
  vis, dets, (w, h), dt_ms = run_on_image_bgr(
@@ -236,7 +256,6 @@ async def detect_upload(
236
  except HTTPException:
237
  raise
238
  except Exception as e:
239
- # esto hará que tu front vea el mensaje real en data.detail
240
  raise HTTPException(500, f"Error procesando la imagen: {e}")
241
 
242
  @app.on_event("startup")
 
3
  import numpy as np, cv2, torch
4
  from ultralytics import YOLO
5
  import easyocr
6
+ from PIL import Image
7
+ import pillow_heif
8
 
9
  from fastapi import FastAPI, HTTPException, File, UploadFile, Form
10
  from fastapi.middleware.cors import CORSMiddleware
11
  from pydantic import BaseModel, Field
12
 
13
+
14
  TMP_DIR = "/tmp"
15
  paths = [
16
  f"{TMP_DIR}/Ultralytics",
 
122
  return None
123
  return base64.b64encode(buf.tobytes()).decode("ascii")
124
 
125
+ def pil_to_bgr(pil_img: Image.Image) -> np.ndarray:
126
+ if pil_img.mode not in ("RGB", "RGBA"):
127
+ pil_img = pil_img.convert("RGB")
128
+ arr = np.array(pil_img)
129
+ if arr.ndim == 2:
130
+ arr = np.stack([arr]*3, axis=-1)
131
+ if arr.shape[2] == 4:
132
+ arr = arr[:, :, :3]
133
+ return cv2.cvtColor(arr, cv2.COLOR_RGB2BGR)
134
+
135
+ def decode_bytes_to_bgr(data: bytes, content_type: str = "") -> np.ndarray:
136
+ # 1) OpenCV rápido
137
  arr = np.frombuffer(data, np.uint8)
138
  bgr = cv2.imdecode(arr, cv2.IMREAD_COLOR)
139
+ if bgr is not None:
140
+ return bgr
141
+ # 2) Fallback PIL (con HEIC soportado por pillow-heif)
142
+ try:
143
+ with Image.open(io.BytesIO(data)) as im:
144
+ return pil_to_bgr(im)
145
+ except Exception as e:
146
+ raise ValueError(f"No pude decodificar la imagen ({content_type}): {e}")
147
 
148
+ def load_image_from_url(url: str) -> np.ndarray:
149
+ ssl._create_default_https_context = ssl._create_unverified_context
150
+ req = urllib.request.Request(url, headers={"User-Agent": "Mozilla/5.0"})
151
+ with urllib.request.urlopen(req, timeout=20) as r:
152
+ data = r.read()
153
+ return decode_bytes_to_bgr(data, content_type=r.headers.get("Content-Type",""))
154
+
155
+ def load_image_from_b64(b64_or_data_url: str) -> np.ndarray:
156
  s = b64_or_data_url
157
  if s.startswith("data:"):
158
  s = s.split(",", 1)[1]
159
  raw = base64.b64decode(s)
160
+ return decode_bytes_to_bgr(raw, content_type="base64")
 
 
 
 
161
 
162
  # --- FastAPI ---
163
  app = FastAPI(title="Plates API (HF Space)")
 
212
  try:
213
  if not req.image_url and not req.image_b64:
214
  raise HTTPException(400, "Proporciona 'image_url' o 'image_b64'.")
215
+
216
  bgr = load_image_from_url(req.image_url) if req.image_url else load_image_from_b64(req.image_b64)
217
  vis, dets, (w, h), dt_ms = run_on_image_bgr(
218
  bgr, conf=req.conf, iou=req.iou, with_ocr=req.ocr, annotate=req.return_image
 
240
  if not data:
241
  raise HTTPException(400, "Archivo vacío.")
242
 
243
+ bgr = decode_bytes_to_bgr(data, content_type=image.content_type or image.filename)
 
244
  if bgr is None:
245
+ # si llega aquí es que ni cv2 ni PIL pudieron
246
  raise HTTPException(415, f"Formato no soportado: {image.content_type or image.filename}")
247
 
248
  vis, dets, (w, h), dt_ms = run_on_image_bgr(
 
256
  except HTTPException:
257
  raise
258
  except Exception as e:
 
259
  raise HTTPException(500, f"Error procesando la imagen: {e}")
260
 
261
  @app.on_event("startup")
requirements.txt CHANGED
@@ -8,3 +8,5 @@ easyocr
8
  opencv-python==4.10.0.84
9
  huggingface_hub
10
  torch
 
 
 
8
  opencv-python==4.10.0.84
9
  huggingface_hub
10
  torch
11
+ pillow
12
+ pillow-heif