CoolFace
Apppublic

newtechdevng/construction-detection-api

sourceHugging Faceupdated 5mo agoView on Hugging Face
0likes
app.py145 linesDownload Raw Back to root
1from fastapi import FastAPI, File, UploadFile, Form2from fastapi.middleware.cors import CORSMiddleware3from huggingface_hub import hf_hub_download4from ultralytics import YOLO5import cv26import numpy as np7import base648import time9import os10 11app = FastAPI(title="Construction Detection API")12 13app.add_middleware(14    CORSMiddleware,15    allow_origins=["*"],16    allow_methods=["*"],17    allow_headers=["*"],18)19 20# Load YOLO model21HF_REPO_ID = "newtechdevng/construction_detection_fine_tune"22MODEL_FILE  = "best_v2_finetune.pt"23model_path  = hf_hub_download(repo_id=HF_REPO_ID, filename=MODEL_FILE)24model       = YOLO(model_path)25 26# ArUco setup27ARUCO_DICT     = cv2.aruco.getPredefinedDictionary(cv2.aruco.DICT_4X4_50)28ARUCO_PARAMS   = cv2.aruco.DetectorParameters()29ARUCO_DETECTOR = cv2.aruco.ArucoDetector(ARUCO_DICT, ARUCO_PARAMS)30 31CLASS_COLORS = {32    "beam":    (255, 100,   0),33    "column":  (  0, 255, 255),34    "door":    (255,   0, 255),35    "floor":   (  0, 255,   0),36    "stairs":  (255, 255,   0),37    "wall":    (  0, 100, 255),38    "window":  (100,   0, 255),39}40 41def detect_aruco_scale(img, marker_size_cm=10.0):42    gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)43    corners, ids, _ = ARUCO_DETECTOR.detectMarkers(gray)44    if ids is None:45        return None, None46    marker_corners = corners[0][0]47    w_px = np.linalg.norm(marker_corners[0] - marker_corners[1])48    h_px = np.linalg.norm(marker_corners[1] - marker_corners[2])49    pixels_per_cm = (w_px + h_px) / 2 / marker_size_cm50    return float(pixels_per_cm), corners51 52@app.get("/")53def root():54    return {55        "model": MODEL_FILE,56        "classes": list(CLASS_COLORS.keys()),57        "calibration": "Auto via ArUco marker on hard hat (10cm x 10cm)",58        "endpoints": {59            "POST /detect": "Send image → get detections in cm",60            "GET  /health": "Health check"61        }62    }63 64@app.get("/health")65def health():66    return {"status": "ok", "model": MODEL_FILE}67 68@app.post("/detect")69async def detect(70    file: UploadFile = File(...),71    marker_size_cm: float = Form(10.0),72    confidence: float = Form(0.2),73    iou: float = Form(0.3)74):75    start = time.time()76 77    contents = await file.read()78    nparr    = np.frombuffer(contents, np.uint8)79    img      = cv2.imdecode(nparr, cv2.IMREAD_COLOR)80 81    # ArUco auto-calibration82    pixels_per_cm, aruco_corners = detect_aruco_scale(img, marker_size_cm)83    calibrated = pixels_per_cm is not None84 85    # Draw ArUco marker highlight86    if calibrated:87        cv2.aruco.drawDetectedMarkers(img, aruco_corners)88 89    # Run YOLO with lower confidence + iou for more detections90    results    = model(img, conf=confidence, iou=iou)[0]91    detections = []92 93    for box in results.boxes:94        x1, y1, x2, y2 = map(int, box.xyxy[0])95        cls   = results.names[int(box.cls[0])]96        conf  = round(float(box.conf[0]), 2)97        w_px  = x2 - x198        h_px  = y2 - y199        color = CLASS_COLORS.get(cls, (0, 255, 0))100 101        w_cm = round(float(w_px) / pixels_per_cm, 1) if calibrated else None102        h_cm = round(float(h_px) / pixels_per_cm, 1) if calibrated else None103 104        # Draw bounding box105        cv2.rectangle(img, (x1, y1), (x2, y2), color, 2)106 107        # Label108        label = f"{cls} {conf:.2f}"109        if calibrated:110            label += f" | {w_cm}x{h_cm}cm"111 112        # Background for label text113        (tw, th), _ = cv2.getTextSize(label, cv2.FONT_HERSHEY_SIMPLEX, 0.55, 2)114        cv2.rectangle(img, (x1, y1 - th - 10), (x1 + tw, y1), color, -1)115        cv2.putText(img, label, (x1, y1 - 5),116                    cv2.FONT_HERSHEY_SIMPLEX, 0.55, (0, 0, 0), 2)117 118        detections.append({119            "class":      cls,120            "confidence": conf,121            "bbox":       [int(x1), int(y1), int(x2), int(y2)],122            "width_px":   int(w_px),123            "height_px":  int(h_px),124            "width_cm":   round(float(w_cm), 1) if w_cm is not None else None,125            "height_cm":  round(float(h_cm), 1) if h_cm is not None else None,126        })127 128    # Encode result image129    _, buf  = cv2.imencode(".jpg", img)130    img_b64 = base64.b64encode(buf).decode()131 132    return {133        "success":          True,134        "calibrated":       bool(calibrated),135        "pixels_per_cm":    round(pixels_per_cm, 2) if calibrated else None,136        "marker_size_cm":   float(marker_size_cm),137        "inference_time_s": round(float(time.time() - start), 3),138        "total":            int(len(detections)),139        "detections":       detections,140        "image_base64":     img_b64,141    }142 143if __name__ == "__main__":144    import uvicorn145    uvicorn.run(app, host="0.0.0.0", port=7860)