-
Notifications
You must be signed in to change notification settings - Fork 0
/
PyElispotAnalysis_StreamlitApp.py
184 lines (125 loc) · 7.06 KB
/
PyElispotAnalysis_StreamlitApp.py
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
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
#!/usr/bin/env python3
# encoding: utf-8
#
# Copyright (C) 2022 Max Planck Institute for Multidisclplinary Sciences
# Copyright (C) 2022 University Medical Center Goettingen
# Copyright (C) 2022 Ajinkya Kulkarni <[email protected]>
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU Affero General Public License as
# published by the Free Software Foundation, either version 3 of the
# License, or (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU Affero General Public License for more details.
#
# You should have received a copy of the GNU Affero General Public License
# along with this program. If not, see <https://www.gnu.org/licenses/>.
##########################################################################
import streamlit as st
from io import BytesIO
from cv2 import MORPH_OPEN, morphologyEx, resize
import numpy as np
from skimage.measure import label
import sys
# Don't generate the __pycache__ folder locally
sys.dont_write_bytecode = True
# Print exception without the buit-in python warning
sys.tracebacklimit = 0
##########################################################################
from modules import *
allowed_image_size = 1000 # Only images with sizes less than 1000x1000 allowed
##########################################################################
# Open the logo file in binary mode and read its contents into memory
with open("logo.jpg", "rb") as f:
image_data = f.read()
# Create a BytesIO object from the image data
image_bytes = BytesIO(image_data)
# Configure the page settings using the "set_page_config" method of Streamlit
st.set_page_config(
page_title='PyElispotAnalysis',
page_icon=image_bytes, # Use the logo image as the page icon
layout="centered",
initial_sidebar_state="expanded",
menu_items={
'Get help': 'mailto:[email protected]',
'Report a bug': 'mailto:[email protected]',
'About': 'This is an application for demonstrating the PyElispotAnalysis package. Developed, tested, and maintained by Ajinkya Kulkarni: https://github.com/ajinkya-kulkarni at the MPI-NAT, Goettingen.'
}
)
##########################################################################
# Set the title of the web app
st.title(':blue[Spot detection for Elispot assay images. Works best for images smaller than 1000x1000 pixels]')
# st.caption('Application screenshots and source code available [here](https://github.com/ajinkya-kulkarni/PySpatialHistologyAnalysis). Sample image to test this application is available [here](https://github.com/ajinkya-kulkarni/PySpatialHistologyAnalysis/blob/main/TestImage.jpeg).', unsafe_allow_html = False)
# Add some vertical space between the title and the next section
st.markdown("")
##########################################################################
# Create a form using the "form" method of Streamlit
with st.form(key = 'form1', clear_on_submit = True):
# Add some text explaining what the user should do next
st.markdown(':blue[Upload a single Elispot assay image/slide to be analyzed.]')
# Add a file uploader to allow the user to upload an image file
uploaded_file = st.file_uploader("Upload a file", type = ["tif", "tiff", "png", "jpg", "jpeg"], accept_multiple_files = False, label_visibility = 'collapsed')
######################################################################
st.markdown("")
left_column, middle_column1, middle_column2, right_column = st.columns(4)
with left_column:
st.slider('Local window size for analyzing image', min_value = 5, max_value = 101, value = 41, step = 2, format = '%d', label_visibility = "visible", key = '-BlockSizeKey-')
BlockSize = int(st.session_state['-BlockSizeKey-'])
with middle_column1:
st.slider('Value to subtract from local window.', min_value = 2, max_value = 50, value = 10, step = 2, format = '%d', label_visibility = "visible", key = '-ConstantKey-')
Constant = int(st.session_state['-ConstantKey-'])
with middle_column2:
st.slider('Minimum area of spots in the image.', min_value = 2, max_value = 50, value = 10, step = 2, format = '%d', label_visibility = "visible", key = '-MinimumAreaKey-')
MinimumAreaKey = int(st.session_state['-MinimumAreaKey-'])
with right_column:
st.slider('Maximum area of spots in the image.', min_value = 500, max_value = 2000, value = 1000, step = 100, format = '%d', label_visibility = "visible", key = '-MaximumAreaKey-')
MaximumAreaKey = int(st.session_state['-MaximumAreaKey-'])
st.markdown("")
######################################################################
# Add a submit button to the form
submitted = st.form_submit_button('Analyze')
######################################################################
# If no file was uploaded, stop processing and exit early
if uploaded_file is None:
st.stop()
######################################################################
if submitted:
# Read and process the image: convert it to grayscale and scale it
img_scaled = read_image(uploaded_file)
if img_scaled.shape[0] > allowed_image_size or img_scaled.shape[1] > allowed_image_size:
st.error('Uploaded image exceeds the allowed image size. Please reduce the image size.')
st.stop()
# Resize image to suit the UI for image comparision
img_scaled = resize_image(img_scaled)
# Segment the processed image to highlight regions of interest
mask_image = make_segmented_image(img_scaled, BlockSize, Constant)
# Define a kernel for morphological operations
# Erosion helps in detaching closely packed regions
kernel_size = (5, 5)
kernel = np.ones(kernel_size, np.uint8)
# Perform morphological opening on the segmented image
# Opening is an operation that consists of erosion followed by dilation
# It helps to remove noise and to separate regions that are close to each other
opened = morphologyEx(mask_image, MORPH_OPEN, kernel)
# Invert the opened image
# This is done so the regions of interest are now considered as foreground (labelled as 1)
inverted_opened = 1 - opened
# Label the regions in the inverted image
# Each connected component/region gets a unique label
labeled_image = label(inverted_opened, connectivity=2)
# Use the counts_spots function to draw circles around detected spots
# Spots are determined based on the area and eccentricity criteria defined in the function
circled_image, counter = counts_spots(labeled_image, img_scaled, MinimumAreaKey, MaximumAreaKey)
# # Generate the results figure
# result_figure = make_figure(img_scaled, circled_image, counter)
##############################################################
st.markdown("""---""")
st.markdown("Results")
##############################################################
image_comparison(img1=img_scaled, img2=circled_image, label1="Uploaded image", label2="Detected spots")
st.markdown(f'{counter} spots detected.')
st.stop()
##########################################################################