Bread-Detector / app.py
Axelottle's picture
Upload folder using huggingface_hub
6387720
import gradio as gr
import pandas as pd
import os, shutil
from PIL import Image
from ultralyticsplus import YOLO
# Gradio Theme
theme = gr.themes.Soft(
primary_hue="yellow",
secondary_hue="blue",
neutral_hue="gray",
font=[gr.themes.GoogleFont('Inter'), 'ui-sans-serif', 'system-ui', 'sans-serif'],
font_mono=[gr.themes.GoogleFont('Inter'), 'ui-monospace', 'Consolas', 'monospace'],
).set(
background_fill_primary='*neutral_100',
)
# Bread Prices
bread_types = {
"baguette": {"name": "Baguette", "price": 108},
"binangkal": {"name": "Binangkal", "price": 11},
"bonete": {"name": "Bonete", "price": 8},
"cornbread": {"name": "Cornbread", "price": 55},
"croissant": {"name": "Croissant", "price": 75},
"ensaymada": {"name": "Ensaymada", "price": 14},
"flatbread": {"name": "Flatbread", "price": 17},
"kalihim": {"name": "Kalihim", "price": 15},
"monay": {"name": "Monay", "price": 6},
"pandesal": {"name": "Pandesal", "price": 3},
"sourdough": {"name": "Sourdough", "price": 150},
"spanish-bread": {"name": "Spanish Bread", "price": 14},
"wheat-bread": {"name": "Wheat Bread", "price": 8},
"white-bread": {"name": "White Bread", "price": 4},
"whole-grain-bread": {"name": "Whole Grain Bread", "price": 10},
}
# Instantiate the model
model = YOLO("best.pt")
# Converts image input into a list
def preprocess_image(image):
img_list = []
# Preprocess the image and add it to the list
for im in image:
image = Image.open(im.name)
resize_img = image.resize((640, 640))
img_list.append(resize_img)
return img_list
# Gets all output images
def get_predictions(directory):
allowed_extensions = ('.png', '.jpg', '.jpeg', '.gif', '.bmp')
return [
os.path.join(root, file)
for root, _, files in os.walk(directory)
for file in files
if file.lower().endswith(allowed_extensions)
]
# Clear output from previous detection
def clear_output():
shutil.rmtree('output/', ignore_errors=True)
# Bread Prediction function
def detect_bread(image):
clear_output()
image_list = preprocess_image(image)
results = model.predict(image_list, conf=0.4, save=True, hide_conf=True, project = "output", name = "results")
detected_classes = []
for result in results:
for cls in result.boxes.cls: # Stores all detected classes in the list
detected_classes.append(result.names[int(cls)])
receipt = generate_receipt(detected_classes)
return get_predictions(f'output/results'), receipt
# Generate Receipt function
def generate_receipt(detected_classes):
detected_items = []
counts = {} # Dictionary to store bread type counts
for item_class in detected_classes: # Counts the quantity of each class
counts[item_class] = counts.get(item_class, 0) + 1
for item_class, count in counts.items(): # Gets the name and price of each class
bread_info = bread_types.get(item_class, {})
item_name = bread_info.get("name", "Unknown Bread")
price = bread_info.get("price", 0)
detected_items.append({"item": item_name, "quantity": count, "price": price})
total_amount = sum(item["quantity"] * item["price"] for item in detected_items)
# Creates the receipt dictionary
data = {"Item": [], "Quantity": [], "Price": [], "Amount": []}
for item_info in detected_items:
item = item_info["item"]
quantity = item_info["quantity"]
price = item_info["price"]
total_item_amount = quantity * price
data["Item"].append(item)
data["Quantity"].append(quantity)
data["Price"].append(price)
data["Amount"].append(total_item_amount)
# Appends the last row of the dataframe for the total amount
data["Item"].append("TOTAL")
data["Quantity"].append("")
data["Price"].append("")
data["Amount"].append(total_amount)
df = pd.DataFrame(data)
return df
# Export to CSV function
def export_csv(df):
df.to_csv("receipt.csv", index=False)
return gr.File.update(value="receipt.csv", visible=True)
# Export to JSON function
def export_json(df):
df.to_json("receipt.json")
return gr.File.update(value="receipt.json", visible=True)
# Select image from Files
def preview(files, sd: gr.SelectData):
prev = files[sd.index].name
return gr.Image.update(value=prev, visible=True)
# Gradio Interface
with gr.Blocks(theme=theme) as demo:
clear_output()
gr.Markdown("# Bread Detector w/ POS")
gr.Markdown("An application that detects different types of bread and calculates the total price.")
gr.Markdown("**Bread types include:** baguette, binangkal, bonete, cornbread, croissant, ensaymada, flatbread, kalihim, monay, pandesal, sourdough, spanish bread, wheat bread, white bread, and whole grain bread.")
with gr.Row():
with gr.Column():
fn = detect_bread
img_input = gr.Files(file_types=["image"], label="Input Image")
img_preview = gr.Image(label="Preview Image", interactive=False, visible=False)
detect_btn = gr.Button(variant="primary", value="Detect")
with gr.Column():
img_output = gr.Gallery(label='Output Image')
receipt_output = gr.Dataframe(
headers=["Item", "Quantity", "Price", "Amount"],
datatype=["str", "number", "number", "number"],
label="Receipt",
interactive=False,
)
with gr.Row():
clear_btn = gr.ClearButton()
export_csv_btn = gr.Button(variant="primary", value="Export as CSV")
export_json_btn = gr.Button(variant="primary", value="Export as JSON")
with gr.Row():
csv = gr.File(interactive=False, visible=False)
# Gradio Buttons
img_input.select(preview, img_input, img_preview)
detect_btn.click(detect_bread, inputs=img_input, outputs=[img_output, receipt_output])
export_csv_btn.click(export_csv, receipt_output, csv)
export_json_btn.click(export_json, receipt_output, csv)
clear_btn.click(lambda: [None, None, None, gr.File.update(visible=False), gr.Image.update(visible=False)],
outputs=[img_input, img_output, receipt_output, csv, img_preview]
)
demo.queue()
demo.launch()