CoolFace
Apppublic

premdeep09/ANPR-System

sourceHugging Faceupdated 5mo agoView on Hugging Face
0likes
main.py161 linesDownload Raw Back to root
1from fastapi import FastAPI, HTTPException, BackgroundTasks, UploadFile, File, Form
2from fastapi.middleware.cors import CORSMiddleware
3from pydantic import BaseModel
4from typing import List, Optional
5import os
6import shutil
7from database import DatabaseManager
8from pipeline import ANPRPipeline
9import logging
10
11logging.basicConfig(level=logging.INFO)
12logger = logging.getLogger("API")
13
14app = FastAPI(title="ANPR System API")
15
16# Add CORS Middleware
17app.add_middleware(
18    CORSMiddleware,
19    allow_origins=["*"],
20    allow_credentials=True,
21    allow_methods=["*"],
22    allow_headers=["*"],
23)
24
25# Initialize DB Manager
26db_manager = DatabaseManager(database="anpr_system")
27
28# Initialize AI Pipeline
29# We start this async/in a background thread inside the startup event
30# In production, RTSP URL can be read from environment variables
31RTSP_URL = os.getenv("RTSP_URL", "0") # Default to webcam for local tests
32pipeline = ANPRPipeline(
33    rtsp_url=RTSP_URL,
34    db_manager=db_manager,
35    storage_dir="storage",
36    cooldown_seconds=30 # 30 seconds cooldown to prevent rapid multi-detections of the same vehicle
37)
38
39@app.on_event("startup")
40def startup_event():
41    logger.info("Initializing ANPR Background Pipeline...")
42    pipeline.start()
43
44@app.on_event("shutdown")
45def shutdown_event():
46    logger.info("Shutting down ANPR Background Pipeline...")
47    pipeline.stop()
48
49# Data models
50class VehicleRecord(BaseModel):
51    id: int
52    plate_number: str
53    vehicle_type: Optional[str] = "Unknown"
54    entry_time: str
55    exit_time: Optional[str] = None
56    status: str
57    blacklisted: bool = False
58    plate_image_path: Optional[str] = None
59    vehicle_image_path: Optional[str] = None
60
61class ManualEntryRequest(BaseModel):
62    plate_number: str
63    vehicle_type: str
64
65from fastapi.responses import StreamingResponse
66import cv2
67import io
68
69@app.get("/")
70def read_root():
71    return {"message": "ANPR System API is running natively with YOLOv8 & MySQL!"}
72
73def generate_frames():
74    import time
75    while True:
76        frame = pipeline.latest_frame
77        if frame is None:
78            time.sleep(0.1)
79            continue
80        try:
81            ret, buffer = cv2.imencode('.jpg', frame)
82            if not ret: 
83                time.sleep(0.1)
84                continue
85            
86            yield (b'--frame\r\n'
87                   b'Content-Type: image/jpeg\r\n\r\n' + buffer.tobytes() + b'\r\n')
88            time.sleep(0.05)
89        except Exception as e:
90            time.sleep(0.1)
91
92@app.get("/api/video_feed")
93def video_feed():
94    return StreamingResponse(generate_frames(), media_type="multipart/x-mixed-replace; boundary=frame")
95
96@app.get("/api/latest_frame")
97def get_latest_frame():
98    frame = pipeline.latest_frame
99    if frame is None:
100        raise HTTPException(status_code=404, detail="No frame available")
101    _, buffer = cv2.imencode('.jpg', frame)
102    return StreamingResponse(io.BytesIO(buffer.tobytes()), media_type="image/jpeg")
103
104@app.get("/api/stats")
105def get_stats():
106    return db_manager.get_stats()
107
108@app.get("/api/vehicles", response_model=List[VehicleRecord])
109def get_vehicles(limit: int = 50):
110    return db_manager.get_recent_vehicles(limit=limit)
111
112@app.post("/api/manual_entry")
113def create_manual_entry(entry: ManualEntryRequest):
114    success = db_manager.add_or_update_vehicle(
115        plate_number=entry.plate_number.upper(),
116        vehicle_type=entry.vehicle_type
117    )
118    if success:
119        return {"message": f"Manual entry added for {entry.plate_number.upper()}"}
120    else:
121        raise HTTPException(status_code=500, detail="Failed to add manual entry to database.")
122
123@app.post("/api/video_source")
124async def change_video_source(
125    source_type: str = Form(...),
126    rtsp_url: Optional[str] = Form(None),
127    file: Optional[UploadFile] = File(None)
128):
129    if source_type == "Webcam":
130        new_source = "0"
131    elif source_type == "CCTV Stream":
132        if not rtsp_url:
133            raise HTTPException(status_code=400, detail="RTSP URL is required for CCTV Stream")
134        new_source = rtsp_url
135    elif source_type in ["Upload Video", "Upload Picture"]:
136        if not file:
137            raise HTTPException(status_code=400, detail="File is required for upload")
138        
139        upload_dir = os.path.join(os.getcwd(), "uploads")
140        os.makedirs(upload_dir, exist_ok=True)
141        file_path = os.path.join(upload_dir, file.filename)
142        
143        try:
144            content = await file.read()
145            with open(file_path, "wb") as buffer:
146                buffer.write(content)
147        except Exception as e:
148            raise HTTPException(status_code=500, detail=f"Failed to save file: {e}")
149            
150        new_source = file_path
151    else:
152        raise HTTPException(status_code=400, detail="Invalid source type")
153        
154    pipeline.set_source(new_source)
155    return {"message": f"Video source changed to: {source_type}"}
156
157if __name__ == "__main__":
158    import uvicorn
159    # Important: Setting reload=False is usually better when using background threads like YOLO
160    uvicorn.run(app, host="0.0.0.0", port=8000, reload=False)
161