spl / app.py
lokesh341's picture
Update app.py
7f2c3c2 verified
import gradio as gr
from PIL import Image, ImageDraw
import io
from fpdf import FPDF
import tempfile
import cv2
import os
import torch
import ultralytics.nn.tasks as tasks
from urllib.request import urlretrieve
from ultralytics import YOLO
import numpy as np
# Monkey patch to use weights_only=False for trusted model
def custom_torch_safe_load(weight):
from ultralytics.utils.checks import check_file
file = check_file(weight)
return torch.load(file, map_location='cpu', weights_only=False), file
tasks.torch_safe_load = custom_torch_safe_load
# Model path
model_path = 'model/yolov8n.pt'
# Download model if not found
if not os.path.exists(model_path):
os.makedirs('model', exist_ok=True)
url = 'https://github.com/ultralytics/assets/releases/download/v0.0.0/yolov8n.pt'
urlretrieve(url, model_path)
# Load the YOLOv8 model
model = YOLO(model_path)
def detect_empty_spots(img_width, img_height, bottle_bboxes, min_gap=50):
empty_bboxes = []
x_coords = sorted([bbox[0] for bbox in bottle_bboxes] + [bbox[2] for bbox in bottle_bboxes])
x_coords = [0] + x_coords + [img_width]
for i in range(len(x_coords) - 1):
gap_start = x_coords[i]
gap_end = x_coords[i + 1]
if gap_end - gap_start > min_gap:
empty_bboxes.append([gap_start, 0, gap_end, img_height])
return empty_bboxes
def process_input(input_file):
if input_file.lower().endswith(('.mp4', '.avi', '.mov')):
cap = cv2.VideoCapture(input_file)
total_frames = int(cap.get(cv2.CAP_PROP_FRAME_COUNT))
cap.set(cv2.CAP_PROP_POS_FRAMES, total_frames // 2)
ret, frame = cap.read()
cap.release()
if not ret:
raise ValueError("Could not read video frame.")
temp_frame_path = tempfile.NamedTemporaryFile(suffix='.jpg', delete=False).name
cv2.imwrite(temp_frame_path, frame)
process_img_path = temp_frame_path
else:
process_img_path = input_file
# Run inference with YOLO parameters
results = model.predict(process_img_path, conf=0.25, iou=0.45, agnostic_nms=False, max_det=1000)
boxes = results[0].boxes
class_names = results[0].names
num_present = 0
bottle_bboxes = []
for box in boxes:
cls_id = int(box.cls.item())
cls_name = class_names[cls_id]
if cls_name == 'bottle':
num_present += 1
bottle_bboxes.append(box.xyxy[0].cpu().numpy())
img = Image.open(process_img_path)
img_width, img_height = img.size
draw = ImageDraw.Draw(img)
for bbox in bottle_bboxes:
draw.rectangle(((bbox[0], bbox[1]), (bbox[2], bbox[3])), outline="green", width=3)
empty_bboxes = detect_empty_spots(img_width, img_height, bottle_bboxes)
num_empty = len(empty_bboxes)
for bbox in empty_bboxes:
draw.rectangle(((bbox[0], bbox[1]), (bbox[2], bbox[3])), outline="red", width=3)
pdf = FPDF()
pdf.add_page()
pdf.set_font("Arial", size=12)
pdf.cell(200, 10, txt="Wine Shop Inventory Report", ln=1, align='C')
pdf.ln(5)
pdf.cell(200, 10, txt=f"Number of bottles detected: {num_present}", ln=1)
pdf.cell(200, 10, txt=f"Number of empty spots (inferred): {num_empty}", ln=1)
pdf.ln(10)
with tempfile.NamedTemporaryFile(suffix='.png') as tmp_annotated:
img.save(tmp_annotated.name)
pdf.image(tmp_annotated.name, x=10, y=pdf.get_y(), w=180)
pdf.add_page()
pdf.cell(200, 10, txt="Detected Bottles and Empty Spots", ln=1, align='C')
pdf.ln(5)
y_pos = pdf.get_y()
for i, bbox in enumerate(bottle_bboxes):
cropped_img = img.crop((bbox[0], bbox[1], bbox[2], bbox[3]))
with tempfile.NamedTemporaryFile(suffix='.png') as tmp_crop:
cropped_img.save(tmp_crop.name)
pdf.image(tmp_crop.name, x=10, y=y_pos, w=90)
y_pos += 100
pdf.cell(200, 10, txt=f"Bottle {i+1} (Location: x1={int(bbox[0])}, y1={int(bbox[1])}, x2={int(bbox[2])}, y2={int(bbox[3])})", ln=1)
pdf.ln(5)
if y_pos > 200:
pdf.add_page()
y_pos = 10
for i, bbox in enumerate(empty_bboxes):
cropped_img = img.crop((bbox[0], bbox[1], bbox[2], bbox[3]))
with tempfile.NamedTemporaryFile(suffix='.png') as tmp_crop:
cropped_img.save(tmp_crop.name)
pdf.image(tmp_crop.name, x=10, y=y_pos, w=90)
y_pos += 100
pdf.cell(200, 10, txt=f"Empty Spot {i+1} (Location: x1={int(bbox[0])}, y1={int(bbox[1])}, x2={int(bbox[2])}, y2={int(bbox[3])})", ln=1)
pdf.ln(5)
if y_pos > 200:
pdf.add_page()
y_pos = 10
pdf_bytes = io.BytesIO()
pdf.output(pdf_bytes)
pdf_bytes.seek(0)
if 'temp_frame_path' in locals():
os.remove(temp_frame_path)
return pdf_bytes.getvalue()
with gr.Blocks() as demo:
gr.Markdown("# Wine Shop CCTV Analyzer")
gr.Markdown("Upload a CCTV image or video to analyze stock and generate a PDF report.")
input_file = gr.File(label="Upload Image/Video (jpg, png, mp4, etc.)")
output_pdf = gr.File(label="Download PDF Report")
button = gr.Button("Generate Report")
button.click(process_input, inputs=input_file, outputs=output_pdf)
demo.launch()