Spaces:
Runtime error
Runtime error
lambda scientist
commited on
Commit
•
1ec5a7d
1
Parent(s):
2dd5ab4
New version
Browse files- Dockerfile +21 -0
- README.md +24 -6
- pages/1_HE_Staining_Analysis.py +157 -278
- pages/2_SDH_Staining_Analysis.py +80 -128
- pages/3_Breast_Muscle_Analysis.py +147 -265
- pages/4_ATP_Staining_Analysis.py +171 -0
- poetry.lock +0 -0
- pyproject.toml +14 -8
Dockerfile
ADDED
@@ -0,0 +1,21 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
FROM python:3.9-slim
|
2 |
+
|
3 |
+
EXPOSE 8501
|
4 |
+
|
5 |
+
WORKDIR /app
|
6 |
+
|
7 |
+
RUN apt-get update && apt-get install -y \
|
8 |
+
build-essential \
|
9 |
+
software-properties-common \
|
10 |
+
git \
|
11 |
+
wget \
|
12 |
+
&& rm -rf /var/lib/apt/lists/*
|
13 |
+
|
14 |
+
RUN git clone https://github.com/lambda-science/MyoQuant.git .
|
15 |
+
RUN wget https://lbgi.fr/~meyer/SDH_models/model.h5
|
16 |
+
|
17 |
+
RUN python -m pip install poetry
|
18 |
+
RUN python -m poetry config virtualenvs.create false
|
19 |
+
RUN python -m poetry install --no-root --no-interaction && rm -rf ~/.cache/pypoetry/{cache,artifacts}
|
20 |
+
|
21 |
+
ENTRYPOINT ["streamlit", "run", "Home.py", "--server.port=8501", "--server.address=0.0.0.0"]
|
README.md
CHANGED
@@ -21,14 +21,33 @@ MyoQuant-Streamlit🔬 is a demo web interface to showcase the usage of MyoQuant
|
|
21 |
</p>
|
22 |
|
23 |
MyoQuant🔬 is a command-line tool to automatically quantify pathological features in muscle fiber histology images.
|
24 |
-
It is built using CellPose, Stardist, custom neural-network models and image analysis techniques to automatically analyze myopathy histology images. Currently MyoQuant is capable of quantifying centralization of nuclei in muscle fiber with HE staining
|
25 |
This web application is intended for demonstration purposes only.
|
26 |
|
27 |
-
## How to
|
28 |
-
|
29 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
30 |
For HE Staining analysis, you can download this sample image: [HERE](https://www.lbgi.fr/~meyer/SDH_models/sample_he.jpg)
|
31 |
-
For SDH Staining analysis, you can download this sample image: [HERE](https://www.lbgi.fr/~meyer/SDH_models/sample_sdh.jpg)
|
|
|
32 |
|
33 |
## Contact
|
34 |
|
@@ -46,4 +65,3 @@ The source code for MyoQuant is available [HERE](https://github.com/lambda-scien
|
|
46 |
</p>
|
47 |
|
48 |
MyoQuant is born within the collaboration between the [CSTB Team @ ICube](https://cstb.icube.unistra.fr/en/index.php/Home) led by Julie D. Thompson, the [Morphological Unit of the Institute of Myology of Paris](https://www.institut-myologie.org/en/recherche-2/neuromuscular-investigation-center/morphological-unit/) led by Teresinha Evangelista, the [imagery platform MyoImage of Center of Research in Myology](https://recherche-myologie.fr/technologies/myoimage/) led by Bruno Cadot, [the photonic microscopy platform of the IGMBC](https://www.igbmc.fr/en/plateformes-technologiques/photonic-microscopy) led by Bertrand Vernay and the [Pathophysiology of neuromuscular diseases team @ IGBMC](https://www.igbmc.fr/en/igbmc/a-propos-de-ligbmc/directory/jocelyn-laporte) led by Jocelyn Laporte
|
49 |
-
|
|
|
21 |
</p>
|
22 |
|
23 |
MyoQuant🔬 is a command-line tool to automatically quantify pathological features in muscle fiber histology images.
|
24 |
+
It is built using CellPose, Stardist, custom neural-network models and image analysis techniques to automatically analyze myopathy histology images. Currently MyoQuant is capable of quantifying centralization of nuclei in muscle fiber with HE staining, anomaly in the mitochondria distribution in muscle fibers with SDH staining and the number of type 1 muscle fiber vs type 2 muscle fiber with ATP staining.
|
25 |
This web application is intended for demonstration purposes only.
|
26 |
|
27 |
+
## How to install or deploy the interface
|
28 |
+
|
29 |
+
The demo version is deployed at https://lbgi.fr/MyoQuant/. You can deploy your own demo version using Docker, your own python environment or google Colab for GPU support.
|
30 |
+
|
31 |
+
### Docker
|
32 |
+
|
33 |
+
You can build the docker image by running `docker build -t streamlit .` and launch the container using `docker run -p 8501:8501 streamlit`.
|
34 |
+
|
35 |
+
### Non-Docker
|
36 |
+
|
37 |
+
If you do not want to use Docker you can install the poetry package in a miniconda (python 3.9, 3.10) base env, run `poetry install` to install the python env, activate the env with `poetry shell` and launch the app by running `streamlit run Home.py`.
|
38 |
+
|
39 |
+
### Deploy on Google Colab for GPU
|
40 |
+
|
41 |
+
As this application uses various deep-learning model, you could benefit from using a deployment solution that provides a GPU.
|
42 |
+
To do so, you can leverage Google Colab free GPU to boost this Streamlit application.
|
43 |
+
To run this app on Google Colab, simply clone the notebook called `google_colab_deploy.ipynb` into Colab and run the four cells. It will automatically download the latest code version, install dependencies and run the app. A link will appear in the output of the lat cell with a structure like `https://word1-word2-try-01-234-567-890.loca.lt`. Click it and the click continue and you’re ready to use the app!
|
44 |
+
|
45 |
+
## How to Use
|
46 |
+
|
47 |
+
Once on the demo, click on the corresponding staining analysis on the sidebar, and upload your histology image. Results will be displayed in the main area automatically.
|
48 |
For HE Staining analysis, you can download this sample image: [HERE](https://www.lbgi.fr/~meyer/SDH_models/sample_he.jpg)
|
49 |
+
For SDH Staining analysis, you can download this sample image: [HERE](https://www.lbgi.fr/~meyer/SDH_models/sample_sdh.jpg)
|
50 |
+
For ATP Staining analysis, you can download this sample image: [HERE](https://www.lbgi.fr/~meyer/SDH_models/sample_atp.jpg)
|
51 |
|
52 |
## Contact
|
53 |
|
|
|
65 |
</p>
|
66 |
|
67 |
MyoQuant is born within the collaboration between the [CSTB Team @ ICube](https://cstb.icube.unistra.fr/en/index.php/Home) led by Julie D. Thompson, the [Morphological Unit of the Institute of Myology of Paris](https://www.institut-myologie.org/en/recherche-2/neuromuscular-investigation-center/morphological-unit/) led by Teresinha Evangelista, the [imagery platform MyoImage of Center of Research in Myology](https://recherche-myologie.fr/technologies/myoimage/) led by Bruno Cadot, [the photonic microscopy platform of the IGMBC](https://www.igbmc.fr/en/plateformes-technologiques/photonic-microscopy) led by Bertrand Vernay and the [Pathophysiology of neuromuscular diseases team @ IGBMC](https://www.igbmc.fr/en/igbmc/a-propos-de-ligbmc/directory/jocelyn-laporte) led by Jocelyn Laporte
|
|
pages/1_HE_Staining_Analysis.py
CHANGED
@@ -1,209 +1,118 @@
|
|
1 |
import streamlit as st
|
2 |
from streamlit.components.v1 import html
|
3 |
-
from cellpose import models, core
|
4 |
-
from stardist.models import StarDist2D
|
5 |
-
from csbdeep.utils import normalize
|
6 |
import matplotlib
|
7 |
|
8 |
try:
|
9 |
from imageio.v2 import imread
|
10 |
except:
|
11 |
from imageio import imread
|
12 |
-
from skimage.measure import regionprops_table
|
13 |
-
import pandas as pd
|
14 |
import matplotlib.pyplot as plt
|
15 |
from stardist import random_label_cmap
|
16 |
-
from
|
17 |
-
|
18 |
-
|
19 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
20 |
|
21 |
st.set_page_config(
|
22 |
page_title="MyoQuant HE Analysis",
|
23 |
page_icon="🔬",
|
24 |
)
|
25 |
|
26 |
-
|
27 |
-
use_GPU = True
|
28 |
-
else:
|
29 |
-
use_GPU = False
|
30 |
|
31 |
|
32 |
@st.experimental_singleton
|
33 |
-
def
|
34 |
-
|
35 |
-
return model_c
|
36 |
|
37 |
|
38 |
@st.experimental_singleton
|
39 |
-
def
|
40 |
-
|
41 |
-
return model_s
|
42 |
|
43 |
|
44 |
@st.experimental_memo
|
45 |
-
def
|
46 |
-
|
47 |
-
mask_cellpose, flow, style, diam = model_cellpose.eval(
|
48 |
-
image, diameter=None, channels=channel
|
49 |
-
)
|
50 |
-
return mask_cellpose
|
51 |
|
52 |
|
53 |
@st.experimental_memo
|
54 |
-
def
|
55 |
-
|
56 |
-
img_norm = normalize(img_norm, 1, 99.8)
|
57 |
-
mask_stardist, details = model_stardist.predict_instances(
|
58 |
-
img_norm, nms_thresh=nms_thresh, prob_thresh=prob_thresh
|
59 |
-
)
|
60 |
-
return mask_stardist
|
61 |
|
62 |
|
63 |
@st.experimental_memo
|
64 |
-
def
|
65 |
-
|
66 |
-
cellpose_df.iloc[index, 5] : cellpose_df.iloc[index, 7],
|
67 |
-
cellpose_df.iloc[index, 6] : cellpose_df.iloc[index, 8],
|
68 |
-
].copy()
|
69 |
-
nucleus_single_cell_img = mask_stardist[
|
70 |
-
cellpose_df.iloc[index, 5] : cellpose_df.iloc[index, 7],
|
71 |
-
cellpose_df.iloc[index, 6] : cellpose_df.iloc[index, 8],
|
72 |
-
].copy()
|
73 |
-
single_cell_mask = cellpose_df.iloc[index, 9]
|
74 |
-
single_cell_img[~single_cell_mask] = 0
|
75 |
-
nucleus_single_cell_img[~single_cell_mask] = 0
|
76 |
-
|
77 |
-
props_nuc_single = regionprops_table(
|
78 |
-
nucleus_single_cell_img,
|
79 |
-
intensity_image=single_cell_img,
|
80 |
-
properties=[
|
81 |
-
"label",
|
82 |
-
"area",
|
83 |
-
"centroid",
|
84 |
-
"eccentricity",
|
85 |
-
"bbox",
|
86 |
-
"image",
|
87 |
-
"perimeter",
|
88 |
-
],
|
89 |
-
)
|
90 |
-
df_nuc_single = pd.DataFrame(props_nuc_single)
|
91 |
-
return single_cell_img, nucleus_single_cell_img, single_cell_mask, df_nuc_single
|
92 |
|
93 |
|
94 |
@st.experimental_memo
|
95 |
-
def
|
96 |
-
|
97 |
-
single_cell_mask,
|
98 |
-
df_nuc_single,
|
99 |
-
x_fiber,
|
100 |
-
y_fiber,
|
101 |
-
internalised_threshold=0.75,
|
102 |
-
):
|
103 |
-
n_nuc, n_nuc_intern, n_nuc_periph = 0, 0, 0
|
104 |
-
for _, value in df_nuc_single.iterrows():
|
105 |
-
n_nuc += 1
|
106 |
-
# Extend line and find closest point
|
107 |
-
m, b = line_equation(x_fiber, y_fiber, value[3], value[2])
|
108 |
-
|
109 |
-
intersections_lst = calculate_intersection(
|
110 |
-
m, b, (single_cell_img.shape[0], single_cell_img.shape[1])
|
111 |
-
)
|
112 |
-
border_point = calculate_closest_point(value[3], value[2], intersections_lst)
|
113 |
-
rr, cc = line(
|
114 |
-
int(y_fiber),
|
115 |
-
int(x_fiber),
|
116 |
-
int(border_point[1]),
|
117 |
-
int(border_point[0]),
|
118 |
-
)
|
119 |
-
for index3, coords in enumerate(list(zip(rr, cc))):
|
120 |
-
try:
|
121 |
-
if single_cell_mask[coords] == 0:
|
122 |
-
dist_nuc_cent = calculate_distance(
|
123 |
-
x_fiber, y_fiber, value[3], value[2]
|
124 |
-
)
|
125 |
-
dist_out_of_fiber = calculate_distance(
|
126 |
-
x_fiber, y_fiber, coords[1], coords[0]
|
127 |
-
)
|
128 |
-
ratio_dist = dist_nuc_cent / dist_out_of_fiber
|
129 |
-
if ratio_dist < internalised_threshold:
|
130 |
-
n_nuc_intern += 1
|
131 |
-
else:
|
132 |
-
n_nuc_periph += 1
|
133 |
-
break
|
134 |
-
except IndexError:
|
135 |
-
coords = list(zip(rr, cc))[index3 - 1]
|
136 |
-
dist_nuc_cent = calculate_distance(x_fiber, y_fiber, value[3], value[2])
|
137 |
-
dist_out_of_fiber = calculate_distance(
|
138 |
-
x_fiber, y_fiber, coords[1], coords[0]
|
139 |
-
)
|
140 |
-
ratio_dist = dist_nuc_cent / dist_out_of_fiber
|
141 |
-
if ratio_dist < internalised_threshold:
|
142 |
-
n_nuc_intern += 1
|
143 |
-
else:
|
144 |
-
n_nuc_periph += 1
|
145 |
-
break
|
146 |
-
|
147 |
-
return n_nuc, n_nuc_intern, n_nuc_periph
|
148 |
|
149 |
|
150 |
@st.experimental_memo
|
151 |
-
def
|
152 |
-
|
153 |
):
|
154 |
-
|
155 |
-
|
156 |
-
|
157 |
-
|
158 |
-
|
159 |
-
|
160 |
-
|
161 |
-
|
162 |
-
x_fiber = cellpose_df.iloc[index, 3] - cellpose_df.iloc[index, 6]
|
163 |
-
y_fiber = cellpose_df.iloc[index, 2] - cellpose_df.iloc[index, 5]
|
164 |
-
n_nuc, n_nuc_intern, n_nuc_periph = single_cell_analysis(
|
165 |
-
single_cell_img, single_cell_mask, df_nuc_single, x_fiber, y_fiber
|
166 |
-
)
|
167 |
-
list_n_nuc.append(n_nuc)
|
168 |
-
list_n_nuc_intern.append(n_nuc_intern)
|
169 |
-
list_n_nuc_periph.append(n_nuc_periph)
|
170 |
-
df_nuc_analysis = pd.DataFrame(
|
171 |
-
list(zip(list_n_nuc, list_n_nuc_intern, list_n_nuc_periph)),
|
172 |
-
columns=["N° Nuc", "N° Nuc Intern", "N° Nuc Periph"],
|
173 |
-
)
|
174 |
-
return df_nuc_analysis
|
175 |
|
176 |
|
177 |
@st.experimental_memo
|
178 |
-
def
|
179 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
180 |
|
181 |
|
182 |
@st.experimental_memo
|
183 |
-
def
|
184 |
-
|
185 |
-
for index in range(len(cellpose_df)):
|
186 |
-
single_cell_mask = cellpose_df.iloc[index, 9].copy()
|
187 |
-
if prediction_df.iloc[index, 1] == 0:
|
188 |
-
paint_img[
|
189 |
-
cellpose_df.iloc[index, 5] : cellpose_df.iloc[index, 7],
|
190 |
-
cellpose_df.iloc[index, 6] : cellpose_df.iloc[index, 8],
|
191 |
-
][single_cell_mask] = 1
|
192 |
-
elif prediction_df.iloc[index, 1] > 0:
|
193 |
-
paint_img[
|
194 |
-
cellpose_df.iloc[index, 5] : cellpose_df.iloc[index, 7],
|
195 |
-
cellpose_df.iloc[index, 6] : cellpose_df.iloc[index, 8],
|
196 |
-
][single_cell_mask] = 2
|
197 |
-
return paint_img
|
198 |
|
199 |
|
200 |
with st.sidebar:
|
201 |
-
st.write("
|
202 |
nms_thresh = st.slider("Stardist NMS Tresh", 0.0, 1.0, 0.4, 0.1)
|
203 |
prob_thresh = st.slider("Stardist Prob Tresh", 0.5, 1.0, 0.5, 0.05)
|
|
|
|
|
204 |
|
205 |
-
model_cellpose =
|
206 |
-
model_stardist =
|
207 |
|
208 |
st.title("HE Staining Analysis")
|
209 |
st.write(
|
@@ -217,10 +126,11 @@ if uploaded_file is not None:
|
|
217 |
st.write("Raw Image")
|
218 |
image = st.image(uploaded_file)
|
219 |
|
220 |
-
mask_cellpose =
|
221 |
-
mask_stardist =
|
|
|
|
|
222 |
mask_stardist_copy = mask_stardist.copy()
|
223 |
-
|
224 |
st.header("Segmentation Results")
|
225 |
st.subheader("CellPose and Stardist overlayed results")
|
226 |
fig, ax = plt.subplots(1, 1)
|
@@ -231,90 +141,78 @@ if uploaded_file is not None:
|
|
231 |
st.pyplot(fig)
|
232 |
|
233 |
st.subheader("All cells detected by CellPose")
|
234 |
-
|
235 |
-
mask_cellpose,
|
236 |
-
properties=[
|
237 |
-
"label",
|
238 |
-
"area",
|
239 |
-
"centroid",
|
240 |
-
"eccentricity",
|
241 |
-
"bbox",
|
242 |
-
"image",
|
243 |
-
"perimeter",
|
244 |
-
],
|
245 |
-
)
|
246 |
-
df_cellpose = pd.DataFrame(props_cellpose)
|
247 |
-
st.dataframe(df_cellpose.drop("image", axis=1))
|
248 |
|
249 |
st.header("Full Nucleus Analysis Results")
|
250 |
-
|
251 |
-
|
252 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
253 |
st.write(
|
254 |
"Total number of internalized nucleus : ",
|
255 |
-
|
256 |
" (",
|
257 |
round(
|
258 |
100
|
259 |
-
*
|
260 |
-
/
|
261 |
2,
|
262 |
),
|
263 |
"%)",
|
264 |
)
|
265 |
st.write(
|
266 |
"Total number of peripherical nucleus : ",
|
267 |
-
|
268 |
" (",
|
269 |
round(
|
270 |
100
|
271 |
-
*
|
272 |
-
/
|
273 |
2,
|
274 |
),
|
275 |
"%)",
|
276 |
)
|
277 |
st.write(
|
278 |
"Number of cell with at least one internalized nucleus : ",
|
279 |
-
|
280 |
" (",
|
281 |
round(
|
282 |
100
|
283 |
-
*
|
284 |
-
/ len(
|
285 |
2,
|
286 |
),
|
287 |
"%)",
|
288 |
)
|
|
|
289 |
st.header("Single Nucleus Analysis Details")
|
290 |
selected_fiber = st.selectbox("Select a cell", list(range(len(df_cellpose))))
|
291 |
selected_fiber = int(selected_fiber)
|
292 |
-
|
293 |
-
|
294 |
-
df_cellpose.iloc[selected_fiber, 6] : df_cellpose.iloc[selected_fiber, 8],
|
295 |
-
]
|
296 |
-
nucleus_single_cell_img = mask_stardist_copy[
|
297 |
-
df_cellpose.iloc[selected_fiber, 5] : df_cellpose.iloc[selected_fiber, 7],
|
298 |
-
df_cellpose.iloc[selected_fiber, 6] : df_cellpose.iloc[selected_fiber, 8],
|
299 |
-
]
|
300 |
-
single_cell_mask = df_cellpose.iloc[selected_fiber, 9]
|
301 |
-
single_cell_img[~single_cell_mask] = 0
|
302 |
-
nucleus_single_cell_img[~single_cell_mask] = 0
|
303 |
-
|
304 |
-
props_nuc_single = regionprops_table(
|
305 |
nucleus_single_cell_img,
|
306 |
-
|
307 |
-
|
308 |
-
|
309 |
-
|
310 |
-
|
311 |
-
"eccentricity",
|
312 |
-
"bbox",
|
313 |
-
"image",
|
314 |
-
"perimeter",
|
315 |
-
],
|
316 |
-
)
|
317 |
-
df_nuc_single = pd.DataFrame(props_nuc_single)
|
318 |
st.markdown(
|
319 |
"""
|
320 |
* White point represent cell centroid.
|
@@ -322,93 +220,74 @@ if uploaded_file is not None:
|
|
322 |
* Red point represent the cell border from a straight line between the cell centroid and the nucleus centroid. The red dashed line represent distance between the nucelus and the cell border.
|
323 |
* The periphery ratio is calculated by the division of the distance centroid - nucleus and the distance centroid - cell border."""
|
324 |
)
|
325 |
-
|
|
|
326 |
ax1.imshow(single_cell_img)
|
327 |
ax2.imshow(nucleus_single_cell_img, cmap="viridis")
|
328 |
# Plot Fiber centroid
|
329 |
x_fiber = df_cellpose.iloc[selected_fiber, 3] - df_cellpose.iloc[selected_fiber, 6]
|
330 |
y_fiber = df_cellpose.iloc[selected_fiber, 2] - df_cellpose.iloc[selected_fiber, 5]
|
331 |
-
ax3.scatter(x_fiber, y_fiber, color="white")
|
332 |
-
# Plot nucleus centroid
|
333 |
-
for index, value in df_nuc_single.iterrows():
|
334 |
-
ax3.scatter(value[3], value[2], color="blue", s=2)
|
335 |
-
# Extend line and find closest point
|
336 |
-
m, b = line_equation(x_fiber, y_fiber, value[3], value[2])
|
337 |
-
|
338 |
-
intersections_lst = calculate_intersection(
|
339 |
-
m, b, (single_cell_img.shape[0], single_cell_img.shape[1])
|
340 |
-
)
|
341 |
-
border_point = calculate_closest_point(value[3], value[2], intersections_lst)
|
342 |
-
ax3.plot(
|
343 |
-
(x_fiber, border_point[0]),
|
344 |
-
(y_fiber, border_point[1]),
|
345 |
-
"ro--",
|
346 |
-
linewidth=1,
|
347 |
-
markersize=1,
|
348 |
-
)
|
349 |
-
ax3.plot(
|
350 |
-
(x_fiber, value[3]),
|
351 |
-
(y_fiber, value[2]),
|
352 |
-
"go--",
|
353 |
-
linewidth=1,
|
354 |
-
markersize=1,
|
355 |
-
)
|
356 |
|
357 |
-
|
358 |
-
|
359 |
-
|
360 |
-
|
361 |
-
|
362 |
-
|
363 |
-
|
364 |
-
|
365 |
-
|
366 |
-
|
367 |
-
|
368 |
-
|
369 |
-
|
370 |
-
|
371 |
-
|
372 |
-
|
373 |
-
|
374 |
-
|
375 |
-
except IndexError:
|
376 |
-
coords = list(zip(rr, cc))[index - 1]
|
377 |
-
dist_nuc_cent = calculate_distance(x_fiber, y_fiber, value[3], value[2])
|
378 |
-
dist_out_of_fiber = calculate_distance(
|
379 |
-
x_fiber, y_fiber, coords[1], coords[0]
|
380 |
-
)
|
381 |
-
ratio_dist = dist_nuc_cent / dist_out_of_fiber
|
382 |
-
ax3.scatter(coords[1], coords[0], color="red", s=10)
|
383 |
-
break
|
384 |
-
|
385 |
-
st.write("Nucleus #{} has a periphery ratio of: {}".format(index, ratio_dist))
|
386 |
-
ax3.imshow(single_cell_img)
|
387 |
-
ax3.imshow(nucleus_single_cell_img, cmap="viridis", alpha=0.5)
|
388 |
ax1.axis("off")
|
389 |
ax2.axis("off")
|
390 |
-
|
391 |
-
|
|
|
|
|
392 |
|
|
|
|
|
393 |
st.subheader("All nucleus inside selected cell")
|
394 |
|
395 |
-
st.dataframe(
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
396 |
|
397 |
st.header("Painted predicted image")
|
398 |
st.write(
|
399 |
"Green color indicates cells with only peripherical nuclei, red color indicates cells with at least one internal nucleus."
|
400 |
)
|
401 |
-
painted_img =
|
402 |
-
|
403 |
cmap = matplotlib.colors.LinearSegmentedColormap.from_list(
|
404 |
"", ["white", "green", "red"]
|
405 |
)
|
406 |
-
|
407 |
-
|
408 |
-
|
409 |
-
st.pyplot(
|
|
|
410 |
html(
|
411 |
f"""
|
412 |
-
<script defer data-domain="
|
413 |
"""
|
414 |
-
)
|
|
|
1 |
import streamlit as st
|
2 |
from streamlit.components.v1 import html
|
|
|
|
|
|
|
3 |
import matplotlib
|
4 |
|
5 |
try:
|
6 |
from imageio.v2 import imread
|
7 |
except:
|
8 |
from imageio import imread
|
|
|
|
|
9 |
import matplotlib.pyplot as plt
|
10 |
from stardist import random_label_cmap
|
11 |
+
from myoquant.src.common_func import (
|
12 |
+
load_cellpose,
|
13 |
+
load_stardist,
|
14 |
+
run_cellpose,
|
15 |
+
run_stardist,
|
16 |
+
is_gpu_availiable,
|
17 |
+
df_from_cellpose_mask,
|
18 |
+
df_from_stardist_mask,
|
19 |
+
)
|
20 |
+
from myoquant.src.HE_analysis import (
|
21 |
+
predict_all_cells,
|
22 |
+
extract_ROIs,
|
23 |
+
single_cell_analysis,
|
24 |
+
paint_histo_img,
|
25 |
+
)
|
26 |
|
27 |
st.set_page_config(
|
28 |
page_title="MyoQuant HE Analysis",
|
29 |
page_icon="🔬",
|
30 |
)
|
31 |
|
32 |
+
use_GPU = is_gpu_availiable()
|
|
|
|
|
|
|
33 |
|
34 |
|
35 |
@st.experimental_singleton
|
36 |
+
def st_load_cellpose():
|
37 |
+
return load_cellpose()
|
|
|
38 |
|
39 |
|
40 |
@st.experimental_singleton
|
41 |
+
def st_load_stardist():
|
42 |
+
return load_stardist()
|
|
|
43 |
|
44 |
|
45 |
@st.experimental_memo
|
46 |
+
def st_run_cellpose(image_ndarray, _model):
|
47 |
+
return run_cellpose(image_ndarray, _model)
|
|
|
|
|
|
|
|
|
48 |
|
49 |
|
50 |
@st.experimental_memo
|
51 |
+
def st_run_stardist(image_ndarray, _model, nms_thresh, prob_thresh):
|
52 |
+
return run_stardist(image_ndarray, _model, nms_thresh, prob_thresh)
|
|
|
|
|
|
|
|
|
|
|
53 |
|
54 |
|
55 |
@st.experimental_memo
|
56 |
+
def st_df_from_cellpose_mask(mask):
|
57 |
+
return df_from_cellpose_mask(mask)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
58 |
|
59 |
|
60 |
@st.experimental_memo
|
61 |
+
def st_df_from_stardist_mask(mask):
|
62 |
+
return df_from_stardist_mask(mask)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
63 |
|
64 |
|
65 |
@st.experimental_memo
|
66 |
+
def st_predict_all_cells(
|
67 |
+
image_ndarray, df_cellpose, mask_stardist, internalised_threshold
|
68 |
):
|
69 |
+
return predict_all_cells(
|
70 |
+
image_ndarray, df_cellpose, mask_stardist, internalised_threshold
|
71 |
+
)
|
72 |
+
|
73 |
+
|
74 |
+
@st.experimental_memo
|
75 |
+
def st_extract_ROIs(image_ndarray, selected_fiber, df_cellpose, mask_stardist):
|
76 |
+
return extract_ROIs(image_ndarray, selected_fiber, df_cellpose, mask_stardist)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
77 |
|
78 |
|
79 |
@st.experimental_memo
|
80 |
+
def st_single_cell_analysis(
|
81 |
+
single_cell_img,
|
82 |
+
single_cell_mask,
|
83 |
+
df_nuc_single,
|
84 |
+
x_fiber,
|
85 |
+
y_fiber,
|
86 |
+
selected_fiber,
|
87 |
+
internalised_threshold,
|
88 |
+
draw_and_return=True,
|
89 |
+
):
|
90 |
+
return single_cell_analysis(
|
91 |
+
single_cell_img,
|
92 |
+
single_cell_mask,
|
93 |
+
df_nuc_single,
|
94 |
+
x_fiber,
|
95 |
+
y_fiber,
|
96 |
+
selected_fiber + 1,
|
97 |
+
internalised_threshold,
|
98 |
+
draw_and_return=True,
|
99 |
+
)
|
100 |
|
101 |
|
102 |
@st.experimental_memo
|
103 |
+
def st_paint_histo_img(image_ndarray, df_cellpose, cellpose_df_stat):
|
104 |
+
return paint_histo_img(image_ndarray, df_cellpose, cellpose_df_stat)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
105 |
|
106 |
|
107 |
with st.sidebar:
|
108 |
+
st.write("Nuclei detection Parameters (Stardist)")
|
109 |
nms_thresh = st.slider("Stardist NMS Tresh", 0.0, 1.0, 0.4, 0.1)
|
110 |
prob_thresh = st.slider("Stardist Prob Tresh", 0.5, 1.0, 0.5, 0.05)
|
111 |
+
st.write("Nuclei Classification Parameter")
|
112 |
+
eccentricity_thresh = st.slider("Eccentricity Score Tresh", 0.0, 1.0, 0.75, 0.05)
|
113 |
|
114 |
+
model_cellpose = st_load_cellpose()
|
115 |
+
model_stardist = st_load_stardist()
|
116 |
|
117 |
st.title("HE Staining Analysis")
|
118 |
st.write(
|
|
|
126 |
st.write("Raw Image")
|
127 |
image = st.image(uploaded_file)
|
128 |
|
129 |
+
mask_cellpose = st_run_cellpose(image_ndarray, model_cellpose)
|
130 |
+
mask_stardist = st_run_stardist(
|
131 |
+
image_ndarray, model_stardist, nms_thresh, prob_thresh
|
132 |
+
)
|
133 |
mask_stardist_copy = mask_stardist.copy()
|
|
|
134 |
st.header("Segmentation Results")
|
135 |
st.subheader("CellPose and Stardist overlayed results")
|
136 |
fig, ax = plt.subplots(1, 1)
|
|
|
141 |
st.pyplot(fig)
|
142 |
|
143 |
st.subheader("All cells detected by CellPose")
|
144 |
+
df_cellpose = st_df_from_cellpose_mask(mask_cellpose)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
145 |
|
146 |
st.header("Full Nucleus Analysis Results")
|
147 |
+
cellpose_df_stat, all_nuc_df_stats = st_predict_all_cells(
|
148 |
+
image_ndarray,
|
149 |
+
df_cellpose,
|
150 |
+
mask_stardist,
|
151 |
+
internalised_threshold=eccentricity_thresh,
|
152 |
+
)
|
153 |
+
st.dataframe(
|
154 |
+
cellpose_df_stat.drop(
|
155 |
+
[
|
156 |
+
"centroid-0",
|
157 |
+
"centroid-1",
|
158 |
+
"bbox-0",
|
159 |
+
"bbox-1",
|
160 |
+
"bbox-2",
|
161 |
+
"bbox-3",
|
162 |
+
"image",
|
163 |
+
],
|
164 |
+
axis=1,
|
165 |
+
)
|
166 |
+
)
|
167 |
+
st.write("Total number of nucleus : ", cellpose_df_stat["N° Nuc"].sum())
|
168 |
st.write(
|
169 |
"Total number of internalized nucleus : ",
|
170 |
+
cellpose_df_stat["N° Nuc Intern"].sum(),
|
171 |
" (",
|
172 |
round(
|
173 |
100
|
174 |
+
* cellpose_df_stat["N° Nuc Intern"].sum()
|
175 |
+
/ cellpose_df_stat["N° Nuc"].sum(),
|
176 |
2,
|
177 |
),
|
178 |
"%)",
|
179 |
)
|
180 |
st.write(
|
181 |
"Total number of peripherical nucleus : ",
|
182 |
+
cellpose_df_stat["N° Nuc Periph"].sum(),
|
183 |
" (",
|
184 |
round(
|
185 |
100
|
186 |
+
* cellpose_df_stat["N° Nuc Periph"].sum()
|
187 |
+
/ cellpose_df_stat["N° Nuc"].sum(),
|
188 |
2,
|
189 |
),
|
190 |
"%)",
|
191 |
)
|
192 |
st.write(
|
193 |
"Number of cell with at least one internalized nucleus : ",
|
194 |
+
cellpose_df_stat["N° Nuc Intern"].astype(bool).sum(axis=0),
|
195 |
" (",
|
196 |
round(
|
197 |
100
|
198 |
+
* cellpose_df_stat["N° Nuc Intern"].astype(bool).sum(axis=0)
|
199 |
+
/ len(cellpose_df_stat),
|
200 |
2,
|
201 |
),
|
202 |
"%)",
|
203 |
)
|
204 |
+
|
205 |
st.header("Single Nucleus Analysis Details")
|
206 |
selected_fiber = st.selectbox("Select a cell", list(range(len(df_cellpose))))
|
207 |
selected_fiber = int(selected_fiber)
|
208 |
+
(
|
209 |
+
single_cell_img,
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
210 |
nucleus_single_cell_img,
|
211 |
+
single_cell_mask,
|
212 |
+
df_nuc_single,
|
213 |
+
) = st_extract_ROIs(image_ndarray, selected_fiber, df_cellpose, mask_stardist)
|
214 |
+
|
215 |
+
# df_nuc_single = df_from_stardist_mask(mask_stardist)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
216 |
st.markdown(
|
217 |
"""
|
218 |
* White point represent cell centroid.
|
|
|
220 |
* Red point represent the cell border from a straight line between the cell centroid and the nucleus centroid. The red dashed line represent distance between the nucelus and the cell border.
|
221 |
* The periphery ratio is calculated by the division of the distance centroid - nucleus and the distance centroid - cell border."""
|
222 |
)
|
223 |
+
|
224 |
+
fig2, (ax1, ax2) = plt.subplots(1, 2)
|
225 |
ax1.imshow(single_cell_img)
|
226 |
ax2.imshow(nucleus_single_cell_img, cmap="viridis")
|
227 |
# Plot Fiber centroid
|
228 |
x_fiber = df_cellpose.iloc[selected_fiber, 3] - df_cellpose.iloc[selected_fiber, 6]
|
229 |
y_fiber = df_cellpose.iloc[selected_fiber, 2] - df_cellpose.iloc[selected_fiber, 5]
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
230 |
|
231 |
+
(
|
232 |
+
n_nuc,
|
233 |
+
n_nuc_intern,
|
234 |
+
n_nuc_periph,
|
235 |
+
df_nuc_single_stats,
|
236 |
+
ax_nuc,
|
237 |
+
) = st_single_cell_analysis(
|
238 |
+
single_cell_img,
|
239 |
+
single_cell_mask,
|
240 |
+
df_nuc_single,
|
241 |
+
x_fiber,
|
242 |
+
y_fiber,
|
243 |
+
selected_fiber + 1,
|
244 |
+
internalised_threshold=eccentricity_thresh,
|
245 |
+
draw_and_return=True,
|
246 |
+
)
|
247 |
+
for index, value in df_nuc_single_stats.iterrows():
|
248 |
+
st.write("Nucleus #{} has a periphery ratio of: {}".format(index, value[12]))
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
249 |
ax1.axis("off")
|
250 |
ax2.axis("off")
|
251 |
+
# st.pyplot(fig2)
|
252 |
+
ax_nuc.imshow(single_cell_img)
|
253 |
+
ax_nuc.imshow(nucleus_single_cell_img, cmap="viridis", alpha=0.5)
|
254 |
+
f = ax_nuc.figure
|
255 |
|
256 |
+
st.pyplot(fig2)
|
257 |
+
st.pyplot(f)
|
258 |
st.subheader("All nucleus inside selected cell")
|
259 |
|
260 |
+
st.dataframe(
|
261 |
+
df_nuc_single_stats.drop(
|
262 |
+
[
|
263 |
+
"centroid-0",
|
264 |
+
"centroid-1",
|
265 |
+
"bbox-0",
|
266 |
+
"bbox-1",
|
267 |
+
"bbox-2",
|
268 |
+
"bbox-3",
|
269 |
+
"image",
|
270 |
+
],
|
271 |
+
axis=1,
|
272 |
+
)
|
273 |
+
)
|
274 |
|
275 |
st.header("Painted predicted image")
|
276 |
st.write(
|
277 |
"Green color indicates cells with only peripherical nuclei, red color indicates cells with at least one internal nucleus."
|
278 |
)
|
279 |
+
painted_img = st_paint_histo_img(image_ndarray, df_cellpose, cellpose_df_stat)
|
280 |
+
fig4, ax4 = plt.subplots(1, 1)
|
281 |
cmap = matplotlib.colors.LinearSegmentedColormap.from_list(
|
282 |
"", ["white", "green", "red"]
|
283 |
)
|
284 |
+
ax4.imshow(image_ndarray)
|
285 |
+
ax4.imshow(painted_img, cmap=cmap, alpha=0.5)
|
286 |
+
ax4.axis("off")
|
287 |
+
st.pyplot(fig4)
|
288 |
+
|
289 |
html(
|
290 |
f"""
|
291 |
+
<script defer data-domain="lbgi.fr/myoquant" src="https://plausible.cmeyer.fr/js/script.js"></script>
|
292 |
"""
|
293 |
+
)
|
pages/2_SDH_Staining_Analysis.py
CHANGED
@@ -1,140 +1,98 @@
|
|
1 |
import streamlit as st
|
2 |
from streamlit.components.v1 import html
|
3 |
-
from cellpose.core import use_gpu
|
4 |
-
from cellpose.models import Cellpose
|
5 |
|
6 |
try:
|
7 |
from imageio.v2 import imread
|
8 |
except:
|
9 |
from imageio import imread
|
10 |
-
from skimage.measure import regionprops_table
|
11 |
import pandas as pd
|
12 |
import matplotlib
|
13 |
import matplotlib.pyplot as plt
|
14 |
-
from stardist import random_label_cmap
|
15 |
import tensorflow as tf
|
16 |
-
|
17 |
-
from tensorflow import keras
|
18 |
-
|
19 |
-
from gradcam import *
|
20 |
from os import path
|
21 |
import urllib.request
|
22 |
-
from
|
23 |
-
|
24 |
-
|
25 |
-
|
26 |
-
|
27 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
28 |
|
29 |
st.set_page_config(
|
30 |
page_title="MyoQuant SDH Analysis",
|
31 |
page_icon="🔬",
|
32 |
)
|
33 |
|
34 |
-
|
35 |
-
st.success("SDH Model ready to use !")
|
36 |
-
pass
|
37 |
-
else:
|
38 |
-
with st.spinner("Please wait we are downloading the SDH Model."):
|
39 |
-
urllib.request.urlretrieve(
|
40 |
-
"https://lbgi.fr/~meyer/SDH_models/model.h5", "model.h5"
|
41 |
-
)
|
42 |
-
st.success("SDH Model have been downloaded !")
|
43 |
-
|
44 |
-
if len(list_physical_devices("GPU")) >= 1:
|
45 |
-
use_GPU = True
|
46 |
-
else:
|
47 |
-
use_GPU = False
|
48 |
|
49 |
|
50 |
@st.experimental_singleton
|
51 |
-
def
|
52 |
-
|
53 |
-
return model_c
|
54 |
|
55 |
|
56 |
@st.experimental_singleton
|
57 |
-
def
|
58 |
-
|
59 |
-
"model.h5", custom_objects={"RandomBrightness": RandomBrightness}
|
60 |
-
)
|
61 |
-
return model_sdh
|
62 |
|
63 |
|
64 |
@st.experimental_memo
|
65 |
-
def
|
66 |
-
|
67 |
-
mask_cellpose, flow, style, diam = model_cellpose.eval(
|
68 |
-
image, diameter=None, channels=channel
|
69 |
-
)
|
70 |
-
return mask_cellpose
|
71 |
|
72 |
|
73 |
@st.experimental_memo
|
74 |
-
def
|
75 |
-
|
76 |
-
img_array[0] = tf.image.resize(single_cell_img, (256, 256))
|
77 |
-
prediction = _model_SDH.predict(img_array)
|
78 |
-
predicted_class = prediction.argmax()
|
79 |
-
predicted_proba = round(np.amax(prediction), 2)
|
80 |
-
heatmap = make_gradcam_heatmap(
|
81 |
-
img_array, _model_SDH.get_layer("resnet50v2"), "conv5_block3_3_conv"
|
82 |
-
)
|
83 |
-
grad_cam_img = save_and_display_gradcam(img_array[0], heatmap)
|
84 |
-
return grad_cam_img, predicted_class, predicted_proba
|
85 |
|
86 |
|
87 |
@st.experimental_memo
|
88 |
-
def
|
89 |
-
|
90 |
-
for index in range(len(cellpose_df)):
|
91 |
-
single_cell_img = histo_img[
|
92 |
-
cellpose_df.iloc[index, 5] : cellpose_df.iloc[index, 7],
|
93 |
-
cellpose_df.iloc[index, 6] : cellpose_df.iloc[index, 8],
|
94 |
-
].copy()
|
95 |
|
96 |
-
single_cell_mask = cellpose_df.iloc[index, 9].copy()
|
97 |
-
single_cell_img[~single_cell_mask] = 0
|
98 |
|
99 |
-
|
100 |
-
|
|
|
101 |
|
102 |
|
103 |
@st.experimental_memo
|
104 |
-
def
|
105 |
-
|
106 |
-
predicted_proba_array = np.empty((len(cellpose_df)))
|
107 |
-
img_array_full = resize_batch_cells(histo_img, cellpose_df)
|
108 |
-
prediction = _model_SDH.predict(img_array_full)
|
109 |
-
index_counter = 0
|
110 |
-
for prediction_result in prediction:
|
111 |
-
predicted_class_array[index_counter] = prediction_result.argmax()
|
112 |
-
predicted_proba_array[index_counter] = np.amax(prediction_result)
|
113 |
-
index_counter += 1
|
114 |
-
return predicted_class_array, predicted_proba_array
|
115 |
|
116 |
|
117 |
@st.experimental_memo
|
118 |
-
def
|
119 |
-
|
120 |
-
|
121 |
-
|
122 |
-
|
123 |
-
|
124 |
-
|
125 |
-
|
126 |
-
|
127 |
-
|
128 |
-
|
129 |
-
|
130 |
-
|
131 |
-
|
132 |
-
|
133 |
-
|
134 |
-
|
135 |
-
|
136 |
-
|
137 |
-
|
|
|
|
|
|
|
138 |
|
139 |
st.title("SDH Staining Analysis")
|
140 |
st.write(
|
@@ -149,7 +107,7 @@ if uploaded_file_sdh is not None:
|
|
149 |
st.write("Raw Image")
|
150 |
image = st.image(uploaded_file_sdh)
|
151 |
|
152 |
-
mask_cellpose =
|
153 |
|
154 |
st.header("Segmentation Results")
|
155 |
st.subheader("CellPose results")
|
@@ -158,35 +116,32 @@ if uploaded_file_sdh is not None:
|
|
158 |
ax.axis("off")
|
159 |
st.pyplot(fig)
|
160 |
|
161 |
-
st.subheader("All cells detected by CellPose")
|
162 |
-
|
163 |
-
props_cellpose = regionprops_table(
|
164 |
-
mask_cellpose,
|
165 |
-
properties=[
|
166 |
-
"label",
|
167 |
-
"area",
|
168 |
-
"centroid",
|
169 |
-
"eccentricity",
|
170 |
-
"bbox",
|
171 |
-
"image",
|
172 |
-
"perimeter",
|
173 |
-
],
|
174 |
-
)
|
175 |
-
df_cellpose = pd.DataFrame(props_cellpose)
|
176 |
-
st.dataframe(df_cellpose.drop("image", axis=1))
|
177 |
-
|
178 |
st.header("SDH Cell Classification Results")
|
179 |
-
|
180 |
-
|
181 |
image_ndarray_sdh, df_cellpose, model_SDH
|
182 |
)
|
183 |
-
|
|
|
184 |
count_per_label = np.unique(class_predicted_all, return_counts=True)
|
185 |
class_and_proba_df = pd.DataFrame(
|
186 |
list(zip(class_predicted_all, proba_predicted_all)),
|
187 |
columns=["class", "proba"],
|
188 |
)
|
189 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
190 |
st.write("Total number of cells detected: ", len(class_predicted_all))
|
191 |
for elem in count_per_label[0]:
|
192 |
st.write(
|
@@ -202,15 +157,11 @@ if uploaded_file_sdh is not None:
|
|
202 |
st.header("Single Cell Grad-CAM")
|
203 |
selected_fiber = st.selectbox("Select a cell", list(range(len(df_cellpose))))
|
204 |
selected_fiber = int(selected_fiber)
|
205 |
-
single_cell_img =
|
206 |
-
|
207 |
-
|
208 |
-
].copy()
|
209 |
-
|
210 |
-
single_cell_mask = df_cellpose.iloc[selected_fiber, 9].copy()
|
211 |
-
single_cell_img[~single_cell_mask] = 0
|
212 |
|
213 |
-
grad_img, class_predicted, proba_predicted =
|
214 |
single_cell_img, model_SDH
|
215 |
)
|
216 |
|
@@ -234,7 +185,7 @@ if uploaded_file_sdh is not None:
|
|
234 |
st.write(
|
235 |
"Green color indicates cells classified as control, red color indicates cells classified as sick"
|
236 |
)
|
237 |
-
paint_img =
|
238 |
fig3, ax3 = plt.subplots(1, 1)
|
239 |
cmap = matplotlib.colors.LinearSegmentedColormap.from_list(
|
240 |
"", ["white", "green", "red"]
|
@@ -243,8 +194,9 @@ if uploaded_file_sdh is not None:
|
|
243 |
ax3.imshow(paint_img, cmap=cmap, alpha=0.5)
|
244 |
ax3.axis("off")
|
245 |
st.pyplot(fig3)
|
|
|
246 |
html(
|
247 |
f"""
|
248 |
-
<script defer data-domain="
|
249 |
"""
|
250 |
-
)
|
|
|
1 |
import streamlit as st
|
2 |
from streamlit.components.v1 import html
|
|
|
|
|
3 |
|
4 |
try:
|
5 |
from imageio.v2 import imread
|
6 |
except:
|
7 |
from imageio import imread
|
|
|
8 |
import pandas as pd
|
9 |
import matplotlib
|
10 |
import matplotlib.pyplot as plt
|
|
|
11 |
import tensorflow as tf
|
12 |
+
import numpy as np
|
|
|
|
|
|
|
13 |
from os import path
|
14 |
import urllib.request
|
15 |
+
from myoquant.src.SDH_analysis import (
|
16 |
+
predict_all_cells,
|
17 |
+
predict_single_cell,
|
18 |
+
paint_full_image,
|
19 |
+
)
|
20 |
+
from myoquant.src.common_func import (
|
21 |
+
load_cellpose,
|
22 |
+
run_cellpose,
|
23 |
+
is_gpu_availiable,
|
24 |
+
df_from_cellpose_mask,
|
25 |
+
load_sdh_model,
|
26 |
+
extract_single_image,
|
27 |
+
)
|
28 |
|
29 |
st.set_page_config(
|
30 |
page_title="MyoQuant SDH Analysis",
|
31 |
page_icon="🔬",
|
32 |
)
|
33 |
|
34 |
+
use_GPU = is_gpu_availiable()
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
35 |
|
36 |
|
37 |
@st.experimental_singleton
|
38 |
+
def st_load_sdh_model(model_path):
|
39 |
+
return load_sdh_model(model_path)
|
|
|
40 |
|
41 |
|
42 |
@st.experimental_singleton
|
43 |
+
def st_load_cellpose():
|
44 |
+
return load_cellpose()
|
|
|
|
|
|
|
45 |
|
46 |
|
47 |
@st.experimental_memo
|
48 |
+
def st_run_cellpose(image_ndarray, _model):
|
49 |
+
return run_cellpose(image_ndarray, _model)
|
|
|
|
|
|
|
|
|
50 |
|
51 |
|
52 |
@st.experimental_memo
|
53 |
+
def st_df_from_cellpose_mask(mask):
|
54 |
+
return df_from_cellpose_mask(mask)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
55 |
|
56 |
|
57 |
@st.experimental_memo
|
58 |
+
def st_predict_all_cells(image_ndarray, cellpose_df, _model_SDH):
|
59 |
+
return predict_all_cells(image_ndarray, cellpose_df, _model_SDH)
|
|
|
|
|
|
|
|
|
|
|
60 |
|
|
|
|
|
61 |
|
62 |
+
@st.experimental_memo
|
63 |
+
def st_extract_single_image(image_ndarray, cellpose_df, index):
|
64 |
+
return extract_single_image(image_ndarray, cellpose_df, index)
|
65 |
|
66 |
|
67 |
@st.experimental_memo
|
68 |
+
def st_predict_single_cell(image_ndarray, _model_SDH):
|
69 |
+
return predict_single_cell(image_ndarray, _model_SDH)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
70 |
|
71 |
|
72 |
@st.experimental_memo
|
73 |
+
def st_paint_full_image(image_sdh, df_cellpose, class_predicted_all):
|
74 |
+
return paint_full_image(image_sdh, df_cellpose, class_predicted_all)
|
75 |
+
|
76 |
+
|
77 |
+
labels_predict = ["control", "sick"]
|
78 |
+
|
79 |
+
tf.random.set_seed(42)
|
80 |
+
np.random.seed(42)
|
81 |
+
|
82 |
+
|
83 |
+
if path.exists("model.h5"):
|
84 |
+
st.success("SDH Model ready to use !")
|
85 |
+
pass
|
86 |
+
else:
|
87 |
+
with st.spinner("Please wait we are downloading the SDH Model."):
|
88 |
+
urllib.request.urlretrieve(
|
89 |
+
"https://lbgi.fr/~meyer/SDH_models/model.h5", "model.h5"
|
90 |
+
)
|
91 |
+
st.success("SDH Model have been downloaded !")
|
92 |
+
|
93 |
+
model_cellpose = st_load_cellpose()
|
94 |
+
|
95 |
+
model_SDH = st_load_sdh_model("model.h5")
|
96 |
|
97 |
st.title("SDH Staining Analysis")
|
98 |
st.write(
|
|
|
107 |
st.write("Raw Image")
|
108 |
image = st.image(uploaded_file_sdh)
|
109 |
|
110 |
+
mask_cellpose = st_run_cellpose(image_ndarray_sdh, model_cellpose)
|
111 |
|
112 |
st.header("Segmentation Results")
|
113 |
st.subheader("CellPose results")
|
|
|
116 |
ax.axis("off")
|
117 |
st.pyplot(fig)
|
118 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
119 |
st.header("SDH Cell Classification Results")
|
120 |
+
df_cellpose = st_df_from_cellpose_mask(mask_cellpose)
|
121 |
+
df_cellpose_results = st_predict_all_cells(
|
122 |
image_ndarray_sdh, df_cellpose, model_SDH
|
123 |
)
|
124 |
+
class_predicted_all = df_cellpose_results["class_predicted"].values
|
125 |
+
proba_predicted_all = df_cellpose_results["proba_predicted"].values
|
126 |
count_per_label = np.unique(class_predicted_all, return_counts=True)
|
127 |
class_and_proba_df = pd.DataFrame(
|
128 |
list(zip(class_predicted_all, proba_predicted_all)),
|
129 |
columns=["class", "proba"],
|
130 |
)
|
131 |
+
st.dataframe(
|
132 |
+
df_cellpose_results.drop(
|
133 |
+
[
|
134 |
+
"centroid-0",
|
135 |
+
"centroid-1",
|
136 |
+
"bbox-0",
|
137 |
+
"bbox-1",
|
138 |
+
"bbox-2",
|
139 |
+
"bbox-3",
|
140 |
+
"image",
|
141 |
+
],
|
142 |
+
axis=1,
|
143 |
+
)
|
144 |
+
)
|
145 |
st.write("Total number of cells detected: ", len(class_predicted_all))
|
146 |
for elem in count_per_label[0]:
|
147 |
st.write(
|
|
|
157 |
st.header("Single Cell Grad-CAM")
|
158 |
selected_fiber = st.selectbox("Select a cell", list(range(len(df_cellpose))))
|
159 |
selected_fiber = int(selected_fiber)
|
160 |
+
single_cell_img = st_extract_single_image(
|
161 |
+
image_ndarray_sdh, df_cellpose, selected_fiber
|
162 |
+
)
|
|
|
|
|
|
|
|
|
163 |
|
164 |
+
grad_img, class_predicted, proba_predicted = st_predict_single_cell(
|
165 |
single_cell_img, model_SDH
|
166 |
)
|
167 |
|
|
|
185 |
st.write(
|
186 |
"Green color indicates cells classified as control, red color indicates cells classified as sick"
|
187 |
)
|
188 |
+
paint_img = st_paint_full_image(image_ndarray_sdh, df_cellpose, class_predicted_all)
|
189 |
fig3, ax3 = plt.subplots(1, 1)
|
190 |
cmap = matplotlib.colors.LinearSegmentedColormap.from_list(
|
191 |
"", ["white", "green", "red"]
|
|
|
194 |
ax3.imshow(paint_img, cmap=cmap, alpha=0.5)
|
195 |
ax3.axis("off")
|
196 |
st.pyplot(fig3)
|
197 |
+
|
198 |
html(
|
199 |
f"""
|
200 |
+
<script defer data-domain="lbgi.fr/myoquant" src="https://plausible.cmeyer.fr/js/script.js"></script>
|
201 |
"""
|
202 |
+
)
|
pages/3_Breast_Muscle_Analysis.py
CHANGED
@@ -1,205 +1,110 @@
|
|
1 |
import streamlit as st
|
2 |
from streamlit.components.v1 import html
|
3 |
-
from cellpose import models, core
|
4 |
-
from stardist.models import StarDist2D
|
5 |
-
from csbdeep.utils import normalize
|
6 |
import matplotlib
|
7 |
|
8 |
try:
|
9 |
from imageio.v2 import imread
|
10 |
except:
|
11 |
from imageio import imread
|
12 |
-
from skimage.measure import regionprops_table
|
13 |
-
import pandas as pd
|
14 |
import matplotlib.pyplot as plt
|
15 |
from stardist import random_label_cmap
|
16 |
-
from tensorflow.config import list_physical_devices
|
17 |
-
from draw_line import *
|
18 |
-
from skimage.draw import line
|
19 |
import numpy as np
|
20 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
21 |
st.set_page_config(
|
22 |
page_title="MyoQuant Breast Analysis",
|
23 |
page_icon="🔬",
|
24 |
)
|
25 |
|
26 |
-
|
27 |
-
use_GPU = True
|
28 |
-
else:
|
29 |
-
use_GPU = False
|
30 |
|
31 |
|
32 |
@st.experimental_singleton
|
33 |
-
def
|
34 |
-
|
35 |
-
return model_c
|
36 |
|
37 |
|
38 |
@st.experimental_singleton
|
39 |
-
def
|
40 |
-
|
41 |
-
return model_s_fluo
|
42 |
|
43 |
|
44 |
@st.experimental_memo
|
45 |
-
def
|
46 |
-
|
47 |
-
mask_cellpose, flow, style, diam = model_cellpose.eval(
|
48 |
-
image, diameter=None, channels=channel
|
49 |
-
)
|
50 |
-
return mask_cellpose
|
51 |
|
52 |
|
53 |
@st.experimental_memo
|
54 |
-
def
|
55 |
-
|
56 |
-
img_norm = normalize(img_norm, 1, 99.8)
|
57 |
-
mask_stardist, _ = model_stardist_fluo.predict_instances(
|
58 |
-
img_norm, nms_thresh=nms_thresh, prob_thresh=prob_thresh
|
59 |
-
)
|
60 |
-
return mask_stardist
|
61 |
|
62 |
|
63 |
@st.experimental_memo
|
64 |
-
def
|
65 |
-
|
66 |
-
cellpose_df.iloc[index, 5] : cellpose_df.iloc[index, 7],
|
67 |
-
cellpose_df.iloc[index, 6] : cellpose_df.iloc[index, 8],
|
68 |
-
].copy()
|
69 |
-
nucleus_single_cell_img = mask_stardist[
|
70 |
-
cellpose_df.iloc[index, 5] : cellpose_df.iloc[index, 7],
|
71 |
-
cellpose_df.iloc[index, 6] : cellpose_df.iloc[index, 8],
|
72 |
-
].copy()
|
73 |
-
single_cell_mask = cellpose_df.iloc[index, 9]
|
74 |
-
single_cell_img[~single_cell_mask] = 0
|
75 |
-
nucleus_single_cell_img[~single_cell_mask] = 0
|
76 |
|
77 |
-
|
78 |
-
|
79 |
-
|
80 |
-
|
81 |
-
"label",
|
82 |
-
"area",
|
83 |
-
"centroid",
|
84 |
-
"eccentricity",
|
85 |
-
"bbox",
|
86 |
-
"image",
|
87 |
-
"perimeter",
|
88 |
-
],
|
89 |
-
)
|
90 |
-
df_nuc_single = pd.DataFrame(props_nuc_single)
|
91 |
-
return single_cell_img, nucleus_single_cell_img, single_cell_mask, df_nuc_single
|
92 |
|
93 |
|
94 |
@st.experimental_memo
|
95 |
-
def
|
96 |
-
|
97 |
-
single_cell_mask,
|
98 |
-
df_nuc_single,
|
99 |
-
x_fiber,
|
100 |
-
y_fiber,
|
101 |
-
internalised_threshold=0.75,
|
102 |
):
|
103 |
-
|
104 |
-
|
105 |
-
|
106 |
-
# Extend line and find closest point
|
107 |
-
m, b = line_equation(x_fiber, y_fiber, value[3], value[2])
|
108 |
-
|
109 |
-
intersections_lst = calculate_intersection(
|
110 |
-
m, b, (single_cell_img.shape[0], single_cell_img.shape[1])
|
111 |
-
)
|
112 |
-
border_point = calculate_closest_point(value[3], value[2], intersections_lst)
|
113 |
-
rr, cc = line(
|
114 |
-
int(y_fiber),
|
115 |
-
int(x_fiber),
|
116 |
-
int(border_point[1]),
|
117 |
-
int(border_point[0]),
|
118 |
-
)
|
119 |
-
for index3, coords in enumerate(list(zip(rr, cc))):
|
120 |
-
try:
|
121 |
-
if single_cell_mask[coords] == 0:
|
122 |
-
dist_nuc_cent = calculate_distance(
|
123 |
-
x_fiber, y_fiber, value[3], value[2]
|
124 |
-
)
|
125 |
-
dist_out_of_fiber = calculate_distance(
|
126 |
-
x_fiber, y_fiber, coords[1], coords[0]
|
127 |
-
)
|
128 |
-
ratio_dist = dist_nuc_cent / dist_out_of_fiber
|
129 |
-
if ratio_dist < internalised_threshold:
|
130 |
-
n_nuc_intern += 1
|
131 |
-
else:
|
132 |
-
n_nuc_periph += 1
|
133 |
-
break
|
134 |
-
except IndexError:
|
135 |
-
coords = list(zip(rr, cc))[index3 - 1]
|
136 |
-
dist_nuc_cent = calculate_distance(x_fiber, y_fiber, value[3], value[2])
|
137 |
-
dist_out_of_fiber = calculate_distance(
|
138 |
-
x_fiber, y_fiber, coords[1], coords[0]
|
139 |
-
)
|
140 |
-
ratio_dist = dist_nuc_cent / dist_out_of_fiber
|
141 |
-
if ratio_dist < internalised_threshold:
|
142 |
-
n_nuc_intern += 1
|
143 |
-
else:
|
144 |
-
n_nuc_periph += 1
|
145 |
-
break
|
146 |
-
|
147 |
-
return n_nuc, n_nuc_intern, n_nuc_periph
|
148 |
|
149 |
|
150 |
@st.experimental_memo
|
151 |
-
def
|
152 |
-
|
153 |
-
):
|
154 |
-
list_n_nuc, list_n_nuc_intern, list_n_nuc_periph = [], [], []
|
155 |
-
for index in range(len(cellpose_df)):
|
156 |
-
(
|
157 |
-
single_cell_img,
|
158 |
-
_,
|
159 |
-
single_cell_mask,
|
160 |
-
df_nuc_single,
|
161 |
-
) = extract_ROIs(histo_img, index, cellpose_df, mask_stardist)
|
162 |
-
x_fiber = cellpose_df.iloc[index, 3] - cellpose_df.iloc[index, 6]
|
163 |
-
y_fiber = cellpose_df.iloc[index, 2] - cellpose_df.iloc[index, 5]
|
164 |
-
n_nuc, n_nuc_intern, n_nuc_periph = single_cell_analysis(
|
165 |
-
single_cell_img,
|
166 |
-
single_cell_mask,
|
167 |
-
df_nuc_single,
|
168 |
-
x_fiber,
|
169 |
-
y_fiber,
|
170 |
-
internalised_threshold,
|
171 |
-
)
|
172 |
-
list_n_nuc.append(n_nuc)
|
173 |
-
list_n_nuc_intern.append(n_nuc_intern)
|
174 |
-
list_n_nuc_periph.append(n_nuc_periph)
|
175 |
-
df_nuc_analysis = pd.DataFrame(
|
176 |
-
list(zip(list_n_nuc, list_n_nuc_intern, list_n_nuc_periph)),
|
177 |
-
columns=["N° Nuc", "N° Nuc Intern", "N° Nuc Periph"],
|
178 |
-
)
|
179 |
-
return df_nuc_analysis
|
180 |
|
181 |
|
182 |
@st.experimental_memo
|
183 |
-
def
|
184 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
185 |
|
186 |
|
187 |
@st.experimental_memo
|
188 |
-
def
|
189 |
-
|
190 |
-
for index in range(len(cellpose_df)):
|
191 |
-
single_cell_mask = cellpose_df.iloc[index, 9].copy()
|
192 |
-
if prediction_df.iloc[index, 1] == 0:
|
193 |
-
paint_img[
|
194 |
-
cellpose_df.iloc[index, 5] : cellpose_df.iloc[index, 7],
|
195 |
-
cellpose_df.iloc[index, 6] : cellpose_df.iloc[index, 8],
|
196 |
-
][single_cell_mask] = 1
|
197 |
-
elif prediction_df.iloc[index, 1] > 0:
|
198 |
-
paint_img[
|
199 |
-
cellpose_df.iloc[index, 5] : cellpose_df.iloc[index, 7],
|
200 |
-
cellpose_df.iloc[index, 6] : cellpose_df.iloc[index, 8],
|
201 |
-
][single_cell_mask] = 2
|
202 |
-
return paint_img
|
203 |
|
204 |
|
205 |
with st.sidebar:
|
@@ -207,10 +112,10 @@ with st.sidebar:
|
|
207 |
nms_thresh = st.slider("Stardist NMS Tresh", 0.0, 1.0, 0.4, 0.1)
|
208 |
prob_thresh = st.slider("Stardist Prob Tresh", 0.5, 1.0, 0.5, 0.05)
|
209 |
st.write("Nuclei Classification Parameter")
|
210 |
-
|
211 |
|
212 |
-
model_cellpose =
|
213 |
-
|
214 |
|
215 |
st.title("Breast Muscle Fiber Analysis")
|
216 |
st.write(
|
@@ -231,8 +136,10 @@ if uploaded_file_cyto is not None and uploaded_file_nuc is not None:
|
|
231 |
st.write("Raw Image Nuc")
|
232 |
image_nuc = st.image(image_ndarray_nuc)
|
233 |
|
234 |
-
mask_cellpose =
|
235 |
-
mask_stardist =
|
|
|
|
|
236 |
mask_stardist_copy = mask_stardist.copy()
|
237 |
|
238 |
st.header("Segmentation Results")
|
@@ -244,60 +151,61 @@ if uploaded_file_cyto is not None and uploaded_file_nuc is not None:
|
|
244 |
ax.axis("off")
|
245 |
st.pyplot(fig)
|
246 |
|
247 |
-
st.subheader("All cells detected by CellPose")
|
248 |
-
props_cellpose = regionprops_table(
|
249 |
-
mask_cellpose,
|
250 |
-
properties=[
|
251 |
-
"label",
|
252 |
-
"area",
|
253 |
-
"centroid",
|
254 |
-
"eccentricity",
|
255 |
-
"bbox",
|
256 |
-
"image",
|
257 |
-
"perimeter",
|
258 |
-
],
|
259 |
-
)
|
260 |
-
df_cellpose = pd.DataFrame(props_cellpose)
|
261 |
-
st.dataframe(df_cellpose.drop("image", axis=1))
|
262 |
-
|
263 |
st.header("Full Nucleus Analysis Results")
|
264 |
-
|
265 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
266 |
)
|
267 |
-
st.
|
268 |
-
st.write("Total number of nucleus : ", df_nuc_analysis["N° Nuc"].sum())
|
269 |
st.write(
|
270 |
"Total number of internalized nucleus : ",
|
271 |
-
|
272 |
" (",
|
273 |
round(
|
274 |
100
|
275 |
-
*
|
276 |
-
/
|
277 |
2,
|
278 |
),
|
279 |
"%)",
|
280 |
)
|
281 |
st.write(
|
282 |
"Total number of peripherical nucleus : ",
|
283 |
-
|
284 |
" (",
|
285 |
round(
|
286 |
100
|
287 |
-
*
|
288 |
-
/
|
289 |
2,
|
290 |
),
|
291 |
"%)",
|
292 |
)
|
293 |
st.write(
|
294 |
"Number of cell with at least one internalized nucleus : ",
|
295 |
-
|
296 |
" (",
|
297 |
round(
|
298 |
100
|
299 |
-
*
|
300 |
-
/ len(
|
301 |
2,
|
302 |
),
|
303 |
"%)",
|
@@ -317,20 +225,13 @@ if uploaded_file_cyto is not None and uploaded_file_nuc is not None:
|
|
317 |
single_cell_img[~single_cell_mask] = 0
|
318 |
nucleus_single_cell_img[~single_cell_mask] = 0
|
319 |
|
320 |
-
|
|
|
321 |
nucleus_single_cell_img,
|
322 |
-
|
323 |
-
|
324 |
-
|
325 |
-
|
326 |
-
"centroid",
|
327 |
-
"eccentricity",
|
328 |
-
"bbox",
|
329 |
-
"image",
|
330 |
-
"perimeter",
|
331 |
-
],
|
332 |
-
)
|
333 |
-
df_nuc_single = pd.DataFrame(props_nuc_single)
|
334 |
st.markdown(
|
335 |
"""
|
336 |
* White point represent cell centroid.
|
@@ -338,83 +239,63 @@ if uploaded_file_cyto is not None and uploaded_file_nuc is not None:
|
|
338 |
* Red point represent the cell border from a straight line between the cell centroid and the nucleus centroid. The red dashed line represent distance between the nucelus and the cell border.
|
339 |
* The periphery ratio is calculated by the division of the distance centroid - nucleus and the distance centroid - cell border."""
|
340 |
)
|
341 |
-
fig2, (ax1, ax2
|
342 |
ax1.imshow(single_cell_img, cmap="gray")
|
343 |
ax2.imshow(nucleus_single_cell_img, cmap="viridis")
|
344 |
# Plot Fiber centroid
|
345 |
x_fiber = df_cellpose.iloc[selected_fiber, 3] - df_cellpose.iloc[selected_fiber, 6]
|
346 |
y_fiber = df_cellpose.iloc[selected_fiber, 2] - df_cellpose.iloc[selected_fiber, 5]
|
347 |
-
ax3.scatter(x_fiber, y_fiber, color="white")
|
348 |
-
# Plot nucleus centroid
|
349 |
-
for index, value in df_nuc_single.iterrows():
|
350 |
-
ax3.scatter(value[3], value[2], color="blue", s=2)
|
351 |
-
# Extend line and find closest point
|
352 |
-
m, b = line_equation(x_fiber, y_fiber, value[3], value[2])
|
353 |
-
|
354 |
-
intersections_lst = calculate_intersection(
|
355 |
-
m, b, (single_cell_img.shape[0], single_cell_img.shape[1])
|
356 |
-
)
|
357 |
-
border_point = calculate_closest_point(value[3], value[2], intersections_lst)
|
358 |
-
ax3.plot(
|
359 |
-
(x_fiber, border_point[0]),
|
360 |
-
(y_fiber, border_point[1]),
|
361 |
-
"ro--",
|
362 |
-
linewidth=1,
|
363 |
-
markersize=1,
|
364 |
-
)
|
365 |
-
ax3.plot(
|
366 |
-
(x_fiber, value[3]),
|
367 |
-
(y_fiber, value[2]),
|
368 |
-
"go--",
|
369 |
-
linewidth=1,
|
370 |
-
markersize=1,
|
371 |
-
)
|
372 |
|
373 |
-
|
374 |
-
|
375 |
-
|
376 |
-
|
377 |
-
|
378 |
-
|
379 |
-
|
380 |
-
|
381 |
-
|
382 |
-
|
383 |
-
|
384 |
-
|
385 |
-
|
386 |
-
|
387 |
-
|
388 |
-
|
389 |
-
|
390 |
-
|
391 |
-
|
392 |
-
coords = list(zip(rr, cc))[index - 1]
|
393 |
-
dist_nuc_cent = calculate_distance(x_fiber, y_fiber, value[3], value[2])
|
394 |
-
dist_out_of_fiber = calculate_distance(
|
395 |
-
x_fiber, y_fiber, coords[1], coords[0]
|
396 |
-
)
|
397 |
-
ratio_dist = dist_nuc_cent / dist_out_of_fiber
|
398 |
-
ax3.scatter(coords[1], coords[0], color="red", s=10)
|
399 |
-
break
|
400 |
-
|
401 |
-
st.write("Nucleus #{} has a periphery ratio of: {}".format(index, ratio_dist))
|
402 |
-
ax3.imshow(single_cell_img)
|
403 |
-
ax3.imshow(nucleus_single_cell_img, cmap="viridis", alpha=0.5)
|
404 |
ax1.axis("off")
|
405 |
ax2.axis("off")
|
406 |
-
|
407 |
-
|
|
|
|
|
408 |
|
|
|
|
|
409 |
st.subheader("All nucleus inside selected cell")
|
410 |
|
411 |
-
st.dataframe(
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
412 |
|
413 |
st.header("Painted predicted image")
|
414 |
st.write(
|
415 |
"Green color indicates cells with only peripherical nuclei, red color indicates cells with at least one internal nucleus (regeneration)."
|
416 |
)
|
417 |
-
painted_img =
|
418 |
fig3, ax3 = plt.subplots(1, 1)
|
419 |
cmap = matplotlib.colors.LinearSegmentedColormap.from_list(
|
420 |
"", ["white", "green", "red"]
|
@@ -423,8 +304,9 @@ if uploaded_file_cyto is not None and uploaded_file_nuc is not None:
|
|
423 |
ax3.imshow(painted_img, cmap=cmap, alpha=0.5)
|
424 |
ax3.axis("off")
|
425 |
st.pyplot(fig3)
|
|
|
426 |
html(
|
427 |
f"""
|
428 |
-
<script defer data-domain="
|
429 |
"""
|
430 |
)
|
|
|
1 |
import streamlit as st
|
2 |
from streamlit.components.v1 import html
|
|
|
|
|
|
|
3 |
import matplotlib
|
4 |
|
5 |
try:
|
6 |
from imageio.v2 import imread
|
7 |
except:
|
8 |
from imageio import imread
|
|
|
|
|
9 |
import matplotlib.pyplot as plt
|
10 |
from stardist import random_label_cmap
|
|
|
|
|
|
|
11 |
import numpy as np
|
12 |
|
13 |
+
from myoquant.src.common_func import (
|
14 |
+
load_cellpose,
|
15 |
+
load_stardist,
|
16 |
+
run_cellpose,
|
17 |
+
run_stardist,
|
18 |
+
is_gpu_availiable,
|
19 |
+
df_from_cellpose_mask,
|
20 |
+
df_from_stardist_mask,
|
21 |
+
)
|
22 |
+
from myoquant.src.HE_analysis import (
|
23 |
+
predict_all_cells,
|
24 |
+
extract_ROIs,
|
25 |
+
single_cell_analysis,
|
26 |
+
paint_histo_img,
|
27 |
+
)
|
28 |
+
|
29 |
+
|
30 |
st.set_page_config(
|
31 |
page_title="MyoQuant Breast Analysis",
|
32 |
page_icon="🔬",
|
33 |
)
|
34 |
|
35 |
+
use_GPU = is_gpu_availiable()
|
|
|
|
|
|
|
36 |
|
37 |
|
38 |
@st.experimental_singleton
|
39 |
+
def st_load_cellpose():
|
40 |
+
return load_cellpose()
|
|
|
41 |
|
42 |
|
43 |
@st.experimental_singleton
|
44 |
+
def st_load_stardist(fluo=False):
|
45 |
+
return load_stardist(fluo)
|
|
|
46 |
|
47 |
|
48 |
@st.experimental_memo
|
49 |
+
def st_run_cellpose(image_ndarray, _model):
|
50 |
+
return run_cellpose(image_ndarray, _model)
|
|
|
|
|
|
|
|
|
51 |
|
52 |
|
53 |
@st.experimental_memo
|
54 |
+
def st_run_stardist(image_ndarray, _model, nms_thresh, prob_thresh):
|
55 |
+
return run_stardist(image_ndarray, _model, nms_thresh, prob_thresh)
|
|
|
|
|
|
|
|
|
|
|
56 |
|
57 |
|
58 |
@st.experimental_memo
|
59 |
+
def st_df_from_cellpose_mask(mask):
|
60 |
+
return df_from_cellpose_mask(mask)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
61 |
|
62 |
+
|
63 |
+
@st.experimental_memo
|
64 |
+
def st_df_from_stardist_mask(mask):
|
65 |
+
return df_from_stardist_mask(mask)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
66 |
|
67 |
|
68 |
@st.experimental_memo
|
69 |
+
def st_predict_all_cells(
|
70 |
+
image_ndarray, df_cellpose, mask_stardist, internalised_threshold
|
|
|
|
|
|
|
|
|
|
|
71 |
):
|
72 |
+
return predict_all_cells(
|
73 |
+
image_ndarray, df_cellpose, mask_stardist, internalised_threshold
|
74 |
+
)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
75 |
|
76 |
|
77 |
@st.experimental_memo
|
78 |
+
def st_extract_ROIs(image_ndarray, selected_fiber, df_cellpose, mask_stardist):
|
79 |
+
return extract_ROIs(image_ndarray, selected_fiber, df_cellpose, mask_stardist)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
80 |
|
81 |
|
82 |
@st.experimental_memo
|
83 |
+
def st_single_cell_analysis(
|
84 |
+
single_cell_img,
|
85 |
+
single_cell_mask,
|
86 |
+
df_nuc_single,
|
87 |
+
x_fiber,
|
88 |
+
y_fiber,
|
89 |
+
selected_fiber,
|
90 |
+
internalised_threshold,
|
91 |
+
draw_and_return=True,
|
92 |
+
):
|
93 |
+
return single_cell_analysis(
|
94 |
+
single_cell_img,
|
95 |
+
single_cell_mask,
|
96 |
+
df_nuc_single,
|
97 |
+
x_fiber,
|
98 |
+
y_fiber,
|
99 |
+
selected_fiber + 1,
|
100 |
+
internalised_threshold,
|
101 |
+
draw_and_return=True,
|
102 |
+
)
|
103 |
|
104 |
|
105 |
@st.experimental_memo
|
106 |
+
def st_paint_histo_img(image_ndarray, df_cellpose, cellpose_df_stat):
|
107 |
+
return paint_histo_img(image_ndarray, df_cellpose, cellpose_df_stat)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
108 |
|
109 |
|
110 |
with st.sidebar:
|
|
|
112 |
nms_thresh = st.slider("Stardist NMS Tresh", 0.0, 1.0, 0.4, 0.1)
|
113 |
prob_thresh = st.slider("Stardist Prob Tresh", 0.5, 1.0, 0.5, 0.05)
|
114 |
st.write("Nuclei Classification Parameter")
|
115 |
+
eccentricity_thresh = st.slider("Eccentricity Score Tresh", 0.0, 1.0, 0.75, 0.05)
|
116 |
|
117 |
+
model_cellpose = st_load_cellpose()
|
118 |
+
model_stardist = st_load_stardist(fluo=True)
|
119 |
|
120 |
st.title("Breast Muscle Fiber Analysis")
|
121 |
st.write(
|
|
|
136 |
st.write("Raw Image Nuc")
|
137 |
image_nuc = st.image(image_ndarray_nuc)
|
138 |
|
139 |
+
mask_cellpose = st_run_cellpose(image_ndarray_cyto, model_cellpose)
|
140 |
+
mask_stardist = st_run_stardist(
|
141 |
+
image_ndarray_nuc, model_stardist, nms_thresh, prob_thresh
|
142 |
+
)
|
143 |
mask_stardist_copy = mask_stardist.copy()
|
144 |
|
145 |
st.header("Segmentation Results")
|
|
|
151 |
ax.axis("off")
|
152 |
st.pyplot(fig)
|
153 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
154 |
st.header("Full Nucleus Analysis Results")
|
155 |
+
df_cellpose = st_df_from_cellpose_mask(mask_cellpose)
|
156 |
+
cellpose_df_stat, all_nuc_df_stats = st_predict_all_cells(
|
157 |
+
image_ndarray_cyto,
|
158 |
+
df_cellpose,
|
159 |
+
mask_stardist,
|
160 |
+
internalised_threshold=eccentricity_thresh,
|
161 |
+
)
|
162 |
+
st.dataframe(
|
163 |
+
cellpose_df_stat.drop(
|
164 |
+
[
|
165 |
+
"centroid-0",
|
166 |
+
"centroid-1",
|
167 |
+
"bbox-0",
|
168 |
+
"bbox-1",
|
169 |
+
"bbox-2",
|
170 |
+
"bbox-3",
|
171 |
+
"image",
|
172 |
+
],
|
173 |
+
axis=1,
|
174 |
+
)
|
175 |
)
|
176 |
+
st.write("Total number of nucleus : ", cellpose_df_stat["N° Nuc"].sum())
|
|
|
177 |
st.write(
|
178 |
"Total number of internalized nucleus : ",
|
179 |
+
cellpose_df_stat["N° Nuc Intern"].sum(),
|
180 |
" (",
|
181 |
round(
|
182 |
100
|
183 |
+
* cellpose_df_stat["N° Nuc Intern"].sum()
|
184 |
+
/ cellpose_df_stat["N° Nuc"].sum(),
|
185 |
2,
|
186 |
),
|
187 |
"%)",
|
188 |
)
|
189 |
st.write(
|
190 |
"Total number of peripherical nucleus : ",
|
191 |
+
cellpose_df_stat["N° Nuc Periph"].sum(),
|
192 |
" (",
|
193 |
round(
|
194 |
100
|
195 |
+
* cellpose_df_stat["N° Nuc Periph"].sum()
|
196 |
+
/ cellpose_df_stat["N° Nuc"].sum(),
|
197 |
2,
|
198 |
),
|
199 |
"%)",
|
200 |
)
|
201 |
st.write(
|
202 |
"Number of cell with at least one internalized nucleus : ",
|
203 |
+
cellpose_df_stat["N° Nuc Intern"].astype(bool).sum(axis=0),
|
204 |
" (",
|
205 |
round(
|
206 |
100
|
207 |
+
* cellpose_df_stat["N° Nuc Intern"].astype(bool).sum(axis=0)
|
208 |
+
/ len(cellpose_df_stat),
|
209 |
2,
|
210 |
),
|
211 |
"%)",
|
|
|
225 |
single_cell_img[~single_cell_mask] = 0
|
226 |
nucleus_single_cell_img[~single_cell_mask] = 0
|
227 |
|
228 |
+
(
|
229 |
+
single_cell_img,
|
230 |
nucleus_single_cell_img,
|
231 |
+
single_cell_mask,
|
232 |
+
df_nuc_single,
|
233 |
+
) = st_extract_ROIs(mergedarrays, selected_fiber, df_cellpose, mask_stardist)
|
234 |
+
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
235 |
st.markdown(
|
236 |
"""
|
237 |
* White point represent cell centroid.
|
|
|
239 |
* Red point represent the cell border from a straight line between the cell centroid and the nucleus centroid. The red dashed line represent distance between the nucelus and the cell border.
|
240 |
* The periphery ratio is calculated by the division of the distance centroid - nucleus and the distance centroid - cell border."""
|
241 |
)
|
242 |
+
fig2, (ax1, ax2) = plt.subplots(1, 2)
|
243 |
ax1.imshow(single_cell_img, cmap="gray")
|
244 |
ax2.imshow(nucleus_single_cell_img, cmap="viridis")
|
245 |
# Plot Fiber centroid
|
246 |
x_fiber = df_cellpose.iloc[selected_fiber, 3] - df_cellpose.iloc[selected_fiber, 6]
|
247 |
y_fiber = df_cellpose.iloc[selected_fiber, 2] - df_cellpose.iloc[selected_fiber, 5]
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
248 |
|
249 |
+
(
|
250 |
+
n_nuc,
|
251 |
+
n_nuc_intern,
|
252 |
+
n_nuc_periph,
|
253 |
+
df_nuc_single_stats,
|
254 |
+
ax_nuc,
|
255 |
+
) = st_single_cell_analysis(
|
256 |
+
single_cell_img,
|
257 |
+
single_cell_mask,
|
258 |
+
df_nuc_single,
|
259 |
+
x_fiber,
|
260 |
+
y_fiber,
|
261 |
+
selected_fiber + 1,
|
262 |
+
internalised_threshold=eccentricity_thresh,
|
263 |
+
draw_and_return=True,
|
264 |
+
)
|
265 |
+
|
266 |
+
for index, value in df_nuc_single_stats.iterrows():
|
267 |
+
st.write("Nucleus #{} has a periphery ratio of: {}".format(index, value[12]))
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
268 |
ax1.axis("off")
|
269 |
ax2.axis("off")
|
270 |
+
# st.pyplot(fig2)
|
271 |
+
ax_nuc.imshow(single_cell_img)
|
272 |
+
ax_nuc.imshow(nucleus_single_cell_img, cmap="viridis", alpha=0.5)
|
273 |
+
f = ax_nuc.figure
|
274 |
|
275 |
+
st.pyplot(fig2)
|
276 |
+
st.pyplot(f)
|
277 |
st.subheader("All nucleus inside selected cell")
|
278 |
|
279 |
+
st.dataframe(
|
280 |
+
df_nuc_single_stats.drop(
|
281 |
+
[
|
282 |
+
"centroid-0",
|
283 |
+
"centroid-1",
|
284 |
+
"bbox-0",
|
285 |
+
"bbox-1",
|
286 |
+
"bbox-2",
|
287 |
+
"bbox-3",
|
288 |
+
"image",
|
289 |
+
],
|
290 |
+
axis=1,
|
291 |
+
)
|
292 |
+
)
|
293 |
|
294 |
st.header("Painted predicted image")
|
295 |
st.write(
|
296 |
"Green color indicates cells with only peripherical nuclei, red color indicates cells with at least one internal nucleus (regeneration)."
|
297 |
)
|
298 |
+
painted_img = st_paint_histo_img(image_ndarray_cyto, df_cellpose, cellpose_df_stat)
|
299 |
fig3, ax3 = plt.subplots(1, 1)
|
300 |
cmap = matplotlib.colors.LinearSegmentedColormap.from_list(
|
301 |
"", ["white", "green", "red"]
|
|
|
304 |
ax3.imshow(painted_img, cmap=cmap, alpha=0.5)
|
305 |
ax3.axis("off")
|
306 |
st.pyplot(fig3)
|
307 |
+
|
308 |
html(
|
309 |
f"""
|
310 |
+
<script defer data-domain="lbgi.fr/myoquant" src="https://plausible.cmeyer.fr/js/script.js"></script>
|
311 |
"""
|
312 |
)
|
pages/4_ATP_Staining_Analysis.py
ADDED
@@ -0,0 +1,171 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
import streamlit as st
|
2 |
+
from streamlit.components.v1 import html
|
3 |
+
import matplotlib
|
4 |
+
|
5 |
+
try:
|
6 |
+
from imageio.v2 import imread
|
7 |
+
except:
|
8 |
+
from imageio import imread
|
9 |
+
import matplotlib.pyplot as plt
|
10 |
+
import pandas as pd
|
11 |
+
import numpy as np
|
12 |
+
from myoquant.src.common_func import (
|
13 |
+
load_cellpose,
|
14 |
+
run_cellpose,
|
15 |
+
is_gpu_availiable,
|
16 |
+
df_from_cellpose_mask,
|
17 |
+
)
|
18 |
+
from myoquant.src.ATP_analysis import (
|
19 |
+
get_all_intensity,
|
20 |
+
estimate_threshold,
|
21 |
+
plot_density,
|
22 |
+
predict_all_cells,
|
23 |
+
paint_full_image,
|
24 |
+
)
|
25 |
+
|
26 |
+
labels_predict = {1: "fiber type 1", 2: "fiber type 2"}
|
27 |
+
|
28 |
+
use_GPU = is_gpu_availiable()
|
29 |
+
np.random.seed(42)
|
30 |
+
|
31 |
+
st.set_page_config(
|
32 |
+
page_title="MyoQuant ATP Analysis",
|
33 |
+
page_icon="🔬",
|
34 |
+
)
|
35 |
+
|
36 |
+
|
37 |
+
@st.experimental_singleton
|
38 |
+
def st_load_cellpose():
|
39 |
+
return load_cellpose()
|
40 |
+
|
41 |
+
|
42 |
+
@st.experimental_memo
|
43 |
+
def st_run_cellpose(image_atp, _model):
|
44 |
+
return run_cellpose(image_atp, _model)
|
45 |
+
|
46 |
+
|
47 |
+
@st.experimental_memo
|
48 |
+
def st_df_from_cellpose_mask(mask):
|
49 |
+
return df_from_cellpose_mask(mask)
|
50 |
+
|
51 |
+
|
52 |
+
@st.experimental_memo
|
53 |
+
def st_get_all_intensity(image_atp, df_cellpose):
|
54 |
+
return get_all_intensity(image_atp, df_cellpose)
|
55 |
+
|
56 |
+
|
57 |
+
@st.experimental_memo
|
58 |
+
def st_estimate_threshold(intensity_list):
|
59 |
+
return estimate_threshold(intensity_list)
|
60 |
+
|
61 |
+
|
62 |
+
@st.experimental_memo
|
63 |
+
def st_plot_density(all_cell_median_intensity, intensity_threshold):
|
64 |
+
return plot_density(all_cell_median_intensity, intensity_threshold)
|
65 |
+
|
66 |
+
|
67 |
+
@st.experimental_memo
|
68 |
+
def st_predict_all_cells(image_atp, cellpose_df, intensity_threshold):
|
69 |
+
return predict_all_cells(image_atp, cellpose_df, intensity_threshold)
|
70 |
+
|
71 |
+
|
72 |
+
@st.experimental_memo
|
73 |
+
def st_paint_full_image(image_atp, df_cellpose, class_predicted_all):
|
74 |
+
return paint_full_image(image_atp, df_cellpose, class_predicted_all)
|
75 |
+
|
76 |
+
|
77 |
+
model_cellpose = st_load_cellpose()
|
78 |
+
|
79 |
+
with st.sidebar:
|
80 |
+
st.write("Threshold Parameters")
|
81 |
+
intensity_threshold = st.slider("Intensity Threshold (0=auto)", 0, 255, 0, 5)
|
82 |
+
|
83 |
+
st.title("ATP Staining Analysis")
|
84 |
+
st.write(
|
85 |
+
"This demo will automatically quantify the number of type 1 muscle fibers vs the number of type 2 muscle fiber on ATP stained images."
|
86 |
+
)
|
87 |
+
st.write("Upload your ATP Staining image")
|
88 |
+
uploaded_file_atp = st.file_uploader("Choose a file")
|
89 |
+
|
90 |
+
if uploaded_file_atp is not None:
|
91 |
+
image_ndarray_atp = imread(uploaded_file_atp)
|
92 |
+
|
93 |
+
st.write("Raw Image")
|
94 |
+
image = st.image(uploaded_file_atp)
|
95 |
+
|
96 |
+
mask_cellpose = st_run_cellpose(image_ndarray_atp, model_cellpose)
|
97 |
+
|
98 |
+
st.header("Segmentation Results")
|
99 |
+
st.subheader("CellPose results")
|
100 |
+
fig, ax = plt.subplots(1, 1)
|
101 |
+
ax.imshow(mask_cellpose, cmap="viridis")
|
102 |
+
ax.axis("off")
|
103 |
+
st.pyplot(fig)
|
104 |
+
|
105 |
+
df_cellpose = st_df_from_cellpose_mask(mask_cellpose)
|
106 |
+
|
107 |
+
st.header("Cell Intensity Plot")
|
108 |
+
all_cell_median_intensity = st_get_all_intensity(image_ndarray_atp, df_cellpose)
|
109 |
+
figure_intensity = st_plot_density(all_cell_median_intensity, intensity_threshold)
|
110 |
+
st.pyplot(figure_intensity)
|
111 |
+
|
112 |
+
st.header("ATP Cell Classification Results")
|
113 |
+
if intensity_threshold == 0:
|
114 |
+
muscle_fiber_type_all, all_cell_median_intensity = st_predict_all_cells(
|
115 |
+
image_ndarray_atp, df_cellpose, intensity_threshold=None
|
116 |
+
)
|
117 |
+
else:
|
118 |
+
muscle_fiber_type_all, all_cell_median_intensity = st_predict_all_cells(
|
119 |
+
image_ndarray_atp, df_cellpose, intensity_threshold=intensity_threshold
|
120 |
+
)
|
121 |
+
df_cellpose["muscle_fiber_type"] = muscle_fiber_type_all
|
122 |
+
df_cellpose["median_intensity"] = all_cell_median_intensity
|
123 |
+
count_per_label = np.unique(muscle_fiber_type_all, return_counts=True)
|
124 |
+
|
125 |
+
st.dataframe(
|
126 |
+
df_cellpose.drop(
|
127 |
+
[
|
128 |
+
"centroid-0",
|
129 |
+
"centroid-1",
|
130 |
+
"bbox-0",
|
131 |
+
"bbox-1",
|
132 |
+
"bbox-2",
|
133 |
+
"bbox-3",
|
134 |
+
"image",
|
135 |
+
],
|
136 |
+
axis=1,
|
137 |
+
)
|
138 |
+
)
|
139 |
+
st.write("Total number of cells detected: ", len(muscle_fiber_type_all))
|
140 |
+
for index, elem in enumerate(count_per_label[0]):
|
141 |
+
st.write(
|
142 |
+
"Number of cells classified as ",
|
143 |
+
labels_predict[int(elem)],
|
144 |
+
": ",
|
145 |
+
count_per_label[1][int(index)],
|
146 |
+
" ",
|
147 |
+
100 * count_per_label[1][int(index)] / len(muscle_fiber_type_all),
|
148 |
+
"%",
|
149 |
+
)
|
150 |
+
|
151 |
+
st.header("Painted predicted image")
|
152 |
+
st.write(
|
153 |
+
"Green color indicates cells classified as control, red color indicates cells classified as sick"
|
154 |
+
)
|
155 |
+
paint_img = st_paint_full_image(
|
156 |
+
image_ndarray_atp, df_cellpose, muscle_fiber_type_all
|
157 |
+
)
|
158 |
+
fig3, ax3 = plt.subplots(1, 1)
|
159 |
+
cmap = matplotlib.colors.LinearSegmentedColormap.from_list(
|
160 |
+
"", ["white", "green", "red"]
|
161 |
+
)
|
162 |
+
ax3.imshow(image_ndarray_atp)
|
163 |
+
ax3.imshow(paint_img, cmap=cmap, alpha=0.5)
|
164 |
+
ax3.axis("off")
|
165 |
+
st.pyplot(fig3)
|
166 |
+
|
167 |
+
html(
|
168 |
+
f"""
|
169 |
+
<script defer data-domain="lbgi.fr/myoquant" src="https://plausible.cmeyer.fr/js/script.js"></script>
|
170 |
+
"""
|
171 |
+
)
|
poetry.lock
CHANGED
The diff for this file is too large to render.
See raw diff
|
|
pyproject.toml
CHANGED
@@ -1,23 +1,29 @@
|
|
1 |
[tool.poetry]
|
2 |
name = "MyoQuant-Streamlit"
|
3 |
-
version = "0.
|
4 |
description = "Streamlit demo version of the MyoQuant tool"
|
5 |
authors = ["Corentin"]
|
6 |
license = "AGPL"
|
7 |
|
8 |
[tool.poetry.dependencies]
|
9 |
-
python = ">=3.
|
10 |
-
|
11 |
-
cellpose = "^2.1.0"
|
12 |
-
stardist = "^0.8.3"
|
13 |
streamlit = "^1.12.0"
|
14 |
-
|
15 |
imageio = "^2.21.1"
|
16 |
-
scikit-image = "^0.19.3"
|
17 |
pandas = "^1.4.3"
|
18 |
matplotlib = "^3.5.3"
|
|
|
19 |
|
20 |
-
[tool.poetry.dev
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
21 |
|
22 |
[build-system]
|
23 |
requires = ["poetry-core>=1.0.0"]
|
|
|
1 |
[tool.poetry]
|
2 |
name = "MyoQuant-Streamlit"
|
3 |
+
version = "0.3.0"
|
4 |
description = "Streamlit demo version of the MyoQuant tool"
|
5 |
authors = ["Corentin"]
|
6 |
license = "AGPL"
|
7 |
|
8 |
[tool.poetry.dependencies]
|
9 |
+
python = ">=3.8,<3.11"
|
10 |
+
myoquant = "^0.3.1"
|
|
|
|
|
11 |
streamlit = "^1.12.0"
|
12 |
+
pyngrok = "^5.1.0"
|
13 |
imageio = "^2.21.1"
|
|
|
14 |
pandas = "^1.4.3"
|
15 |
matplotlib = "^3.5.3"
|
16 |
+
ipykernel = "^6.15.1"
|
17 |
|
18 |
+
[tool.poetry.group.dev.dependencies]
|
19 |
+
ruff = "*"
|
20 |
+
mkdocs-material = "*"
|
21 |
+
black = {extras = ["jupyter"], version = "*"}
|
22 |
+
ipykernel = "*"
|
23 |
+
pytest = "*"
|
24 |
+
pre-commit = "*"
|
25 |
+
mypy = "*"
|
26 |
+
mkdocstrings = "*"
|
27 |
|
28 |
[build-system]
|
29 |
requires = ["poetry-core>=1.0.0"]
|