lambda scientist commited on
Commit
1ec5a7d
1 Parent(s): 2dd5ab4

New version

Browse files
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 and anomaly in the mitochondria distribution in muscle fibers with SDH staining.
25
  This web application is intended for demonstration purposes only.
26
 
27
- ## How to Use
28
- This space is deployed at https://huggingface.co/spaces/corentinm7/MyoQuant
29
- Once on the space, click on the corresponding staining analysis on the sidebar, and upload your histology image. Results will be displayed in the main area automatically.
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
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 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 HE Analysis",
23
  page_icon="🔬",
24
  )
25
 
26
- if len(list_physical_devices("GPU")) >= 1:
27
- use_GPU = True
28
- else:
29
- use_GPU = False
30
 
31
 
32
  @st.experimental_singleton
33
- def load_cellpose():
34
- model_c = models.Cellpose(gpu=use_GPU, model_type="cyto2")
35
- return model_c
36
 
37
 
38
  @st.experimental_singleton
39
- def load_stardist():
40
- model_s = StarDist2D.from_pretrained("2D_versatile_he")
41
- return model_s
42
 
43
 
44
  @st.experimental_memo
45
- def run_cellpose(image):
46
- channel = [[0, 0]]
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 run_stardist(image, nms_thresh=0.4, prob_thresh=0.5):
55
- img_norm = image / 255
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 extract_ROIs(histo_img, index, cellpose_df, mask_stardist):
65
- single_cell_img = histo_img[
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 single_cell_analysis(
96
- single_cell_img,
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 predict_all_cells(
152
- histo_img, cellpose_df, mask_stardist, internalised_threshold=0.75
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, 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 predict_single_cell(histo_img, cellpose_df, mask_stardist):
179
- pass
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
180
 
181
 
182
  @st.experimental_memo
183
- def paint_histo_img(histo_img, cellpose_df, prediction_df):
184
- paint_img = np.zeros((histo_img.shape[0], histo_img.shape[1]), dtype=np.uint8)
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("Models Parameters")
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 = load_cellpose()
206
- model_stardist = load_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 = run_cellpose(image_ndarray)
221
- mask_stardist = run_stardist(image_ndarray, nms_thresh, prob_thresh)
 
 
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
- props_cellpose = regionprops_table(
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
- df_nuc_analysis = predict_all_cells(image_ndarray, df_cellpose, mask_stardist)
251
- st.dataframe(df_nuc_analysis)
252
- st.write("Total number of nucleus : ", df_nuc_analysis["N° Nuc"].sum())
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
253
  st.write(
254
  "Total number of internalized nucleus : ",
255
- df_nuc_analysis["N° Nuc Intern"].sum(),
256
  " (",
257
  round(
258
  100
259
- * df_nuc_analysis["N° Nuc Intern"].sum()
260
- / df_nuc_analysis["N° Nuc"].sum(),
261
  2,
262
  ),
263
  "%)",
264
  )
265
  st.write(
266
  "Total number of peripherical nucleus : ",
267
- df_nuc_analysis["N° Nuc Periph"].sum(),
268
  " (",
269
  round(
270
  100
271
- * df_nuc_analysis["N° Nuc Periph"].sum()
272
- / df_nuc_analysis["N° Nuc"].sum(),
273
  2,
274
  ),
275
  "%)",
276
  )
277
  st.write(
278
  "Number of cell with at least one internalized nucleus : ",
279
- df_nuc_analysis["N° Nuc Intern"].astype(bool).sum(axis=0),
280
  " (",
281
  round(
282
  100
283
- * df_nuc_analysis["N° Nuc Intern"].astype(bool).sum(axis=0)
284
- / len(df_nuc_analysis),
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
- single_cell_img = image_ndarray[
293
- df_cellpose.iloc[selected_fiber, 5] : df_cellpose.iloc[selected_fiber, 7],
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
- intensity_image=single_cell_img,
307
- properties=[
308
- "label",
309
- "area",
310
- "centroid",
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
- fig2, (ax1, ax2, ax3) = plt.subplots(1, 3)
 
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
- rr, cc = line(
358
- int(y_fiber),
359
- int(x_fiber),
360
- int(border_point[1]),
361
- int(border_point[0]),
362
- )
363
- for index, coords in enumerate(list(zip(rr, cc))):
364
- try:
365
- if single_cell_mask[coords] == 0:
366
- dist_nuc_cent = calculate_distance(
367
- x_fiber, y_fiber, value[3], value[2]
368
- )
369
- dist_out_of_fiber = calculate_distance(
370
- x_fiber, y_fiber, coords[1], coords[0]
371
- )
372
- ratio_dist = dist_nuc_cent / dist_out_of_fiber
373
- ax3.scatter(coords[1], coords[0], color="red", s=10)
374
- break
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
- ax3.axis("off")
391
- st.pyplot(fig2)
 
 
392
 
 
 
393
  st.subheader("All nucleus inside selected cell")
394
 
395
- st.dataframe(df_nuc_single.drop("image", axis=1))
 
 
 
 
 
 
 
 
 
 
 
 
 
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 = paint_histo_img(image_ndarray, df_cellpose, df_nuc_analysis)
402
- fig3, ax3 = plt.subplots(1, 1)
403
  cmap = matplotlib.colors.LinearSegmentedColormap.from_list(
404
  "", ["white", "green", "red"]
405
  )
406
- ax3.imshow(image_ndarray)
407
- ax3.imshow(painted_img, cmap=cmap, alpha=0.5)
408
- ax3.axis("off")
409
- st.pyplot(fig3)
 
410
  html(
411
  f"""
412
- <script defer data-domain="huggingface.co/spaces/corentinm7/myoquant" src="https://plausible.cmeyer.fr/js/script.js"></script>
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
- from tensorflow.config import list_physical_devices
17
- from tensorflow import keras
18
-
19
- from gradcam import *
20
  from os import path
21
  import urllib.request
22
- from random_brightness import *
23
-
24
- labels_predict = ["control", "sick"]
25
-
26
- tf.random.set_seed(42)
27
- np.random.seed(42)
 
 
 
 
 
 
 
28
 
29
  st.set_page_config(
30
  page_title="MyoQuant SDH Analysis",
31
  page_icon="🔬",
32
  )
33
 
34
- if path.exists("model.h5"):
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 load_cellpose():
52
- model_c = Cellpose(gpu=use_GPU, model_type="cyto2")
53
- return model_c
54
 
55
 
56
  @st.experimental_singleton
57
- def load_sdh_model():
58
- model_sdh = keras.models.load_model(
59
- "model.h5", custom_objects={"RandomBrightness": RandomBrightness}
60
- )
61
- return model_sdh
62
 
63
 
64
  @st.experimental_memo
65
- def run_cellpose(image):
66
- channel = [[0, 0]]
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 predict_single_cell(single_cell_img, _model_SDH):
75
- img_array = np.empty((1, 256, 256, 3))
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 resize_batch_cells(histo_img, cellpose_df):
89
- img_array_full = np.empty((len(cellpose_df), 256, 256, 3))
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
- img_array_full[index] = tf.image.resize(single_cell_img, (256, 256))
100
- return img_array_full
 
101
 
102
 
103
  @st.experimental_memo
104
- def predict_all_cells(histo_img, cellpose_df, _model_SDH):
105
- predicted_class_array = np.empty((len(cellpose_df)))
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 paint_full_image(image_sdh, df_cellpose, class_predicted_all):
119
- image_sdh_paint = np.zeros((image_sdh.shape[0], image_sdh.shape[1]), dtype=np.uint8)
120
- for index in range(len(df_cellpose)):
121
- single_cell_mask = df_cellpose.iloc[index, 9].copy()
122
- if class_predicted_all[index] == 0:
123
- image_sdh_paint[
124
- df_cellpose.iloc[index, 5] : df_cellpose.iloc[index, 7],
125
- df_cellpose.iloc[index, 6] : df_cellpose.iloc[index, 8],
126
- ][single_cell_mask] = 1
127
- elif class_predicted_all[index] == 1:
128
- image_sdh_paint[
129
- df_cellpose.iloc[index, 5] : df_cellpose.iloc[index, 7],
130
- df_cellpose.iloc[index, 6] : df_cellpose.iloc[index, 8],
131
- ][single_cell_mask] = 2
132
- return image_sdh_paint
133
-
134
-
135
- model_cellpose = load_cellpose()
136
-
137
- model_SDH = load_sdh_model()
 
 
 
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 = run_cellpose(image_ndarray_sdh)
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
- class_predicted_all, proba_predicted_all = predict_all_cells(
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
- class_and_proba_df
 
 
 
 
 
 
 
 
 
 
 
 
 
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 = image_ndarray_sdh[
206
- df_cellpose.iloc[selected_fiber, 5] : df_cellpose.iloc[selected_fiber, 7],
207
- df_cellpose.iloc[selected_fiber, 6] : df_cellpose.iloc[selected_fiber, 8],
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 = predict_single_cell(
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 = paint_full_image(image_ndarray_sdh, df_cellpose, class_predicted_all)
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="huggingface.co/spaces/corentinm7/myoquant" src="https://plausible.cmeyer.fr/js/script.js"></script>
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
- if len(list_physical_devices("GPU")) >= 1:
27
- use_GPU = True
28
- else:
29
- use_GPU = False
30
 
31
 
32
  @st.experimental_singleton
33
- def load_cellpose():
34
- model_c = models.Cellpose(gpu=use_GPU, model_type="cyto2")
35
- return model_c
36
 
37
 
38
  @st.experimental_singleton
39
- def load_stardist_fluo():
40
- model_s_fluo = StarDist2D.from_pretrained("2D_versatile_fluo")
41
- return model_s_fluo
42
 
43
 
44
  @st.experimental_memo
45
- def run_cellpose(image):
46
- channel = [[0, 0]]
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 run_stardist(image, nms_thresh=0.4, prob_thresh=0.5):
55
- img_norm = image / 255
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 extract_ROIs(histo_img, index, cellpose_df, mask_stardist):
65
- single_cell_img = histo_img[
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 single_cell_analysis(
96
- single_cell_img,
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 predict_all_cells(
152
- histo_img, cellpose_df, mask_stardist, internalised_threshold=0.75
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 predict_single_cell(histo_img, cellpose_df, mask_stardist):
184
- pass
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
185
 
186
 
187
  @st.experimental_memo
188
- def paint_histo_img(histo_img, cellpose_df, prediction_df):
189
- paint_img = np.zeros((histo_img.shape[0], histo_img.shape[1]), dtype=np.uint8)
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
- center_thresh = st.slider("Eccentricity Score Tresh", 0.0, 1.0, 0.75, 0.05)
211
 
212
- model_cellpose = load_cellpose()
213
- model_stardist_fluo = load_stardist_fluo()
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 = run_cellpose(image_ndarray_cyto)
235
- mask_stardist = run_stardist(image_ndarray_nuc, nms_thresh, prob_thresh)
 
 
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
- df_nuc_analysis = predict_all_cells(
265
- image_ndarray_cyto, df_cellpose, mask_stardist, center_thresh
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
266
  )
267
- st.dataframe(df_nuc_analysis)
268
- st.write("Total number of nucleus : ", df_nuc_analysis["N° Nuc"].sum())
269
  st.write(
270
  "Total number of internalized nucleus : ",
271
- df_nuc_analysis["N° Nuc Intern"].sum(),
272
  " (",
273
  round(
274
  100
275
- * df_nuc_analysis["N° Nuc Intern"].sum()
276
- / df_nuc_analysis["N° Nuc"].sum(),
277
  2,
278
  ),
279
  "%)",
280
  )
281
  st.write(
282
  "Total number of peripherical nucleus : ",
283
- df_nuc_analysis["N° Nuc Periph"].sum(),
284
  " (",
285
  round(
286
  100
287
- * df_nuc_analysis["N° Nuc Periph"].sum()
288
- / df_nuc_analysis["N° Nuc"].sum(),
289
  2,
290
  ),
291
  "%)",
292
  )
293
  st.write(
294
  "Number of cell with at least one internalized nucleus : ",
295
- df_nuc_analysis["N° Nuc Intern"].astype(bool).sum(axis=0),
296
  " (",
297
  round(
298
  100
299
- * df_nuc_analysis["N° Nuc Intern"].astype(bool).sum(axis=0)
300
- / len(df_nuc_analysis),
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
- props_nuc_single = regionprops_table(
 
321
  nucleus_single_cell_img,
322
- intensity_image=single_cell_img,
323
- properties=[
324
- "label",
325
- "area",
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, ax3) = plt.subplots(1, 3)
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
- rr, cc = line(
374
- int(y_fiber),
375
- int(x_fiber),
376
- int(border_point[1]),
377
- int(border_point[0]),
378
- )
379
- for index, coords in enumerate(list(zip(rr, cc))):
380
- try:
381
- if single_cell_mask[coords] == 0:
382
- dist_nuc_cent = calculate_distance(
383
- x_fiber, y_fiber, value[3], value[2]
384
- )
385
- dist_out_of_fiber = calculate_distance(
386
- x_fiber, y_fiber, coords[1], coords[0]
387
- )
388
- ratio_dist = dist_nuc_cent / dist_out_of_fiber
389
- ax3.scatter(coords[1], coords[0], color="red", s=10)
390
- break
391
- except IndexError:
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
- ax3.axis("off")
407
- st.pyplot(fig2)
 
 
408
 
 
 
409
  st.subheader("All nucleus inside selected cell")
410
 
411
- st.dataframe(df_nuc_single.drop("image", axis=1))
 
 
 
 
 
 
 
 
 
 
 
 
 
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 = paint_histo_img(image_ndarray_cyto, df_cellpose, df_nuc_analysis)
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="huggingface.co/spaces/corentinm7/myoquant" src="https://plausible.cmeyer.fr/js/script.js"></script>
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.1.0"
4
  description = "Streamlit demo version of the MyoQuant tool"
5
  authors = ["Corentin"]
6
  license = "AGPL"
7
 
8
  [tool.poetry.dependencies]
9
- python = ">=3.9,<3.11"
10
- tensorflow = "^2.9.1"
11
- cellpose = "^2.1.0"
12
- stardist = "^0.8.3"
13
  streamlit = "^1.12.0"
14
- csbdeep = "^0.7.2"
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-dependencies]
 
 
 
 
 
 
 
 
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"]