Skip to content

Commit ea24108

Browse files
Merge pull request #12 from lambda-science/dev
Dev
2 parents 31190a9 + 695659e commit ea24108

11 files changed

+531
-362
lines changed

.gitignore

+5-1
Original file line numberDiff line numberDiff line change
@@ -169,4 +169,8 @@ debug_data/
169169
!nuclei.tif
170170
!cytoplasm.tif
171171
!binary_mask_sdh.tif
172-
data/*
172+
data/*
173+
*intensity_plot.png
174+
*.idea
175+
cellpose.sh
176+
nohup.out

.python-version

+1-1
Original file line numberDiff line numberDiff line change
@@ -1 +1 @@
1-
3.10.9
1+
3.10.11

.vscode/launch.json

+1-1
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,7 @@
2626
"request": "launch",
2727
"module": "myoquant",
2828
"justMyCode": true,
29-
"args": ["atp-analysis", "sample_img/sample_atp.jpg", "--cellpose-path", "sample_img/sample_atp_cellpose_mask.tiff"],
29+
"args": ["atp-analysis", "sample_img/sample_atp.jpg", "--cellpose-path", "sample_img/sample_atp_cellpose_mask.tiff", "--intensity-method", "mean", "--n-classes", "2", "--erosion"],
3030
}
3131
]
3232
}

CLI_Documentation.md

+7
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@ $ myoquant [OPTIONS] COMMAND [ARGS]...
1010

1111
**Options**:
1212

13+
- `--version`
1314
- `--help`: Show this message and exit.
1415

1516
**Commands**:
@@ -43,6 +44,12 @@ $ myoquant atp-analysis [OPTIONS] IMAGE_PATH
4344
- `--output-path PATH`: The path to the folder to save the results. Will save in the same folder as input image if not specified.
4445
- `--intensity-threshold INTEGER RANGE`: Fiber intensity threshold to differenciate between the two fiber types. If not specified, the analysis will try to deduce it. [1<=x<=254]
4546
- `--cellpose-diameter INTEGER`: Approximative single cell diameter in pixel for CellPose detection. If not specified, Cellpose will try to deduce it.
47+
- `--channel INTEGER`: Image channel to use for the analysis. If not specified, the analysis will be performed on all three channels.
48+
- `--channel-first / --no-channel-first`: If the channel is the first dimension of the image, set this to True. False by default. [default: no-channel-first]
49+
- `--rescale-exposure / --no-rescale-exposure`: Rescale the image exposure if your image is not in the 0 255 forma, False by default. [default: no-rescale-exposure]
50+
- `--n-classes INTEGER RANGE`: The number of classes of cell to detect. If not specified this is defaulted to two classes. [default: 2; x<=10]
51+
- `--intensity-method TEXT`: The method to use to compute the intensity of the cell. Can be either 'median' or 'mean'. [default: median]
52+
- `--erosion INTEGER RANGE`: Perform an erosion on the cells images to remove signal in the cell membrane (usefull for fluo). Expressed in percentage of the cell radius [default: False; x<=45]
4653
- `--export-map / --no-export-map`: Export the original image with cells painted by classification label. [default: export-map]
4754
- `--export-stats / --no-export-stats`: Export per fiber and per nuclei stat table. [default: export-stats]
4855
- `--help`: Show this message and exit.

myoquant/__main__.py

+27
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,27 @@
11
import typer
22
from rich.console import Console
3+
import pkg_resources
4+
5+
__version__ = pkg_resources.get_distribution("myoquant").version
6+
__version_cellpose__ = pkg_resources.get_distribution("cellpose").version
7+
__version_stardist__ = pkg_resources.get_distribution("stardist").version
8+
__version_torch__ = pkg_resources.get_distribution("torch").version
9+
__version_tensorflow__ = pkg_resources.get_distribution("tensorflow").version
310

411
from .commands.docs import app as docs_app
512
from .commands import run_sdh, run_he, run_atp
613

714
console = Console()
815

16+
17+
def version_callback(value: bool):
18+
if value:
19+
print(
20+
f"MyoQuant Version: {__version__} \nCellpose Version: {__version_cellpose__} \nStardist Version: {__version_stardist__} \nTorch Version: {__version_torch__} \nTensorflow Version: {__version_tensorflow__}"
21+
)
22+
raise typer.Exit()
23+
24+
925
app = typer.Typer(
1026
name="MyoQuant",
1127
add_completion=False,
@@ -15,6 +31,17 @@
1531
app.add_typer(docs_app, name="docs", help="Generate documentation")
1632

1733

34+
@app.callback()
35+
def main(
36+
version: bool = typer.Option(
37+
None, "--version", callback=version_callback, is_eager=True
38+
)
39+
):
40+
"""
41+
MyoQuant Analysis Command Line Interface
42+
"""
43+
44+
1845
app.registered_commands += (
1946
run_sdh.app.registered_commands
2047
+ run_he.app.registered_commands

myoquant/commands/run_atp.py

+56-4
Original file line numberDiff line numberDiff line change
@@ -59,6 +59,32 @@ def atp_analysis(
5959
None,
6060
help="Approximative single cell diameter in pixel for CellPose detection. If not specified, Cellpose will try to deduce it.",
6161
),
62+
channel: int = typer.Option(
63+
None,
64+
help="Image channel to use for the analysis. If not specified, the analysis will be performed on all three channels.",
65+
),
66+
channel_first: bool = typer.Option(
67+
False,
68+
help="If the channel is the first dimension of the image, set this to True. False by default.",
69+
),
70+
rescale_exposure: bool = typer.Option(
71+
False,
72+
help="Rescale the image exposure if your image is not in the 0 255 forma, False by default.",
73+
),
74+
n_classes: int = typer.Option(
75+
2,
76+
max=10,
77+
help="The number of classes of cell to detect. If not specified this is defaulted to two classes.",
78+
),
79+
intensity_method: str = typer.Option(
80+
"median",
81+
help="The method to use to compute the intensity of the cell. Can be either 'median' or 'mean'.",
82+
),
83+
erosion: int = typer.Option(
84+
False,
85+
max=45,
86+
help="Perform an erosion on the cells images to remove signal in the cell membrane (usefull for fluo). Expressed in percentage of the cell radius",
87+
),
6288
export_map: bool = typer.Option(
6389
True,
6490
help="Export the original image with cells painted by classification label.",
@@ -110,6 +136,7 @@ def atp_analysis(
110136
from ..src.ATP_analysis import run_atp_analysis
111137
import numpy as np
112138
from PIL import Image
139+
from skimage.exposure import rescale_intensity
113140

114141
try:
115142
from imageio.v2 import imread
@@ -135,7 +162,17 @@ def atp_analysis(
135162
) as progress:
136163
progress.add_task(description="Reading all inputs...", total=None)
137164
image_ndarray = imread(image_path)
138-
165+
if channel is not None:
166+
if channel_first:
167+
# Put the channel as third dimension instead of first
168+
image_ndarray = np.moveaxis(image_ndarray, 0, -1)
169+
image_ndarray = image_ndarray[:, :, channel]
170+
if rescale_exposure:
171+
image_ndarray = rescale_intensity(
172+
image_ndarray,
173+
in_range=(np.amin(image_ndarray), np.amax(image_ndarray)),
174+
out_range=np.uint8,
175+
)
139176
if mask_path is not None:
140177
mask_ndarray = imread(mask_path)
141178
if np.unique(mask_ndarray).shape[0] != 2:
@@ -200,8 +237,13 @@ def atp_analysis(
200237
transient=False,
201238
) as progress:
202239
progress.add_task(description="Detecting fiber types...", total=None)
203-
result_df, full_label_map, df_cellpose_details = run_atp_analysis(
204-
image_ndarray, mask_cellpose, intensity_threshold
240+
result_df, full_label_map, df_cellpose_details, fig = run_atp_analysis(
241+
image_ndarray,
242+
mask_cellpose,
243+
intensity_threshold,
244+
n_classes,
245+
intensity_method,
246+
erosion,
205247
)
206248
if export_map:
207249
with Progress(
@@ -214,7 +256,12 @@ def atp_analysis(
214256
description="Blending label and original image together...", total=None
215257
)
216258
labelRGB_map = label2rgb(image_ndarray, full_label_map)
217-
overlay_img = blend_image_with_label(image_ndarray, labelRGB_map)
259+
if channel is not None:
260+
overlay_img = blend_image_with_label(
261+
image_ndarray, labelRGB_map, fluo=True
262+
)
263+
else:
264+
overlay_img = blend_image_with_label(image_ndarray, labelRGB_map)
218265
overlay_filename = image_path.stem + "_label_blend.tiff"
219266
overlay_img.save(output_path / overlay_filename)
220267

@@ -239,6 +286,11 @@ def atp_analysis(
239286
f"💾 OUTPUT: Summary Table saved as {output_path/csv_name}",
240287
style="green",
241288
)
289+
plot_name = image_path.stem + "_intensity_plot.png"
290+
fig.savefig(output_path / plot_name)
291+
console.print(
292+
f"💾 OUTPUT: Intensity Plot saved as {output_path/plot_name}", style="green"
293+
)
242294
if export_map:
243295
console.print(
244296
f"💾 OUTPUT: Overlay image saved as {output_path/overlay_filename}",

0 commit comments

Comments
 (0)