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, | |
| ) | |