sadhya / app.py
RatanPrakash's picture
product overview updated
ce27e44 verified
raw
history blame
25.4 kB
import streamlit as st
from ultralytics import YOLO
import tensorflow as tf # Change this to import TensorFlow
import numpy as np
from PIL import Image, ImageOps, ImageDraw, ImageFont
import pandas as pd
import time
from paddleocr import PaddleOCR, draw_ocr
import re
import dateparser
import os
import matplotlib.pyplot as plt
# Initialize PaddleOCR model
ocr = PaddleOCR(use_angle_cls=True, lang='en')
# Define the class names based on your dataset
class_names = [
'fresh_apple', 'fresh_banana', 'fresh_bitter_gourd', 'fresh_capsicum',
'fresh_orange', 'fresh_tomato', 'stale_apple', 'stale_banana',
'stale_bitter_gourd', 'stale_capsicum', 'stale_orange', 'stale_tomato'
]
# Team details
team_members = [
{"name": "Aman Deep", "image": "aman.jpg"}, # Replace with actual paths to images
{"name": "Nandini", "image": "myimage.jpg"},
{"name": "Abhay Sharma", "image": "gaurav.jpg"},
{"name": "Ratan Prakash Mishra", "image": "anandimg.jpg"}
]
# Function to preprocess the images for the model
from PIL import Image
import numpy as np
def preprocess_image(image):
"""
Preprocess the input image for model prediction.
Args:
image (PIL.Image): Input image in PIL format.
Returns:
np.ndarray: Preprocessed image array ready for prediction.
"""
try:
# Resize image to match model input size
img = image.resize((128, 128), Image.LANCZOS) # Using LANCZOS filter for high-quality resizing
# Convert image to NumPy array
img_array = np.array(img)
# Check if the image is grayscale and convert to RGB if needed
if img_array.ndim == 2: # Grayscale image
img_array = np.stack([img_array] * 3, axis=-1) # Convert to 3-channel RGB
elif img_array.shape[2] == 1: # Single-channel image
img_array = np.concatenate([img_array, img_array, img_array], axis=-1) # Convert to RGB
# Normalize pixel values to [0, 1] range
img_array = img_array / 255.0
# Add batch dimension
img_array = np.expand_dims(img_array, axis=0) # Shape: (1, 128, 128, 3)
return img_array
except Exception as e:
print(f"Error processing image: {e}")
return None # Return None if there's an error
# Function to create a high-quality circular mask for an image
def make_image_circular1(img, size=(256, 256)):
img = img.resize(size, Image.LANCZOS)
mask = Image.new("L", size, 0)
draw = ImageDraw.Draw(mask)
draw.ellipse((0, 0) + size, fill=255)
output = ImageOps.fit(img, mask.size, centering=(0.5, 0.5))
output.putalpha(mask) # Apply the mask as transparency
return output
# Function to check if a file exists
def file_exists(file_path):
return os.path.isfile(file_path)
def make_image_circular(image):
# Create a circular mask
mask = Image.new("L", image.size, 0)
draw = ImageDraw.Draw(mask)
draw.ellipse((0, 0, image.size[0], image.size[1]), fill=255)
# Apply the mask to the image
circular_image = Image.new("RGB", image.size)
circular_image.paste(image.convert("RGBA"), (0, 0), mask)
return circular_image
# Function to extract dates from recognized text using regex
def extract_dates_with_dateparser(texts, result):
date_texts = []
date_boxes = []
date_scores = []
def is_potential_date(text):
valid_date_pattern = r'^(0[1-9]|[12][0-9]|3[01])[-/.]?(0[1-9]|1[0-2])[-/.]?(\d{2}|\d{4})$|' \
r'^(0[1-9]|[12][0-9]|3[01])[-/.]?[A-Za-z]{3}[-/.]?(\d{2}|\d{4})$|' \
r'^(0[1-9]|1[0-2])[-/.]?(\d{2}|\d{4})$|' \
r'^[A-Za-z]{3}[-/.]?(\d{2}|\d{4})$'
return bool(re.match(valid_date_pattern, text))
dates_found = []
for i, text in enumerate(texts):
if is_potential_date(text): # Only process texts that are potential dates
parsed_date = dateparser.parse(text, settings={'DATE_ORDER': 'DMY'})
if parsed_date:
dates_found.append(parsed_date.strftime('%Y-%m-%d')) # Store as 'YYYY-MM-DD'
date_texts.append(text) # Store the original text
date_boxes.append(result[0][i][0]) # Store the bounding box
date_scores.append(result[0][i][1][1]) # Store confidence score
return dates_found, date_texts, date_boxes, date_scores
# Function to display circular images in a matrix format
def display_images_in_grid(images, max_images_per_row=4):
num_images = len(images)
num_rows = (num_images + max_images_per_row - 1) // max_images_per_row # Calculate number of rows
for i in range(num_rows):
cols = st.columns(min(max_images_per_row, num_images - i * max_images_per_row))
for j, img in enumerate(images[i * max_images_per_row:(i + 1) * max_images_per_row]):
with cols[j]:
st.image(img, use_column_width=True)
# Function to display team members in circular format
def display_team_members(members, max_members_per_row=4):
num_members = len(members)
num_rows = (num_members + max_members_per_row - 1) // max_members_per_row # Calculate number of rows
for i in range(num_rows):
cols = st.columns(min(max_members_per_row, num_members - i * max_members_per_row))
for j, member in enumerate(members[i * max_members_per_row:(i + 1) * max_members_per_row]):
with cols[j]:
img = Image.open(member["image"]) # Load the image
circular_img = make_image_circular(img) # Convert to circular format
st.image(circular_img, use_column_width=True) # Display the circular image
st.write(member["name"]) # Display the name below the image
# Title and description
st.title("Amazon Smbhav")
# Team Details with links
st.sidebar.title("Amazon Smbhav")
st.sidebar.write("DELHI TECHNOLOGICAL UNIVERSITY")
# Navbar with task tabs
st.sidebar.title("Navigation")
st.sidebar.write("Team Name: sadhya")
app_mode = st.sidebar.selectbox("Choose the task", ["Welcome","Project Details", "Task 1","Team Details"])
if app_mode == "Welcome":
# Navigation Menu
st.write("# Welcome to Amazon Smbhav! πŸŽ‰")
# Example for adding a local video
video_file = open('Finalist.mp4', 'rb') # Replace with the path to your video file
video_bytes = video_file.read()
# Embed the video using st.video()
st.video(video_bytes)
# Add a welcome image
welcome_image = Image.open("grid_banner.jpg") # Replace with the path to your welcome image
st.image(welcome_image, use_column_width=True) # Display the welcome image
elif app_mode=="Project Details":
st.markdown("""
## Navigation
- [Project Overview](#project-overview)
- [Proposal Round](#proposal-round)
- [Problem Statement](#problem-statement)
- [Proposed Solution](#proposed-solution)
""")
# Project Overview
st.write("## Project Overview:")
st.write("""
### Problem Statement
_Develop a system that automates Amazon product listings from social media content, extracting and organizing details from posts to generate accurate, engaging, and optimized listings._
---
### Solution Overview
Our system simplifies the listing process by analyzing social media content, using OCR, image recognition, LLMs, and internet data to create professional Amazon listings.
---
### Task Breakdown
#### Task 1: OCR for Image and Label Details
**Objective:** Extract core product details from images, labels, and packaging found in social media posts.
- **Tools:** PaddleOCR, LLMs.
- **Approach:**
- Use PaddleOCR to scan images for text, identifying product names, brands, and key features.
- Apply LLMs to refine extracted data, categorize key information (product name, type, features), and enhance product descriptions.
- Integrate internet sources to cross-verify product details, retrieve additional information, and collect metadata like the brand background or product specs.
---
#### Additional Task: Image Recognition & Object Counting
**Objective:** Quantify objects within social media images for batch products or multi-item listings.
- **Tools:** YOLOv8.
- **Approach:**
- Train YOLOv8 on a relevant dataset to recognize specific product types or packaging layouts.
- Use object detection counts to provide quantitative data (e.g., "3-item bundle"), enhancing accuracy in listings.
---
#### Task 2: Data Validation & Structuring
**Objective:** Organize and validate extracted information, ensuring it’s formatted to meet Amazon’s listing requirements.
- **Tools:** Regex, LLMs.
- **Approach:**
- Format and validate extracted details into Amazon-compliant structures (titles, descriptions, bullet points).
- Use regex and parser tools for accuracy checks.
- Leverage LLMs to create compelling descriptions and marketing brochures.
- Search online for supplementary media (images/videos) to enrich the listing.
---
#### Task 3: Amazon API Integration
**Objective:** Connect with Amazon’s API to publish fully formed product listings directly.
- **Tools:** Amazon MWS or Selling Partner API.
- **Approach:**
- Send structured listing data (text, media, product details) to Amazon’s API endpoints.
- Handle feedback for submission errors and make necessary adjustments.
- Develop a UI/dashboard for users to preview and edit listings before publishing.
---
### Future Enhancements
- **Model Improvement:** Further refine OCR and parsing accuracy.
- **Dashboard Development:** Enable users to preview and customize listings.
- **Multi-Market Compatibility:** Expand support to other e-commerce platforms.
This approach automates listing creation directly from social media content, helping sellers quickly launch optimized Amazon product pages.
""")
elif app_mode == "Team Details":
st.write("## Meet Our Team:")
display_team_members(team_members)
st.write("Delhi Technological University")
elif app_mode == "Task 1":
st.write("## Task 1: πŸ–ΌοΈ OCR to Extract Details πŸ“„")
st.write("Using OCR to extract details from product packaging material, including brand name and pack size.")
# File uploader for images (supports multiple files)
uploaded_files = st.file_uploader("Upload images of products", type=["jpeg", "png", "jpg"], accept_multiple_files=True)
if uploaded_files:
st.write("### Uploaded Images in Circular Format:")
circular_images = []
for uploaded_file in uploaded_files:
img = Image.open(uploaded_file)
circular_img = make_image_circular(img) # Create circular images
circular_images.append(circular_img)
# Display the circular images in a matrix/grid format
display_images_in_grid(circular_images, max_images_per_row=4)
# Function to simulate loading process with a progress bar
def simulate_progress():
progress_bar = st.progress(0)
for percent_complete in range(100):
time.sleep(0.02)
progress_bar.progress(percent_complete + 1)
# Function to remove gibberish using regex (removes non-alphanumeric chars, filters out very short text)
def clean_text(text):
# Keep text with letters, digits, and spaces, and remove short/irrelevant text
return re.sub(r'[^a-zA-Z0-9\s]', '', text).strip()
# Function to extract the most prominent text (product name) and other details
def extract_product_info(results):
product_name = ""
product_details = ""
largest_text_size = 0
for line in results:
for box in line:
text, confidence = box[1][0], box[1][1]
text_size = box[0][2][1] - box[0][0][1] # Calculate height of the text box
# Clean the text to avoid gibberish
clean_text_line = clean_text(text)
if confidence > 0.7 and len(clean_text_line) > 2: # Only consider confident, meaningful text
if text_size > largest_text_size: # Assume the largest text is the product name
largest_text_size = text_size
product_name = clean_text_line
else:
product_details += clean_text_line + " "
return product_name, product_details.strip()
if st.button("Start Analysis"):
simulate_progress()
# Loop through each uploaded image and process them
for uploaded_image in uploaded_files:
# Load the uploaded image
image = Image.open(uploaded_image)
# st.image(image, caption=f'Uploaded Image: {uploaded_image.name}', use_column_width=True)
# Convert image to numpy array for OCR processing
img_array = np.array(image)
# Perform OCR on the image
st.write(f"Extracting details from {uploaded_image.name}...")
result = ocr.ocr(img_array, cls=True)
# Process the OCR result to extract product name and properties
product_name, product_details = extract_product_info(result)
# UI display for single image product details
st.markdown("---")
st.markdown(f"### **Product Name:** `{product_name}`")
st.write(f"**Product Properties:** {product_details}")
st.markdown("---")
else:
st.write("Please upload images to extract product details.")
elif app_mode == "Task 2":
st.write("## Task 2:πŸ“… Expiry Date Validation βœ…")
st.write("Use OCR to get expiry and MRP details printed on items.")
# File uploader for images (supports multiple files)
uploaded_files = st.file_uploader("Upload images of products containing expiry date", type=["jpeg", "png", "jpg"], accept_multiple_files=True)
if uploaded_files:
st.write("### Uploaded Images in Circular Format:")
circular_images = []
for uploaded_file in uploaded_files:
img = Image.open(uploaded_file)
circular_img = make_image_circular(img) # Create circular images
circular_images.append(circular_img)
# Display the circular images in a matrix/grid format
display_images_in_grid(circular_images, max_images_per_row=4)
# Function to simulate loading process with a progress bar
def simulate_progress():
progress_bar = st.progress(0)
for percent_complete in range(100):
time.sleep(0.02)
progress_bar.progress(percent_complete + 1)
for idx, uploaded_file in enumerate(uploaded_files):
image = Image.open(uploaded_file)
img_array = np.array(image)
result = ocr.ocr(img_array, cls=True)
if result and result[0]:
# Extract recognized texts
recognized_texts = [line[1][0] for line in result[0]]
# Clean up recognized texts by removing extra spaces and standardizing formats
cleaned_texts = []
for text in recognized_texts:
cleaned_text = re.sub(r'\s+', ' ', text.strip()) # Replace multiple spaces with a single space
cleaned_text = cleaned_text.replace('.', '').replace(',', '') # Remove dots and commas for date detection
cleaned_texts.append(cleaned_text)
# Extract dates from recognized texts
extracted_dates, date_texts, date_boxes, date_scores = extract_dates_with_dateparser(cleaned_texts, result)
if extracted_dates:
# Display extracted dates
st.write("**Extracted Dates**:")
for date, text in zip(extracted_dates, date_texts):
st.write(f"Detected Date: **{date}**, Original Text: *{text}*")
else:
st.write("No valid dates found in the image.")
# Option to visualize the bounding boxes on the image
if st.checkbox(f"Show image with highlighted dates for {uploaded_file.name}", key=f"highlight_{idx}"):
# Draw the OCR results on the image
image_with_boxes = draw_ocr(image, date_boxes, date_texts, date_scores,font_path='CedarvilleCursive-Regular.ttf') # Removed font path
# Display the image with highlighted boxes
plt.figure(figsize=(10, 10))
plt.imshow(image_with_boxes)
plt.axis('off') # Hide axes
st.pyplot(plt)
else:
st.write("No text detected in the image.")
def make_image_circular1(image):
# Create a circular mask
mask = Image.new("L", image.size, 0)
draw = ImageDraw.Draw(mask)
draw.ellipse((0, 0, image.size[0], image.size[1]), fill=255)
# Apply the mask to the image
circular_image = Image.new("RGB", image.size)
circular_image.paste(image.convert("RGBA"), (0, 0), mask)
return circular_image
def display_images_in_grid1(images, max_images_per_row=4):
rows = (len(images) + max_images_per_row - 1) // max_images_per_row # Calculate number of rows needed
for i in range(0, len(images), max_images_per_row):
cols_to_show = images[i:i + max_images_per_row]
# Prepare to display in a grid format
cols = st.columns(max_images_per_row) # Create columns dynamically
for idx, img in enumerate(cols_to_show):
img = img.convert("RGB") # Ensure the image is in RGB mode
if idx < len(cols):
cols[idx].image(img, use_column_width=True)
# Initialize your Streamlit app
if app_mode == "Task 3":
st.write("## Task 3: Image Recognition πŸ“Έ and IR-Based Counting πŸ“Š")
# File uploader for images (supports multiple files)
uploaded_files = st.file_uploader("Upload images of fruits, vegetables, or products for brand recognition and freshness detection",
type=["jpeg", "png", "jpg"], accept_multiple_files=True)
if uploaded_files:
st.write("### Uploaded Images:")
# Load the pre-trained YOLOv8 model
model = YOLO('yolov9c.pt') # Adjust path to your YOLO model if needed
# Initialize a dictionary to store counts of detected products
product_count_dict = {}
circular_images = []
images=[]
for uploaded_file in uploaded_files:
img = Image.open(uploaded_file)
circular_img = make_image_circular(img) # Create circular images
circular_images.append(circular_img)
images.append(img)
# Display the circular images in a matrix/grid format
display_images_in_grid(circular_images, max_images_per_row=4)
detected_images = []
for idx, image in enumerate(images):
# Run object detection
results = model(image)
# Initialize counts for this image
image_counts = {}
# Display results with bounding boxes
for result in results:
img_with_boxes = result.plot() # Get image with bounding boxes
detected_images.append(make_image_circular(image.resize((150, 150)))) # Resize and make circular
# Display detected object counts per class
counts = result.boxes.cls.tolist() # Extract class IDs
class_counts = {int(cls): counts.count(cls) for cls in set(counts)}
# Update the image counts for this image
for cls_id, count in class_counts.items():
product_name = result.names[cls_id] # Get the product name from class ID
image_counts[product_name] = count
# Aggregate counts into the main product count dictionary
for product, count in image_counts.items():
if product in product_count_dict:
product_count_dict[product] += count
else:
product_count_dict[product] = count
# Option to visualize the bounding boxes on the image
if st.checkbox(f"Show image with highlighted boxes for image {idx + 1}", key=f"checkbox_{idx}"):
st.image(img_with_boxes, caption="Image with Highlighted Boxes", use_column_width=True)
# Display the total counts as a bar chart
st.write("### Total Product Counts Across All Images:")
if product_count_dict:
product_count_df = pd.DataFrame(product_count_dict.items(), columns=["Product", "Count"])
st.bar_chart(product_count_df.set_index("Product"))
else:
st.write("No products detected.")
elif app_mode == "Task 4":
st.write("## Task 4: 🍏 Fruit and Vegetable Freshness Detector πŸ…")
# Load the trained model
try:
model = tf.keras.models.load_model('fruit_freshness_model.h5') # Using TensorFlow to load the model
st.success("Model loaded successfully!")
except Exception as e:
st.error(f"Error loading model: {e}")
# File uploader for images (supports multiple files)
uploaded_files = st.file_uploader("Upload images of fruits/vegetables", type=["jpeg", "png", "jpg"], accept_multiple_files=True)
if uploaded_files:
st.write("### Uploaded Images in Circular Format:")
circular_images = []
images=[]
for uploaded_file in uploaded_files:
img = Image.open(uploaded_file)
circular_img = make_image_circular(img) # Create circular images
circular_images.append(circular_img)
images.append(img)
# Display the circular images in a matrix/grid format
display_images_in_grid(circular_images, max_images_per_row=4)
# Function to simulate loading process with a progress bar
def simulate_progress():
progress_bar = st.progress(0)
for percent_complete in range(100):
time.sleep(0.02)
progress_bar.progress(percent_complete + 1)
# Create an empty DataFrame to hold the image name and prediction results
results_df = pd.DataFrame(columns=["Image", "Prediction"])
# Create a dictionary to count the occurrences of each class
class_counts = {class_name: 0 for class_name in class_names}
# Button to initiate predictions
if st.button("Run Prediction"):
# Display progress bar
simulate_progress()
for idx, img in enumerate(images): # Use circular images for predictions
img_array = preprocess_image(img.convert('RGB')) # Convert to RGB
try:
# Perform the prediction
prediction = model.predict(img_array)
# Get the class with the highest probability
result = class_names[np.argmax(prediction)]
st.success(f'Prediction for Image {idx + 1}: **{result}**')
# Increment the class count
class_counts[result] += 1
# Add the result to the DataFrame
result_data = pd.DataFrame({"Image": [uploaded_files[idx].name], "Prediction": [result]})
results_df = pd.concat([results_df, result_data], ignore_index=True)
except Exception as e:
st.error(f"Error occurred during prediction: {e}")
# Display class distribution as a bar chart
st.write("### Class Distribution:")
class_counts_df = pd.DataFrame(list(class_counts.items()), columns=['Class', 'Count'])
st.bar_chart(class_counts_df.set_index('Class'))
# Option to download the prediction results as a CSV file
st.write("### Download Results:")
csv = results_df.to_csv(index=False).encode('utf-8')
st.download_button(
label="Download prediction results as CSV",
data=csv,
file_name='prediction_results.csv',
mime='text/csv',
)
# Display the dataframe after the graph
st.write("### Prediction Data:")
st.dataframe(results_df)
# Footer with animation
st.markdown("""
<style>
@keyframes fade-in {
from { opacity: 0; }
to { opacity: 1;}
}
.footer {
text-align: center;
font-size: 1.1em;
animation: fade-in 2s;
padding-top: 2rem;
}
</style>
<div class="footer">
<p>Β© 2024 Amazon Smbhav Challenge. All rights reserved.</p>
</div>
""", unsafe_allow_html=True)