308 lines
15 KiB
Python
308 lines
15 KiB
Python
#!/usr/bin/env python
|
|
# coding: utf-8
|
|
|
|
# In[2]:
|
|
|
|
|
|
import streamlit as st
|
|
from PIL import Image
|
|
import numpy as np
|
|
import os
|
|
import pydicom as dicom
|
|
import io
|
|
import matplotlib.pyplot as plt
|
|
from Segment_Stack_without_gpu import SegBScan, SegShrinkBScan
|
|
|
|
|
|
# In[7]:
|
|
st.set_page_config(layout="wide")
|
|
|
|
def main():
|
|
selected_box = st.sidebar.selectbox(
|
|
'Choose one of the following',
|
|
('Welcome','LC-OCT image analysis')
|
|
)
|
|
|
|
if selected_box == 'Welcome':
|
|
welcome()
|
|
if selected_box == 'LC-OCT image analysis':
|
|
#selected_radio = st.sidebar.radio("Select analysis:", ["Visualisation", "Segmentation"])
|
|
#if selected_radio == "Visualisation":
|
|
lcoct()
|
|
|
|
|
|
|
|
|
|
def welcome():
|
|
|
|
st.title('3D Stack LCOCT images Visualisation and Processing')
|
|
|
|
|
|
st.subheader("This app is designed to swiftly visualize and analyze LCOCT images, specifically focusing on segmentation."
|
|
+ " The application is currently in deployment, and additional tools will be incorporated in the future.")
|
|
|
|
st.image('LCOCT_Stack.png',use_column_width=True)
|
|
|
|
|
|
def lcoct():
|
|
|
|
st.title('Visualisation')
|
|
allowed_extensions = ["dcm"]
|
|
uploaded_files = st.file_uploader("Choose LCOCT files", type=allowed_extensions, accept_multiple_files=True)
|
|
#file_contents = uploaded_file.read()
|
|
|
|
# Display the contents
|
|
count = 0
|
|
if uploaded_files:
|
|
st.text("Uploaded LCOCT data:")
|
|
for i, file in enumerate(uploaded_files):
|
|
file_size = len(file.read())
|
|
#if (file_size//1024)>2000 :
|
|
st.text(f"{i}, {file.name}")
|
|
count+=1
|
|
#st.text(file_size)
|
|
if uploaded_files:
|
|
stack = st.slider('Which stack do you whant to visualize?', 0, count, 0)
|
|
st.write("Current Selected Stack: ", stack)
|
|
|
|
if uploaded_files:
|
|
selected_file = uploaded_files[stack]
|
|
data = dicom.dcmread(io.BytesIO(selected_file.getvalue())).pixel_array
|
|
if data.ndim == 3 :
|
|
data = data
|
|
else :
|
|
data = np.transpose(data[np.newaxis,...], (1,0,2))
|
|
selected_slice = st.slider("Select Slice", 0, data.shape[1] - 1, 0)
|
|
selected_image_slice = data[:, selected_slice, :]
|
|
st.image(selected_image_slice, caption=f"Slice {selected_slice}", use_column_width=True)
|
|
|
|
|
|
save_directory1 = st.text_input("Enter the download directory path:", key="file_uploader1")
|
|
# Button to save the current slice
|
|
if st.button("Save Slice", key="save_button1"):
|
|
#save_directory1 = st.file_uploader("Choose a directory to save the slice", type=["directory"], key="file_uploader1")
|
|
# Check if the directory is selected
|
|
if save_directory1 is not None:
|
|
# Get the selected directory path
|
|
directory_path = os.path.abspath(save_directory1)
|
|
|
|
# Create the directory if it doesn't exist
|
|
os.makedirs(directory_path, exist_ok=True)
|
|
|
|
# Save the slice as an image using matplotlib with a custom filename and selected directory
|
|
filename = f"dicom_slice_{selected_slice}.png"
|
|
full_path = os.path.join(directory_path, filename)
|
|
plt.imsave(full_path, selected_image_slice, cmap='gray')
|
|
st.success(f"Slice {selected_slice} saved successfully.")
|
|
else:
|
|
st.warning("Please choose a directory to save the image.")
|
|
#if st.button("Save Slice"):
|
|
# plt.imsave(f"lcoct_slice_{selected_slice}.png", selected_image_slice, cmap='gray')
|
|
# st.success(f"Slice {selected_slice} saved successfully.")
|
|
if uploaded_files:
|
|
selected_file = uploaded_files[stack]
|
|
data = dicom.dcmread(io.BytesIO(selected_file.getvalue())).pixel_array
|
|
if data.ndim == 3 :
|
|
data = data
|
|
else :
|
|
data = np.transpose(data[np.newaxis,...], (1,0,2))
|
|
selected_slice = st.slider("Select Slice", 0, data.shape[0] - 1, 0)
|
|
selected_image_slice = data[selected_slice, :, :]
|
|
st.image(selected_image_slice, caption=f"Slice {selected_slice}", use_column_width=True)
|
|
|
|
#save_directory2 = st.file_uploader("Choose a directory to save the slice", type=["directory"], key="file_uploader2")
|
|
save_directory2 = st.text_input("Enter the download directory path:", key="file_uploader2")
|
|
|
|
# Button to save the current slice
|
|
if st.button("Save Slice", key="save_button2"):
|
|
# Check if the directory is selected
|
|
if save_directory2 is not None:
|
|
# Get the selected directory path
|
|
directory_path = os.path.abspath(save_directory2)
|
|
|
|
# Create the directory if it doesn't exist
|
|
os.makedirs(directory_path, exist_ok=True)
|
|
|
|
# Save the slice as an image using matplotlib with a custom filename and selected directory
|
|
filename = f"dicom_slice_{selected_slice}.png"
|
|
full_path = os.path.join(directory_path, filename)
|
|
plt.imsave(full_path, selected_image_slice, cmap='gray')
|
|
st.success(f"Slice {selected_slice} saved successfully.")
|
|
else:
|
|
st.warning("Please choose a directory to save the image.")
|
|
|
|
if uploaded_files:
|
|
selected_file = uploaded_files[stack]
|
|
data = dicom.dcmread(io.BytesIO(selected_file.getvalue())).pixel_array
|
|
if data.ndim == 3 :
|
|
data = data
|
|
else :
|
|
data = np.transpose(data[np.newaxis,...], (1,0,2))
|
|
selected_slice = st.slider("Select Slice", 0, data.shape[2] - 1, 0)
|
|
selected_image_slice = data[:, :, selected_slice]
|
|
st.image(selected_image_slice, caption=f"Slice {selected_slice}", use_column_width=True)
|
|
|
|
#save_directory3 = st.file_uploader("Choose a directory to save the slice", type=["directory"], key="file_uploader3")
|
|
save_directory3 = st.text_input("Enter the download directory path:", key="file_uploader3")
|
|
|
|
# Button to save the current slice
|
|
if st.button("Save Slice", key="save_button3"):
|
|
# Check if the directory is selected
|
|
if save_directory3 is not None:
|
|
# Get the selected directory path
|
|
directory_path = os.path.abspath(save_directory3)
|
|
|
|
# Create the directory if it doesn't exist
|
|
os.makedirs(directory_path, exist_ok=True)
|
|
|
|
# Save the slice as an image using matplotlib with a custom filename and selected directory
|
|
filename = f"dicom_slice_{selected_slice}.png"
|
|
full_path = os.path.join(directory_path, filename)
|
|
plt.imsave(full_path, selected_image_slice, cmap='gray')
|
|
st.success(f"Slice {selected_slice} saved successfully.")
|
|
else:
|
|
st.warning("Please choose a directory to save the image.")
|
|
|
|
##################################Segmentation########################################
|
|
st.title('Segmentation of Stratum Corneum')
|
|
st.write("This will take a few minitues ")
|
|
@st.cache_data
|
|
def segmentation(data1, remove1, disk1) :
|
|
#if uploaded_files:
|
|
result = SegBScan(data1, remove_num=remove1, disk_num=disk1)
|
|
contours1, denoised_med1, epaiss1 = result.return_im_cont()
|
|
epaiss1mean = result.sc_shrink()
|
|
epaiss1std = result.image_std()
|
|
return contours1, denoised_med1, epaiss1, epaiss1mean, epaiss1std
|
|
@st.cache_data
|
|
def segmentation1(data2, remove2, disk2):
|
|
#if uploaded_files:
|
|
result2 = SegShrinkBScan(data2, remove_num=remove2, disk_num=disk2)
|
|
contours2, denoised_med2, epaiss2 = result2.return_im_cont()
|
|
epaiss2mean = result2.sc_shrink()
|
|
epaiss2std = result2.image_std()
|
|
return contours2, denoised_med2, epaiss2, epaiss2mean, epaiss2std
|
|
|
|
@st.cache_data
|
|
def segmentation2(data1, disk1, disk2, octagon1, octagon2) :
|
|
#if uploaded_files:
|
|
result = SegBScan(data1, disk_num1 = disk1, disk_num2 = disk2, octagon_num1 = octagon1, octagon_num2 = octagon2)
|
|
contours1, denoised_med1, epaiss1 = result.return_im_cont()
|
|
epaiss1mean = result.sc_shrink()
|
|
epaiss1std = result.image_std()
|
|
return contours1, denoised_med1, epaiss1, epaiss1mean, epaiss1std
|
|
@st.cache_data
|
|
def segmentation3(data2, disk1, disk2, octagon1, octagon2):
|
|
#if uploaded_files:
|
|
result2 = SegShrinkBScan(data2, disk_num1 = disk1, disk_num2 = disk2, octagon_num1 = octagon1, octagon_num2 = octagon2)
|
|
contours2, denoised_med2, epaiss2 = result2.return_im_cont()
|
|
epaiss2mean = result2.sc_shrink()
|
|
epaiss2std = result2.image_std()
|
|
return contours2, denoised_med2, epaiss2, epaiss2mean, epaiss2std
|
|
|
|
selected_box = st.sidebar.selectbox(
|
|
'Choose one of the following postprocessing',
|
|
('1st way','2nd way')
|
|
)
|
|
|
|
if selected_box == '2nd way':
|
|
st.text("This postprocessing uses morphology.remove_small_objects followed by morphology.dilatation")
|
|
|
|
|
|
|
|
if uploaded_files:
|
|
selected_remove = st.slider("Select the smallest allowable object size. Choosing a value will rerun the whole segmentation", 0, 500, 50, key='remove')
|
|
selected_disk = st.slider("Select the radius of the disk-shaped footprint. Choosing a value will rerun the whole segmentation", 0, 10, 3, key='disk')
|
|
|
|
contours, denoised_med, epaiss, epaiss_mean, epaiss_std = segmentation(data,selected_remove, selected_disk)
|
|
denoised_med_get = denoised_med.copy()
|
|
selected_slice = st.slider("Select Slice", 0, denoised_med.shape[1] - 1, 0)
|
|
|
|
selected_image_slice = denoised_med_get[:, selected_slice,:]
|
|
#st.image(selected_image_slice, caption=f"Slice {selected_slice}", use_column_width=True)
|
|
fig, ax = plt.subplots()
|
|
ax.imshow(selected_image_slice, cmap='gray')
|
|
ax.set_title(f"Slice N°{selected_slice} ; Epaisseur du Stratum Corneum : {np.round(epaiss[selected_slice],3)}µm, (Epaisseur du stack {np.round(epaiss_mean,3)}µm +/- {np.round(epaiss_std,3)})", fontsize=6)
|
|
ax.axis('off')
|
|
for i in contours[selected_slice] :
|
|
if (len(i)> 200):
|
|
ax.plot(i[:,1],i[:,0])
|
|
st.pyplot(fig)
|
|
|
|
if uploaded_files:
|
|
selected_remove = st.slider("Select the smallest allowable object size. Choosing a value will rerun the whole segmentation", 0, 500, 50, key='remove2')
|
|
selected_disk = st.slider("Select the radius of the disk-shaped footprint. Choosing a value will rerun the whole segmentation", 0, 10, 2, key='disk2')
|
|
contours1, denoised_med1, epaiss1, epaiss_mean1, epaiss_std1 = segmentation1(data, selected_remove, selected_disk)
|
|
denoised_med_get1 = denoised_med1.copy()
|
|
selected_slice = st.slider("Select Slice", 0, denoised_med1.shape[2] - 1, 0, key =6)
|
|
selected_image_slice = denoised_med_get1[:, :,selected_slice]
|
|
#st.image(selected_image_slice, caption=f"Slice {selected_slice}", use_column_width=True)
|
|
fig, ax = plt.subplots()
|
|
ax.imshow(selected_image_slice, cmap='gray')
|
|
ax.set_title(f"Slice N°{selected_slice} ; Epaisseur du Stratum Corneum : {np.round(epaiss1[selected_slice],3)}µm, (Epaisseur du stack {np.round(epaiss_mean1,3)}µm +/- {np.round(epaiss_std1,3)})", fontsize=6)
|
|
ax.axis('off')
|
|
for i in contours1[selected_slice] :
|
|
if (len(i)> 200):
|
|
ax.plot(i[:,1],i[:,0])
|
|
st.pyplot(fig)
|
|
|
|
|
|
|
|
if selected_box == '1st way':
|
|
st.text("This postprocessing uses morphology.erosion followed by dilation and binary.closing")
|
|
|
|
|
|
|
|
if uploaded_files:
|
|
selected_disk11 = st.slider("Select the radius of the disk-shaped footprint. Choosing a value will rerun the whole segmentation", 0, 10, 3, key='disk11')
|
|
selected_disk12 = st.slider("Select the radius of the disk-shaped footprint. Choosing a value will rerun the whole segmentation", 0, 20, 0, key='disk12')
|
|
st.text("Generates an octagon shaped footprint")
|
|
selected_octagon1 = st.slider("The size of the horizontal and vertical sides. Choosing a value will rerun the whole segmentation", 0, 5, 0, key='octagon1')
|
|
selected_octagon2 = st.slider("The height or width of the slanted sides. Choosing a value will rerun the whole segmentation", 0, 5, 1, key='octagon2')
|
|
|
|
contours, denoised_med, epaiss, epaiss_mean, epaiss_std = segmentation2(data,selected_disk11, selected_disk12, selected_octagon1, selected_octagon2)
|
|
denoised_med_get = denoised_med.copy()
|
|
selected_slice = st.slider("Select Slice", 0, denoised_med.shape[1] - 1, 0)
|
|
|
|
selected_image_slice = denoised_med_get[:, selected_slice,:]
|
|
#st.image(selected_image_slice, caption=f"Slice {selected_slice}", use_column_width=True)
|
|
fig, ax = plt.subplots()
|
|
ax.imshow(selected_image_slice, cmap='gray')
|
|
ax.set_title(f"Slice N°{selected_slice} ; Epaisseur du Stratum Corneum : {np.round(epaiss[selected_slice],3)}µm, (Epaisseur du stack {np.round(epaiss_mean,3)}µm +/- {np.round(epaiss_std,3)})", fontsize=6)
|
|
ax.axis('off')
|
|
for i in contours[selected_slice] :
|
|
if (len(i)> 500):
|
|
ax.plot(i[:,1],i[:,0])
|
|
st.pyplot(fig)
|
|
|
|
if uploaded_files:
|
|
selected_disk11 = st.slider("Select the radius of the disk-shaped footprint. Choosing a value will rerun the whole segmentation", 0, 10, 3, key='disk13')
|
|
selected_disk12 = st.slider("Select the radius of the disk-shaped footprint. Choosing a value will rerun the whole segmentation", 0, 20, 0, key='disk14')
|
|
st.text("Generates an octagon shaped footprint")
|
|
selected_octagon1 = st.slider("The size of the horizontal and vertical sides. Choosing a value will rerun the whole segmentation", 0, 5, 0, key='octagon3')
|
|
selected_octagon2 = st.slider("The height or width of the slanted sides. Choosing a value will rerun the whole segmentation", 0, 5, 1, key='octagon4')
|
|
|
|
contours1, denoised_med1, epaiss1, epaiss_mean1, epaiss_std1 = segmentation3(data,selected_disk11, selected_disk12, selected_octagon1, selected_octagon2)
|
|
denoised_med_get1 = denoised_med1.copy()
|
|
selected_slice = st.slider("Select Slice", 0, denoised_med1.shape[2] - 1, 0, key =6)
|
|
selected_image_slice = denoised_med_get1[:, :,selected_slice]
|
|
#st.image(selected_image_slice, caption=f"Slice {selected_slice}", use_column_width=True)
|
|
fig, ax = plt.subplots()
|
|
ax.imshow(selected_image_slice, cmap='gray')
|
|
ax.set_title(f"Slice N°{selected_slice} ; Epaisseur du Stratum Corneum : {np.round(epaiss1[selected_slice],3)}µm, (Epaisseur du stack {np.round(epaiss_mean1,3)}µm +/- {np.round(epaiss_std1,3)})", fontsize=6)
|
|
ax.axis('off')
|
|
for i in contours1[selected_slice] :
|
|
if (len(i)> 200):
|
|
ax.plot(i[:,1],i[:,0])
|
|
st.pyplot(fig)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
if __name__ == "__main__":
|
|
main()
|
|
|
|
|