File size: 6,152 Bytes
c511886
 
 
 
 
 
 
 
 
3612acd
c511886
 
ebcc800
 
c511886
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
3612acd
 
c511886
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
3eed454
c511886
 
 
 
 
 
3612acd
c511886
 
3612acd
 
 
 
 
 
 
c511886
3612acd
 
 
 
 
 
 
 
 
 
 
 
 
 
c511886
 
 
 
 
3612acd
 
c511886
 
 
 
 
 
 
 
 
 
 
 
 
 
ebcc800
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
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
import streamlit as st
import numpy as np
import tensorflow as tf
from tensorflow.keras.models import load_model
from tensorflow.keras.preprocessing import image
# Import preprocess_input specifically from the efficientnet application module
from tensorflow.keras.applications.efficientnet import preprocess_input
import os
from PIL import Image # Needed to display image in Streamlit
import io # Needed to handle camera input which is a BytesIO object

# --- Configuration ---

IMG_SIZE = 224
# Define the expected model filename
MODEL_FILENAME = 'skin_lesion_model.keras'
# Define class names based on the training script output
CLASS_NAMES = ['Benign', 'Malignant'] # From training: ['benign', 'malignant']

# --- Model Loading (Cached) ---
@st.cache_resource # Decorator to cache the model loading
def load_skin_model():
    """Loads the Keras model. Returns the model or None if not found."""
    if not os.path.exists(MODEL_FILENAME):
        st.error(f"Error: Model file '{MODEL_FILENAME}' not found.")
        st.info(f"Please ensure the model file is in the same directory as the script.")
        return None
    try:
        # Load the model, compile=False speeds up loading for inference only
        model = load_model(MODEL_FILENAME, compile=False)
        print("Model loaded successfully.") # Log for server console
        return model
    except Exception as e:
        st.error(f"Error loading model: {e}")
        print(f"Error loading model: {e}") # Log for server console
        return None

# --- Preprocessing Function ---
def preprocess_image(img_input):
    """Loads and preprocesses an image for EfficientNetB0."""
    try:
        # Load image directly from uploaded file object, camera input, or path
        # Use PIL to open the image from the BytesIO object provided by file_uploader/camera_input
        img = Image.open(img_input).convert('RGB') # Ensure image is RGB
        img = img.resize((IMG_SIZE, IMG_SIZE))

        img_array = image.img_to_array(img)
        img_array = np.expand_dims(img_array, axis=0)
        # Use the appropriate preprocessing function for EfficientNet
        processed_img = preprocess_input(img_array)
        print(f"Image preprocessed successfully. Shape: {processed_img.shape}") # Debug print
        return processed_img
    except Exception as e:
        st.error(f"Error during image preprocessing: {e}")
        print(f"Error during image preprocessing: {e}") # Log for server console
        return None # Return None to indicate failure

# --- Prediction Function ---
def predict_skin_lesion(model, processed_image):
    """Makes predictions using the loaded model and preprocessed image."""
    try:
        # Make prediction
        print("Making prediction...") # Debug print
        prediction = model.predict(processed_image)[0]
        print(f"Raw prediction output: {prediction}") # Debug print

        # Get the class with highest probability
        class_index = np.argmax(prediction)
        confidence = float(prediction[class_index])

        # Map class index to label using CLASS_NAMES
        class_label = CLASS_NAMES[class_index]

        print(f"Predicted class: {class_label}, Confidence: {confidence:.4f}") # Debug print
        return class_label, confidence

    except Exception as e:
        st.error(f"An error occurred during prediction: {e}")
        print(f"An error occurred during prediction: {e}") # Log for server console
        return None, None # Return None to indicate failure

# --- Streamlit App UI ---
st.set_page_config(page_title="Skin Lesion Classifier", layout="centered")
st.title("Skin Lesion Classification (EfficientNetB0)")
st.markdown(f"Upload an image of a skin lesion or use your camera for a potential classification (benign or malignant). Important: This tool uses a probabilistic model and its output is not a substitute for a professional medical diagnosis. Always consult your physician.")

# Load the model using the cached function
model = load_skin_model()

# Only proceed if the model loaded successfully
if model is not None:
    # Option 1: File uploader
    uploaded_file = st.file_uploader("Choose a skin lesion image...", type=["jpg", "jpeg", "png"])

    # Option 2: Camera input
    camera_input = st.camera_input("Or take a picture using your camera:")

    # Determine the source of the image
    image_source = None
    source_type = None # To adjust the caption later

    if uploaded_file is not None:
        image_source = uploaded_file
        source_type = "Uploaded"
        # Clear camera input if a file is uploaded after taking a picture
        if camera_input is not None:
            st.warning("You provided both an uploaded file and a camera shot. Using the uploaded file.")
            camera_input = None # Prioritize uploaded file
    elif camera_input is not None:
        image_source = camera_input
        source_type = "Camera"

    # Process the image if one was provided
    if image_source is not None:
        # Display the image
        st.image(image_source, caption=f'{source_type} Image.', use_column_width=True)
        st.write("") # Add a little space

        # Classify button
        if st.button('Classify Lesion'):
            with st.spinner('Preprocessing image and making prediction...'):
                # Preprocess the image (works for both file uploader and camera input)
                processed_image = preprocess_image(image_source)

                if processed_image is not None:
                    # Make prediction
                    label, confidence = predict_skin_lesion(model, processed_image)

                    if label is not None:
                        # Display result
                        st.success(f'Prediction: **{label}**')
                        st.metric(label="Confidence", value=f"{confidence:.2%}")
                    else:
                        st.error("Prediction failed. Please check the logs or try a different image.")
                else:
                    st.error("Image preprocessing failed. Please ensure the image is valid.")
else:
    st.warning("Model could not be loaded. Please check the setup.")