Spaces:
Sleeping
Sleeping
File size: 3,384 Bytes
743db56 60f715f 743db56 df039cf 743db56 60f715f 743db56 df039cf 60f715f df039cf 743db56 df039cf 743db56 df039cf 743db56 df039cf 743db56 df039cf 743db56 df039cf 743db56 df039cf 60f715f 743db56 df039cf 60f715f df039cf 60f715f df039cf 743db56 60f715f 743db56 df039cf 743db56 | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 | import gradio as gr
import tensorflow as tf
import numpy as np
import json
from tensorflow.keras.preprocessing.image import img_to_array
from PIL import Image
import re
# ---------- Helper Function: Clean Class Names ----------
def clean_class_name(raw_name):
"""
Converts raw class names like 'apple_red_1' to 'Apple Red'
and 'pear_1' to 'Pear'.
"""
# Remove the trailing underscore and number (e.g., '_1', '_2')
cleaned = re.sub(r'_\d+$', '', raw_name)
# Replace underscores with spaces
cleaned = cleaned.replace('_', ' ')
# Capitalize each word
cleaned = cleaned.title()
return cleaned
# ---------- Load the Model (.keras format) ----------
model_path = 'fruits_classifier.keras'
model = tf.keras.models.load_model(model_path)
print("β
Model loaded successfully!")
# ---------- Load Class Names ----------
with open('class_indices.json', 'r') as f:
class_names_dict = json.load(f)
# Convert dictionary to a list for easy index-based access
class_names_list = [class_names_dict[str(i)] for i in range(len(class_names_dict))]
print(f"β
Total classes loaded: {len(class_names_list)}")
# ---------- Prediction Function (Matches Training Preprocessing) ----------
def predict_image(image):
"""
Preprocessing exactly matches training:
- Resize to (64, 64)
- Rescale by 1.0/255.0 (same as ImageDataGenerator rescale)
- NO preprocess_input (VGG16 mean subtraction) because training didn't use it
"""
# Step 1: Resize image to (64, 64) - matches target_size in training
img = image.resize((64, 64))
# Step 2: Convert PIL image to numpy array
img_array = img_to_array(img)
# Step 3: Rescale pixel values to [0, 1]
# This matches: rescale=1.0/255.0 in ImageDataGenerator
img_array = img_array / 255.0
# Step 4: Add batch dimension (1, 64, 64, 3)
img_array = np.expand_dims(img_array, axis=0)
# Step 5: Run inference (same as model.predict in notebook)
predictions = model.predict(img_array, verbose=0)
predicted_index = np.argmax(predictions, axis=-1)[0]
confidence = np.max(predictions, axis=-1)[0]
# Step 6: Get the raw class name and clean it for display
raw_class_name = class_names_list[predicted_index]
predicted_class = clean_class_name(raw_class_name)
confidence_percentage = float(confidence) * 100
return predicted_class, f"{confidence_percentage:.2f}%"
# ---------- Create Categories List for Display ----------
cleaned_class_names = [clean_class_name(name) for name in class_names_list]
categories_list = sorted(cleaned_class_names)
categories_text = ", ".join(categories_list)
description_text = f"""
### π Upload an image of a fruit.
**The model can predict the following {len(categories_list)} categories:**
{', '.join(categories_list)}
---
*Model: VGG16-based Transfer Learning*
*Input size: 64x64 | Preprocessing: Rescale to [0, 1]*
"""
# ---------- Gradio Interface ----------
interface = gr.Interface(
fn=predict_image,
inputs=gr.Image(type="pil", label="Upload Fruit Image"),
outputs=[
gr.Textbox(label="π Predicted Fruit"),
gr.Textbox(label="π Confidence")
],
title="π Fruit Classification Using Transfer Learning",
description=description_text,
)
# ---------- Launch ----------
if __name__ == "__main__":
interface.launch() |