Skip to content

Dev #12

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 5 commits into from
May 10, 2023
Merged

Dev #12

Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 5 additions & 1 deletion .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -169,4 +169,8 @@ debug_data/
!nuclei.tif
!cytoplasm.tif
!binary_mask_sdh.tif
data/*
data/*
*intensity_plot.png
*.idea
cellpose.sh
nohup.out
2 changes: 1 addition & 1 deletion .python-version
Original file line number Diff line number Diff line change
@@ -1 +1 @@
3.10.9
3.10.11
2 changes: 1 addition & 1 deletion .vscode/launch.json
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@
"request": "launch",
"module": "myoquant",
"justMyCode": true,
"args": ["atp-analysis", "sample_img/sample_atp.jpg", "--cellpose-path", "sample_img/sample_atp_cellpose_mask.tiff"],
"args": ["atp-analysis", "sample_img/sample_atp.jpg", "--cellpose-path", "sample_img/sample_atp_cellpose_mask.tiff", "--intensity-method", "mean", "--n-classes", "2", "--erosion"],
}
]
}
7 changes: 7 additions & 0 deletions CLI_Documentation.md
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ $ myoquant [OPTIONS] COMMAND [ARGS]...

**Options**:

- `--version`
- `--help`: Show this message and exit.

**Commands**:
Expand Down Expand Up @@ -43,6 +44,12 @@ $ myoquant atp-analysis [OPTIONS] IMAGE_PATH
- `--output-path PATH`: The path to the folder to save the results. Will save in the same folder as input image if not specified.
- `--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]
- `--cellpose-diameter INTEGER`: Approximative single cell diameter in pixel for CellPose detection. If not specified, Cellpose will try to deduce it.
- `--channel INTEGER`: Image channel to use for the analysis. If not specified, the analysis will be performed on all three channels.
- `--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]
- `--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]
- `--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]
- `--intensity-method TEXT`: The method to use to compute the intensity of the cell. Can be either 'median' or 'mean'. [default: median]
- `--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]
- `--export-map / --no-export-map`: Export the original image with cells painted by classification label. [default: export-map]
- `--export-stats / --no-export-stats`: Export per fiber and per nuclei stat table. [default: export-stats]
- `--help`: Show this message and exit.
Expand Down
27 changes: 27 additions & 0 deletions myoquant/__main__.py
Original file line number Diff line number Diff line change
@@ -1,11 +1,27 @@
import typer
from rich.console import Console
import pkg_resources

__version__ = pkg_resources.get_distribution("myoquant").version
__version_cellpose__ = pkg_resources.get_distribution("cellpose").version
__version_stardist__ = pkg_resources.get_distribution("stardist").version
__version_torch__ = pkg_resources.get_distribution("torch").version
__version_tensorflow__ = pkg_resources.get_distribution("tensorflow").version

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

console = Console()


def version_callback(value: bool):
if value:
print(
f"MyoQuant Version: {__version__} \nCellpose Version: {__version_cellpose__} \nStardist Version: {__version_stardist__} \nTorch Version: {__version_torch__} \nTensorflow Version: {__version_tensorflow__}"
)
raise typer.Exit()


app = typer.Typer(
name="MyoQuant",
add_completion=False,
Expand All @@ -15,6 +31,17 @@
app.add_typer(docs_app, name="docs", help="Generate documentation")


@app.callback()
def main(
version: bool = typer.Option(
None, "--version", callback=version_callback, is_eager=True
)
):
"""
MyoQuant Analysis Command Line Interface
"""


app.registered_commands += (
run_sdh.app.registered_commands
+ run_he.app.registered_commands
Expand Down
60 changes: 56 additions & 4 deletions myoquant/commands/run_atp.py
Original file line number Diff line number Diff line change
Expand Up @@ -59,6 +59,32 @@ def atp_analysis(
None,
help="Approximative single cell diameter in pixel for CellPose detection. If not specified, Cellpose will try to deduce it.",
),
channel: int = typer.Option(
None,
help="Image channel to use for the analysis. If not specified, the analysis will be performed on all three channels.",
),
channel_first: bool = typer.Option(
False,
help="If the channel is the first dimension of the image, set this to True. False by default.",
),
rescale_exposure: bool = typer.Option(
False,
help="Rescale the image exposure if your image is not in the 0 255 forma, False by default.",
),
n_classes: int = typer.Option(
2,
max=10,
help="The number of classes of cell to detect. If not specified this is defaulted to two classes.",
),
intensity_method: str = typer.Option(
"median",
help="The method to use to compute the intensity of the cell. Can be either 'median' or 'mean'.",
),
erosion: int = typer.Option(
False,
max=45,
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",
),
export_map: bool = typer.Option(
True,
help="Export the original image with cells painted by classification label.",
Expand Down Expand Up @@ -110,6 +136,7 @@ def atp_analysis(
from ..src.ATP_analysis import run_atp_analysis
import numpy as np
from PIL import Image
from skimage.exposure import rescale_intensity

try:
from imageio.v2 import imread
Expand All @@ -135,7 +162,17 @@ def atp_analysis(
) as progress:
progress.add_task(description="Reading all inputs...", total=None)
image_ndarray = imread(image_path)

if channel is not None:
if channel_first:
# Put the channel as third dimension instead of first
image_ndarray = np.moveaxis(image_ndarray, 0, -1)
image_ndarray = image_ndarray[:, :, channel]
if rescale_exposure:
image_ndarray = rescale_intensity(
image_ndarray,
in_range=(np.amin(image_ndarray), np.amax(image_ndarray)),
out_range=np.uint8,
)
if mask_path is not None:
mask_ndarray = imread(mask_path)
if np.unique(mask_ndarray).shape[0] != 2:
Expand Down Expand Up @@ -200,8 +237,13 @@ def atp_analysis(
transient=False,
) as progress:
progress.add_task(description="Detecting fiber types...", total=None)
result_df, full_label_map, df_cellpose_details = run_atp_analysis(
image_ndarray, mask_cellpose, intensity_threshold
result_df, full_label_map, df_cellpose_details, fig = run_atp_analysis(
image_ndarray,
mask_cellpose,
intensity_threshold,
n_classes,
intensity_method,
erosion,
)
if export_map:
with Progress(
Expand All @@ -214,7 +256,12 @@ def atp_analysis(
description="Blending label and original image together...", total=None
)
labelRGB_map = label2rgb(image_ndarray, full_label_map)
overlay_img = blend_image_with_label(image_ndarray, labelRGB_map)
if channel is not None:
overlay_img = blend_image_with_label(
image_ndarray, labelRGB_map, fluo=True
)
else:
overlay_img = blend_image_with_label(image_ndarray, labelRGB_map)
overlay_filename = image_path.stem + "_label_blend.tiff"
overlay_img.save(output_path / overlay_filename)

Expand All @@ -239,6 +286,11 @@ def atp_analysis(
f"💾 OUTPUT: Summary Table saved as {output_path/csv_name}",
style="green",
)
plot_name = image_path.stem + "_intensity_plot.png"
fig.savefig(output_path / plot_name)
console.print(
f"💾 OUTPUT: Intensity Plot saved as {output_path/plot_name}", style="green"
)
if export_map:
console.print(
f"💾 OUTPUT: Overlay image saved as {output_path/overlay_filename}",
Expand Down
Loading