import cv2 import streamlit as st st.set_page_config(layout="wide") import streamlit.components.v1 as components import time import numpy as np import pandas as pd import tensorflow as tf import matplotlib.pyplot as plt import matplotlib.cm as cm from PIL import Image from tf_keras_vis.gradcam import Gradcam from io import BytesIO from sklearn.metrics import classification_report,confusion_matrix, roc_curve, auc,precision_recall_curve, average_precision_score from sklearn.preprocessing import label_binarize import seaborn as sns import torch import torch.nn as nn import torchvision.models as models from torchvision import datasets, transforms import torchvision.transforms as transforms import torch.nn.functional as F from gradcam import GradCAM # Import your GradCAM class if "model" not in st.session_state: st.session_state.model = tf.keras.models.load_model( "best_model.h5" ) if "framework" not in st.session_state: st.session_state.framework = "Tensorflow" if "menu" not in st.session_state: st.session_state.menu = "1" if st.session_state.menu =="1": st.session_state.show_summary = True st.session_state.show_arch = False st.session_state.show_desc = False elif st.session_state.menu =="2": st.session_state.show_arch = True st.session_state.show_summary = False st.session_state.show_desc = False elif st.session_state.menu =="3": st.session_state.show_arch = False st.session_state.show_summary = False st.session_state.show_desc = True else: st.session_state.show_desc = True import base64 import os import tf_keras_vis # ****************************************/ # GRAD CAM # *********************************************# if st.session_state.framework == "TensorFlow": gradcam = Gradcam(st.session_state.model, model_modifier=None, clone=False) def generate_gradcam(pil_image, target_class): # Convert PIL to array and preprocess img_array = np.array(pil_image) img_preprocessed = tf.keras.applications.vgg16.preprocess_input(img_array.copy()) img_tensor = tf.expand_dims(img_preprocessed, axis=0) # Generate heatmap loss = lambda output: tf.reduce_mean(output[:, target_class]) cam = gradcam(loss, img_tensor, penultimate_layer=-1) # Process heatmap cam = cam if cam.ndim > 2: cam = cam.squeeze() cam = np.maximum(cam, 0) cam = cv2.resize(cam, (224, 224)) cam = cam / cam.max() if cam.max() > 0 else cam return cam if st.session_state.framework == "PyTorch": target_layer = st.session_state.model.conv3 # Typically last convolutional layer #gradcam = GradCAM(st.session_state.model, target_layer) def preprocess_image(image): preprocess = transforms.Compose([ transforms.Resize((224, 224)), transforms.ToTensor() ]) return preprocess(image).unsqueeze(0) # Add batch dimension def generate_gradcams(image, target_class): # Preprocess the image and convert it to a tensor input_image = preprocess_image(image) # Instantiate GradCAM gradcampy = GradCAM(st.session_state.model, target_layer) # Generate the CAM cam = gradcampy.generate(input_image, target_class) return cam def convert_image_to_base64(pil_image): buffered = BytesIO() pil_image.save(buffered, format="PNG") return base64.b64encode(buffered.getvalue()).decode() #------------------------------------------------- #loading pytorch class KidneyCNN(nn.Module): def __init__(self, num_classes=4): super(KidneyCNN, self).__init__() # Convolutional layers self.conv1 = nn.Conv2d(in_channels=3, out_channels=32, kernel_size=3, stride=1, padding=1) self.conv2 = nn.Conv2d(in_channels=32, out_channels=64, kernel_size=3, stride=1, padding=1) self.conv3 = nn.Conv2d(in_channels=64, out_channels=128, kernel_size=3, stride=1, padding=1) self.conv4 = nn.Conv2d(in_channels=128, out_channels=256, kernel_size=3, stride=1, padding=1) # Batch normalization layers self.bn1 = nn.BatchNorm2d(32) self.bn2 = nn.BatchNorm2d(64) self.bn3 = nn.BatchNorm2d(128) self.bn4 = nn.BatchNorm2d(256) # Max pooling layers self.pool = nn.MaxPool2d(kernel_size=2, stride=2, padding=0) # Fully connected layers self.fc1 = nn.Linear(256 * 14 * 14, 512) self.fc2 = nn.Linear(512, num_classes) # Dropout for regularization self.dropout = nn.Dropout(0.5) def forward(self, x): # Conv block 1 x = self.pool(F.relu(self.bn1(self.conv1(x)))) # Conv block 2 x = self.pool(F.relu(self.bn2(self.conv2(x)))) # Conv block 3 x = self.pool(F.relu(self.bn3(self.conv3(x)))) # Conv block 4 x = self.pool(F.relu(self.bn4(self.conv4(x)))) x = x.view(x.size(0), -1) # Fully connected layers x = self.dropout(F.relu(self.fc1(x))) x = self.fc2(x) return x if st.session_state.framework =="PyTorch": st.session_state.model = torch.load('kidney_model .pth', map_location=torch.device('cpu')) st.session_state.model.eval() print(type(st.session_state.model)) #********************************************* # /#*********************************************/ # LOADING TEST DATASET # ************************************************* if st.session_state.framework == "TensorFlow": test_dir = "test" BATCH_SIZE = 32 IMG_SIZE = (224, 224) test_dataset = tf.keras.utils.image_dataset_from_directory( test_dir, shuffle=False, batch_size=BATCH_SIZE, image_size=IMG_SIZE ) class_names = test_dataset.class_names def one_hot_encode(image, label): label = tf.one_hot(label, num_classes) return image, label # One-hot encode labels using CategoryEncoding class_labels = class_names # One-hot encode labels using CategoryEncoding # One-hot encode labels using CategoryEncoding num_classes = len(class_names) test_dataset = test_dataset.map(one_hot_encode) elif st.session_state.framework == "PyTorch": test_dir = "test" BATCH_SIZE = 32 IMG_SIZE = (224, 224) transform = transforms.Compose([ transforms.Resize((224, 224)), transforms.ToTensor(), transforms.Normalize(mean=[0.485, 0.456, 0.406], std=[0.229, 0.224, 0.225]) ]) test_dataset = datasets.ImageFolder(root='test', transform=transform) class_names = test_dataset.classes # One-hot encode labels using CategoryEncoding class_labels = class_names # One-hot encode labels using CategoryEncoding # One-hot encode labels using CategoryEncoding num_classes = len(class_names) ####################################################### # --------------------------------------------------# class_labels = ["Cyst", "Normal", "Stone", "Tumor"] def load_tensorflow_model(): tf_model = tf.keras.models.load_model("best_model.h5") return tf_model if st.session_state.framework =="TensorFlow": def predict_image(image): time.sleep(2) image = image.resize((224, 224)) image = np.expand_dims(image, axis=0) predictions = st.session_state.model.predict(image) return predictions if st.session_state.framework == "PyTorch": logo_path = "pytorch.png" bg_color = "#FF5733" # For example, a warm red/orange bg_color_iv = "orange" # For example, a warm red/orange model = "TENSORFLOW" def predict_image(image): # Preprocess the image to match the model input requirements transform = transforms.Compose([ transforms.Resize((224, 224)), transforms.ToTensor(), transforms.Normalize(mean=[0.485, 0.456, 0.406], std=[0.229, 0.224, 0.225]), # Standard VGG16 normalization ]) image = transform(image).unsqueeze(0) # Add batch dimension # Move image to the same device as the model (GPU or CPU) image = image # Set the model to evaluation mode st.session_state.model.eval() with torch.no_grad(): # Disable gradient calculation outputs = st.session_state.model(image) # Forward pass # Get predicted probabilities (softmax for multi-class) if outputs.shape[1] == 1: probs = torch.sigmoid(outputs) # Apply sigmoid activation for binary classification prob_class_1 = probs[0].item() # Probability for class 1 prob_class_0 = 1 - prob_class_1 # Probability for class 0 # If the output has two units (binary classification with softmax) else: probs = torch.nn.functional.softmax(outputs, dim=1) prob_class_0 = probs[0, 0].item() prob_class_1 = probs[0, 1].item() # Get the predicted class print("Raw model output (logits):", outputs) return prob_class_0, prob_class_1, probs else: logo_path = "tensorflow.png" bg_color = "orange" # For example, a warm red/orange bg_color_iv = "#FF5733" # For example, a warm red/orange model = "PYTORCH" #/*******************loading pytorch summary def get_layers_data(model, prefix=""): layers_data = [] for name, layer in model.named_children(): # Iterate over layers full_name = f"{prefix}.{name}" if prefix else name # Track hierarchy try: shape = str(list(layer.parameters())[0].shape) # Get shape of the first param except Exception: shape = "N/A" param_count = sum(p.numel() for p in layer.parameters()) # Count parameters layers_data.append((full_name, layer.__class__.__name__, shape, f"{param_count:,}")) # Recursively get layers inside this layer (for nested structures) layers_data.extend(get_layers_data(layer, full_name)) return layers_data ########################################### main_bg_ext = "png" main_bg = "bg1.jpg" # Read and encode the logo image with open(logo_path, "rb") as image_file: encoded_logo = base64.b64encode(image_file.read()).decode() # Custom CSS to style the logo above the sidebar st.markdown( f"""
Logo

KidneyScan AI

Empowering Early Diagnosis with AI
""", unsafe_allow_html=True, ) loading_html = """
""" # Sidebar content # Use radio buttons for navigation page = "pome" # Sidebar buttons # Display content based on the selected page # Define the page content dynamically if page == "Home": # components.html(html_string) # JavaScript works # st.markdown(html_string, unsafe_allow_html=True) image_path = "image.jpg" st.container() st.markdown( f"""

Kidney Disease Classfication
Using Transfer learning

This web application utilizes deep learning to classify kidney ultrasound images
into four categories: Normal, Cyst, Tumor, and Stone Class. Built with Streamlit and powered by
a TensorFlow transfer learning model based on VGG16 the app provides a simple and efficient way for users
to upload kidney scans and receive instant predictions. The model analyzes the image and classifies it based
on learned patterns, offering a confidence score for better interpretation.
""", unsafe_allow_html=True, ) uploaded_file = st.file_uploader( "Choose a file", type=["png", "jpg", "jpeg"], key="upload-btn" ) if uploaded_file is not None: images = Image.open(uploaded_file) # Rewind file pointer to the beginning uploaded_file.seek(0) file_content = uploaded_file.read() # Read file once # Convert to base64 for HTML display encoded_image = base64.b64encode(file_content).decode() # Read and process image pil_image = Image.open(uploaded_file).convert("RGB").resize((224, 224)) img_array = np.array(pil_image) prediction = predict_image(images) max_index = int(np.argmax(prediction[0])) print(f"max index:{max_index}") max_score = prediction[0][max_index] predicted_class = np.argmax(prediction[0]) highlight_class = "highlight" # Special class for the highest confidence score # Generate Grad-CAM cam = generate_gradcam(pil_image, predicted_class) # Create overlay heatmap = cm.jet(cam)[..., :3] heatmap = (heatmap * 255).astype(np.uint8) overlayed_image = cv2.addWeighted(img_array, 0.6, heatmap, 0.4, 0) # Convert to PIL overlayed_pil = Image.fromarray(overlayed_image) # Convert to base64 orig_b64 = convert_image_to_base64(pil_image) overlay_b64 = convert_image_to_base64(overlayed_pil) content = f"""
Uploaded Image

{class_labels[0]}

T Score: {prediction[0][0]:.2f}

{class_labels[1]}

T Score: {prediction[0][1]:.2f}

{class_labels[2]}

T Score: {prediction[0][2]:.2f}

{class_labels[3]}

T Score: {prediction[0][3]:.2f}

""" # Close the gallery and content div # Render the content placeholder = st.empty() # Create a placeholder placeholder.markdown(loading_html, unsafe_allow_html=True) time.sleep(5) # Wait for 5 seconds placeholder.empty() st.markdown(content, unsafe_allow_html=True) else: default_image_path = "image.jpg" with open(image_path, "rb") as image_file: encoded_image = base64.b64encode(image_file.read()).decode() st.markdown( f"""
Default Image
""", unsafe_allow_html=True, ) if page == "pome": gif_path = "bg3.gif" with open(gif_path, "rb") as image_file: encode_image = base64.b64encode(image_file.read()).decode() st.markdown( f"""
Default Image
""", unsafe_allow_html=True, ) col1, col2 = st.columns([1, 2]) # Adjust column widths with col1: if st.button("๐Ÿ“„ Model Summary"): st.session_state.menu ="1" # Store state st.rerun() # Add your model description logic here if st.button("๐Ÿ“Š Model Results Analysis",key="header"): st.session_state.menu ="2" st.rerun() # Add model analysis logic here if st.button("๐Ÿงช Model Testing"): st.session_state.menu ="3" st.rerun() # Toggle switch UI def framework_toggle(): toggle = st.toggle("Enable PyTorch", value=(st.session_state.framework == "PyTorch")) if toggle and st.session_state.framework != "PyTorch": st.session_state.framework = "PyTorch" st.session_state.model = torch.load('kidney_model .pth', map_location=torch.device('cpu')) st.rerun() elif not toggle and st.session_state.framework != "TensorFlow": st.session_state.framework = "TensorFlow" st.session_state.model = tf.keras.models.load_model( "best_model.h5" ) st.rerun() print(st.session_state.framework) framework_toggle() # Custom CSS for table styling table_style = """ """ with col2: if st.session_state.show_summary: layers_data = [] print(st.session_state) if st.session_state.framework == "TensorFlow": for layer in st.session_state.model.layers: try: shape = {layer.output.shape} except Exception: shape = "N/A" if isinstance(shape, tuple): shape = str(shape) elif isinstance(shape, list): shape = ", ".join(str(s) for s in shape) elif shape is None: shape = "N/A" param_count = f"{layer.count_params():,}" layers_data.append( (layer.name, layer.__class__.__name__, shape, param_count) ) print(layers_data) elif st.session_state.framework == "PyTorch": layers_data = get_layers_data(st.session_state.model) # Get layer information # Convert to HTML table table_html = "" for name, layer_type, shape, params in layers_data: table_html += f"" table_html += "
Layer NameTypeOutput ShapeParam #
{name}{layer_type}{shape}{params}
" # Render table with custom styling st.markdown(table_style + table_html, unsafe_allow_html=True) if st.session_state.show_arch: if st.session_state.framework == "TensorFlow": y_true = np.concatenate([y.numpy() for _, y in test_dataset]) # Get model predictions y_pred_probs = st.session_state.model.predict(test_dataset) y_pred = np.argmax(y_pred_probs, axis=1) # Convert one-hot true labels to class indices y_true = np.argmax(y_true, axis=1) # Class names (modify for your dataset) class_names = ["Cyst", "Normal", "Stone", "Tumor"] # Generate classification report as a dictionary report_dict = classification_report(y_true, y_pred, target_names=class_names, output_dict=True) # Convert to DataFrame report_df = pd.DataFrame(report_dict).transpose().round(2) accuracy = report_dict["accuracy"] precision = report_df.loc["weighted avg", "precision"] recall = report_df.loc["weighted avg", "recall"] f1_score = report_df.loc["weighted avg", "f1-score"] elif st.session_state.framework == "PyTorch": y_true = [] y_pred = [] for image, label in test_dataset: # test_dataset is an instance of ImageFolder or similar image = image.unsqueeze(0) # Add batch dimension and move to device label = label with torch.no_grad(): output = st.session_state.model(image) # Get model output _, predicted = torch.max(output, 1) # Get predicted class y_true.append(label) # Append true label y_pred.append(predicted.item()) # Append predicted label # Generate the classification report report_dict = classification_report(y_true, y_pred, target_names=class_names, output_dict=True) # Convert to DataFrame for better readability report_df = pd.DataFrame(report_dict).transpose().round(2) accuracy = report_dict["accuracy"] precision = report_df.loc["weighted avg", "precision"] recall = report_df.loc["weighted avg", "recall"] f1_score = report_df.loc["weighted avg", "f1-score"] st.markdown("""
Precision
""" + f"{precision:.2f}" + """
Recall
""" + f"{recall:.2f}" + """
Accuracy
""" + f"{accuracy:.2f}" + """
F1-Score
""" + f"{f1_score:.2f}" + """
""", unsafe_allow_html=True) # Remove last rows (accuracy/macro avg/weighted avg) and reset index report_df = report_df.iloc[:-3].reset_index() report_df.rename(columns={"index": "Class"}, inplace=True) # Custom CSS for Table Styling st.markdown(""" """, unsafe_allow_html=True) col1,col2 = st.columns([3,3]) with col1: # Convert DataFrame to HTML Table report_html = report_df.to_html(index=False, classes="report-table", escape=False) st.markdown(f'

classification report

{report_html}
', unsafe_allow_html=True) # Generate Confusion Matrix # Generate Confusion Matrix cm = confusion_matrix(y_true, y_pred) # Create Confusion Matrix Heatmap fig, ax = plt.subplots(figsize=(1, 1)) fig.patch.set_alpha(0) # Make figure background transparent # Seaborn Heatmap (Confusion Matrix) sns.heatmap(cm, annot=True, fmt="d", cmap="Blues", xticklabels=class_names, yticklabels=class_names, linewidths=1, linecolor="black", cbar=False, square=True, alpha=0.9, annot_kws={"size": 5, "family": "Times New Roman"}) # Change font for tick labels for text in ax.texts: text.set_bbox(dict(facecolor='none', edgecolor='none', alpha=0)) plt.xticks(fontsize=4, family="Times New Roman") # X-axis font plt.yticks(fontsize=4, family="Times New Roman") # Y-axis font # Enhance Labels and Title plt.title("Confusion Matrix", fontsize=5, family="Times New Roman",color="black", loc='center') # Apply transparent background and double border (via Streamlit Markdown) st.markdown(""" """, unsafe_allow_html=True) # Show Plot in Streamlit inside a styled container st.markdown('
', unsafe_allow_html=True) st.pyplot(fig) st.markdown("
", unsafe_allow_html=True) with col2: if st.session_state.framework == "TensorFlow": # Binarizing the true labels for multi-class classification y_true_bin = label_binarize(y_true, classes=np.arange(len(class_names))) # Calculating ROC curve and AUC for each class fpr, tpr, roc_auc = {}, {}, {} for i in range(len(class_names)): fpr[i], tpr[i], _ = roc_curve(y_true_bin[:, i], y_pred_probs[:, i]) roc_auc[i] = auc(fpr[i], tpr[i]) # Plotting ROC curve for each class plt.figure(figsize=(11, 9)) for i in range(len(class_names)): plt.plot(fpr[i], tpr[i], lw=2, label=f'{class_names[i]} (AUC = {roc_auc[i]:.2f})') # Plot random guess line plt.plot([0, 1], [0, 1], color='navy', lw=5, linestyle='--') # Labels and legend plt.xlim([0.0, 1.0]) plt.ylim([0.0, 1.05]) plt.xlabel('False Positive Rate',fontsize=28,family="Times New Roman") plt.ylabel('True Positive Rate',fontsize=28,family="Times New Roman") plt.title('ROC Curve (One-vs-Rest) for Each Class',fontsize=30, family="Times New Roman",color="black", loc='center',pad=3) plt.legend(loc='lower right',fontsize=18) # Save the plot as an image plt.savefig('roc_curve.png', transparent=True) plt.close() # Display the plot in Streamlit with st.container(key="roc"): st.image('roc_curve.png') elif st.session_state.framework == "PyTorch": # Display the ROC curve in Streamlit with st.container(key="roc"): st.image('roc-py.png') with st.container(key="precision"): st.image('precision_recall_curve.png') if st.session_state.show_desc: # components.html(html_string) # JavaScript works # st.markdown(html_string, unsafe_allow_html=True) image_path = "image.jpg" st.container() st.markdown( f"""

Kidney Disease Classfication
Using Deep learning

This web application utilizes deep learning to classify kidney ultrasound images
into four categories: Normal, Cyst, Tumor, and Stone Class. Built with Streamlit and powered by
a TensorFlow transfer learning model based on CNN the app provides a simple and efficient way for users
to upload kidney scans and receive instant predictions. The model analyzes the image and classifies it based
on learned patterns, offering a confidence score for better interpretation.
""", unsafe_allow_html=True, ) uploaded_file = st.file_uploader( "Choose a file", type=["png", "jpg", "jpeg"], key="upload-btn" ) if uploaded_file is not None: images = Image.open(uploaded_file) # Rewind file pointer to the beginning uploaded_file.seek(0) file_content = uploaded_file.read() # Read file once # Convert to base64 for HTML display encoded_image = base64.b64encode(file_content).decode() # Read and process image pil_image = Image.open(uploaded_file).convert("RGB").resize((224, 224)) img_array = np.array(pil_image) prediction = predict_image(images) if st.session_state.framework == "TensorFlow": max_index = int(np.argmax(prediction[0])) print(f"max index:{max_index}") max_score = prediction[0][max_index] predicted_class = np.argmax(prediction[0]) highlight_class = "highlight" # Special class for the highest confidence score # Generate Grad-CAM cam = generate_gradcam(pil_image, predicted_class) # Create overlay heatmap = cm.jet(cam)[..., :3] heatmap = (heatmap * 255).astype(np.uint8) overlayed_image = cv2.addWeighted(img_array, 0.6, heatmap, 0.4, 0) # Convert to PIL overlayed_pil = Image.fromarray(overlayed_image) # Convert to base64 orig_b64 = convert_image_to_base64(pil_image) overlay_b64 = convert_image_to_base64(overlayed_pil) content = f"""
Uploaded Image

{class_labels[0]}

T Score: {prediction[0][0]:.2f}

{class_labels[1]}

T Score: {prediction[0][1]:.2f}

{class_labels[2]}

T Score: {prediction[0][2]:.2f}

{class_labels[3]}

T Score: {prediction[0][3]:.2f}

""" elif st.session_state.framework == "PyTorch": class0, class1,prediction = predict_image(images) max_index = int(np.argmax(prediction[0])) print(f"max index:{max_index}") max_score = prediction[0][max_index] predicted_class = np.argmax(prediction[0]) print(f"predicted class is :{predicted_class}") #cams = generate_gradcams(pil_image, predicted_class) #heatmap = cm.jet(cams)[..., :3] #heatmap = (heatmap * 255).astype(np.uint8) #overlayed_image = cv2.addWeighted(img_array, 0.6, heatmap, 0.4, 0) # Convert to PIL #overlayed_pil = Image.fromarray(overlayed_image) # Convert to base64 orig_b64 = convert_image_to_base64(pil_image) #overlay_b64 = convert_image_to_base64(overlayed_pil) highlight_class = "highlight" # Special class for the highest confidence score # Generate Grad-CAM # Create overlay orig_b64 = convert_image_to_base64(pil_image) content = f"""
Uploaded Image

{class_labels[0]}

T Score: {prediction[0][0]:.2f}

{class_labels[1]}

T Score: {prediction[0][1]:.2f}

{class_labels[2]}

T Score: {prediction[0][2]:.2f}

{class_labels[3]}

T Score: {prediction[0][3]:.2f}

""" # Render the content placeholder = st.empty() # Create a placeholder placeholder.markdown(loading_html, unsafe_allow_html=True) time.sleep(5) # Wait for 5 seconds placeholder.empty() st.markdown(content, unsafe_allow_html=True) else: default_image_path = "image.jpg" with open(image_path, "rb") as image_file: encoded_image = base64.b64encode(image_file.read()).decode() st.markdown( f"""
Default Image
""", unsafe_allow_html=True, )