|
|
import gradio as gr |
|
|
import numpy as np |
|
|
import cv2 |
|
|
import tempfile |
|
|
import os |
|
|
import sys |
|
|
|
|
|
sys.path.append(os.path.dirname(os.path.dirname(os.path.abspath(__file__)))) |
|
|
|
|
|
|
|
|
from src.predict_fracture import FracturePredictor |
|
|
|
|
|
|
|
|
current_dir = os.path.dirname(os.path.abspath(__file__)) |
|
|
project_root = os.path.dirname(current_dir) |
|
|
|
|
|
|
|
|
MODEL_PATH = 'models/fracture_detection_model.joblib' |
|
|
ENCODER_PATH = 'models/label_encoder.joblib' |
|
|
|
|
|
print(f"Project root: {project_root}") |
|
|
print(f"Model path: {MODEL_PATH}") |
|
|
print(f"Model exists: {os.path.exists(MODEL_PATH)}") |
|
|
print(f"Encoder exists: {os.path.exists(ENCODER_PATH)}") |
|
|
|
|
|
|
|
|
if os.path.exists(MODEL_PATH) and os.path.exists(ENCODER_PATH): |
|
|
predictor = FracturePredictor(model_path=MODEL_PATH, encoder_path=ENCODER_PATH) |
|
|
else: |
|
|
print("ERROR: Model files not found. Please run training first.") |
|
|
|
|
|
print(f"Current working directory: {os.getcwd()}") |
|
|
print(f"Files in models directory: {os.listdir(os.path.join(project_root, 'models'))}") |
|
|
exit(1) |
|
|
|
|
|
def is_xray_image(img): |
|
|
"""Validate if image is an X-ray using intensity distribution""" |
|
|
try: |
|
|
if isinstance(img, np.ndarray): |
|
|
|
|
|
if len(img.shape) == 3 and img.shape[2] == 3: |
|
|
img_gray = np.dot(img[...,:3], [0.2989, 0.5870, 0.1140]) |
|
|
elif len(img.shape) == 3 and img.shape[2] == 4: |
|
|
img_gray = np.dot(img[...,:3], [0.2989, 0.5870, 0.1140]) |
|
|
else: |
|
|
img_gray = img if len(img.shape) == 2 else img[:, :, 0] |
|
|
else: |
|
|
|
|
|
img_array = cv2.imread(img, cv2.IMREAD_GRAYSCALE) |
|
|
if img_array is None: |
|
|
return False |
|
|
img_gray = np.array(img_array) |
|
|
|
|
|
|
|
|
mean_intensity = np.mean(img_gray) |
|
|
std_intensity = np.std(img_gray) |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
is_valid = (20 <= mean_intensity <= 230) and (std_intensity >= 10) |
|
|
return is_valid |
|
|
|
|
|
except Exception as e: |
|
|
print(f"Validation error: {str(e)}") |
|
|
return False |
|
|
|
|
|
def predict_fracture(img): |
|
|
"""Process uploaded image and return prediction results""" |
|
|
try: |
|
|
|
|
|
if not is_xray_image(img): |
|
|
return "⚠️ Not an X-ray image", "Upload a valid X-ray", None |
|
|
|
|
|
|
|
|
if isinstance(img, np.ndarray): |
|
|
|
|
|
if img.shape[2] == 4: |
|
|
img_bgr = cv2.cvtColor(img, cv2.COLOR_RGBA2BGR) |
|
|
else: |
|
|
img_bgr = cv2.cvtColor(img, cv2.COLOR_RGB2BGR) |
|
|
|
|
|
|
|
|
with tempfile.NamedTemporaryFile(suffix=".jpg", delete=False) as tmp: |
|
|
tmp_path = tmp.name |
|
|
cv2.imwrite(tmp_path, img_bgr) |
|
|
else: |
|
|
|
|
|
tmp_path = img |
|
|
|
|
|
|
|
|
label, confidence, vis_path = predictor.predict(tmp_path) |
|
|
|
|
|
|
|
|
vis_img = cv2.imread(vis_path) |
|
|
if vis_img is not None: |
|
|
vis_img = cv2.cvtColor(vis_img, cv2.COLOR_BGR2RGB) |
|
|
|
|
|
|
|
|
if isinstance(img, np.ndarray) and os.path.exists(tmp_path): |
|
|
os.unlink(tmp_path) |
|
|
|
|
|
return label, f"{confidence:.4f}", vis_img |
|
|
|
|
|
except Exception as e: |
|
|
print(f"Prediction error: {str(e)}") |
|
|
return "Error", "N/A", None |
|
|
|
|
|
|
|
|
iface = gr.Interface( |
|
|
fn=predict_fracture, |
|
|
inputs=gr.Image(label="Upload X-Ray Image"), |
|
|
outputs=[ |
|
|
gr.Label(label="Prediction Result"), |
|
|
gr.Textbox(label="Confidence Score"), |
|
|
gr.Image(label="Prediction Visualization") |
|
|
], |
|
|
title="🦴 Bone Fracture Detection System", |
|
|
description="Upload an X-ray image to detect bone fractures using GLCM features and SVM classifier", |
|
|
examples=[ |
|
|
[os.path.join("samples", "fractured_1.jpg")], |
|
|
[os.path.join("samples", "normal_1.jpg")] |
|
|
], |
|
|
flagging_mode="never" |
|
|
) |
|
|
|
|
|
if __name__ == "__main__": |
|
|
iface.launch( |
|
|
server_name="0.0.0.0", |
|
|
server_port=7860, |
|
|
share=True |
|
|
) |
|
|
|