Spaces:
Sleeping
Sleeping
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 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 | |
if "model" not in st.session_state: | |
st.session_state.model = tf_model = tf.keras.models.load_model('best_model.h5') | |
import base64 | |
import os | |
#****************************************/ | |
# GRAD CAM | |
#*********************************************# | |
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 | |
def convert_image_to_base64(pil_image): | |
buffered = BytesIO() | |
pil_image.save(buffered, format="PNG") | |
return base64.b64encode(buffered.getvalue()).decode() | |
#--------------------------------------------------# | |
class_labels=[ 'Cyst', 'Normal','Stone', 'Tumor'] | |
def load_tensorflow_model(): | |
tf_model = tf.keras.models.load_model('best_model.h5') | |
return tf_model | |
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 | |
logo_path = "tensorflow.png" | |
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""" | |
<style> | |
/* Container for logo and text */ | |
.logo-text-container {{ | |
position: fixed; | |
top: 20px; /* Adjust vertical position */ | |
left: 30px; /* Align with sidebar */ | |
display: flex; | |
align-items: center; | |
gap: 5px; | |
width: 70%; | |
z-index:1000; | |
}} | |
/* Logo styling */ | |
.logo-text-container img {{ | |
width: 50px; /* Adjust logo size */ | |
border-radius: 10px; /* Optional: round edges */ | |
margin-top:-10px; | |
margin-left:-5px; | |
}} | |
/* Bold text styling */ | |
.logo-text-container h1 {{ | |
font-family: Nunito; | |
color: #0175C2; | |
font-size: 28px; | |
font-weight: bold; | |
margin-right :100px; | |
padding:0px; | |
}} | |
.logo-text-container i{{ | |
font-family: Nunito; | |
color: orange; | |
font-size: 15px; | |
margin-right :10px; | |
padding:0px; | |
margin-left:-18.5%; | |
margin-top:1%; | |
}} | |
/* Sidebar styling */ | |
section[data-testid="stSidebar"][aria-expanded="true"] {{ | |
margin-top: 100px !important; /* Space for the logo */ | |
border-radius: 0 60px 0px 60px !important; /* Top-left and bottom-right corners */ | |
width: 200px !important; /* Sidebar width */ | |
background:none; /* Gradient background */ | |
/* box-shadow: 0px 4px 8px rgba(0, 0, 0, 0.2); /* Shadow effect */ | |
/* border: 1px solid #FFD700; /* Shiny golden border */ | |
margin-bottom: 1px !important; | |
color:white !important; | |
}} | |
header[data-testid="stHeader"] {{ | |
/*background: transparent !important;*/ | |
background: white; | |
/*margin-right: 10px !important;*/ | |
margin-top: 0.5px !important; | |
z-index: 1 !important; | |
color: orange; /* White text */ | |
font-family: "Times New Roman " !important; /* Font */ | |
font-size: 18px !important; /* Font size */ | |
font-weight: bold !important; /* Bold text */ | |
padding: 10px 20px; /* Padding for buttons */ | |
border: none; /* Remove border */ | |
border-radius: 1px; /* Rounded corners */ | |
box-shadow: 0px 4px 10px rgba(0, 0, 0, 0.2); /* Shadow effect */ | |
transition: all 0.3s ease-in-out; /* Smooth transition */ | |
align-items: left; | |
justify-content: center; | |
/*margin: 10px 0;*/ | |
width:100%; | |
height:80px; | |
backdrop-filter: blur(10px); | |
border: 2px solid rgba(255, 255, 255, 0.4); /* Light border */ | |
}} | |
div[data-testid="stDecoration"]{{ | |
background-image:none; | |
}} | |
div[data-testid="stApp"]{{ | |
/*background: grey;*/ | |
background: rgba(255, 255, 255, 0.5); /* Semi-transparent white background */ | |
height: 100vh; /* Full viewport height */ | |
width: 99.5%; | |
border-radius: 2px !important; | |
margin-left:5px; | |
margin-right:5px; | |
margin-top:0px; | |
/* box-shadow: 0px 4px 10px rgba(0, 0, 0, 0.2); /* Shadow effect */ | |
background: url(data:image/{main_bg_ext};base64,{base64.b64encode(open(main_bg, "rb").read()).decode()}); | |
background-size: cover; /* Ensure the image covers the full page */ | |
background-position: center; | |
overflow: hidden; | |
}} | |
.content-container {{ | |
background-color: rgba(173, 216, 230, 0.5); /* Light blue with 50% transparency */ | |
backdrop-filter: blur(10px); /* Adds a slight blur effect */ border-radius: 1px; | |
width: 28%; | |
margin-left: 150px; | |
/* margin-top: -60px;*/ | |
margin-bottom: 10px; | |
margin-right:10px; | |
padding:0; | |
/* border-radius:0px 0px 15px 15px ;*/ | |
border:1px solid transparent; | |
overflow-y: auto; /* Enable vertical scrolling for the content */ | |
position: fixed; /* Fix the position of the container */ | |
top: 10%; /* Adjust top offset */ | |
left: 60%; /* Adjust left offset */ | |
height: 89.5vh; /* Full viewport height */ | |
}} | |
.content-container2 {{ | |
background-color: rgba(0, 0, 0, 0.1); /* Light blue with 50% transparency */ | |
backdrop-filter: blur(10px); /* Adds a slight blur effect */ border-radius: 1px; | |
width: 90%; | |
margin-left: 10px; | |
/* margin-top: -10px;*/ | |
margin-bottom: 160px; | |
margin-right:10px; | |
padding:0; | |
border-radius:1px ; | |
border:1px solid transparent; | |
overflow-y: auto; /* Enable vertical scrolling for the content */ | |
position: fixed; /* Fix the position of the container */ | |
top: 3%; /* Adjust top offset */ | |
left: 2.5%; /* Adjust left offset */ | |
height: 78vh; /* Full viewport height */ | |
}} | |
.content-container4 {{ | |
background-color: rgba(0, 0, 0, 0.1); /* Light blue with 50% transparency */ | |
backdrop-filter: blur(10px); /* Adds a slight blur effect */ width: 40%; | |
margin-left: 10px; | |
margin-bottom: 160px; | |
margin-right:10px; | |
padding:0; | |
overflow-y: auto; /* Enable vertical scrolling for the content */ | |
position: fixed; /* Fix the position of the container */ | |
top: 60%; /* Adjust top offset */ | |
left: 2.5%; /* Adjust left offset */ | |
height: 10vh; /* Full viewport height */ | |
}} | |
.content-container4 h3 ,p {{ | |
font-family: "Times New Roman" !important; /* Elegant font for title */ | |
font-size: 1rem; | |
font-weight: bold; | |
text-align:center; | |
}} | |
.content-container5 h3 ,p {{ | |
font-family: "Times New Roman" !important; /* Elegant font for title */ | |
font-size: 1rem; | |
font-weight: bold; | |
text-align:center; | |
}} | |
.content-container6 h3 ,p {{ | |
font-family: "Times New Roman" !important; /* Elegant font for title */ | |
font-size: 1rem; | |
font-weight: bold; | |
text-align:center; | |
}} | |
.content-container7 h3 ,p {{ | |
font-family: "Times New Roman" !important; /* Elegant font for title */ | |
font-size: 1rem; | |
font-weight: bold; | |
text-align:center; | |
}} | |
.content-container5 {{ | |
background-color: rgba(0, 0, 0, 0.1); /* Light blue with 50% transparency */ | |
backdrop-filter: blur(10px); /* Adds a slight blur effect */ width: 40%; | |
margin-left: 180px; | |
margin-bottom: 130px; | |
margin-right:10px; | |
padding:0; | |
overflow-y: auto; /* Enable vertical scrolling for the content */ | |
position: fixed; /* Fix the position of the container */ | |
top: 60%; /* Adjust top offset */ | |
left: 5.5%; /* Adjust left offset */ | |
height: 10vh; /* Full viewport height */ | |
}} | |
.content-container3 {{ | |
background-color: rgba(216, 216, 230, 0.5); /* Light blue with 50% transparency */ | |
backdrop-filter: blur(10px); /* Adds a slight blur effect */ border-radius: 1px; | |
width: 92%; | |
margin-left: 10px; | |
/* margin-top: -10px;*/ | |
margin-bottom: 160px; | |
margin-right:10px; | |
padding:0; | |
border: 10px solid white; | |
overflow-y: auto; /* Enable vertical scrolling for the content */ | |
position: fixed; /* Fix the position of the container */ | |
top: 3%; /* Adjust top offset */ | |
left: 1.5%; /* Adjust left offset */ | |
height: 40vh; /* Full viewport height */ | |
}} | |
.content-container6 {{ | |
background-color: rgba(0, 0, 0, 0.1); /* Light blue with 50% transparency */ | |
backdrop-filter: blur(10px); /* Adds a slight blur effect */ width: 40%; | |
margin-left: 10px; | |
margin-bottom: 160px; | |
margin-right:10px; | |
padding:0; | |
overflow-y: auto; /* Enable vertical scrolling for the content */ | |
position: fixed; /* Fix the position of the container */ | |
top: 80%; /* Adjust top offset */ | |
left: 2.5%; /* Adjust left offset */ | |
height: 10vh; /* Full viewport height */ | |
}} | |
.content-container7 {{ | |
background-color: rgba(0, 0, 0, 0.1); /* Light blue with 50% transparency */ | |
backdrop-filter: blur(10px); /* Adds a slight blur effect */ width: 40%; | |
margin-left: 180px; | |
margin-bottom: 130px; | |
margin-right:10px; | |
padding:0; | |
overflow-y: auto; /* Enable vertical scrolling for the content */ | |
position: fixed; /* Fix the position of the container */ | |
top: 80%; /* Adjust top offset */ | |
left: 5.5%; /* Adjust left offset */ | |
height: 10vh; /* Full viewport height */ | |
}} | |
.content-container2 img {{ | |
width:99%; | |
height:50%; | |
}} | |
.content-container3 img {{ | |
width:100%; | |
height:100%; | |
}} | |
div.stButton > button {{ | |
background: rgba(255, 255, 255, 0.2); | |
color: blue; /* White text */ | |
font-family: "Times New Roman " !important; /* Font */ | |
font-size: 18px !important; /* Font size */ | |
font-weight: bold !important; /* Bold text */ | |
padding: 10px 20px; /* Padding for buttons */ | |
border: none; /* Remove border */ | |
border-radius: 15px; /* Rounded corners */ | |
box-shadow: 0px 4px 10px rgba(0, 0, 0, 0.2); /* Shadow effect */ | |
transition: all 0.3s ease-in-out; /* Smooth transition */ | |
display: flex; | |
align-items: center; | |
justify-content: center; | |
margin: 10px 0; | |
width:170px; | |
height:60px; | |
backdrop-filter: blur(10px); | |
}} | |
/* Hover effect */ | |
div.stButton > button:hover {{ | |
background: rgba(255, 255, 255, 0.2); | |
box-shadow: 0px 6px 12px rgba(0, 0, 0, 0.4); /* Enhanced shadow on hover */ | |
transform: scale(1.05); /* Slightly enlarge button */ | |
transform: scale(1.1); /* Slight zoom on hover */ | |
box-shadow: 0px 4px 12px rgba(255, 255, 255, 0.4); /* Glow effect */ | |
}} | |
.titles{{ | |
margin-top:50px !important; | |
}} | |
/* Title styling */ | |
.titles h1{{ | |
/*font-family: "Times New Roman" !important; /* Elegant font for title */ | |
/* font-size: 2.9rem;*/ | |
/*font-weight: bold;*/ | |
margin-left: 5px; | |
/* margin-top:-50px;*/ | |
margin-bottom:50px; | |
padding: 0; | |
color: black; /* Neutral color for text */ | |
}} | |
.titles > div{{ | |
font-family: "Times New Roman" !important; /* Elegant font for title */ | |
font-size: 1.2rem; | |
margin-left: 5px; | |
margin-bottom:1px; | |
padding: 0; | |
color:black; /* Neutral color for text */ | |
}} | |
/* Recently viewed section */ | |
.recently-viewed {{ | |
display: flex; | |
align-items: center; | |
justify-content: flex-start; /* Align items to the extreme left */ | |
margin-bottom: 10px; | |
margin-top: 20px; | |
gap: 10px; /* Add spacing between the elements */ | |
padding-left: 20px; /* Add some padding if needed */ | |
margin-left:35px; | |
height:100px; | |
}} | |
/* Style for the upload button */ | |
[class*="st-key-upload-btn"] {{ | |
position: absolute; | |
top: 100%; /* Position from the top of the inner circle */ | |
left: -3%; /* Position horizontally at the center */ | |
padding: 10px 20px; | |
color: red; | |
border: none; | |
border-radius: 20px; | |
cursor: pointer; | |
font-size: 35px !important; | |
width:30px; | |
height:20px; | |
}} | |
.upload-btn:hover {{ | |
background-color: rgba(0, 123, 255, 1); | |
}} | |
div[data-testid="stFileUploader"] label > div > p {{ | |
display:none; | |
color:white !important; | |
}} | |
section[data-testid="stFileUploaderDropzone"] {{ | |
width:200px; | |
height: 60px; | |
background-color: white; | |
border-radius: 40px; | |
display: flex; | |
justify-content: center; | |
align-items: center; | |
margin-top:-10px; | |
box-shadow: 0px 4px 8px rgba(0, 0, 0, 0.3); | |
margin:20px; | |
background-color: rgba(255, 255, 255, 0.7); /* Transparent blue background */ | |
color:white; | |
}} | |
div[data-testid="stFileUploaderDropzoneInstructions"] div > small{{ | |
color:white !important; | |
display:none; | |
}} | |
div[data-testid="stFileUploaderDropzoneInstructions"] span{{ | |
margin-left:65px; | |
color:orange; | |
}} | |
div[data-testid="stFileUploaderDropzoneInstructions"] div{{ | |
display:none; | |
}} | |
section[data-testid="stFileUploaderDropzone"] button{{ | |
display:none; | |
}} | |
div[data-testid="stMarkdownContainer"] p {{ | |
font-family: "Times New Roman" !important; /* Elegant font for title */ | |
color:white !important; | |
}} | |
.highlight {{ | |
border: 4px solid lime; | |
font-weight: bold; | |
background: radial-gradient(circle, rgba(0,255,0,0.3) 0%, rgba(0,0,0,0) 70%); | |
box-shadow: 0px 0px 30px 10px rgba(0, 255, 0, 0.9), | |
0px 0px 60px 20px rgba(0, 255, 0, 0.6), | |
inset 0px 0px 15px rgba(0, 255, 0, 0.8); | |
transition: all 0.3s ease-in-out; | |
}} | |
.highlight:hover {{ | |
transform: scale(1.05); | |
background: radial-gradient(circle, rgba(0,255,0,0.6) 0%, rgba(0,0,0,0) 80%); | |
box-shadow: 0px 0px 40px 15px rgba(0, 255, 0, 1), | |
0px 0px 70px 30px rgba(0, 255, 0, 0.7), | |
inset 0px 0px 20px rgba(0, 255, 0, 1); | |
}} | |
</style> | |
<div class="logo-text-container"> | |
<img src="data:image/png;base64,{encoded_logo}" alt="Logo"> | |
<h1>KidneyScan AI<br> | |
</h1> | |
<i>Empowering Early Diagnosis with AI</ai> | |
</div> | |
""", unsafe_allow_html=True | |
) | |
loading_html = """ | |
<style> | |
.loader { | |
border: 8px solid #f3f3f3; | |
border-top: 8px solid #0175C2; /* Blue color */ | |
border-radius: 50%; | |
width: 50px; | |
height: 50px; | |
animation: spin 1s linear infinite; | |
margin: auto; | |
} | |
@keyframes spin { | |
0% { transform: rotate(0deg); } | |
100% { transform: rotate(360deg); } | |
} | |
</style> | |
<div class="loader"></div> | |
""" | |
page = "Home" | |
# 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""" | |
<div class="titles"> | |
<h1>Kidney Disease Classfication</br> Using Transfer learning</h1> | |
<div> This web application utilizes deep learning to classify kidney ultrasound images</br> | |
into four categories: Normal, Cyst, Tumor, and Stone Class. | |
Built with Streamlit and powered by </br>a TensorFlow transfer learning | |
model based on <strong>VGG16</strong> | |
the app provides a simple and efficient way for users </br> | |
to upload kidney scans and receive instant predictions. The model analyzes the image | |
and classifies it based </br>on learned patterns, offering a confidence score for better interpretation. | |
</div> | |
</div> | |
""", | |
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""" | |
<div class="content-container"> | |
<!-- Title --> | |
<!-- Recently Viewed Section --> | |
<div class="content-container2"> | |
<div class="content-container3"> | |
<img src="data:image/png;base64,{orig_b64}" alt="Uploaded Image"> | |
</div> | |
<div class="content-container3"> | |
<img src="data:image/png;base64,{overlay_b64}" class="result-image"> | |
</div> | |
<div class="content-container4 {'highlight' if max_index == 0 else ''}"> | |
<h3>{class_labels[0]}</h3> | |
<p>T Score: {prediction[0][0]:.2f}</p> | |
</div> | |
<div class="content-container5 {'highlight' if max_index == 1 else ''}"> | |
<h3> {class_labels[1]}</h3> | |
<p>T Score: {prediction[0][1]:.2f}</p> | |
</div> | |
<div class="content-container6 {'highlight' if max_index == 2 else ''}"> | |
<h3> {class_labels[2]}</h3> | |
<p>T Score: {prediction[0][2]:.2f}</p> | |
</div> | |
<div class="content-container7 {'highlight' if max_index == 3 else ''}"> | |
<h3>{class_labels[3]}</h3> | |
<p>T Score: {prediction[0][3]:.2f}</p> | |
</div> | |
""" | |
# 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""" | |
<div class="content-container"> | |
<!-- Title --> | |
<!-- Recently Viewed Section --> | |
<div class="content-container2"> | |
<div class="content-container3"> | |
<img src="data:image/png;base64,{encoded_image}" alt="Default Image"> | |
</div> | |
</div> | |
""", | |
unsafe_allow_html=True, | |
) | |