File size: 1,726 Bytes
f698f1c | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 | from fastapi import FastAPI, File, UploadFile
from fastapi.responses import JSONResponse
import numpy as np
import cv2
import base64
from sentinelscan.modeling.infer import CrackModel
from sentinelscan.utils.viz import overlay_mask
from sentinelscan.utils.severity import crack_metrics, severity_from_metrics
app = FastAPI(title="SentinelScan API", version="0.1.0")
model = CrackModel(ckpt_path="models/best.pt", size=512)
def _read_image(file_bytes: bytes):
arr = np.frombuffer(file_bytes, np.uint8)
bgr = cv2.imdecode(arr, cv2.IMREAD_COLOR)
if bgr is None:
raise ValueError("Could not decode image")
rgb = cv2.cvtColor(bgr, cv2.COLOR_BGR2RGB)
return rgb
def _to_base64_png(rgb: np.ndarray):
bgr = cv2.cvtColor(rgb, cv2.COLOR_RGB2BGR)
ok, buf = cv2.imencode(".png", bgr)
if not ok:
raise ValueError("Could not encode image")
return base64.b64encode(buf.tobytes()).decode("utf-8")
@app.post("/predict")
async def predict(file: UploadFile = File(...)):
try:
rgb = _read_image(await file.read())
pred = model.predict(rgb, threshold=0.5)
m = crack_metrics(pred["mask"])
sev = severity_from_metrics(m)
crack_detected = m["area_px"] > 50 # tiny specks ignored
overlay = overlay_mask(rgb, pred["mask"])
overlay_b64 = _to_base64_png(overlay)
return JSONResponse({
"crack_detected": bool(crack_detected),
"confidence": float(pred["confidence"]),
"severity": sev if crack_detected else "None",
"metrics": m,
"overlay_png_base64": overlay_b64,
})
except Exception as e:
return JSONResponse({"error": str(e)}, status_code=400) |