Paradise151 commited on
Commit
79fb9b5
·
verified ·
1 Parent(s): 8bfd0e0

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +73 -24
app.py CHANGED
@@ -1,12 +1,21 @@
1
- from fastapi import FastAPI, Request
2
- from fastapi.responses import StreamingResponse, FileResponse
3
- import cv2
4
  from ultralytics import YOLO
5
  import torch
 
 
6
 
7
- # Сначала создаём приложение
8
  app = FastAPI()
9
 
 
 
 
 
 
 
 
 
10
  # Загружаем модель
11
  model = YOLO("best.pt")
12
  device = "cuda" if torch.cuda.is_available() else "cpu"
@@ -16,23 +25,63 @@ model.to(device)
16
  def root():
17
  return FileResponse("index.html")
18
 
19
- @app.get("/video_feed")
20
- def video_feed(request: Request):
21
- conf = float(request.query_params.get("conf", 0.25))
22
- iou = float(request.query_params.get("iou", 0.45))
23
- cam_id = int(request.query_params.get("camera", 0))
24
-
25
- cap = cv2.VideoCapture(cam_id)
26
-
27
- def gen_frames():
28
- while True:
29
- success, frame = cap.read()
30
- if not success:
31
- break
32
- results = model.track(frame, conf=conf, iou=iou, persist=True, tracker="botsort.yaml")
33
- annotated = results[0].plot()
34
- _, buffer = cv2.imencode(".jpg", annotated)
35
- yield (b"--frame\r\n"
36
- b"Content-Type: image/jpeg\r\n\r\n" + buffer.tobytes() + b"\r\n")
37
-
38
- return StreamingResponse(gen_frames(), media_type="multipart/x-mixed-replace; boundary=frame")
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ from fastapi import FastAPI, UploadFile, File, Form
2
+ from fastapi.responses import JSONResponse, Response, FileResponse
3
+ from fastapi.middleware.cors import CORSMiddleware
4
  from ultralytics import YOLO
5
  import torch
6
+ import cv2
7
+ import numpy as np
8
 
 
9
  app = FastAPI()
10
 
11
+ # Разрешаем вызовы из фронта того же Space
12
+ app.add_middleware(
13
+ CORSMiddleware,
14
+ allow_origins=["*"],
15
+ allow_methods=["*"],
16
+ allow_headers=["*"],
17
+ )
18
+
19
  # Загружаем модель
20
  model = YOLO("best.pt")
21
  device = "cuda" if torch.cuda.is_available() else "cpu"
 
25
  def root():
26
  return FileResponse("index.html")
27
 
28
+ def read_image_to_bgr(file_bytes: bytes) -> np.ndarray:
29
+ # Декод JPEG/PNG в BGR
30
+ img_array = np.frombuffer(file_bytes, dtype=np.uint8)
31
+ img = cv2.imdecode(img_array, cv2.IMREAD_COLOR) # BGR
32
+ return img
33
+
34
+ def annotate_bgr(results) -> np.ndarray:
35
+ # results[0].plot() возвращает BGR с нарисованными боксами
36
+ return results[0].plot()
37
+
38
+ def results_to_json(results):
39
+ # Конвертация результатов в чистые боксы/классы/скор
40
+ r = results[0]
41
+ boxes = r.boxes
42
+ out = []
43
+ if boxes is not None and len(boxes) > 0:
44
+ xyxy = boxes.xyxy.cpu().numpy() # (N,4)
45
+ conf = boxes.conf.cpu().numpy() # (N,)
46
+ cls = boxes.cls.cpu().numpy().astype(int) # (N,)
47
+ names = r.names
48
+ for i in range(len(xyxy)):
49
+ x1, y1, x2, y2 = xyxy[i].tolist()
50
+ out.append({
51
+ "bbox": [x1, y1, x2, y2],
52
+ "conf": float(conf[i]),
53
+ "class_id": int(cls[i]),
54
+ "class_name": names[int(cls[i])] if names else str(cls[i])
55
+ })
56
+ return {"detections": out}
57
+
58
+ @app.post("/predict")
59
+ async def predict(
60
+ file: UploadFile = File(...),
61
+ conf: float = Form(0.25),
62
+ iou: float = Form(0.45),
63
+ return_image: int = Form(1) # 1 = вернуть аннотированное изображение, 0 = вернуть JSON боксов
64
+ ):
65
+ data = await file.read()
66
+ bgr = read_image_to_bgr(data)
67
+ if bgr is None:
68
+ return JSONResponse({"error": "Invalid image"}, status_code=400)
69
+
70
+ # Инференс (без трекинга — кадры независимы; для трекинга можно persist и tracker)
71
+ results = model.predict(
72
+ source=bgr,
73
+ conf=conf,
74
+ iou=iou,
75
+ imgsz=640,
76
+ verbose=False
77
+ )
78
+
79
+ if return_image == 1:
80
+ annotated = annotate_bgr(results) # BGR
81
+ # Кодируем в JPEG для отправки
82
+ ok, buf = cv2.imencode(".jpg", annotated)
83
+ if not ok:
84
+ return JSONResponse({"error": "Encode failed"}, status_code=500)
85
+ return Response(content=buf.tobytes(), media_type="image/jpeg")
86
+ else:
87
+ return JSONResponse(results_to_json(results))