Spaces:
Runtime error
Runtime error
File size: 4,956 Bytes
af3260e d797d24 af3260e 3bb9819 af3260e b1b16f3 af3260e d797d24 b1b16f3 d797d24 af3260e d797d24 3bb9819 d797d24 3bb9819 b1b16f3 d797d24 af3260e d797d24 3bb9819 b1b16f3 ffc503e d797d24 af3260e 3bb9819 d797d24 af3260e 3bb9819 b1b16f3 d797d24 b1b16f3 d797d24 b1b16f3 3bb9819 d797d24 b1b16f3 ffc503e af3260e d797d24 ffc503e b1b16f3 af3260e d797d24 b1b16f3 d797d24 b1b16f3 d797d24 b1b16f3 af3260e |
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 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 |
import gradio as gr
import tensorflow as tf
import numpy as np
from PIL import Image, ImageStat
import cv2
# 🧠 Load your TFLite model
interpreter = tf.lite.Interpreter(model_path="stool_model.tflite")
interpreter.allocate_tensors()
input_details = interpreter.get_input_details()
output_details = interpreter.get_output_details()
# 🏷️ Labels of your stool model
labels = ["bloody", "hard stool", "normal", "parasite", "watery"]
# 💬 Diagnosis summaries
diagnosis_advice = {
"bloody": "Possible hemorrhagic gastroenteritis. ⚠️ Visit a vet immediately as it may indicate internal bleeding or infection.",
"hard stool": "Your pet may be constipated. 💧 Encourage hydration and increase dietary fiber intake.",
"normal": "✅ Healthy stool detected. Your pet appears to be in good digestive health.",
"parasite": "⚠️ Possible tapeworm or other parasite infection. Schedule deworming and a vet check-up.",
"watery": "Possible diarrhea. 💧 Ensure hydration and monitor for dehydration or weakness.",
"Not stool image": "❌ This image doesn’t appear to be a stool sample. Please upload a clearer photo of stool.",
"Uncertain / unclear stool image": "⚠️ The image is unclear or confidence is low. Try retaking the photo in better lighting."
}
# 🧩 Image preprocessing for the TFLite model
def preprocess_image(img: Image.Image):
img = img.convert("RGB").resize((128, 128))
arr = np.asarray(img).astype(np.float32) / 255.0
arr = np.expand_dims(arr, axis=0)
return arr
# 🚫 Strict non-stool detection
def is_not_stool_image(image):
"""Multi-layer detection for non-stool photos"""
np_img = np.array(image.convert("RGB"))
stat = ImageStat.Stat(image)
# 🧠 1️⃣ Brightness & contrast checks
brightness = stat.mean[0]
contrast = stat.stddev[0]
if brightness > 210 or brightness < 30:
return True # too bright or dark
if contrast < 25:
return True # too flat / no texture
# 🧠 2️⃣ Dominant color detection (stool tends to be brownish)
avg_color = np.mean(np_img.reshape(-1, 3), axis=0)
r, g, b = avg_color
# Detect unnatural colors (too blue, green, or red)
if (r > 200 and g < 100 and b < 100) or (g > 180 and r < 100) or (b > 180):
return True
# 🧠 3️⃣ Color tone validation — real stool is usually brown (RGB ratios)
brownish_score = (r * 0.5 + g * 0.3 + b * 0.2)
grayish_score = abs(r - g) + abs(g - b)
if brownish_score < 60 or grayish_score > 80:
return True
# 🧠 4️⃣ Texture detection with OpenCV
gray = cv2.cvtColor(np_img, cv2.COLOR_RGB2GRAY)
lap_var = cv2.Laplacian(gray, cv2.CV_64F).var() # blur measure
if lap_var < 50:
return True # image too smooth or blurry (likely not stool)
return False # passes all checks, likely stool
# 🧠 Main classifier
def classify_image(image):
try:
# 🧩 Step 1: Reject non-stool images first
if is_not_stool_image(image):
return {"Not stool image": 1.0}, diagnosis_advice["Not stool image"]
# 🧩 Step 2: Run TFLite model
input_data = preprocess_image(image)
interpreter.set_tensor(input_details[0]['index'], input_data)
interpreter.invoke()
output_data = interpreter.get_tensor(output_details[0]['index'])[0]
# 🧩 Step 3: Sort predictions
results = {labels[i]: float(output_data[i]) for i in range(len(labels))}
sorted_results = dict(sorted(results.items(), key=lambda x: x[1], reverse=True))
top_label, top_score = list(sorted_results.items())[0]
# 🧩 Step 4: Handle low-confidence predictions
if top_score < 0.45:
return {"Uncertain / unclear stool image": top_score}, diagnosis_advice["Uncertain / unclear stool image"]
# 🧩 Step 5: Add readable confidence %
formatted_results = {
f"{label} ({score * 100:.2f}%)": score for label, score in sorted_results.items()
}
# 🩺 Step 6: Generate human-readable advice
advice = diagnosis_advice.get(top_label, "No advice available for this diagnosis.")
return formatted_results, advice
except Exception as e:
return {"Error": 0.0}, f"⚠️ Error: {str(e)}"
# 🎨 Gradio Interface
demo = gr.Interface(
fn=classify_image,
inputs=gr.Image(type="pil", label="📸 Upload Stool Image"),
outputs=[
gr.Label(num_top_classes=3, label="Predicted Diagnosis & Confidence"),
gr.Textbox(label="💬 Diagnosis Summary", lines=3),
],
title="🐾 Pet Stool Diagnosis AI (Strict Validation)",
description=(
"Upload a stool image for AI-based diagnosis. The system will first verify if it's a real stool photo, "
"then predict the stool type and give a simple health summary."
),
)
if __name__ == "__main__":
demo.launch(server_name="0.0.0.0", server_port=7860)
|