From 12e247809190167938888fd955baaa7a0d4ef8e0 Mon Sep 17 00:00:00 2001 From: Florian Mueller Date: Thu, 31 Mar 2022 18:19:42 +0200 Subject: [PATCH 1/3] upgrade to new CP version --- docs/imjoy-installation.md | 6 +++-- ...ze_of_RNA_as_an_ideal_branched_polymer.pdf | Bin 0 -> 341151 bytes requirements.txt | 4 +-- segwrap/__init__.py | 2 +- segwrap/utils_cellpose.py | 24 +++++------------- 5 files changed, 13 insertions(+), 23 deletions(-) create mode 100644 imjoy-plugins/The_size_of_RNA_as_an_ideal_branched_polymer.pdf diff --git a/docs/imjoy-installation.md b/docs/imjoy-installation.md index 26e2e1e..a6956b7 100644 --- a/docs/imjoy-installation.md +++ b/docs/imjoy-installation.md @@ -2,7 +2,7 @@ Here we describe how you can install and maintain the ImJoy Jupyter plugin engine, which is needed to run the Python code for cell/nuclear segmentation and the pre/post processing -workflows. +workflows. ## Install Jupyter engine for ImJoy @@ -15,9 +15,11 @@ to excecute the commands listed below. We recommend creating a **dedicated environment** to run code in this analysis package. To create an environment called `fq-segmentation`, open an anaconda prompt and type (Confirm with `y` when asked if you want to proceed (`Proceed ([y]/n)?`): ``` bash -conda create --name fq-segmentation python=3.7 +conda create --name fq-segmentation pytorch=1.8.2 cudatoolkit=10.2 -c pytorch-lts ``` +Note (31-3-2022): specifying the environment seems necessary due to a change in the Pytorch channel (more [information](https://github.com/MouseLand/cellpose/issues/481)). + **Activate the environment**: ``` bash diff --git a/imjoy-plugins/The_size_of_RNA_as_an_ideal_branched_polymer.pdf b/imjoy-plugins/The_size_of_RNA_as_an_ideal_branched_polymer.pdf new file mode 100644 index 0000000000000000000000000000000000000000..27400c523945d6a7c3d4907ab1cb6cc6ef138e4b GIT binary patch literal 341151 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 FJ|S4@(#xiff6x;ghW?^c_sS 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"Qo6k8K#Pc(s`=$_Iy6@R_?c{6fOcO(U2t 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

!v*D_w4)%1mO9l*gmzlm^5@NX;9dX=+kmeN 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 literal 0 HcmV?d00001 diff --git a/requirements.txt b/requirements.txt index d5304cb..d87defd 100644 --- a/requirements.txt +++ b/requirements.txt @@ -1,3 +1,3 @@ -cellpose == 0.6.5 -matplotlib == 3.4.2 +cellpose == 1.0.2 +matplotlib == 3.5.1 scikit-image == 0.19.2 \ No newline at end of file diff --git a/segwrap/__init__.py b/segwrap/__init__.py index 3d6124d..145e56b 100644 --- a/segwrap/__init__.py +++ b/segwrap/__init__.py @@ -12,4 +12,4 @@ # MINOR: new features # PATCH: backwards compatible bug fixes # MAJOR.MINOR.PATCHdev means a version under development -__version__ = "0.3.3" +__version__ = "0.3.4" diff --git a/segwrap/utils_cellpose.py b/segwrap/utils_cellpose.py index 0a91e5b..aaaaa3c 100644 --- a/segwrap/utils_cellpose.py +++ b/segwrap/utils_cellpose.py @@ -1,4 +1,4 @@ -# Imports +# Imports of general libraries import numpy as np from tqdm import tqdm import time @@ -7,6 +7,7 @@ from pathlib import Path import json import cv2 +from skimage.exposure import rescale_intensity # Imports of CellPose specific libraries from cellpose import models, io, plot @@ -64,16 +65,12 @@ def cellpose_predict(data, config, path_save, callback_log=None): imgi = imgs[idx] # Rescale each channel separately - imgi_norm = imgi.copy() + imgi_scaled = imgi.copy() for idim in range(3): imgdum = imgi[:, :, idim] - - # Renormalize to 8bit between 1 and 99 percentile pa = np.percentile(imgdum, 0.5) pb = np.percentile(imgdum, 99.5) - - if pb > pa: - imgi_norm[:, :, idim] = 255 * (imgdum - pa) / (pb - pa) + imgi_scaled[:, :, idim] = rescale_intensity(imgdum, in_range=(pa, pb),out_range=np.uint8) # Save flow io.imsave(str(path_save / f'{file_name.stem}__flow__{obj_name}.png'), flowi) @@ -81,23 +78,15 @@ def cellpose_predict(data, config, path_save, callback_log=None): # Resize masks if necessary if new_size: mask_full = resize_mask(maski, sizes_orginal[idx]) - io.imsave(str(path_save / f'{file_name.stem}__mask__{obj_name}.png'), mask_full) io.imsave(str(path_save / f'{file_name.stem}__mask_resize__{obj_name}.png'), maski) else: io.imsave(str(path_save / f'{file_name.stem}__mask__{obj_name}.png'), maski) - # Save mask and flow images - #f_mask = str(path_save / f'{file_name.stem}__mask__{obj_name}.png') - #log_message(f'\nMask saved to file: {f_mask}\n', callback_fun=callback_log) - - #io.imsave(str(path_save / f'{file_name.stem}__mask__{obj_name}.png'), maski) - - # Save overview image fig = plt.figure(figsize=(12,3)) - plot.show_segmentation(fig, imgi_norm.astype('uint8'), maski, flowi) + plot.show_segmentation(fig, imgi_scaled, maski, flowi) plt.tight_layout() fig.savefig(str(path_save / f'{file_name.stem}__seg__{obj_name}.png'), dpi=300) plt.close(fig) @@ -107,7 +96,7 @@ def cellpose_predict(data, config, path_save, callback_log=None): def clean_par_dict(par_dict): """ - Cleam up dictionary containing all parameters such that it can + Clean dictionary containing all parameters such that it can be written into a json file. """ par_dict['path_scan'] = str(par_dict['path_scan']) @@ -255,7 +244,6 @@ def segment_obj_indiv(path_scan, obj_name, str_channel, img_ext, new_size, model # Create new output path if specified if not isinstance(path_save, pathlib.PurePath): path_save_results = create_output_path(path_img.parent, path_save_str_replace, subfolder='', create_path=True) - path_save_settings = path_save_results cellpose_predict(data, config, path_save=path_save_results, callback_log=callback_log) From bf4d10bb422ae6b306afe4cbabd16ca59557ad69 Mon Sep 17 00:00:00 2001 From: Florian Mueller Date: Thu, 5 May 2022 17:04:13 +0200 Subject: [PATCH 2/3] Update mkdocs.yml --- mkdocs.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/mkdocs.yml b/mkdocs.yml index 5546dad..9d4bc5a 100644 --- a/mkdocs.yml +++ b/mkdocs.yml @@ -35,8 +35,8 @@ theme: text: Roboto code: Roboto Mono favicon: /img/icons8-eukaryotic-cells-filled-100.png - logo: - icon: wb_sunny +# logo: +# icon: wb_sunny # Customization extra: From 7a741d8fa5304b209c923e4d3dab2b05d6a871bf Mon Sep 17 00:00:00 2001 From: Florian Mueller Date: Thu, 8 Jun 2023 16:28:35 +0200 Subject: [PATCH 3/3] transfer to new workstation --- .gitignore | 12 +- .readthedocs.yml | 32 +- LICENSE | 50 +- docs/analysis-general-behavior.md | 46 +- docs/analysis-overview.md | 54 +- docs/analysis-preprocessing.md | 106 +-- docs/analysis-segmentation.md | 250 +++--- docs/contact.md | 58 +- docs/data.md | 84 +- docs/developer.md | 82 +- docs/img/imjoy-logo-powered.svg | 536 +++++------ docs/imjoy-faq.md | 92 +- docs/imjoy-installation.md | 156 ++-- docs/imjoy-overview.md | 92 +- docs/index.md | 66 +- docs/licence.md | 78 +- docs/workflows-create-fq-outlines.md | 70 +- docs/workflows-create-numbered-labels.md | 40 +- docs/workflows-distance-objects.md | 96 +- docs/workflows-fiji-split-channels.md | 96 +- docs/workflows-overview.md | 16 +- imjoy-plugins/ObjectDist.imjoy.html | 224 ++--- imjoy-plugins/PreProcess.imjoy.html | 242 ++--- imjoy-plugins/SegmentCellsNuclei.imjoy.html | 310 +++---- imjoy-plugins/SegmentObjects.imjoy.html | 312 +++---- mkdocs.yml | 176 ++-- notebooks/distance-closest-object.ipynb | 148 +-- notebooks/pre-processing.ipynb | 160 ++-- notebooks/segment-cells-nuclei.ipynb | 176 ++-- notebooks/segment-nuclei.ipynb | 182 ++-- readme.md | 120 +-- requirements.txt | 4 +- segwrap/__init__.py | 30 +- segwrap/utils_cellpose.py | 948 ++++++++++---------- segwrap/utils_general.py | 140 +-- segwrap/utils_masks.py | 234 ++--- segwrap/utils_segmentation.py | 248 ++--- setup.py | 68 +- update_manifest.js | 170 ++-- workflows/MacroBatchSplitChannel.ijm | 262 +++--- 40 files changed, 3133 insertions(+), 3133 deletions(-) diff --git a/.gitignore b/.gitignore index d4e388e..1d390e3 100644 --- a/.gitignore +++ b/.gitignore @@ -1,7 +1,7 @@ -.DS_Store -__pycache__ -*.pyc -.ipynb_checkpoints/ -segwrap.egg-info/ -site/ +.DS_Store +__pycache__ +*.pyc +.ipynb_checkpoints/ +segwrap.egg-info/ +site/ .vscode/ \ No newline at end of file diff --git a/.readthedocs.yml b/.readthedocs.yml index e483ad2..5e0758c 100644 --- a/.readthedocs.yml +++ b/.readthedocs.yml @@ -1,16 +1,16 @@ -# .readthedocs.yml -# Read the Docs configuration file -# See https://docs.readthedocs.io/en/stable/config-file/v2.html for details - -# Required -version: 2 - -# Build documentation with MkDocs -mkdocs: - configuration: mkdocs.yml - -# Optionally set the version of Python and requirements required to build your docs -python: - version: 3.7 - install: - - requirements: docs/requirements.txt +# .readthedocs.yml +# Read the Docs configuration file +# See https://docs.readthedocs.io/en/stable/config-file/v2.html for details + +# Required +version: 2 + +# Build documentation with MkDocs +mkdocs: + configuration: mkdocs.yml + +# Optionally set the version of Python and requirements required to build your docs +python: + version: 3.7 + install: + - requirements: docs/requirements.txt diff --git a/LICENSE b/LICENSE index 40d364e..7e6ca34 100644 --- a/LICENSE +++ b/LICENSE @@ -1,26 +1,26 @@ -BSD 3-Clause License - -Copyright © 2020, Florian Mueller -All rights reserved. - -Redistribution and use in source and binary forms, with or without -modification, are permitted provided that the following conditions are met: - * Redistributions of source code must retain the above copyright - notice, this list of conditions and the following disclaimer. - * Redistributions in binary form must reproduce the above copyright - notice, this list of conditions and the following disclaimer in the - documentation and/or other materials provided with the distribution. - * Neither the name of the copyright holder nor the names of its - contributors may be used to endorse or promote products derived from - this software without specific prior written permission. - -THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND -ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED -WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE -DISCLAIMED. IN NO EVENT SHALL COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY -DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES -(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; -LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND -ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +BSD 3-Clause License + +Copyright © 2020, Florian Mueller +All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are met: + * Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + * Neither the name of the copyright holder nor the names of its + contributors may be used to endorse or promote products derived from + this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND +ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +DISCLAIMED. IN NO EVENT SHALL COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY +DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES +(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND +ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. \ No newline at end of file diff --git a/docs/analysis-general-behavior.md b/docs/analysis-general-behavior.md index 8f2a7d8..af934ba 100644 --- a/docs/analysis-general-behavior.md +++ b/docs/analysis-general-behavior.md @@ -1,24 +1,24 @@ -# General behavior - -Here, we describe some general concepts that are shared by most plugins. - -## Recursive search for data - -Some plugins will perform by default a recursive search for data, for others this is an option. - -A recursive search means simply that not only the provided folder will be searched for files fitting the specified criteria, but also all subfolders. - -## Specify folder to save results - -Several possibilities are provided to specify the folder to save the results of the different workflows. Here, the general options are described, if -a plugin deviates from this default behavior it will be described in the respective plugin. - -When asked to define a folder to save results, you can: - -1. Directly define a **full path** where the results should be stored. If the folder doesn't exist, it will be created. -2. Define a folder with a **text replacement**. This option can be useful if many folders are processed, e.g. when a recursive search is performed. - - * Such a replacement operation is indicated with a string in the format `str_orig>>str_new`, - where 'str_orig' is the orginal string, `str_new` is the new string. - * For instance, using the string `acquisition>>analysis` implies that in the folder name +# General behavior + +Here, we describe some general concepts that are shared by most plugins. + +## Recursive search for data + +Some plugins will perform by default a recursive search for data, for others this is an option. + +A recursive search means simply that not only the provided folder will be searched for files fitting the specified criteria, but also all subfolders. + +## Specify folder to save results + +Several possibilities are provided to specify the folder to save the results of the different workflows. Here, the general options are described, if +a plugin deviates from this default behavior it will be described in the respective plugin. + +When asked to define a folder to save results, you can: + +1. Directly define a **full path** where the results should be stored. If the folder doesn't exist, it will be created. +2. Define a folder with a **text replacement**. This option can be useful if many folders are processed, e.g. when a recursive search is performed. + + * Such a replacement operation is indicated with a string in the format `str_orig>>str_new`, + where 'str_orig' is the orginal string, `str_new` is the new string. + * For instance, using the string `acquisition>>analysis` implies that in the folder name `D:\example_data\acquisition`, `acquisition` will be replaced with `analysis`, yielding `D:\example_data\analysis`. \ No newline at end of file diff --git a/docs/analysis-overview.md b/docs/analysis-overview.md index eb6f79d..361f700 100644 --- a/docs/analysis-overview.md +++ b/docs/analysis-overview.md @@ -1,27 +1,27 @@ -## ImJoy plugins -Most of the workflows are implemented as **ImJoy plugins**, with a simple interface to -specify the different workflow parameters. We describe in a dedicated [sections] how to [**use**](imjoy-overview.md) and [**install**](imjoy-installation.md) the **Plugin engine** to run these plugins. - -Once a plugin is installed, it will be available for later use in the ImJoy **workspace `fq-segmentation`** as explained [here](imjoy-overview.md#opening-a-workspace). - -!!! abstract "Quick summary for how to connect ImJoy to Jupyter engine" - 1. Open **anaconda terminal**. - 2. **Activate environment**: `conda activate fq-segmentation` - 3. **Start Jupyter engine**: `imjoy --jupyter` - 4. **Connect** ImJoy to Jupyter Engine with 🚀 button. - -We also provide **Jupyter notebooks** for these workflows, which we recommend only for more experienced Python users. - -## Typical workflows -For most purposes, the segmentation will consist of two steps. Each of these steps is described in a -dedicated section. In this section you can also find a recommended workflow, which allows you to also -process the test data. - -1. **Pre-processing** of the data: segmentation is performed on 2D images. If your images are 3D, you have to either split them, or project them into 2D images. This can be done with the [pre-processing workflow](analysis-preprocessing.md). -2. **Actual segmentation** of your images. We provide different plugins to [**segment**](analysis-segmentation.md). one type of structure, e.g. nuclei or cells, or two, e.g. cells and nuclei. - -Each **workflow** is documented in a dedicated section. We provide - -* **Installation links**. -* Detailed explanations of the different **parameters**. -* A **Recommended workflow** for how to set the parameters following the recommended data organization. +## ImJoy plugins +Most of the workflows are implemented as **ImJoy plugins**, with a simple interface to +specify the different workflow parameters. We describe in a dedicated [sections] how to [**use**](imjoy-overview.md) and [**install**](imjoy-installation.md) the **Plugin engine** to run these plugins. + +Once a plugin is installed, it will be available for later use in the ImJoy **workspace `fq-segmentation`** as explained [here](imjoy-overview.md#opening-a-workspace). + +!!! abstract "Quick summary for how to connect ImJoy to Jupyter engine" + 1. Open **anaconda terminal**. + 2. **Activate environment**: `conda activate fq-segmentation` + 3. **Start Jupyter engine**: `imjoy --jupyter` + 4. **Connect** ImJoy to Jupyter Engine with 🚀 button. + +We also provide **Jupyter notebooks** for these workflows, which we recommend only for more experienced Python users. + +## Typical workflows +For most purposes, the segmentation will consist of two steps. Each of these steps is described in a +dedicated section. In this section you can also find a recommended workflow, which allows you to also +process the test data. + +1. **Pre-processing** of the data: segmentation is performed on 2D images. If your images are 3D, you have to either split them, or project them into 2D images. This can be done with the [pre-processing workflow](analysis-preprocessing.md). +2. **Actual segmentation** of your images. We provide different plugins to [**segment**](analysis-segmentation.md). one type of structure, e.g. nuclei or cells, or two, e.g. cells and nuclei. + +Each **workflow** is documented in a dedicated section. We provide + +* **Installation links**. +* Detailed explanations of the different **parameters**. +* A **Recommended workflow** for how to set the parameters following the recommended data organization. diff --git a/docs/analysis-preprocessing.md b/docs/analysis-preprocessing.md index 7aca6ab..ed730c6 100644 --- a/docs/analysis-preprocessing.md +++ b/docs/analysis-preprocessing.md @@ -1,53 +1,53 @@ - -# Preprocessing of 3D images - -Segmentation is performed on **2D images**. This plugin allows to obtain 2D images from 3D images either by -a projection or by saving each z-plane separately. These images are typically stored in a separate folder. -2D images by applying a projection, and these images are typically stored in a separate folder. - -Install ImJoy plugin `PreProcess` ** from here.** - -## Recommended workflow - -The default settings of the plugins allow to quickly perform the recommended workflow. You only have -to paste your data folder. - -1. 3D images are stored in a folder `acquisition` -2. In the pre-processing step, the folder to save data is obtained with - - 1. the text replacement `acquisition>>analysis`. - 2. Images are stored in a new subfolder `segmentation-input` - - With these options, the images will be saved in a folder `acquisition\segmentation-input` - -## Running the plugin - -1. Before running the plugin, you have to specify a few parameters. Note that you have to perform this - projection for each channel-type. This allows to use different projection methods for a channel. This can be set in the plugin interface, avaible after clicking on the arrow down next to the plugin name. - - ![imjoy-preprocess](img/imjoy-preprocess-ui.png){: style="width:300px"} - - Here the following parameters can be set. - - Option | Type | Default | Description - ---------------- | ---- | ----------- | ----------- - `Path DATA` | str | | Full path to folder containing data to be segmented. - `Path SAVE` | str | acquisition>>analysis | Several options exist. See dedicated section here [below](analysis-general-behavior.md#specify-folder-to-save-your-data) for more details. - `Subfolder` | str | segmentation-input | Sub-folder where results should be saved (if defined) - `Channel string` | str | dapi | Unique string to identify channel that should be processed. - `Img extension` | str | .tif | Extensions of images to be loaded. - `Projection type` | str | mean | Different projection types: `max`, `mean`, `indiv`. The option `indiv` implies that a z-stack is split into individual slices, stored in subfolder for each image. - `Search recursive` | bool | false | Should provided folder be search [**recursively**](analysis-general-behavior.md#recursive-search-for-data) for images (true/false). - - -2. Pressing the button `PreProcess` will **start the pre-processing**. Progress - can be monitored in the plugin log, available by pressing on the `i` next to the plugin name. - -3. **Results** will be saved in the specified folder. For each image a json file with - basic properties of the file, and an image with the same name as the original one will be saved. - - - - - - + +# Preprocessing of 3D images + +Segmentation is performed on **2D images**. This plugin allows to obtain 2D images from 3D images either by +a projection or by saving each z-plane separately. These images are typically stored in a separate folder. +2D images by applying a projection, and these images are typically stored in a separate folder. + +Install ImJoy plugin `PreProcess` ** from here.** + +## Recommended workflow + +The default settings of the plugins allow to quickly perform the recommended workflow. You only have +to paste your data folder. + +1. 3D images are stored in a folder `acquisition` +2. In the pre-processing step, the folder to save data is obtained with + + 1. the text replacement `acquisition>>analysis`. + 2. Images are stored in a new subfolder `segmentation-input` + + With these options, the images will be saved in a folder `acquisition\segmentation-input` + +## Running the plugin + +1. Before running the plugin, you have to specify a few parameters. Note that you have to perform this + projection for each channel-type. This allows to use different projection methods for a channel. This can be set in the plugin interface, avaible after clicking on the arrow down next to the plugin name. + + ![imjoy-preprocess](img/imjoy-preprocess-ui.png){: style="width:300px"} + + Here the following parameters can be set. + + Option | Type | Default | Description + ---------------- | ---- | ----------- | ----------- + `Path DATA` | str | | Full path to folder containing data to be segmented. + `Path SAVE` | str | acquisition>>analysis | Several options exist. See dedicated section here [below](analysis-general-behavior.md#specify-folder-to-save-your-data) for more details. + `Subfolder` | str | segmentation-input | Sub-folder where results should be saved (if defined) + `Channel string` | str | dapi | Unique string to identify channel that should be processed. + `Img extension` | str | .tif | Extensions of images to be loaded. + `Projection type` | str | mean | Different projection types: `max`, `mean`, `indiv`. The option `indiv` implies that a z-stack is split into individual slices, stored in subfolder for each image. + `Search recursive` | bool | false | Should provided folder be search [**recursively**](analysis-general-behavior.md#recursive-search-for-data) for images (true/false). + + +2. Pressing the button `PreProcess` will **start the pre-processing**. Progress + can be monitored in the plugin log, available by pressing on the `i` next to the plugin name. + +3. **Results** will be saved in the specified folder. For each image a json file with + basic properties of the file, and an image with the same name as the original one will be saved. + + + + + + diff --git a/docs/analysis-segmentation.md b/docs/analysis-segmentation.md index b5566d1..a8aa295 100644 --- a/docs/analysis-segmentation.md +++ b/docs/analysis-segmentation.md @@ -1,125 +1,125 @@ -# Segmentation - -We provide different plugins for different segmentation tasks: - -* Install plugin `SegmentObjects` to segment cells OR nuclei **from here.** -* Install plugin `SegmentCellsNuclei` to segment cells AND nuclei **from here.** - -## General behavior - -### Recursive search - -The plugins will search [**recursively**](analysis-general-behavior.md#recursive-search-for-data) the provided subfolder for images to segment. - -By default, all images matching the naming scheme will be processed. An optional parameter allows to specify -in which subfolder the images have to be in order to be segmented. This allows to process nested folder -hierachies and only segmenting images in the relevant subfolders. - -As an example, in the provided data we could specif the folder `example_data\analysis` as the data folder. -This would then scan this folder and all subfolders and potentially find inappropriate files for segmentation. -By defining the `Input subfolder` to be `segmentation-input`, the analysis will be restricted to this folder. - -### Results - -Results will be saved in the specified folder. For each image the following files, results files with different suffixes are created: - -* `..._flow`: these are the predicted distance maps of CellPose. They are an intermediate result, and - not needed for most end-users. -* `..._mask`: these contain the actual segmentation results. Each segmented object is a filled - object with a constant pixel value. If the images were resized during segmentation, the mask is scaled - back up to the original image size. The actually obtained (smaller) mask is saved under the name `mask__rescale_...`. -* `..._seg`: summary plot showing the input image, the predicted distance map, and the segmented - objects. This plot is also shown in the interface. - -![segmentation__nuclei](img/segmentation__nuclei.png) - -### Resizing can speed up prediction & yield better results - -We found that resizing images before segmentation can yield better results for certain images. -Also, it will lead to faster computation time. In case you resize the images, we implemented a post-processing -routine that will resize the predicted masks back to the original image size. - -Resizing can be specified in two ways - -1. **Scaling factor** recommended]: simply add an integer value. The actual image size will then be divided by this factor - to obtain the new size, i.e. a value of 2 will resize an image 512x512 to 256x256. -2. **New size**: you can directly define the new size of the image, e.g. 256x256. Please note that this size - will be applied to all images, independly of their size. This option is hence not suitable if your data-sets - contain differently sized images. - -## Recommended workflow - -The default settings of the plugins allow to quickly perform the recommended workflow. You only have -to paste your data folder. - -1. 2D images are stored in a subfolder `segmentation-input` -2. Segmentation results will be stored in a subfolder `segmentation-results`, this can be achieved by setting - the save path to the string replacement `segmentation-input>>segmentation-results` - -## Segmentation of nuclei OR cells - -![imjoy-segment-objects-ui](img/imjoy-segment-objects-ui.png){: style="width:300px"} - -1. Before running the plugin, you have to **specify a few parameters**. This can be done in the plugin interface, - avaible after clicking on the arrow down next to the plugin name. - - Here the following parameters can be set: - - Option | Type | Default | Description - ---------------- | ---- | ----------- | ----------- - `Path DATA` | str | | Full path to folder containing data to be segmented. - `Input subfolder` | str | | Name of the subfolder containing the images that should be segmented. - `Path SAVE` | str | | Several options exist. See dedicated section [below](analysis-general-behavior.md#specify-folder-to-save-your-data) for more details. - `String channel` | str | `dapi` | Unique identifier to identify channel. - `Object name` | str | `nuclei` | How the object is called. - `Cellpose model` | str | `nuclei` | Cellpose model for segmentation: `cyto` or `nuclei`. Note that for dense nuclei, the cytoplasmic model might work better. - `New size` | int | 2 | Numbers to specify resizing (see above). No resizing if empty. - `Object diameter` | int | 50 | Typical diameter of the object. Better to be set a bit to small. - `Net Average` | Bool | False | Can improve segmentation accuracy, but is slower (Runs the 4 built-in networks and averages them). - `Resample` | Bool | False | Gives more accurate boundaries, but can be very slow (Runs dynamics at original image size). - `String img ext` | str | `.png` | File extension of images that should be segmented. - `New size` | int | 2 | Numbers to specify resizing (see abov. No resizing if empty. - -2. Pressing on the plugin name `SegmentObjects` will start the segmentation. - When using CellPose for the first time, the models for nuclear and cytoplasmic segmentations are downloaded. - - The actual segmentation can take a while, depending on the numberof images that should be segmented - (and their size). Progress will be displayed in the ImJoy status bar, and more details provided in the - plugin log available by pressing on the `i` next to the plugin name. - - Once a image is segmented, the results will be saved (see below). So you can monitor the result folder - to verify on the fly if the segmentation works. - -## Segmentation of cells AND nuclei - -![imjoy-segment-cells-nuclei-ui](img/imjoy-segment-cells-nuclei-ui.png){: style="width:300px"} - -1. Before running the plugin, you have to **specify a few parameters**. This can be done in the plugin interface, - avaible after clicking on the arrow down next to the plugin name. - - Here the following parameters can be set: - - Option | Type | Default | Description - ---------------- | ---- | ----------- | ----------- - `Path DATA` | str | | Full path to folder containing data to be segmented. - `Input subfolder` | str | | Name of the subfolder containing the images that should be segmented. - `Path SAVE` | str | | Path to folder where results should be stored (for more details see above). - `String CELLS` | str | `cy3` | Unique identifier for images of cytoplasmic stain. - `String NUCLEI` | str | `dapi` | Unique identifier for images of nuclear stain. - `String img ext` | str | `.png` | File extension of images that should be segmented. - `New size` | int | 2 | Numbers to specify resizing (see above). No resizing if empty. - `Size CELLS` | int | 100 | Typical size of a cell (in resized image). - `Size NUCLEI` | int | 50 | Typical size of a nucleus (in resized image). - `Net Average` | Bool | False | Can improve segmentation accuracy, but is slower (Runs the 4 built-in networks and averages them). - `Resample` | Bool | False | Gives more accurate boundaries, but can be very slow (Runs dynamics at original image size). - `String img ext` | str | `.png` | File extension of images that should be segmented. - -2. Pressing on the plugin name `SegmentCellsNuclei` will start the segmentation. - When using CellPose for the first time, the models for nuclear and cytoplasmic segmentations are downloaded. - - The actual segmentation can take a while, depending on the numberof images that should be segmented - (and their size). Progress will be displayed in the ImJoy status bar, and more details provided in the - plugin log available by pressing on the `i` next to the plugin name. - - Once a image is segmented, the results will be saved (see below). So you can monitor the result folder - to verify on the fly if the segmentation works. +# Segmentation + +We provide different plugins for different segmentation tasks: + +* Install plugin `SegmentObjects` to segment cells OR nuclei **from here.** +* Install plugin `SegmentCellsNuclei` to segment cells AND nuclei **from here.** + +## General behavior + +### Recursive search + +The plugins will search [**recursively**](analysis-general-behavior.md#recursive-search-for-data) the provided subfolder for images to segment. + +By default, all images matching the naming scheme will be processed. An optional parameter allows to specify +in which subfolder the images have to be in order to be segmented. This allows to process nested folder +hierachies and only segmenting images in the relevant subfolders. + +As an example, in the provided data we could specif the folder `example_data\analysis` as the data folder. +This would then scan this folder and all subfolders and potentially find inappropriate files for segmentation. +By defining the `Input subfolder` to be `segmentation-input`, the analysis will be restricted to this folder. + +### Results + +Results will be saved in the specified folder. For each image the following files, results files with different suffixes are created: + +* `..._flow`: these are the predicted distance maps of CellPose. They are an intermediate result, and + not needed for most end-users. +* `..._mask`: these contain the actual segmentation results. Each segmented object is a filled + object with a constant pixel value. If the images were resized during segmentation, the mask is scaled + back up to the original image size. The actually obtained (smaller) mask is saved under the name `mask__rescale_...`. +* `..._seg`: summary plot showing the input image, the predicted distance map, and the segmented + objects. This plot is also shown in the interface. + +![segmentation__nuclei](img/segmentation__nuclei.png) + +### Resizing can speed up prediction & yield better results + +We found that resizing images before segmentation can yield better results for certain images. +Also, it will lead to faster computation time. In case you resize the images, we implemented a post-processing +routine that will resize the predicted masks back to the original image size. + +Resizing can be specified in two ways + +1. **Scaling factor** recommended]: simply add an integer value. The actual image size will then be divided by this factor + to obtain the new size, i.e. a value of 2 will resize an image 512x512 to 256x256. +2. **New size**: you can directly define the new size of the image, e.g. 256x256. Please note that this size + will be applied to all images, independly of their size. This option is hence not suitable if your data-sets + contain differently sized images. + +## Recommended workflow + +The default settings of the plugins allow to quickly perform the recommended workflow. You only have +to paste your data folder. + +1. 2D images are stored in a subfolder `segmentation-input` +2. Segmentation results will be stored in a subfolder `segmentation-results`, this can be achieved by setting + the save path to the string replacement `segmentation-input>>segmentation-results` + +## Segmentation of nuclei OR cells + +![imjoy-segment-objects-ui](img/imjoy-segment-objects-ui.png){: style="width:300px"} + +1. Before running the plugin, you have to **specify a few parameters**. This can be done in the plugin interface, + avaible after clicking on the arrow down next to the plugin name. + + Here the following parameters can be set: + + Option | Type | Default | Description + ---------------- | ---- | ----------- | ----------- + `Path DATA` | str | | Full path to folder containing data to be segmented. + `Input subfolder` | str | | Name of the subfolder containing the images that should be segmented. + `Path SAVE` | str | | Several options exist. See dedicated section [below](analysis-general-behavior.md#specify-folder-to-save-your-data) for more details. + `String channel` | str | `dapi` | Unique identifier to identify channel. + `Object name` | str | `nuclei` | How the object is called. + `Cellpose model` | str | `nuclei` | Cellpose model for segmentation: `cyto` or `nuclei`. Note that for dense nuclei, the cytoplasmic model might work better. + `New size` | int | 2 | Numbers to specify resizing (see above). No resizing if empty. + `Object diameter` | int | 50 | Typical diameter of the object. Better to be set a bit to small. + `Net Average` | Bool | False | Can improve segmentation accuracy, but is slower (Runs the 4 built-in networks and averages them). + `Resample` | Bool | False | Gives more accurate boundaries, but can be very slow (Runs dynamics at original image size). + `String img ext` | str | `.png` | File extension of images that should be segmented. + `New size` | int | 2 | Numbers to specify resizing (see abov. No resizing if empty. + +2. Pressing on the plugin name `SegmentObjects` will start the segmentation. + When using CellPose for the first time, the models for nuclear and cytoplasmic segmentations are downloaded. + + The actual segmentation can take a while, depending on the numberof images that should be segmented + (and their size). Progress will be displayed in the ImJoy status bar, and more details provided in the + plugin log available by pressing on the `i` next to the plugin name. + + Once a image is segmented, the results will be saved (see below). So you can monitor the result folder + to verify on the fly if the segmentation works. + +## Segmentation of cells AND nuclei + +![imjoy-segment-cells-nuclei-ui](img/imjoy-segment-cells-nuclei-ui.png){: style="width:300px"} + +1. Before running the plugin, you have to **specify a few parameters**. This can be done in the plugin interface, + avaible after clicking on the arrow down next to the plugin name. + + Here the following parameters can be set: + + Option | Type | Default | Description + ---------------- | ---- | ----------- | ----------- + `Path DATA` | str | | Full path to folder containing data to be segmented. + `Input subfolder` | str | | Name of the subfolder containing the images that should be segmented. + `Path SAVE` | str | | Path to folder where results should be stored (for more details see above). + `String CELLS` | str | `cy3` | Unique identifier for images of cytoplasmic stain. + `String NUCLEI` | str | `dapi` | Unique identifier for images of nuclear stain. + `String img ext` | str | `.png` | File extension of images that should be segmented. + `New size` | int | 2 | Numbers to specify resizing (see above). No resizing if empty. + `Size CELLS` | int | 100 | Typical size of a cell (in resized image). + `Size NUCLEI` | int | 50 | Typical size of a nucleus (in resized image). + `Net Average` | Bool | False | Can improve segmentation accuracy, but is slower (Runs the 4 built-in networks and averages them). + `Resample` | Bool | False | Gives more accurate boundaries, but can be very slow (Runs dynamics at original image size). + `String img ext` | str | `.png` | File extension of images that should be segmented. + +2. Pressing on the plugin name `SegmentCellsNuclei` will start the segmentation. + When using CellPose for the first time, the models for nuclear and cytoplasmic segmentations are downloaded. + + The actual segmentation can take a while, depending on the numberof images that should be segmented + (and their size). Progress will be displayed in the ImJoy status bar, and more details provided in the + plugin log available by pressing on the `i` next to the plugin name. + + Once a image is segmented, the results will be saved (see below). So you can monitor the result folder + to verify on the fly if the segmentation works. diff --git a/docs/contact.md b/docs/contact.md index 93ce655..19141ba 100644 --- a/docs/contact.md +++ b/docs/contact.md @@ -1,29 +1,29 @@ -# Reporting bugs - -If you encounter a bug, best is to create a [**GitHub issue**](https://github.com/fish-quant/fq-segmentation/issues). This would allow other users to see -reported bugs and proposed solutions. If possible, please provide the following information - -1. **How** can the bug be produced? -2. Which **browser** and browser version are you using? -3. **Complete plugin log**. Can be obtained by clicking on the `i` next to the FISH-QUANT plugin. Please copy to a text file. This will also contain the version of the plugin and the used code - - ``` bash - Loading plugin SegmentCellsNuclei_i862g1602770955978 (TAG=stable, WORKSPACE=fq-segmentation) - ENGINE_URL=http://127.0.0.1:9527/ - Setting up plugin. - - Plugin SegmentCellsNuclei initialized - * plugin version: 0.1.11 - * segwrap version: 0.1.7 - * utils_cellpose location: c:\users\muellerf\miniconda3\envs\fq-segmentation\lib\site-packages\segwrap\utils_cellpose.py - ``` - -4. **Console log**. The console log of the browser provides further details that can help for debugging. To acces the console log in **Chrome**: - - 1. In the ImJoy app mouse-right-click. - 2. Select `Inspect`. - 3. This will open a new interface on the right size of your browser windows. Select the panel `Console` and copy the entire content, and paste it to a file. - -# Development team - -* Florian Mueller. [Github](https://github.com/muellerflorian). +# Reporting bugs + +If you encounter a bug, best is to create a [**GitHub issue**](https://github.com/fish-quant/fq-segmentation/issues). This would allow other users to see +reported bugs and proposed solutions. If possible, please provide the following information + +1. **How** can the bug be produced? +2. Which **browser** and browser version are you using? +3. **Complete plugin log**. Can be obtained by clicking on the `i` next to the FISH-QUANT plugin. Please copy to a text file. This will also contain the version of the plugin and the used code + + ``` bash + Loading plugin SegmentCellsNuclei_i862g1602770955978 (TAG=stable, WORKSPACE=fq-segmentation) + ENGINE_URL=http://127.0.0.1:9527/ + Setting up plugin. + + Plugin SegmentCellsNuclei initialized + * plugin version: 0.1.11 + * segwrap version: 0.1.7 + * utils_cellpose location: c:\users\muellerf\miniconda3\envs\fq-segmentation\lib\site-packages\segwrap\utils_cellpose.py + ``` + +4. **Console log**. The console log of the browser provides further details that can help for debugging. To acces the console log in **Chrome**: + + 1. In the ImJoy app mouse-right-click. + 2. Select `Inspect`. + 3. This will open a new interface on the right size of your browser windows. Select the panel `Console` and copy the entire content, and paste it to a file. + +# Development team + +* Florian Mueller. [Github](https://github.com/muellerflorian). diff --git a/docs/data.md b/docs/data.md index a3e6caf..4157277 100644 --- a/docs/data.md +++ b/docs/data.md @@ -1,42 +1,42 @@ -# Data - -Please note that we recommend a **data organization**, described below, to facilitate the usage of these tools. - -We provide test data, which allows you to inspect how the data is organized, but then also run a local installation -of these tools to see if everything works correctly. - -## Test data -Already processed test data can be downloaded from [**Dropbox**](https://www.dropbox.com/sh/yr1s5olqwkvyx0i/AADH0QQtdNuWWq7z9wgQpLiOa?dl=0). With these data, you can verify if the different analysis steps are properly executed. - -## Data organization -We strongly recommend the following data-organization on which this workflow has been tested. - -1. Images are store as single-channel multi-z-stack tif files, e.g on tif per position and channel. If your data are not single-channel, see the section on how to split channels with [Fiji](workflows-fiji-split-channels.md). -2. All raw 3D images are stored in a folder `acquisition` -3. All analysis results are stored in subfolder `analysis`, where each analysis step has a separate subfolder. - -The organization of the provided test data is the following - -``` bash -├─ example_data/ -│ ├─ acquisition # Folder with raw data -│ │ ├─ test_pos001_cy3.tif -│ │ ├─ test_pos002_dapi.tif -│ │ ├─ test_pos002_cy3.tif -│ │ ├─ test_pos002_dapi.tif -│ ├─ analysis # Folder with all analysis results -│ │ ├─ segmentation-input # Folder with projected images for segmentation -│ │ │ ├─ img-prop__test_pos001_cy3.json # json file with image properties -│ │ │ ├─ test_pos001_cy3.png # Projected image -│ │ │ ├─ .... -│ │ ├─ segmentation-results # Folder with segmentation results -│ │ │ ├─ test_pos001_cy3.tif -│ │ │ ├─ test_pos001_cy3.tif -│ │ │ ├─ test_pos001_cy3.tif -│ │ │ ├─ .... -│ │ ├─ .... -│ │ ├─ FQ_outline # [Optional] FQ outlines -│ │ │ ├─ test_pos001_cy3_outline.txt -│ │ │ ├─ .... -``` - +# Data + +Please note that we recommend a **data organization**, described below, to facilitate the usage of these tools. + +We provide test data, which allows you to inspect how the data is organized, but then also run a local installation +of these tools to see if everything works correctly. + +## Test data +Already processed test data can be downloaded from [**Dropbox**](https://www.dropbox.com/sh/yr1s5olqwkvyx0i/AADH0QQtdNuWWq7z9wgQpLiOa?dl=0). With these data, you can verify if the different analysis steps are properly executed. + +## Data organization +We strongly recommend the following data-organization on which this workflow has been tested. + +1. Images are store as single-channel multi-z-stack tif files, e.g on tif per position and channel. If your data are not single-channel, see the section on how to split channels with [Fiji](workflows-fiji-split-channels.md). +2. All raw 3D images are stored in a folder `acquisition` +3. All analysis results are stored in subfolder `analysis`, where each analysis step has a separate subfolder. + +The organization of the provided test data is the following + +``` bash +├─ example_data/ +│ ├─ acquisition # Folder with raw data +│ │ ├─ test_pos001_cy3.tif +│ │ ├─ test_pos002_dapi.tif +│ │ ├─ test_pos002_cy3.tif +│ │ ├─ test_pos002_dapi.tif +│ ├─ analysis # Folder with all analysis results +│ │ ├─ segmentation-input # Folder with projected images for segmentation +│ │ │ ├─ img-prop__test_pos001_cy3.json # json file with image properties +│ │ │ ├─ test_pos001_cy3.png # Projected image +│ │ │ ├─ .... +│ │ ├─ segmentation-results # Folder with segmentation results +│ │ │ ├─ test_pos001_cy3.tif +│ │ │ ├─ test_pos001_cy3.tif +│ │ │ ├─ test_pos001_cy3.tif +│ │ │ ├─ .... +│ │ ├─ .... +│ │ ├─ FQ_outline # [Optional] FQ outlines +│ │ │ ├─ test_pos001_cy3_outline.txt +│ │ │ ├─ .... +``` + diff --git a/docs/developer.md b/docs/developer.md index 39622ff..b350bd4 100644 --- a/docs/developer.md +++ b/docs/developer.md @@ -1,41 +1,41 @@ - -# Developer - -Here we provide some information for developers who want to contribute to this repository. - -## Documentation - -Documentation - -* is **written** with mkdocs using the readthedocs theme: [mkdocs website](https://www.mkdocs.org/) - -* **Online documentation** is automatically build by [readthedocs.com](https://readthedocs.org/) from the GitHub repository. - -### Local build - -You can build the documentation locally, before pushing to GitHub: - -Install mkdocs: `pip install mkdocs` - -__Basic use__: - -* Launch dev-server: `mkdocs serve` -* Building the site: `mkdocs build` - -## ImJoy plugins - -### Update imjoy manifest - -After changes in ImJoy plugins, update the plugin manifest. - -Install `node.js` with conda - -``` bash -conda install -c conda-forge nodejs -``` - -Run this command in project root path - -``` bash -node update_manifest.js -``` + +# Developer + +Here we provide some information for developers who want to contribute to this repository. + +## Documentation + +Documentation + +* is **written** with mkdocs using the readthedocs theme: [mkdocs website](https://www.mkdocs.org/) + +* **Online documentation** is automatically build by [readthedocs.com](https://readthedocs.org/) from the GitHub repository. + +### Local build + +You can build the documentation locally, before pushing to GitHub: + +Install mkdocs: `pip install mkdocs` + +__Basic use__: + +* Launch dev-server: `mkdocs serve` +* Building the site: `mkdocs build` + +## ImJoy plugins + +### Update imjoy manifest + +After changes in ImJoy plugins, update the plugin manifest. + +Install `node.js` with conda + +``` bash +conda install -c conda-forge nodejs +``` + +Run this command in project root path + +``` bash +node update_manifest.js +``` diff --git a/docs/img/imjoy-logo-powered.svg b/docs/img/imjoy-logo-powered.svg index 36d9643..ca01846 100644 --- a/docs/img/imjoy-logo-powered.svg +++ b/docs/img/imjoy-logo-powered.svg @@ -1,268 +1,268 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -Powered by - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +Powered by + diff --git a/docs/imjoy-faq.md b/docs/imjoy-faq.md index 5858679..84f8643 100644 --- a/docs/imjoy-faq.md +++ b/docs/imjoy-faq.md @@ -1,46 +1,46 @@ -# Overview - -[ImJoy](https://imjoy.io/docs/#/) is image processing platform with an easy to use interface running in your browser. - -* While ImJoy is a browser app, **NO** user data will be transferred over the internet. -* For best stability, we recommend using [**Chrome**](https://www.google.com/chrome/) to run the ImJoy app. -* Some of its main **features** are: - - 1. Specific functionality is provided by **plugins**, which can be installed with simple links. Available - plugins are listed in the plugin list on the left part of the interface. Plugins using Python require a Plugin engine to be executed. Installation and usasage is detailed below. - - 2. ImJoy can have several **workspaces**. Each workspace can contain multiple plugins and is - dedicated to a specific data processing task. Workspaces can be selected from little puzzle - symbol in the upper left part of the interface. - -![imjoy-interface](img/imjoy-interface.png) - -## Running Python plugins - -Most of the provided plugins use Python for data processing. To use these plugins, -you have to connect ImJoy to a Plugin engine. For this repository, we use **Jupyter notebooks** as -and engine, which can be installed via Miniconda (see [**installation instructions**](#install-jupyter-engine-for-imjoy)). - -## Installing plugins - -We provide links to install ImJoy plugins for the different workflows. - -If you press on the installation link, the ImJoy app will open and display a -dialog asking if you want to install the specified plugin. To confirm, press -the `install` button. - -![imjoy-plugin-installation](img/imjoy-plugin-installation.png){: style="width:400px"} - -These installation links also specify in which [ImJoy workspaces](imjoy-overview.md#opening-a-workspace) the plugin will be installed. - -## Opening a workspace - -Once a plugin is installed, ImJoy remembers the workspaces and plugins it contains. - -If you want to redo an analysis, you simply have to open the [ImJoy app](https://imjoy.io/#/app) -and select the workspace `fq-segmentation` for this package. - -If **updates** for the installed plugins -are available, you will see a corresponding symbol next to the plugin name. - -![imjoy-workspacer.gif](img/imjoy-workspace.gif){: style="width:500px"} +# Overview + +[ImJoy](https://imjoy.io/docs/#/) is image processing platform with an easy to use interface running in your browser. + +* While ImJoy is a browser app, **NO** user data will be transferred over the internet. +* For best stability, we recommend using [**Chrome**](https://www.google.com/chrome/) to run the ImJoy app. +* Some of its main **features** are: + + 1. Specific functionality is provided by **plugins**, which can be installed with simple links. Available + plugins are listed in the plugin list on the left part of the interface. Plugins using Python require a Plugin engine to be executed. Installation and usasage is detailed below. + + 2. ImJoy can have several **workspaces**. Each workspace can contain multiple plugins and is + dedicated to a specific data processing task. Workspaces can be selected from little puzzle + symbol in the upper left part of the interface. + +![imjoy-interface](img/imjoy-interface.png) + +## Running Python plugins + +Most of the provided plugins use Python for data processing. To use these plugins, +you have to connect ImJoy to a Plugin engine. For this repository, we use **Jupyter notebooks** as +and engine, which can be installed via Miniconda (see [**installation instructions**](#install-jupyter-engine-for-imjoy)). + +## Installing plugins + +We provide links to install ImJoy plugins for the different workflows. + +If you press on the installation link, the ImJoy app will open and display a +dialog asking if you want to install the specified plugin. To confirm, press +the `install` button. + +![imjoy-plugin-installation](img/imjoy-plugin-installation.png){: style="width:400px"} + +These installation links also specify in which [ImJoy workspaces](imjoy-overview.md#opening-a-workspace) the plugin will be installed. + +## Opening a workspace + +Once a plugin is installed, ImJoy remembers the workspaces and plugins it contains. + +If you want to redo an analysis, you simply have to open the [ImJoy app](https://imjoy.io/#/app) +and select the workspace `fq-segmentation` for this package. + +If **updates** for the installed plugins +are available, you will see a corresponding symbol next to the plugin name. + +![imjoy-workspacer.gif](img/imjoy-workspace.gif){: style="width:500px"} diff --git a/docs/imjoy-installation.md b/docs/imjoy-installation.md index a6956b7..36ebb47 100644 --- a/docs/imjoy-installation.md +++ b/docs/imjoy-installation.md @@ -1,78 +1,78 @@ -# ImJoy installation - -Here we describe how you can install and maintain the ImJoy Jupyter plugin engine, which is -needed to run the Python code for cell/nuclear segmentation and the pre/post processing -workflows. - -## Install Jupyter engine for ImJoy - -This you only need to do **once**. - -We recommend installing [**Miniconda** with Python](https://docs.conda.io/en/latest/miniconda.html): -choose latest Python version (3.X) and your operating system. You can then use the annoconda prompt -to excecute the commands listed below. - -We recommend creating a **dedicated environment** to run code in this analysis package. To create an environment called `fq-segmentation`, open an anaconda prompt and type (Confirm with `y` when asked if you want to proceed (`Proceed ([y]/n)?`): - -``` bash -conda create --name fq-segmentation pytorch=1.8.2 cudatoolkit=10.2 -c pytorch-lts -``` - -Note (31-3-2022): specifying the environment seems necessary due to a change in the Pytorch channel (more [information](https://github.com/MouseLand/cellpose/issues/481)). - -**Activate the environment**: - -``` bash -conda activate fq-segmentation -``` - -**Install code Jupyter optimized for ImJoy**: - -``` bash -pip install -U imjoy[jupyter] -``` - -## Connect to Jupyter engine - -Once installed Jupyter is installed, you can start a Jupyter Notebook in the anaconda terminal, -to which ImJoy can connect. - -* Please note that this engine runs on your local machine, so no data-transfer over the internet is taking place. -* In order to connect a Jupyter engine, you need to specify its url that also contains a token (a passphrase). - If you launch a Jupyter notebook for the first time, you have to provide this URL to ImJoy - (indicated below with **First time only**). After this, ImJoy will remember it. - -![terminal-launch-jupyter.png](img/terminal-launch-jupyter.png) - -1. Launch a **Jupyter Engine for ImJoy**: - - 1. Start an **anaconda terminal**. - 2. **Activate the environment**: `conda activate fq-segmentation` - 3. **Start Jupyter engine**: `imjoy --jupyter` - 4. **First time only**: copy the provided URL including the token, - e.g. `http://127.0.0.1:8888/?token=8b4885e452db1af7cd7b3cfa6c62036cbae46995e473c25e` - -2. **Connect ImJoy to Jupyter Engine**: - - 1. In the ImJoy app, press on the rocket symbol in the upper right corner. - * **First time only**: select `Add Jupyter-Engine`, paste the URL from the step above, and you can give a new name to the engine - * **Subsequent use**: press on the pre-defined plugin engine to connect to it (of course you have to launch it first). - -3. If this is the only engine, plugins will be **automatically connected**. You can verify this, - by clicking on the puzzle symbol next to the plugin name. Depending on the plugin, installation - might take a while, during this period the plugin name will be in red. - - If yoy have multiple engines, you have to choose on which engine the plugin should be running - (more details [below](#plugin-running-on-wrong-engine)). - - ![imjoy-connect-jupyter.gif](img/imjoy-connect-jupyter.gif) - -## Managing plugin engines - -ImJoy remembers the plugin engines it connected to (including the token). You can obtain the list of all -registered engines by pressing on the rocket symbol. - -![imjoy-plugin-manager.png](img/imjoy-plugin-manager.png){: style="width:300px"} - -* **Connected engines** will be shown with their name in black, and a red cross next to the name. Pressing the cross will disconnect ImJoy from the engine, but it will remain in the list. -* **Known engines** (but not connected) will be shown with their name in gray, with a little trash symbol next to them. Pressing on the trash symbol will remove the engine. +# ImJoy installation + +Here we describe how you can install and maintain the ImJoy Jupyter plugin engine, which is +needed to run the Python code for cell/nuclear segmentation and the pre/post processing +workflows. + +## Install Jupyter engine for ImJoy + +This you only need to do **once**. + +We recommend installing [**Miniconda** with Python](https://docs.conda.io/en/latest/miniconda.html): +choose latest Python version (3.X) and your operating system. You can then use the annoconda prompt +to excecute the commands listed below. + +We recommend creating a **dedicated environment** to run code in this analysis package. To create an environment called `fq-segmentation`, open an anaconda prompt and type (Confirm with `y` when asked if you want to proceed (`Proceed ([y]/n)?`): + +``` bash +conda create --name fq-segmentation pytorch=1.8.2 cudatoolkit=10.2 -c pytorch-lts +``` + +Note (31-3-2022): specifying the environment seems necessary due to a change in the Pytorch channel (more [information](https://github.com/MouseLand/cellpose/issues/481)). + +**Activate the environment**: + +``` bash +conda activate fq-segmentation +``` + +**Install code Jupyter optimized for ImJoy**: + +``` bash +pip install -U imjoy[jupyter] +``` + +## Connect to Jupyter engine + +Once installed Jupyter is installed, you can start a Jupyter Notebook in the anaconda terminal, +to which ImJoy can connect. + +* Please note that this engine runs on your local machine, so no data-transfer over the internet is taking place. +* In order to connect a Jupyter engine, you need to specify its url that also contains a token (a passphrase). + If you launch a Jupyter notebook for the first time, you have to provide this URL to ImJoy + (indicated below with **First time only**). After this, ImJoy will remember it. + +![terminal-launch-jupyter.png](img/terminal-launch-jupyter.png) + +1. Launch a **Jupyter Engine for ImJoy**: + + 1. Start an **anaconda terminal**. + 2. **Activate the environment**: `conda activate fq-segmentation` + 3. **Start Jupyter engine**: `imjoy --jupyter` + 4. **First time only**: copy the provided URL including the token, + e.g. `http://127.0.0.1:8888/?token=8b4885e452db1af7cd7b3cfa6c62036cbae46995e473c25e` + +2. **Connect ImJoy to Jupyter Engine**: + + 1. In the ImJoy app, press on the rocket symbol in the upper right corner. + * **First time only**: select `Add Jupyter-Engine`, paste the URL from the step above, and you can give a new name to the engine + * **Subsequent use**: press on the pre-defined plugin engine to connect to it (of course you have to launch it first). + +3. If this is the only engine, plugins will be **automatically connected**. You can verify this, + by clicking on the puzzle symbol next to the plugin name. Depending on the plugin, installation + might take a while, during this period the plugin name will be in red. + + If yoy have multiple engines, you have to choose on which engine the plugin should be running + (more details [below](#plugin-running-on-wrong-engine)). + + ![imjoy-connect-jupyter.gif](img/imjoy-connect-jupyter.gif) + +## Managing plugin engines + +ImJoy remembers the plugin engines it connected to (including the token). You can obtain the list of all +registered engines by pressing on the rocket symbol. + +![imjoy-plugin-manager.png](img/imjoy-plugin-manager.png){: style="width:300px"} + +* **Connected engines** will be shown with their name in black, and a red cross next to the name. Pressing the cross will disconnect ImJoy from the engine, but it will remain in the list. +* **Known engines** (but not connected) will be shown with their name in gray, with a little trash symbol next to them. Pressing on the trash symbol will remove the engine. diff --git a/docs/imjoy-overview.md b/docs/imjoy-overview.md index 3479873..4b62433 100644 --- a/docs/imjoy-overview.md +++ b/docs/imjoy-overview.md @@ -1,46 +1,46 @@ -# Overview - -[ImJoy](https://imjoy.io/docs/#/) is image processing platform with an easy to use interface running in your browser. - -* While ImJoy is a browser app, **NO** user data will be transferred over the internet. -* For best stability, we recommend using [**Chrome**](https://www.google.com/chrome/) to run the ImJoy app. -* Some of its main **features** are: - - 1. Specific functionality is provided by **plugins**, which can be installed with simple links. Available - plugins are listed in the plugin list on the left part of the interface. Plugins using Python require a Plugin engine to be executed. Installation and usasage is detailed below. - - 2. ImJoy can have several **workspaces**. Each workspace can contain multiple plugins and is - dedicated to a specific data processing task. Workspaces can be selected from little puzzle - symbol in the upper left part of the interface. - -![imjoy-interface](img/imjoy-interface.png) - -## Running Python plugins - -Most of the provided plugins use Python for data processing. To use these plugins, -you have to connect ImJoy to a Plugin engine. For this repository, we use **Jupyter notebooks** as -and engine, which can be installed via Miniconda (see [**installation instructions**](#install-jupyter-engine-for-imjoy)). - -## Installing plugins - -We provide links to install ImJoy plugins for the different workflows. - -If you press on the installation link, the ImJoy app will open and display a -dialog asking if you want to install the specified plugin. To confirm, press -the `install` button. - -![imjoy-plugin-installation](img/imjoy-plugin-installation.png){: style="width:400px"} - -These installation links also specify in which [ImJoy workspaces](imjoy-overview.md#opening-a-workspace) the plugin will be installed. - -## Opening a workspace - -Once a plugin is installed, ImJoy remembers the workspaces and plugins it contains. - -If you want to redo an analysis, you simply have to open the [ImJoy app](https://imjoy.io/#/app) -and select the workspace `fq-segmentation` for this package. - -If **updates** for the installed plugins -are available, you will see a corresponding symbol next to the plugin name. - -![imjoy-workspacer.gif](img/imjoy-workspace.gif){: style="width:500px"} +# Overview + +[ImJoy](https://imjoy.io/docs/#/) is image processing platform with an easy to use interface running in your browser. + +* While ImJoy is a browser app, **NO** user data will be transferred over the internet. +* For best stability, we recommend using [**Chrome**](https://www.google.com/chrome/) to run the ImJoy app. +* Some of its main **features** are: + + 1. Specific functionality is provided by **plugins**, which can be installed with simple links. Available + plugins are listed in the plugin list on the left part of the interface. Plugins using Python require a Plugin engine to be executed. Installation and usasage is detailed below. + + 2. ImJoy can have several **workspaces**. Each workspace can contain multiple plugins and is + dedicated to a specific data processing task. Workspaces can be selected from little puzzle + symbol in the upper left part of the interface. + +![imjoy-interface](img/imjoy-interface.png) + +## Running Python plugins + +Most of the provided plugins use Python for data processing. To use these plugins, +you have to connect ImJoy to a Plugin engine. For this repository, we use **Jupyter notebooks** as +and engine, which can be installed via Miniconda (see [**installation instructions**](#install-jupyter-engine-for-imjoy)). + +## Installing plugins + +We provide links to install ImJoy plugins for the different workflows. + +If you press on the installation link, the ImJoy app will open and display a +dialog asking if you want to install the specified plugin. To confirm, press +the `install` button. + +![imjoy-plugin-installation](img/imjoy-plugin-installation.png){: style="width:400px"} + +These installation links also specify in which [ImJoy workspaces](imjoy-overview.md#opening-a-workspace) the plugin will be installed. + +## Opening a workspace + +Once a plugin is installed, ImJoy remembers the workspaces and plugins it contains. + +If you want to redo an analysis, you simply have to open the [ImJoy app](https://imjoy.io/#/app) +and select the workspace `fq-segmentation` for this package. + +If **updates** for the installed plugins +are available, you will see a corresponding symbol next to the plugin name. + +![imjoy-workspacer.gif](img/imjoy-workspace.gif){: style="width:500px"} diff --git a/docs/index.md b/docs/index.md index dcb3bd3..06e54f0 100644 --- a/docs/index.md +++ b/docs/index.md @@ -1,33 +1,33 @@ - -# Segmentation with ImJoy and Cellpose - -This repository provides convience wrapper code for the **segmentation of cells and nuclei**. - -__How to get started:__ - -1. Read this documentation. -2. Install the ImJoy plugin engine (we explain what this is just a bit further down). -3. Install the FISH-quant plugins. -4. Try to analyze the provided test data. - -!!! example "Example of **nuclear segmentation** and **cytoplasmic segmentation**" - ![segmentation__nuclei](img/segmentation__nuclei.png) - ![segmentation__cells](img/segmentation__cells.png) - -## Python? ImJoy? Plugin engine? - -For new users it might be a bit confusing how the different software packages work together. We hence provide here a small overview of hwo the different pieces work together. There are **three essential parts**: - -![fq-get-version.gif](img/segmentation-overview.png){: style="width:500px"} - -1. **Python**: code performing the actual analysis in two essential parts - * The actual **segmentation** is performed with the [**Cellpose package**](https://github.com/mouseland/cellpose). - * Additional code to pre/post process images, and perform batch processing: - * We provide **convenient wrappers** to apply this approach in batch mode to a large number of images. - * We provide **pre- and post-processing** routines to prepare images for segmentation and extract further information, e.g. distance measurements for objects. - -2. **ImJoy**: ImJoy is a plugin powered computing platform to deploy advanced image analysis tools. Here, we provide as a set of such plugins. Plugins can be installed with a simple installation link. More details about ImJoy and how it can be installed, can be found in the decicated overview section. -3. **Plugin Engine**: the ImJoy app is running in your webbrowser (prefereably Chrome). In order to perform computations, you have to install a -so-called plugin engine. ImJoy can connect to such an engine, and launch data processing tasks. Importantly, this engine can run locally or remotely, but the ImJoy interface will always be the same. YOu have to install this engine once. Each time you want to use FISH-quant, you have to launch it and connect ImJoy to this engine. - - + +# Segmentation with ImJoy and Cellpose + +This repository provides convience wrapper code for the **segmentation of cells and nuclei**. + +__How to get started:__ + +1. Read this documentation. +2. Install the ImJoy plugin engine (we explain what this is just a bit further down). +3. Install the FISH-quant plugins. +4. Try to analyze the provided test data. + +!!! example "Example of **nuclear segmentation** and **cytoplasmic segmentation**" + ![segmentation__nuclei](img/segmentation__nuclei.png) + ![segmentation__cells](img/segmentation__cells.png) + +## Python? ImJoy? Plugin engine? + +For new users it might be a bit confusing how the different software packages work together. We hence provide here a small overview of hwo the different pieces work together. There are **three essential parts**: + +![fq-get-version.gif](img/segmentation-overview.png){: style="width:500px"} + +1. **Python**: code performing the actual analysis in two essential parts + * The actual **segmentation** is performed with the [**Cellpose package**](https://github.com/mouseland/cellpose). + * Additional code to pre/post process images, and perform batch processing: + * We provide **convenient wrappers** to apply this approach in batch mode to a large number of images. + * We provide **pre- and post-processing** routines to prepare images for segmentation and extract further information, e.g. distance measurements for objects. + +2. **ImJoy**: ImJoy is a plugin powered computing platform to deploy advanced image analysis tools. Here, we provide as a set of such plugins. Plugins can be installed with a simple installation link. More details about ImJoy and how it can be installed, can be found in the decicated overview section. +3. **Plugin Engine**: the ImJoy app is running in your webbrowser (prefereably Chrome). In order to perform computations, you have to install a +so-called plugin engine. ImJoy can connect to such an engine, and launch data processing tasks. Importantly, this engine can run locally or remotely, but the ImJoy interface will always be the same. YOu have to install this engine once. Each time you want to use FISH-quant, you have to launch it and connect ImJoy to this engine. + + diff --git a/docs/licence.md b/docs/licence.md index 5c65be5..d132171 100644 --- a/docs/licence.md +++ b/docs/licence.md @@ -1,40 +1,40 @@ -- **Cellpose** is (general) are BSD-licenced (3 clause) - -> Copyright © 2020 Howard Hughes Medical Institute - -> Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: - -> Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. -Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. -Neither the name of HHMI nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission. -THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS “AS IS” AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - - -- The **rest of the code** provided in this repository is BSD-licenced (3 clause): - ->Copyright © 2020, Florian Mueller ->All rights reserved. -> ->Redistribution and use in source and binary forms, with or without ->modification, are permitted provided that the following conditions are met: -> * Redistributions of source code must retain the above copyright - notice, this list of conditions and the following disclaimer. -> * Redistributions in binary form must reproduce the above copyright - notice, this list of conditions and the following disclaimer in the - documentation and/or other materials provided with the distribution. -> * Neither the name of the copyright holder nor the names of its - contributors may be used to endorse or promote products derived from - this software without specific prior written permission. -> ->THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND -ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED -WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE -DISCLAIMED. IN NO EVENT SHALL COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY -DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES -(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; -LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND -ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS -SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - +- **Cellpose** is (general) are BSD-licenced (3 clause) + +> Copyright © 2020 Howard Hughes Medical Institute + +> Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: + +> Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. +Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. +Neither the name of HHMI nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission. +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS “AS IS” AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + + +- The **rest of the code** provided in this repository is BSD-licenced (3 clause): + +>Copyright © 2020, Florian Mueller +>All rights reserved. +> +>Redistribution and use in source and binary forms, with or without +>modification, are permitted provided that the following conditions are met: +> * Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. +> * Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. +> * Neither the name of the copyright holder nor the names of its + contributors may be used to endorse or promote products derived from + this software without specific prior written permission. +> +>THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND +ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +DISCLAIMED. IN NO EVENT SHALL COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY +DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES +(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND +ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + https://fish-quant.github.io/segmentation/imjoy-pre-processing/img/imjoy-preprocess-ui.png \ No newline at end of file diff --git a/docs/workflows-create-fq-outlines.md b/docs/workflows-create-fq-outlines.md index aa55a2c..b3bbc1f 100644 --- a/docs/workflows-create-fq-outlines.md +++ b/docs/workflows-create-fq-outlines.md @@ -1,35 +1,35 @@ -# Create FISH-quant [Matlab] outline files -In order to use the segmentation results in the Matlab version of FISH-quant, -FISH-quant outline files have to be created from the mask images. - -For this, we provide a Matlab GUI distributed with the [FISH-quant package](https://bitbucket.org/muellerflorian/fish_quant/src/master/). After installing FISH-quant, you can open this GUI from the command window -with `FQ_seg`. The relevant part of the interface is the central panel _Cell Profiler: generate FQ outlines from segmentation_. - -![](img/fq-create-outlines.png "fq-create-outlines") - - -1. **Specify experimental parameters**. These parameters have to be defined – even if the default parameters are good. - Only then the button to generate the outlines will be enabled. - -0. **Define naming scheme of original images and segmentation results**. You have to define a few parameters regarding - the naming convention of your files. - 1. Unique identifier for the FISH and DAPI images. These identifiers have to be defined in a way that when you take the - full file-name of the FISH image and you replace the identifier for FISH, e.g. `cy3`, by the identifier of the DAPI, e.g. `dapi`, you obtain the DAPI file-name. - 2. Then, you have to define the identifier of your segmentation results. For this workflow, `mask__nuclei__` for the nuclei and - `mask__cells__` for the cells. - 3. File-extensions of the masks and original file-names, e.g. `tif` for the example data. - -0. [Optional] **Generating outline files for a second color**. This option allows to generate outline files for a second color, - e.g. for a dual-color FISH experiment or if the cell segmentation was performed with a different channel than the FISH channel. The outlines for this color will be based on the segmentation results of the first color and the exact cells will be used. This allows a simple comparison between the detection results. As above, the identifier for the second color has to be specified, e.g. `cy5`. You also have to redefine the experimental parameters (most often to adjust the excitation and emission wavelength). - - Additionally, you can choose to not create the outlines for the channel that was used for cell segmentation. This option is useful if the first color does not contain actual smFISH data but results of a dedicated cell segmentation stain. - -0. Several options exist to **specify the folder** where the results will be saved. By default, the FQ outlines will be stored - in a sub-folder `__FQ_outlines` within the folder containing the segmentation results. You can then move it to another location, e.g. directly into the `analysis` folder as done for the example data. - -0. Specify **images that will be analyzed**. You can either choose different images that you want to analyze (`Define images`), - or select an entire folder (`Select folder`). For the latter, you can also specify a recursive search; this means that all subfolders will be searched as well (not recommended for this workflow). The script will only consider images that follow the above explained naming convention – other images will be ignored. - In the example data, the folder `analysis\segmentation-results` contains the relevant data. - -0. **Create outlines**. Lastly, press the button `Create FQ outlines`. The script will then automatically search for the files - describing the segmentation of cells and nuclei. For each image an outline file with the reference to the ORIGINAL 3D image will be generated and nuclei assigned to their respective cells. +# Create FISH-quant [Matlab] outline files +In order to use the segmentation results in the Matlab version of FISH-quant, +FISH-quant outline files have to be created from the mask images. + +For this, we provide a Matlab GUI distributed with the [FISH-quant package](https://bitbucket.org/muellerflorian/fish_quant/src/master/). After installing FISH-quant, you can open this GUI from the command window +with `FQ_seg`. The relevant part of the interface is the central panel _Cell Profiler: generate FQ outlines from segmentation_. + +![](img/fq-create-outlines.png "fq-create-outlines") + + +1. **Specify experimental parameters**. These parameters have to be defined – even if the default parameters are good. + Only then the button to generate the outlines will be enabled. + +0. **Define naming scheme of original images and segmentation results**. You have to define a few parameters regarding + the naming convention of your files. + 1. Unique identifier for the FISH and DAPI images. These identifiers have to be defined in a way that when you take the + full file-name of the FISH image and you replace the identifier for FISH, e.g. `cy3`, by the identifier of the DAPI, e.g. `dapi`, you obtain the DAPI file-name. + 2. Then, you have to define the identifier of your segmentation results. For this workflow, `mask__nuclei__` for the nuclei and + `mask__cells__` for the cells. + 3. File-extensions of the masks and original file-names, e.g. `tif` for the example data. + +0. [Optional] **Generating outline files for a second color**. This option allows to generate outline files for a second color, + e.g. for a dual-color FISH experiment or if the cell segmentation was performed with a different channel than the FISH channel. The outlines for this color will be based on the segmentation results of the first color and the exact cells will be used. This allows a simple comparison between the detection results. As above, the identifier for the second color has to be specified, e.g. `cy5`. You also have to redefine the experimental parameters (most often to adjust the excitation and emission wavelength). + + Additionally, you can choose to not create the outlines for the channel that was used for cell segmentation. This option is useful if the first color does not contain actual smFISH data but results of a dedicated cell segmentation stain. + +0. Several options exist to **specify the folder** where the results will be saved. By default, the FQ outlines will be stored + in a sub-folder `__FQ_outlines` within the folder containing the segmentation results. You can then move it to another location, e.g. directly into the `analysis` folder as done for the example data. + +0. Specify **images that will be analyzed**. You can either choose different images that you want to analyze (`Define images`), + or select an entire folder (`Select folder`). For the latter, you can also specify a recursive search; this means that all subfolders will be searched as well (not recommended for this workflow). The script will only consider images that follow the above explained naming convention – other images will be ignored. + In the example data, the folder `analysis\segmentation-results` contains the relevant data. + +0. **Create outlines**. Lastly, press the button `Create FQ outlines`. The script will then automatically search for the files + describing the segmentation of cells and nuclei. For each image an outline file with the reference to the ORIGINAL 3D image will be generated and nuclei assigned to their respective cells. diff --git a/docs/workflows-create-numbered-labels.md b/docs/workflows-create-numbered-labels.md index c38e956..937178f 100644 --- a/docs/workflows-create-numbered-labels.md +++ b/docs/workflows-create-numbered-labels.md @@ -1,21 +1,21 @@ -# Numbered label image - -Segmentation results in a filled mask for each segmented object (cell or nucleus). Each mask has a unique integer value (0 is reserved for background). This value can be used to uniquely identify each object. An inspection of the resulting label image is possible in any image processing tool, such as FIJI. However, for convience, it might also be useful to have an overview image showing all labels, such as the one shown below - -After segmentation, each object (cell or nucleus) has a unique id. - ![label-image-numbered.png](img/label-image-numbered.png) - -This workflow permits to create such an image from any label image created by the segmentation workflow. - -You can install the plugin from **here.** - -## Workflow - -The default settings of the plugins allow to quickly perform the recommended workflow. You only have -to paste the path to folder containing the segmentation results (usually a folder called `segmentation-results`). The plugin will then loop over all files in this folder, and select the onces fitting the other two parameters: - -- `File string`: specify a string that the file-name has to contain. The default `mask__` fits for both segmentation of cells and nuclei. -- `Img extension: file-extension of the label images. The default is `.png`, which is the extension used by our segmentation pipeline. - -The plugin will then create a new subfolder called `labels_numbered` where the numbered label images +# Numbered label image + +Segmentation results in a filled mask for each segmented object (cell or nucleus). Each mask has a unique integer value (0 is reserved for background). This value can be used to uniquely identify each object. An inspection of the resulting label image is possible in any image processing tool, such as FIJI. However, for convience, it might also be useful to have an overview image showing all labels, such as the one shown below + +After segmentation, each object (cell or nucleus) has a unique id. + ![label-image-numbered.png](img/label-image-numbered.png) + +This workflow permits to create such an image from any label image created by the segmentation workflow. + +You can install the plugin from **here.** + +## Workflow + +The default settings of the plugins allow to quickly perform the recommended workflow. You only have +to paste the path to folder containing the segmentation results (usually a folder called `segmentation-results`). The plugin will then loop over all files in this folder, and select the onces fitting the other two parameters: + +- `File string`: specify a string that the file-name has to contain. The default `mask__` fits for both segmentation of cells and nuclei. +- `Img extension: file-extension of the label images. The default is `.png`, which is the extension used by our segmentation pipeline. + +The plugin will then create a new subfolder called `labels_numbered` where the numbered label images will be stored under their original file-name with an added suffix `__numbered.png`. \ No newline at end of file diff --git a/docs/workflows-distance-objects.md b/docs/workflows-distance-objects.md index e404af1..990d838 100644 --- a/docs/workflows-distance-objects.md +++ b/docs/workflows-distance-objects.md @@ -1,48 +1,48 @@ -# Closest object in image - -For several workflows, it might be interesting to know the object that is the closest each pixel in the. - -![obj-dist-example.png](img/obj-dist-example.png) - -This workflow takes the image of a segmentation results as an input (right image above shows a -nuclear segmentation), and calculates two images of the same size, where each pixel value corresponds to - -1. Distance to the closted object (left image). -2. Index of clostest object (central image). - -With these two images, question about proximity can be answered: for each position in the image, the closest -object and the distance to this object can now be easily identified. - -In the **example data**, you can find processed images for the nuclei segmentation: `example_data\analysis\distance-maps`. - -## Recommended workflow - -The default settings of the plugins allow to quickly perform the recommended workflow. You only have -to paste your data folder. - -1. Segmentation results are stored `segmentation-input` -2. In the pre-processing step, the folder to save data is obtained with - - 1. the text replacement `segmentation-results˃˃distance-maps`. - 2. Images are stored in a new subfolder `segmentation-input` - - With these options, the images will be saved in a folder `distance-maps`. - -## Implementations - -To **calculate these images** for all masks in a folder, you can use either - -* **Jupyter notebook**: notebooks\distance-closest-object.ipynb -* **ImJoy plugin**: `ObjectDist`, which you -**install from here.** - -In either case, the following **parameters** have to be specified - -Option | Type | Description ----------------- | ---- | ----------- -`Path DATA` | str | Full path to folder containing data to be analyzed. -`String label` | str | Unique string identified the mask image that you want to analyze, e.g. `mask__nuclei__` -`String save` | tuple | Pair of strings defining the names under which the images with the index of the object, and the distance to this object will be saved, e.g. `('nuclei_close_ind__', 'nuclei_close_dist__')` -`Trunc distance` | int | Threshold above which distances will be clipped. -`Path SAVE` | str | Several options exist. See dedicated section here [below](data.md#specify-folder-to-save-your-data) for more details. -`Search recursive` | bool | Should provided folder be search [**recursively**](analysis-general-behavior.md#recursive-search-for-data) for images (true/false). +# Closest object in image + +For several workflows, it might be interesting to know the object that is the closest each pixel in the. + +![obj-dist-example.png](img/obj-dist-example.png) + +This workflow takes the image of a segmentation results as an input (right image above shows a +nuclear segmentation), and calculates two images of the same size, where each pixel value corresponds to + +1. Distance to the closted object (left image). +2. Index of clostest object (central image). + +With these two images, question about proximity can be answered: for each position in the image, the closest +object and the distance to this object can now be easily identified. + +In the **example data**, you can find processed images for the nuclei segmentation: `example_data\analysis\distance-maps`. + +## Recommended workflow + +The default settings of the plugins allow to quickly perform the recommended workflow. You only have +to paste your data folder. + +1. Segmentation results are stored `segmentation-input` +2. In the pre-processing step, the folder to save data is obtained with + + 1. the text replacement `segmentation-results˃˃distance-maps`. + 2. Images are stored in a new subfolder `segmentation-input` + + With these options, the images will be saved in a folder `distance-maps`. + +## Implementations + +To **calculate these images** for all masks in a folder, you can use either + +* **Jupyter notebook**: notebooks\distance-closest-object.ipynb +* **ImJoy plugin**: `ObjectDist`, which you +**install from here.** + +In either case, the following **parameters** have to be specified + +Option | Type | Description +---------------- | ---- | ----------- +`Path DATA` | str | Full path to folder containing data to be analyzed. +`String label` | str | Unique string identified the mask image that you want to analyze, e.g. `mask__nuclei__` +`String save` | tuple | Pair of strings defining the names under which the images with the index of the object, and the distance to this object will be saved, e.g. `('nuclei_close_ind__', 'nuclei_close_dist__')` +`Trunc distance` | int | Threshold above which distances will be clipped. +`Path SAVE` | str | Several options exist. See dedicated section here [below](data.md#specify-folder-to-save-your-data) for more details. +`Search recursive` | bool | Should provided folder be search [**recursively**](analysis-general-behavior.md#recursive-search-for-data) for images (true/false). diff --git a/docs/workflows-fiji-split-channels.md b/docs/workflows-fiji-split-channels.md index eaa2e01..5ac3cb9 100644 --- a/docs/workflows-fiji-split-channels.md +++ b/docs/workflows-fiji-split-channels.md @@ -1,48 +1,48 @@ -# Split channels - -This workflow requires that each channel is stored as a separate z-stack. -If your images are stored as multi-channel z-stacks you have to split these images into -individual channels. This can be done with different software packages, below we describe some options. - -## Manual conversion with Fiji - -For this you need to install [Fiji](https://fiji.sc/). - -1. Create a new folder for each multi-channel image. -2. Open image stack in FIJI. -3. Split channels (FQ only supports mono-channel input images) - 1. From menu: `Image` > `Color` > `Split channels` - 2. Save each channels with a unique channel identifier, e.g. `C1-` or `DAPI_`. - -## Batch conversion with Fiji - -We provide a FIJI macro that allows to recursively search for multi-channel images -and convert them to mono-channel images, which will be saved in a newly created subfolder. - -For this you need to - -* Install [Fiji](https://fiji.sc/). -* Use the provided macro `MacroBatchSplitChannel.ijm`, provided in the folder `workflows`. - -### Workflow - -Once you start the macro, it will perform the following steps - -1. Scan the provided folder for images ending in the specified suffix. -2. Images will be opened, split in different channels and maximum intensity projections (MIP) created -3. Results will be saved in a new folder. Will create additional subfolders 'MIP' to store the MIPs. - -### How to use the macro - -1. By default your data has to be in a folder `multi_channel_stacks`, but you can change this in the macro -2. Open Fiji and drag the macro file in Fiji. -3. This will open the macro, here you can modify two parameters - * `suffix` (default `ome.tif`): last part of the file-name. Only files containing this string will be processed. - * `folder_img` (default `multi_channel_stacks`): part of the file-name that will be replaced by `acquisition` in order to save the results (see below). -4. Press the `Run` button and you will be asked to specify the folder that should be processed. - -### Filename and path for saved images - -* For each multi-channel image, the individual channels will be saved as a separate tif file, with **a suffix in -the file-name** indicating the channel index, e.g. `_ch1_` for the first channel. -* Files will be saved in a newly created folder, where the string specified in `folder_img` will be replaced with `acquisition`. This allows to keep nested folder structures when larger data-sets are processed. +# Split channels + +This workflow requires that each channel is stored as a separate z-stack. +If your images are stored as multi-channel z-stacks you have to split these images into +individual channels. This can be done with different software packages, below we describe some options. + +## Manual conversion with Fiji + +For this you need to install [Fiji](https://fiji.sc/). + +1. Create a new folder for each multi-channel image. +2. Open image stack in FIJI. +3. Split channels (FQ only supports mono-channel input images) + 1. From menu: `Image` > `Color` > `Split channels` + 2. Save each channels with a unique channel identifier, e.g. `C1-` or `DAPI_`. + +## Batch conversion with Fiji + +We provide a FIJI macro that allows to recursively search for multi-channel images +and convert them to mono-channel images, which will be saved in a newly created subfolder. + +For this you need to + +* Install [Fiji](https://fiji.sc/). +* Use the provided macro `MacroBatchSplitChannel.ijm`, provided in the folder `workflows`. + +### Workflow + +Once you start the macro, it will perform the following steps + +1. Scan the provided folder for images ending in the specified suffix. +2. Images will be opened, split in different channels and maximum intensity projections (MIP) created +3. Results will be saved in a new folder. Will create additional subfolders 'MIP' to store the MIPs. + +### How to use the macro + +1. By default your data has to be in a folder `multi_channel_stacks`, but you can change this in the macro +2. Open Fiji and drag the macro file in Fiji. +3. This will open the macro, here you can modify two parameters + * `suffix` (default `ome.tif`): last part of the file-name. Only files containing this string will be processed. + * `folder_img` (default `multi_channel_stacks`): part of the file-name that will be replaced by `acquisition` in order to save the results (see below). +4. Press the `Run` button and you will be asked to specify the folder that should be processed. + +### Filename and path for saved images + +* For each multi-channel image, the individual channels will be saved as a separate tif file, with **a suffix in +the file-name** indicating the channel index, e.g. `_ch1_` for the first channel. +* Files will be saved in a newly created folder, where the string specified in `folder_img` will be replaced with `acquisition`. This allows to keep nested folder structures when larger data-sets are processed. diff --git a/docs/workflows-overview.md b/docs/workflows-overview.md index 037b990..cc6e5b3 100644 --- a/docs/workflows-overview.md +++ b/docs/workflows-overview.md @@ -1,9 +1,9 @@ - -Here we provide a description of less frequently used workflows. - -* [**Split multi-channel images**](workflows-fiji-split-channels.md) to obain single-channel images for analysis. -* [**Create numbered label images**](workflows-create-numbered-labels.md) to create an image with color-code segmentation masks including their identifer. -* [**Calculate distance to objects**](workflows-distance-objects.md) to calculate images summarizing which object is closest to each pixel. -* [**Convert segmentation results in FQ outlines**](workflows-create-fq-outlines.md) that can be used by the older Matlab version of FISH-quant. - + +Here we provide a description of less frequently used workflows. + +* [**Split multi-channel images**](workflows-fiji-split-channels.md) to obain single-channel images for analysis. +* [**Create numbered label images**](workflows-create-numbered-labels.md) to create an image with color-code segmentation masks including their identifer. +* [**Calculate distance to objects**](workflows-distance-objects.md) to calculate images summarizing which object is closest to each pixel. +* [**Convert segmentation results in FQ outlines**](workflows-create-fq-outlines.md) that can be used by the older Matlab version of FISH-quant. + Each workflow is documented in a dedicated section. \ No newline at end of file diff --git a/imjoy-plugins/ObjectDist.imjoy.html b/imjoy-plugins/ObjectDist.imjoy.html index aa9496b..1018e37 100644 --- a/imjoy-plugins/ObjectDist.imjoy.html +++ b/imjoy-plugins/ObjectDist.imjoy.html @@ -1,113 +1,113 @@ - -ImJoy plugin to calculate images facilitating distance calculations. - - - -{ - "name": "ObjectDist", - "type": "native-python", - "version": "0.2.1", - "description": "Pre-process 3D images to obtain 2D images for segmentation.", - "tags": ["stable","dev"], - "ui": [ - "Path DATA: {id: 'path_scan', type: 'string', placeholder: 'paste-path-to-data'}", - "Path SAVE: {id: 'path_save', type: 'string', placeholder: 'segmentation-results˃˃distance-maps'}", - "String channel: {id: 'str_label', type: 'string', placeholder: 'mask__nuclei__'}", - "String save INDEX: {id: 'str_save_ind', type: 'string', placeholder: 'nuclei_close_ind__'}", - "String save DIST: {id: 'str_save_dist', type: 'string', placeholder: 'nuclei_close_dist__'}", - "Truncate distance: {id: 'truncate_distance', type: 'number', placeholder: 255}", - "Search recursive: {id: 'search_recursive', type: 'choose', options: ['false', 'true'], placeholder: 'false'}" - ], - "cover": "", - "inputs": null, - "outputs": null, - "flags": [], - "icon": "extension", - "api_version": "0.1.7", - "env": "", - "permissions": [], - "requirements": { - "dev": [""], - "stable":["pip: -U git+https://github.com/fish-quant/fq-segmentation@master scikit-image"] - }, - "dependencies": [] -} - - - \ No newline at end of file diff --git a/imjoy-plugins/PreProcess.imjoy.html b/imjoy-plugins/PreProcess.imjoy.html index f4d2d83..5e1bbc5 100644 --- a/imjoy-plugins/PreProcess.imjoy.html +++ b/imjoy-plugins/PreProcess.imjoy.html @@ -1,121 +1,121 @@ - -ImJoy plugin to per-process images for cell segmentation with -the generalist cell/nuclei segmentation package [**Cellpose**](https://github.com/mouseland/cellpose). - - - -{ - "name": "PreProcess", - "type": "native-python", - "version": "0.2.0", - "description": "Pre-process 3D images to obtain 2D images for segmentation.", - "tags": ["stable","dev"], - "ui": [ - "Path DATA: {id: 'path_process', type: 'string', placeholder: 'paste-path-to-data'}", - "Path SAVE: {id: 'path_save', type: 'string', placeholder: 'acquisition˃˃analysis'}", - "Subfolder: {id: 'subfolder', type: 'string', placeholder: 'segmentation-input'}", - "Channel string: {id: 'channel_ident', type: 'string', placeholder: 'dapi'}", - "Img extension: {id: 'img_ext', type: 'string', placeholder: '.tif'}", - "Projection type: {id: 'projection_type', type: 'choose', options: ['max', 'mean','indiv'], placeholder: 'max'}", - "Search recursive: {id: 'search_recursive', type: 'choose', options: ['false', 'true'], placeholder: 'false'}" - ], - "cover": "", - "inputs": null, - "outputs": null, - "flags": [], - "icon": "extension", - "api_version": "0.1.7", - "env": "", - "permissions": [], - "requirements": { - "dev": [""], - "stable":["pip: -U git+https://github.com/fish-quant/fq-segmentation@master"] - }, - "dependencies": [] -} - - - + +ImJoy plugin to per-process images for cell segmentation with +the generalist cell/nuclei segmentation package [**Cellpose**](https://github.com/mouseland/cellpose). + + + +{ + "name": "PreProcess", + "type": "native-python", + "version": "0.2.0", + "description": "Pre-process 3D images to obtain 2D images for segmentation.", + "tags": ["stable","dev"], + "ui": [ + "Path DATA: {id: 'path_process', type: 'string', placeholder: 'paste-path-to-data'}", + "Path SAVE: {id: 'path_save', type: 'string', placeholder: 'acquisition˃˃analysis'}", + "Subfolder: {id: 'subfolder', type: 'string', placeholder: 'segmentation-input'}", + "Channel string: {id: 'channel_ident', type: 'string', placeholder: 'dapi'}", + "Img extension: {id: 'img_ext', type: 'string', placeholder: '.tif'}", + "Projection type: {id: 'projection_type', type: 'choose', options: ['max', 'mean','indiv'], placeholder: 'max'}", + "Search recursive: {id: 'search_recursive', type: 'choose', options: ['false', 'true'], placeholder: 'false'}" + ], + "cover": "", + "inputs": null, + "outputs": null, + "flags": [], + "icon": "extension", + "api_version": "0.1.7", + "env": "", + "permissions": [], + "requirements": { + "dev": [""], + "stable":["pip: -U git+https://github.com/fish-quant/fq-segmentation@master"] + }, + "dependencies": [] +} + + + diff --git a/imjoy-plugins/SegmentCellsNuclei.imjoy.html b/imjoy-plugins/SegmentCellsNuclei.imjoy.html index 36d8bfd..d87fa3c 100644 --- a/imjoy-plugins/SegmentCellsNuclei.imjoy.html +++ b/imjoy-plugins/SegmentCellsNuclei.imjoy.html @@ -1,155 +1,155 @@ - -ImJoy plugin to perform cell segmentation with -the generalist cell/nuclei segmentation package [**Cellpose**](https://github.com/mouseland/cellpose). - - - -{ - "name": "SegmentCellsNuclei", - "type": "native-python", - "version": "0.2.2", - "description": "Segment cells AND nuclei.", - "tags": ["stable","dev"], - "ui": [ - "Path DATA: {id: 'path_scan', type: 'string', placeholder: 'paste-path-to-data'}", - "Input subfolder: {id: 'input_subfolder', type: 'string', placeholder: 'segmentation-input'}", - "Path SAVE: {id: 'path_save', type: 'string', placeholder: 'segmentation-input˃˃segmentation-results'}", - "String CELLS: {id: 'str_cyto', type: 'string', placeholder: 'cy3'}", - "String NUCLEI: {id: 'str_nuclei', type: 'string', placeholder: 'dapi'}", - "Scaling factor/New size: : {id: 'new_size', type: 'string', placeholder: '2'}", - "Size CELLS: {id: 'size_cells', type: 'number', placeholder: 200}", - "Size NUCLEI: {id: 'size_nuclei', type: 'number', placeholder: 100}", - "Net Average: {id: 'net_avg', type: 'choose', options: ['false', 'true'], placeholder: 'false'}", - "Resample: {id: 'resample', type: 'choose', options: ['false', 'true'], placeholder: 'false'}", - "String img ext: {id: 'img_ext', type: 'string', placeholder: '.png'}" - ], - "cover": "", - "inputs": null, - "outputs": null, - "flags": [], - "icon": "extension", - "api_version": "0.1.7", - "env": "", - "permissions": [], - "requirements": { - "dev": [""], - "stable":["pip: -U git+https://github.com/fish-quant/fq-segmentation@master"] - }, - "dependencies": [], - "cover": "https://fq-segmentation.readthedocs.io/en/latest/img/segmentation__cells.png" -} - - - + +ImJoy plugin to perform cell segmentation with +the generalist cell/nuclei segmentation package [**Cellpose**](https://github.com/mouseland/cellpose). + + + +{ + "name": "SegmentCellsNuclei", + "type": "native-python", + "version": "0.2.2", + "description": "Segment cells AND nuclei.", + "tags": ["stable","dev"], + "ui": [ + "Path DATA: {id: 'path_scan', type: 'string', placeholder: 'paste-path-to-data'}", + "Input subfolder: {id: 'input_subfolder', type: 'string', placeholder: 'segmentation-input'}", + "Path SAVE: {id: 'path_save', type: 'string', placeholder: 'segmentation-input˃˃segmentation-results'}", + "String CELLS: {id: 'str_cyto', type: 'string', placeholder: 'cy3'}", + "String NUCLEI: {id: 'str_nuclei', type: 'string', placeholder: 'dapi'}", + "Scaling factor/New size: : {id: 'new_size', type: 'string', placeholder: '2'}", + "Size CELLS: {id: 'size_cells', type: 'number', placeholder: 200}", + "Size NUCLEI: {id: 'size_nuclei', type: 'number', placeholder: 100}", + "Net Average: {id: 'net_avg', type: 'choose', options: ['false', 'true'], placeholder: 'false'}", + "Resample: {id: 'resample', type: 'choose', options: ['false', 'true'], placeholder: 'false'}", + "String img ext: {id: 'img_ext', type: 'string', placeholder: '.png'}" + ], + "cover": "", + "inputs": null, + "outputs": null, + "flags": [], + "icon": "extension", + "api_version": "0.1.7", + "env": "", + "permissions": [], + "requirements": { + "dev": [""], + "stable":["pip: -U git+https://github.com/fish-quant/fq-segmentation@master"] + }, + "dependencies": [], + "cover": "https://fq-segmentation.readthedocs.io/en/latest/img/segmentation__cells.png" +} + + + diff --git a/imjoy-plugins/SegmentObjects.imjoy.html b/imjoy-plugins/SegmentObjects.imjoy.html index 9f9b8b0..6cff88b 100644 --- a/imjoy-plugins/SegmentObjects.imjoy.html +++ b/imjoy-plugins/SegmentObjects.imjoy.html @@ -1,156 +1,156 @@ - -ImJoy plugin to perform object segmentation with -the generalist cell/nuclei segmentation package [**Cellpose**](https://github.com/mouseland/cellpose). - - - -{ - "name": "SegmentObjects", - "type": "native-python", - "version": "0.2.2", - "description": "Segment cells OR nuclei.", - "tags": ["stable","dev"], - "ui": [ - "Path DATA: {id: 'path_scan', type: 'string', placeholder: 'paste-path-to-data'}", - "Input subfolder: {id: 'input_subfolder', type: 'string', placeholder: 'segmentation-input'}", - "Path SAVE: {id: 'path_save', type: 'string', placeholder: 'segmentation-input˃˃segmentation-results'}", - "String channel: {id: 'str_channel', type: 'string', placeholder: 'dapi'}", - "Object name: {id: 'obj_name', type: 'string', placeholder: 'nuclei'}", - "Cellpose model: {id: 'model_type', type: 'choose', options: ['nuclei', 'cyto'], placeholder: 'nuclei'}", - "Scaling factor/New size:: {id: 'new_size', type: 'string', placeholder: '1'}", - "Object diameter: {id: 'diameter', type: 'number', placeholder: 100}", - "Net Average: {id: 'net_avg', type: 'choose', options: ['false', 'true'], placeholder: 'false'}", - "Resample: {id: 'resample', type: 'choose', options: ['false', 'true'], placeholder: 'false'}", - "String img ext: {id: 'img_ext', type: 'string', placeholder: '.png'}" - ], - "cover": "", - "inputs": null, - "outputs": null, - "flags": [], - "icon": "extension", - "api_version": "0.1.7", - "env": "", - "permissions": [], - "requirements": { - "dev": [""], - "stable":["pip: -U git+https://github.com/fish-quant/fq-segmentation@master"] - }, - "dependencies": [], - "cover": "https://fq-segmentation.readthedocs.io/en/latest/img/segmentation__cells.png" -} - - - + +ImJoy plugin to perform object segmentation with +the generalist cell/nuclei segmentation package [**Cellpose**](https://github.com/mouseland/cellpose). + + + +{ + "name": "SegmentObjects", + "type": "native-python", + "version": "0.2.2", + "description": "Segment cells OR nuclei.", + "tags": ["stable","dev"], + "ui": [ + "Path DATA: {id: 'path_scan', type: 'string', placeholder: 'paste-path-to-data'}", + "Input subfolder: {id: 'input_subfolder', type: 'string', placeholder: 'segmentation-input'}", + "Path SAVE: {id: 'path_save', type: 'string', placeholder: 'segmentation-input˃˃segmentation-results'}", + "String channel: {id: 'str_channel', type: 'string', placeholder: 'dapi'}", + "Object name: {id: 'obj_name', type: 'string', placeholder: 'nuclei'}", + "Cellpose model: {id: 'model_type', type: 'choose', options: ['nuclei', 'cyto'], placeholder: 'nuclei'}", + "Scaling factor/New size:: {id: 'new_size', type: 'string', placeholder: '1'}", + "Object diameter: {id: 'diameter', type: 'number', placeholder: 100}", + "Net Average: {id: 'net_avg', type: 'choose', options: ['false', 'true'], placeholder: 'false'}", + "Resample: {id: 'resample', type: 'choose', options: ['false', 'true'], placeholder: 'false'}", + "String img ext: {id: 'img_ext', type: 'string', placeholder: '.png'}" + ], + "cover": "", + "inputs": null, + "outputs": null, + "flags": [], + "icon": "extension", + "api_version": "0.1.7", + "env": "", + "permissions": [], + "requirements": { + "dev": [""], + "stable":["pip: -U git+https://github.com/fish-quant/fq-segmentation@master"] + }, + "dependencies": [], + "cover": "https://fq-segmentation.readthedocs.io/en/latest/img/segmentation__cells.png" +} + + + diff --git a/mkdocs.yml b/mkdocs.yml index 9d4bc5a..32920b1 100644 --- a/mkdocs.yml +++ b/mkdocs.yml @@ -1,88 +1,88 @@ -# Project information -site_name: Cell segmentation -site_description: Wrapper code to use the generalist cell/nuclei segmentation package [**Cellpose**] -site_author: Florian MUELLER -site_url: https://github.com/fish-quant/fq-segmentation - -# Repository -repo_name: GitHub -repo_url: https://github.com/fish-quant/fq-segmentation.git -edit_uri: "" - -# Copyright -copyright: 'Copyright © 2019 Florian MUELLER' - -# Configuration -theme: - name: 'readthedocs' - #name: mkdocs - # 404 page - static_templates: - - 404.html - - # Don't include MkDocs' JavaScript - #include_search_page: false - #search_index_only: true - - # Default values, taken from mkdocs_theme.yml - language: en - feature: - tabs: true - palette: - primary: indigo - accent: indigo - font: - text: Roboto - code: Roboto Mono - favicon: /img/icons8-eukaryotic-cells-filled-100.png -# logo: -# icon: wb_sunny - -# Customization -extra: - social: - - type: github-alt - link: https://github.com/fish-quant/fq-segmentation - -# MD extension -markdown_extensions: - - admonition - - pymdownx.details - - pymdownx.tasklist - - pymdownx.superfences - - pymdownx.tilde - - attr_list - - toc: - permalink: true - -nav: - - Overview: index.md # Needed for material theme but not for other - - - ImJoy: - - Overview: imjoy-overview.md - - Installation: imjoy-installation.md - - FAQ: imjoy-faq.md - - - ImJoy Analysis: - - Overview: analysis-overview.md - - General behavior: analysis-general-behavior.md - - Data: data.md - - Preprocessing: analysis-preprocessing.md - - Segmentation: analysis-segmentation.md - - - Diverse workflows: - - Overview: workflows-overview.md - - Split channels: workflows-fiji-split-channels.md - - Numbered label image: workflows-create-numbered-labels.md - - Distance to objects: workflows-distance-objects.md - - Create FQ outline files: workflows-create-fq-outlines.md - - - Advanced: - - Developers: developer.md - - - More: - - Licence: licence.md - - Contact: contact.md - -#theme: -# name: 'material' +# Project information +site_name: Cell segmentation +site_description: Wrapper code to use the generalist cell/nuclei segmentation package [**Cellpose**] +site_author: Florian MUELLER +site_url: https://github.com/fish-quant/fq-segmentation + +# Repository +repo_name: GitHub +repo_url: https://github.com/fish-quant/fq-segmentation.git +edit_uri: "" + +# Copyright +copyright: 'Copyright © 2019 Florian MUELLER' + +# Configuration +theme: + name: 'readthedocs' + #name: mkdocs + # 404 page + static_templates: + - 404.html + + # Don't include MkDocs' JavaScript + #include_search_page: false + #search_index_only: true + + # Default values, taken from mkdocs_theme.yml + language: en + feature: + tabs: true + palette: + primary: indigo + accent: indigo + font: + text: Roboto + code: Roboto Mono + favicon: /img/icons8-eukaryotic-cells-filled-100.png +# logo: +# icon: wb_sunny + +# Customization +extra: + social: + - type: github-alt + link: https://github.com/fish-quant/fq-segmentation + +# MD extension +markdown_extensions: + - admonition + - pymdownx.details + - pymdownx.tasklist + - pymdownx.superfences + - pymdownx.tilde + - attr_list + - toc: + permalink: true + +nav: + - Overview: index.md # Needed for material theme but not for other + + - ImJoy: + - Overview: imjoy-overview.md + - Installation: imjoy-installation.md + - FAQ: imjoy-faq.md + + - ImJoy Analysis: + - Overview: analysis-overview.md + - General behavior: analysis-general-behavior.md + - Data: data.md + - Preprocessing: analysis-preprocessing.md + - Segmentation: analysis-segmentation.md + + - Diverse workflows: + - Overview: workflows-overview.md + - Split channels: workflows-fiji-split-channels.md + - Numbered label image: workflows-create-numbered-labels.md + - Distance to objects: workflows-distance-objects.md + - Create FQ outline files: workflows-create-fq-outlines.md + + - Advanced: + - Developers: developer.md + + - More: + - Licence: licence.md + - Contact: contact.md + +#theme: +# name: 'material' diff --git a/notebooks/distance-closest-object.ipynb b/notebooks/distance-closest-object.ipynb index ff7fbf0..31cff34 100644 --- a/notebooks/distance-closest-object.ipynb +++ b/notebooks/distance-closest-object.ipynb @@ -1,75 +1,75 @@ -{ - "cells": [ - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "# Notebook to perform segmentation of either cells or nuclei with cellpose.\n", - "* Requires that `cellpose` and the code of this respository are installed. One way to do this is with a pip install (recommended in a dedicated conda environment as explained in the documentation).\n", - " ```\n", - " pip install git+https://github.com/muellerflorian/fq-segmentation/ --upgrade\n", - " ```" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "# Imports \n", - "import pathlib\n", - "from pathlib import Path\n", - "\n", - "from segwrap import utils_masks # Either on sys path or pip installed" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "# >>>> Function call\n", - "\n", - "# >> Parameters\n", - "path_scan = Path(r'paste-path-to-data') # For example data: example_data\\analysis\\segmentation-input\n", - "\n", - "str_label = 'mask__nuclei__'\n", - "strs_save = ('nuclei_close_ind__', 'nuclei_close_dist__')\n", - "truncate_distance = 255 # Distance above which distances will be truncated. \n", - "path_save = None\n", - "\n", - "# >> Call processing function\n", - "importlib.reload(utils_masks)\n", - "utils_masks.create_img_closest_obj(path_scan=path_scan,\n", - " str_label=str_label,\n", - " strs_save=strs_save,\n", - " path_save = path_save,\n", - " search_recursive=false,\n", - " truncate_distance=255)\n" - ] - } - ], - "metadata": { - "kernelspec": { - "display_name": "Python 3.7.6 64-bit ('cellpose': conda)", - "language": "python", - "name": "python37664bitcellposecondafe33b8fac7d34fcb85d1f0e07041e8c2" - }, - "language_info": { - "codemirror_mode": { - "name": "ipython", - "version": 3 - }, - "file_extension": ".py", - "mimetype": "text/x-python", - "name": "python", - "nbconvert_exporter": "python", - "pygments_lexer": "ipython3", - "version": "3.7.6" - } - }, - "nbformat": 4, - "nbformat_minor": 4 +{ + "cells": [ + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# Notebook to perform segmentation of either cells or nuclei with cellpose.\n", + "* Requires that `cellpose` and the code of this respository are installed. One way to do this is with a pip install (recommended in a dedicated conda environment as explained in the documentation).\n", + " ```\n", + " pip install git+https://github.com/muellerflorian/fq-segmentation/ --upgrade\n", + " ```" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "# Imports \n", + "import pathlib\n", + "from pathlib import Path\n", + "\n", + "from segwrap import utils_masks # Either on sys path or pip installed" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "# >>>> Function call\n", + "\n", + "# >> Parameters\n", + "path_scan = Path(r'paste-path-to-data') # For example data: example_data\\analysis\\segmentation-input\n", + "\n", + "str_label = 'mask__nuclei__'\n", + "strs_save = ('nuclei_close_ind__', 'nuclei_close_dist__')\n", + "truncate_distance = 255 # Distance above which distances will be truncated. \n", + "path_save = None\n", + "\n", + "# >> Call processing function\n", + "importlib.reload(utils_masks)\n", + "utils_masks.create_img_closest_obj(path_scan=path_scan,\n", + " str_label=str_label,\n", + " strs_save=strs_save,\n", + " path_save = path_save,\n", + " search_recursive=false,\n", + " truncate_distance=255)\n" + ] + } + ], + "metadata": { + "kernelspec": { + "display_name": "Python 3.7.6 64-bit ('cellpose': conda)", + "language": "python", + "name": "python37664bitcellposecondafe33b8fac7d34fcb85d1f0e07041e8c2" + }, + "language_info": { + "codemirror_mode": { + "name": "ipython", + "version": 3 + }, + "file_extension": ".py", + "mimetype": "text/x-python", + "name": "python", + "nbconvert_exporter": "python", + "pygments_lexer": "ipython3", + "version": "3.7.6" + } + }, + "nbformat": 4, + "nbformat_minor": 4 } \ No newline at end of file diff --git a/notebooks/pre-processing.ipynb b/notebooks/pre-processing.ipynb index bbac6b0..f02ce40 100644 --- a/notebooks/pre-processing.ipynb +++ b/notebooks/pre-processing.ipynb @@ -1,81 +1,81 @@ -{ - "cells": [ - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "# Notebook to perform preprocessing of images for segmentation\n", - "* Takes 3D images and performs a 2D projection to obtain 2D png that can be used in the segmentation algorithm.\n", - "* Requires that `cellpose` and the code of this respository are installed. One way to do this is with a pip install (recommended in a dedicated conda environment as explained in the documentation).\n", - " ```\n", - " pip install git+https://github.com/muellerflorian/fq-segmentation/ --upgrade\n", - " ```" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "# >>> Imports \n", - "import segwrap\n", - "from segwrap import utils_segmentation\n", - "from pathlib import Path \n", - "\n", - "# Print version and location of package\n", - "print(f' * segwrap version: {segwrap.__version__}')\n", - "print(f' * utils_segmentation location: {utils_segmentation.__file__}')" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "# >>> Function call\n", - "\n", - "# Parameters\n", - "path_process = Path(r'paste-path-to-data') # For example data: \\example_data\\acquisition\n", - "path_save = 'acquisition>>analysis' # If defined with >>, a string replacement will be performed (see https://fq-segmentation--27.org.readthedocs.build/en/27/analysis-general-behavior/#specify-folder-to-save-results)\n", - "subbfolder = 'segmentation-input' # Name of subfolder to store results.\n", - "channel_ident = 'dapi' # Identifier of channel that should be pre-processed \n", - "img_ext = '.tif' # Extension of images that should be processed\n", - "projection_type = 'max' # Projection type (mean, max, indiv)\n", - "search_recursive = False # Search folder recursively for data?\n", - "\n", - "# Call pre-processing function\n", - "utils_segmentation.folder_prepare_prediction(\n", - " path_process=path_process,\n", - " channel_ident=channel_ident,\n", - " img_ext=img_ext,\n", - " path_save=path_save,\n", - " projection_type=projection_type,\n", - " subfolder=subbfolder,\n", - " search_recursive=search_recursive)" - ] - } - ], - "metadata": { - "kernelspec": { - "display_name": "Python 3.7.6 64-bit ('cellpose': conda)", - "language": "python", - "name": "python37664bitcellposecondafe33b8fac7d34fcb85d1f0e07041e8c2" - }, - "language_info": { - "codemirror_mode": { - "name": "ipython", - "version": 3 - }, - "file_extension": ".py", - "mimetype": "text/x-python", - "name": "python", - "nbconvert_exporter": "python", - "pygments_lexer": "ipython3", - "version": "3.7.6" - } - }, - "nbformat": 4, - "nbformat_minor": 4 +{ + "cells": [ + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# Notebook to perform preprocessing of images for segmentation\n", + "* Takes 3D images and performs a 2D projection to obtain 2D png that can be used in the segmentation algorithm.\n", + "* Requires that `cellpose` and the code of this respository are installed. One way to do this is with a pip install (recommended in a dedicated conda environment as explained in the documentation).\n", + " ```\n", + " pip install git+https://github.com/muellerflorian/fq-segmentation/ --upgrade\n", + " ```" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "# >>> Imports \n", + "import segwrap\n", + "from segwrap import utils_segmentation\n", + "from pathlib import Path \n", + "\n", + "# Print version and location of package\n", + "print(f' * segwrap version: {segwrap.__version__}')\n", + "print(f' * utils_segmentation location: {utils_segmentation.__file__}')" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "# >>> Function call\n", + "\n", + "# Parameters\n", + "path_process = Path(r'paste-path-to-data') # For example data: \\example_data\\acquisition\n", + "path_save = 'acquisition>>analysis' # If defined with >>, a string replacement will be performed (see https://fq-segmentation--27.org.readthedocs.build/en/27/analysis-general-behavior/#specify-folder-to-save-results)\n", + "subbfolder = 'segmentation-input' # Name of subfolder to store results.\n", + "channel_ident = 'dapi' # Identifier of channel that should be pre-processed \n", + "img_ext = '.tif' # Extension of images that should be processed\n", + "projection_type = 'max' # Projection type (mean, max, indiv)\n", + "search_recursive = False # Search folder recursively for data?\n", + "\n", + "# Call pre-processing function\n", + "utils_segmentation.folder_prepare_prediction(\n", + " path_process=path_process,\n", + " channel_ident=channel_ident,\n", + " img_ext=img_ext,\n", + " path_save=path_save,\n", + " projection_type=projection_type,\n", + " subfolder=subbfolder,\n", + " search_recursive=search_recursive)" + ] + } + ], + "metadata": { + "kernelspec": { + "display_name": "Python 3.7.6 64-bit ('cellpose': conda)", + "language": "python", + "name": "python37664bitcellposecondafe33b8fac7d34fcb85d1f0e07041e8c2" + }, + "language_info": { + "codemirror_mode": { + "name": "ipython", + "version": 3 + }, + "file_extension": ".py", + "mimetype": "text/x-python", + "name": "python", + "nbconvert_exporter": "python", + "pygments_lexer": "ipython3", + "version": "3.7.6" + } + }, + "nbformat": 4, + "nbformat_minor": 4 } \ No newline at end of file diff --git a/notebooks/segment-cells-nuclei.ipynb b/notebooks/segment-cells-nuclei.ipynb index f0d5bdd..155ab18 100644 --- a/notebooks/segment-cells-nuclei.ipynb +++ b/notebooks/segment-cells-nuclei.ipynb @@ -1,89 +1,89 @@ -{ - "cells": [ - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "# Notebook to perform segmentation of cells and nuclei with cellpose.\n", - "* Requires that `cellpose` and the code of this respository are installed. One way to do this is with a pip install (recommended in a dedicated conda environment as explained in the documentation).\n", - " ```\n", - " pip install git+https://github.com/fish-quant/fq-segmentation/ --upgrade\n", - " ```" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "# Imports \n", - "import segwrap \n", - "from segwrap import utils_cellpose\n", - "from pathlib import Path\n", - "\n", - "# Print version and location of package\n", - "print(f' * segwrap version: {segwrap.__version__}')\n", - "print(f' * utils_cellpose location: {utils_cellpose.__file__}')" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "# >> Function call\n", - "\n", - "# Parameters\n", - "path_scan = Path(r'paste-path-to-data') # For example data: example_data\\analysis\\segmentation-input\n", - "input_subfolder = 'segmentation-input' # Name of subfolder containing the images to be segmented\n", - "path_save = 'segmentation-input>>segmentation-results' # For example data: example_data\\analysis\\segmentation-results\n", - "str_cyto = 'cy3' # Identifier of channel for cytoplasmic segmentation\n", - "str_nuclei = 'dapi' # Identifier of channel for nuclear segmentation\n", - "img_ext = '.png' # Extension of images to be segmented\n", - "\n", - "new_size = (2,) # Size of images (when resize should be applied, empty tuple otherwise)\n", - "diameter_cells = 100 # Typical size (diameter) of cells\n", - "diameter_nuclei = 50 # Typical size (diameter) of nuclei\n", - "\n", - "net_avg=False # runs the 4 built-in networks and averages them if True, runs one network if False\n", - "resample=False # run dynamics at original image size (will be (much) slower but create more accurate boundaries)\n", - "\n", - "# Call segmentation function\n", - "utils_cellpose.segment_cells_nuclei_indiv(\n", - " path_scan=path_scan, \n", - " str_channels=str_channels, \n", - " img_ext=img_ext, \n", - " new_size=new_size,\n", - " model_types=('cyto','nuclei'), \n", - " diameters = (diameter_cells, diameter_nuclei), \n", - " net_avg=net_avg, \n", - " resample=resample, \n", - " path_save=path_save,\n", - " input_subfolder=input_subfolder)" - ] - } - ], - "metadata": { - "kernelspec": { - "display_name": "Python 3.7.6 64-bit ('cellpose': conda)", - "language": "python", - "name": "python37664bitcellposecondafe33b8fac7d34fcb85d1f0e07041e8c2" - }, - "language_info": { - "codemirror_mode": { - "name": "ipython", - "version": 3 - }, - "file_extension": ".py", - "mimetype": "text/x-python", - "name": "python", - "nbconvert_exporter": "python", - "pygments_lexer": "ipython3", - "version": "3.7.6" - } - }, - "nbformat": 4, - "nbformat_minor": 4 +{ + "cells": [ + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# Notebook to perform segmentation of cells and nuclei with cellpose.\n", + "* Requires that `cellpose` and the code of this respository are installed. One way to do this is with a pip install (recommended in a dedicated conda environment as explained in the documentation).\n", + " ```\n", + " pip install git+https://github.com/fish-quant/fq-segmentation/ --upgrade\n", + " ```" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "# Imports \n", + "import segwrap \n", + "from segwrap import utils_cellpose\n", + "from pathlib import Path\n", + "\n", + "# Print version and location of package\n", + "print(f' * segwrap version: {segwrap.__version__}')\n", + "print(f' * utils_cellpose location: {utils_cellpose.__file__}')" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "# >> Function call\n", + "\n", + "# Parameters\n", + "path_scan = Path(r'paste-path-to-data') # For example data: example_data\\analysis\\segmentation-input\n", + "input_subfolder = 'segmentation-input' # Name of subfolder containing the images to be segmented\n", + "path_save = 'segmentation-input>>segmentation-results' # For example data: example_data\\analysis\\segmentation-results\n", + "str_cyto = 'cy3' # Identifier of channel for cytoplasmic segmentation\n", + "str_nuclei = 'dapi' # Identifier of channel for nuclear segmentation\n", + "img_ext = '.png' # Extension of images to be segmented\n", + "\n", + "new_size = (2,) # Size of images (when resize should be applied, empty tuple otherwise)\n", + "diameter_cells = 100 # Typical size (diameter) of cells\n", + "diameter_nuclei = 50 # Typical size (diameter) of nuclei\n", + "\n", + "net_avg=False # runs the 4 built-in networks and averages them if True, runs one network if False\n", + "resample=False # run dynamics at original image size (will be (much) slower but create more accurate boundaries)\n", + "\n", + "# Call segmentation function\n", + "utils_cellpose.segment_cells_nuclei_indiv(\n", + " path_scan=path_scan, \n", + " str_channels=str_channels, \n", + " img_ext=img_ext, \n", + " new_size=new_size,\n", + " model_types=('cyto','nuclei'), \n", + " diameters = (diameter_cells, diameter_nuclei), \n", + " net_avg=net_avg, \n", + " resample=resample, \n", + " path_save=path_save,\n", + " input_subfolder=input_subfolder)" + ] + } + ], + "metadata": { + "kernelspec": { + "display_name": "Python 3.7.6 64-bit ('cellpose': conda)", + "language": "python", + "name": "python37664bitcellposecondafe33b8fac7d34fcb85d1f0e07041e8c2" + }, + "language_info": { + "codemirror_mode": { + "name": "ipython", + "version": 3 + }, + "file_extension": ".py", + "mimetype": "text/x-python", + "name": "python", + "nbconvert_exporter": "python", + "pygments_lexer": "ipython3", + "version": "3.7.6" + } + }, + "nbformat": 4, + "nbformat_minor": 4 } \ No newline at end of file diff --git a/notebooks/segment-nuclei.ipynb b/notebooks/segment-nuclei.ipynb index e1564aa..1074e08 100644 --- a/notebooks/segment-nuclei.ipynb +++ b/notebooks/segment-nuclei.ipynb @@ -1,92 +1,92 @@ -{ - "cells": [ - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "# Notebook to perform segmentation of either cells or nuclei with cellpose.\n", - "* Requires that `cellpose` and the code of this respository are installed. One way to do this is with a pip install (recommended in a dedicated conda environment as explained in the documentation).\n", - " ```\n", - " pip install git+https://github.com/fish-quant/fq-segmentation/ --upgrade\n", - " ```" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "# Imports \n", - "import segwrap \n", - "from segwrap import utils_cellpose\n", - "from pathlib import Path\n", - "\n", - "# Print version and location of package\n", - "print(f' * segwrap version: {segwrap.__version__}')\n", - "print(f' * utils_cellpose location: {utils_cellpose.__file__}')" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "# >> Function call\n", - "\n", - "# Parameters\n", - "path_scan = Path(r'paste-path-to-data') # For example data: example_data\\analysis\\segmentation-input\n", - "input_subfolder = 'segmentation-input' # Name of subfolder containing the images to be segmented\n", - "path_save = 'segmentation-input>>segmentation-results' # For example data: example_data\\analysis\\segmentation-results\n", - "obj_name='nuclei', # Name of object that should be segmented\n", - "str_channel = 'dapi' # Identifier of channel for nuclear segmentation\n", - "img_ext = '.png' # Extension of images to be segmented\n", - "\n", - "new_size = (2,) # Size of images (when resize should be applied, empty tuple otherwise)\n", - "diameter = 50 # Typical size (diameter) of nuclei\n", - "\n", - "model_type = 'nuclei' # Can be 'nuclei' or 'cyto', for densely packed nuclei 'cyto' might work well. \n", - "net_avg=False # runs the 4 built-in networks and averages them if True, runs one network if False\n", - "resample=False # run dynamics at original image size (will be (much) slower but create more accurate boundaries)\n", - "\n", - "# Call segmentation function\n", - "utils_cellpose.segment_obj_indiv(\n", - " path_scan=path_scan, \n", - " obj_name=obj_name, \n", - " str_channel=str_channel, \n", - " img_ext=img_ext,\n", - " new_size=new_size, \n", - " model_type=model_type, \n", - " diameter = diameter, \n", - " net_avg=net_avg, \n", - " resample=resample, \n", - " path_save=path_save\n", - " input_subfolder=input_subfolder)\n", - "\n", - "\n" - ] - } - ], - "metadata": { - "kernelspec": { - "display_name": "Python 3.7.6 64-bit ('cellpose': conda)", - "language": "python", - "name": "python37664bitcellposecondafe33b8fac7d34fcb85d1f0e07041e8c2" - }, - "language_info": { - "codemirror_mode": { - "name": "ipython", - "version": 3 - }, - "file_extension": ".py", - "mimetype": "text/x-python", - "name": "python", - "nbconvert_exporter": "python", - "pygments_lexer": "ipython3", - "version": "3.7.6" - } - }, - "nbformat": 4, - "nbformat_minor": 4 +{ + "cells": [ + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# Notebook to perform segmentation of either cells or nuclei with cellpose.\n", + "* Requires that `cellpose` and the code of this respository are installed. One way to do this is with a pip install (recommended in a dedicated conda environment as explained in the documentation).\n", + " ```\n", + " pip install git+https://github.com/fish-quant/fq-segmentation/ --upgrade\n", + " ```" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "# Imports \n", + "import segwrap \n", + "from segwrap import utils_cellpose\n", + "from pathlib import Path\n", + "\n", + "# Print version and location of package\n", + "print(f' * segwrap version: {segwrap.__version__}')\n", + "print(f' * utils_cellpose location: {utils_cellpose.__file__}')" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "# >> Function call\n", + "\n", + "# Parameters\n", + "path_scan = Path(r'paste-path-to-data') # For example data: example_data\\analysis\\segmentation-input\n", + "input_subfolder = 'segmentation-input' # Name of subfolder containing the images to be segmented\n", + "path_save = 'segmentation-input>>segmentation-results' # For example data: example_data\\analysis\\segmentation-results\n", + "obj_name='nuclei', # Name of object that should be segmented\n", + "str_channel = 'dapi' # Identifier of channel for nuclear segmentation\n", + "img_ext = '.png' # Extension of images to be segmented\n", + "\n", + "new_size = (2,) # Size of images (when resize should be applied, empty tuple otherwise)\n", + "diameter = 50 # Typical size (diameter) of nuclei\n", + "\n", + "model_type = 'nuclei' # Can be 'nuclei' or 'cyto', for densely packed nuclei 'cyto' might work well. \n", + "net_avg=False # runs the 4 built-in networks and averages them if True, runs one network if False\n", + "resample=False # run dynamics at original image size (will be (much) slower but create more accurate boundaries)\n", + "\n", + "# Call segmentation function\n", + "utils_cellpose.segment_obj_indiv(\n", + " path_scan=path_scan, \n", + " obj_name=obj_name, \n", + " str_channel=str_channel, \n", + " img_ext=img_ext,\n", + " new_size=new_size, \n", + " model_type=model_type, \n", + " diameter = diameter, \n", + " net_avg=net_avg, \n", + " resample=resample, \n", + " path_save=path_save\n", + " input_subfolder=input_subfolder)\n", + "\n", + "\n" + ] + } + ], + "metadata": { + "kernelspec": { + "display_name": "Python 3.7.6 64-bit ('cellpose': conda)", + "language": "python", + "name": "python37664bitcellposecondafe33b8fac7d34fcb85d1f0e07041e8c2" + }, + "language_info": { + "codemirror_mode": { + "name": "ipython", + "version": 3 + }, + "file_extension": ".py", + "mimetype": "text/x-python", + "name": "python", + "nbconvert_exporter": "python", + "pygments_lexer": "ipython3", + "version": "3.7.6" + } + }, + "nbformat": 4, + "nbformat_minor": 4 } \ No newline at end of file diff --git a/readme.md b/readme.md index e929799..103fd98 100644 --- a/readme.md +++ b/readme.md @@ -1,60 +1,60 @@ - -[![powered by ImJoy](https://imjoy.io/static/badge/powered-by-imjoy-badge.svg)](https://imjoy.io/) -![GitHub](https://img.shields.io/github/license/muellerflorian/segmentation) -[![Documentation Status](https://readthedocs.org/projects/fq-segmentation/badge/?version=latest)](https://fq-segmentation.readthedocs.io/en/latest/?badge=latest) -[![Python 3.7](https://img.shields.io/badge/python-3.7-blue.svg)](https://www.python.org/downloads/release/python-370/) - -# Overview -This repository provides wrapper code to use the generalist cell/nuclei segmentation package [**Cellpose**](https://github.com/mouseland/cellpose). - -For more information, please consult the dedicated [**documentation**](https://fq-segmentation.readthedocs.io/en/latest/). - -If you encounter a problems, please file an [**issue**](https://github.com/fish-quant/fq-segmentation/issues). - -Example of **nuclear segmentation**: - - - -Example of **cytoplasmic segmentation**: - - - -# Licensing - -- **Cellpose** is BSD-licenced (3 clause) - -> Copyright © 2020 Howard Hughes Medical Institute -> -> Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: -> -> Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. -Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. -Neither the name of HHMI nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission. -THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS “AS IS” AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - - -- The rest of the code provided in this repository is BSD-licenced (3 clause): ->Copyright © 2020, Florian Mueller ->All rights reserved. -> ->Redistribution and use in source and binary forms, with or without ->modification, are permitted provided that the following conditions are met: -> * Redistributions of source code must retain the above copyright - notice, this list of conditions and the following disclaimer. -> * Redistributions in binary form must reproduce the above copyright - notice, this list of conditions and the following disclaimer in the - documentation and/or other materials provided with the distribution. -> * Neither the name of the copyright holder nor the names of its - contributors may be used to endorse or promote products derived from - this software without specific prior written permission. -> ->THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND -ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED -WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE -DISCLAIMED. IN NO EVENT SHALL COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY -DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES -(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; -LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND -ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS -SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +[![powered by ImJoy](https://imjoy.io/static/badge/powered-by-imjoy-badge.svg)](https://imjoy.io/) +![GitHub](https://img.shields.io/github/license/muellerflorian/segmentation) +[![Documentation Status](https://readthedocs.org/projects/fq-segmentation/badge/?version=latest)](https://fq-segmentation.readthedocs.io/en/latest/?badge=latest) +[![Python 3.7](https://img.shields.io/badge/python-3.7-blue.svg)](https://www.python.org/downloads/release/python-370/) + +# Overview +This repository provides wrapper code to use the generalist cell/nuclei segmentation package [**Cellpose**](https://github.com/mouseland/cellpose). + +For more information, please consult the dedicated [**documentation**](https://fq-segmentation.readthedocs.io/en/latest/). + +If you encounter a problems, please file an [**issue**](https://github.com/fish-quant/fq-segmentation/issues). + +Example of **nuclear segmentation**: + + + +Example of **cytoplasmic segmentation**: + + + +# Licensing + +- **Cellpose** is BSD-licenced (3 clause) + +> Copyright © 2020 Howard Hughes Medical Institute +> +> Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: +> +> Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. +Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. +Neither the name of HHMI nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission. +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS “AS IS” AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + + +- The rest of the code provided in this repository is BSD-licenced (3 clause): +>Copyright © 2020, Florian Mueller +>All rights reserved. +> +>Redistribution and use in source and binary forms, with or without +>modification, are permitted provided that the following conditions are met: +> * Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. +> * Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. +> * Neither the name of the copyright holder nor the names of its + contributors may be used to endorse or promote products derived from + this software without specific prior written permission. +> +>THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND +ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +DISCLAIMED. IN NO EVENT SHALL COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY +DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES +(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND +ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. diff --git a/requirements.txt b/requirements.txt index d87defd..b6bae75 100644 --- a/requirements.txt +++ b/requirements.txt @@ -1,3 +1,3 @@ -cellpose == 1.0.2 -matplotlib == 3.5.1 +cellpose == 1.0.2 +matplotlib == 3.5.1 scikit-image == 0.19.2 \ No newline at end of file diff --git a/segwrap/__init__.py b/segwrap/__init__.py index 145e56b..c8c5318 100644 --- a/segwrap/__init__.py +++ b/segwrap/__init__.py @@ -1,15 +1,15 @@ -# -*- coding: utf-8 -*- -# Author: Florian Mueller -# License: BSD 3 clause - -""" -segmentation package. -""" - - -# keep a MAJOR.MINOR.PATCH format -# MAJOR: major API changes -# MINOR: new features -# PATCH: backwards compatible bug fixes -# MAJOR.MINOR.PATCHdev means a version under development -__version__ = "0.3.4" +# -*- coding: utf-8 -*- +# Author: Florian Mueller +# License: BSD 3 clause + +""" +segmentation package. +""" + + +# keep a MAJOR.MINOR.PATCH format +# MAJOR: major API changes +# MINOR: new features +# PATCH: backwards compatible bug fixes +# MAJOR.MINOR.PATCHdev means a version under development +__version__ = "0.3.4" diff --git a/segwrap/utils_cellpose.py b/segwrap/utils_cellpose.py index aaaaa3c..a6089b8 100644 --- a/segwrap/utils_cellpose.py +++ b/segwrap/utils_cellpose.py @@ -1,475 +1,475 @@ -# Imports of general libraries -import numpy as np -from tqdm import tqdm -import time -import matplotlib.pyplot as plt -import pathlib -from pathlib import Path -import json -import cv2 -from skimage.exposure import rescale_intensity - -# Imports of CellPose specific libraries -from cellpose import models, io, plot -from segwrap.utils_general import log_message, create_output_path - -# Call predict function -def cellpose_predict(data, config, path_save, callback_log=None): - """ Perform prediction with CellPose. - - Parameters - ---------- - data : dict - Contains data on which prediction should be performed. - config : dict - Configuration of CellPose prediction. - path_save : pathline Path object - Path where results will be saved. - """ - - # Get data - imgs = data['imgs'] - file_names = data['file_names'] - channels = data['channels'] - obj_name = data['obj_name'] - sizes_orginal = data['sizes_orginal'] - new_size = data['new_size'] - - # Get config - model_type = config['model_type'] - diameter = config['diameter'] - net_avg = config['net_avg'] - resample = config['resample'] - - log_message(f'\nPerforming segmentation of {obj_name}\n', callback_fun=callback_log) - - start_time = time.time() - - if not path_save.is_dir(): - path_save.mkdir() - - # Perform segmentation with CellPose - model = models.Cellpose(gpu=False, model_type=model_type) # model_type can be 'cyto' or 'nuclei' - masks, flows, styles, diams = model.eval(imgs, diameter=diameter, channels=channels, net_avg=net_avg, resample=resample) - - # Display and save results - log_message(f'\n Creating outputs ...\n', callback_fun=callback_log) - n_img = len(imgs) - - for idx in tqdm(range(n_img)): - - # Get images and file-name - file_name = file_names[idx] - maski = masks[idx] - flowi = flows[idx][0] - imgi = imgs[idx] - - # Rescale each channel separately - imgi_scaled = imgi.copy() - for idim in range(3): - imgdum = imgi[:, :, idim] - pa = np.percentile(imgdum, 0.5) - pb = np.percentile(imgdum, 99.5) - imgi_scaled[:, :, idim] = rescale_intensity(imgdum, in_range=(pa, pb),out_range=np.uint8) - - # Save flow - io.imsave(str(path_save / f'{file_name.stem}__flow__{obj_name}.png'), flowi) - - # Resize masks if necessary - if new_size: - mask_full = resize_mask(maski, sizes_orginal[idx]) - io.imsave(str(path_save / f'{file_name.stem}__mask__{obj_name}.png'), mask_full) - io.imsave(str(path_save / f'{file_name.stem}__mask_resize__{obj_name}.png'), maski) - - else: - io.imsave(str(path_save / f'{file_name.stem}__mask__{obj_name}.png'), maski) - - # Save overview image - fig = plt.figure(figsize=(12,3)) - plot.show_segmentation(fig, imgi_scaled, maski, flowi) - plt.tight_layout() - fig.savefig(str(path_save / f'{file_name.stem}__seg__{obj_name}.png'), dpi=300) - plt.close(fig) - - log_message(f"\nSegmentation of provided images finished ({(time.time() - start_time)}s)", callback_fun=callback_log) - - -def clean_par_dict(par_dict): - """ - Clean dictionary containing all parameters such that it can - be written into a json file. - """ - par_dict['path_scan'] = str(par_dict['path_scan']) - par_dict['path_save'] = str(par_dict['path_save']) - par_dict['callback_log'] = str(par_dict['callback_log']) - par_dict['callback_progress'] = str(par_dict['callback_progress']) - par_dict['callback_status'] = str(par_dict['callback_status']) - return par_dict - - -# Function to load and segment objects individually -def segment_obj_indiv(path_scan, obj_name, str_channel, img_ext, new_size, model_type, diameter, net_avg, resample, path_save, input_subfolder=None, callback_log=None, callback_status=None, callback_progress=None): - """ Will recursively search folder for images to be analyzed! - - Parameters - ---------- - path_scan : [type] - [description] - str_nuclei : [type] - [description] - img_ext : [type] - [description] - diameter : [type] - [description] - model_type : [type] - [description] - path_save : pathlib object or string - Path to save results, - - If Pathlib object, then this absolute path is used. - - If 'string' a replacement operation on the provided name of the data path will be applied (see create_output_path). - input_subfolder : str - Name of subfolder that contains results. If specified ONLY files in this folder will be processed. - callback_log : [type], optional - [description], by default None - callback_status : [type], optional - [description], by default None - callback_progress : [type], optional - [description], by default None - - Returns - ------- - [type] - [description] - """ - - # Print all input parameters - par_dict = locals() - par_dict = clean_par_dict(par_dict) - log_message(f"Function (segment_obj_indiv) called with: {str(par_dict)} ", callback_fun=callback_log) - - # Configurations - config = {'model_type': model_type, - 'diameter': diameter, - 'net_avg': net_avg, - 'resample': resample} - - channels = [0, 1] - - # Use provided absolute user-path to save images. - if isinstance(path_save, pathlib.PurePath): - path_save_results = path_save - if not path_save_results.is_dir(): - path_save_results.mkdir(parents=True) - - else: - path_save_str_replace = path_save - - if not path_scan.is_dir(): - log_message(f'Path {path_scan} does not exist.', callback_fun=callback_log) - return - - # Search for file to be analyzed - log_message(f'\nLoading images and segment them on the fly', callback_fun=callback_log) - files_proc = [] - for path_img in path_scan.rglob(f'*{str_channel}*{img_ext}'): - if input_subfolder: - if path_img.parts[-2] == input_subfolder: - files_proc.append(path_img) - else: - files_proc.append(path_img) - n_imgs = len(files_proc) - - if n_imgs == 0: - log_message(f'NO IMAGES FOUND. Check your settings.', callback_fun=callback_log) - return - - # Process files - for idx, path_img in enumerate(files_proc): - imgs = [] - files = [] - sizes_orginal = [] - - log_message(f'Segmenting image : {path_img.name}', callback_fun=callback_log) - - if callback_status: - callback_status(f'Segmenting image : {path_img.name}') - - if callback_progress: - progress = float((idx+1)/n_imgs) - callback_progress(progress) - - # Read images - img = io.imread(str(path_img)) - if img.ndim != 2: - log_message(f'\nERROR\n Input image has to be 2D. Current image is {img.ndim}D', callback_fun=callback_log) - continue - - - # IMPORTANT: CV2 resize is defined as (width, height) - print('>>> process file') - print(f'input file (size): {img.shape}') - - sizes_orginal.append(img.shape) - - # Resize - if new_size: - - # New size can also be defined as a scalar factor - if len(new_size) == 1: - scale_factor = new_size[0] - img_size = img.shape - new_size = tuple(int(ti/scale_factor) for ti in img_size) - - # IMPORTANT: CV2 resize is defined as (width, height) - dsize = (new_size[1], new_size[0]) - img = cv2.resize(img, dsize) - - print(f'resized file (size): {img.shape}') - - - # For object segmentation - img_zeros = np.zeros(img.shape) - img_3d_dpi = np.dstack([img_zeros, img_zeros, img]) - imgs.append(img_3d_dpi) - files.append(path_img) - - # >>> Call function for prediction - data = {'imgs': imgs, - 'file_names': files, - 'channels': channels, - 'obj_name': obj_name, - 'sizes_orginal': sizes_orginal, - 'new_size': new_size} - - # Create new output path if specified - if not isinstance(path_save, pathlib.PurePath): - path_save_results = create_output_path(path_img.parent, path_save_str_replace, subfolder='', create_path=True) - - cellpose_predict(data, config, path_save=path_save_results, callback_log=callback_log) - - # Save settings - if len(imgs) > 0: - fp = open(str(path_save_results / f'segmentation_settings__{obj_name}.json'), "w") - json.dump(par_dict, fp, indent=4, sort_keys=True) - fp.close() - - log_message(f'\n BATCH SEGMENTATION finished', callback_fun=callback_log) - - -# Function to load and segment cells and nuclei images individually -def segment_cells_nuclei_indiv(path_scan, str_channels, img_ext, new_size, model_types, diameters, net_avg, resample, path_save, input_subfolder=None, callback_log=None, callback_status=None, callback_progress=None): - """[summary] segment cells and nuclei in bulk, e.g. first all images are loaded and then segmented. - TODO: specify parameters - Parameters - ---------- - path_scan : [type] - [description] - strings : [type] - [description] - img_ext : [type] - [description] - new_size : tuple - Defines resizing of image. If two elements, new size of image. If one element, resizing factor. - If emtpy, no resizing. - sizes : [type] - [description] - models : [type] - [description] - path_save : pathlin object or string - Path to save results, - - If Pathlib object, then this absolute path is used. - - If 'string' a replacement operation on the provided name of the data path will be applied (see create_output_path). - And results will be stored in subfolder 'segmentation-input' - callback_log : [type], optional - [description], by default None - callback_status : [type], optional - [description], by default None - callback_progress : [type], optional - [description], by default None - """ - - par_dict = locals() - par_dict = clean_par_dict(par_dict) - log_message(f"Function (segment_obj_indiv) called with: {str(par_dict)} ", callback_fun=callback_log) - - # Get parameters - (str_cyto, str_nuclei) = str_channels - (diameter_cells, diameter_nuclei) = diameters - (model_type_cells, model_type_nuclei) = model_types - - # Use provided absolute user-path to save images. - if isinstance(path_save, pathlib.PurePath): - path_save_results = path_save - if not path_save_results.is_dir(): - path_save_results.mkdir(parents=True) - - else: - path_save_str_replace = path_save - - # Configurations - config_nuclei = {'model_type': model_type_nuclei, - 'diameter': diameter_nuclei, - 'net_avg': net_avg, - 'resample': resample} - - config_cyto = {'model_type': model_type_cells, - 'diameter': diameter_cells, - 'net_avg': net_avg, - 'resample': resample} - - channels_cyto = [1, 3] - channels_nuclei = [0, 1] - - # Loop over data - log_message(f'\nLoading image pairs and segment them on the fly', callback_fun=callback_log) - - if not path_scan.is_dir(): - log_message(f'Path {path_scan} does not exist.', callback_fun=callback_log) - return - - # Search for file to be analyzed - log_message(f'\nLoading images and segment them on the fly', callback_fun=callback_log) - files_proc = [] - for path_img in path_scan.rglob(f'*{str_cyto}*{img_ext}'): - if input_subfolder: - if path_img.parts[-2] == input_subfolder: - files_proc.append(path_img) - else: - files_proc.append(path_img) - n_imgs = len(files_proc) - - if n_imgs == 0: - log_message(f'NO IMAGES FOUND. Check your settings.', callback_fun=callback_log) - return - - # Process files - for idx, path_cyto in enumerate(files_proc): - imgs_cyto = [] - imgs_nuclei = [] - files_cyto = [] - files_nuclei = [] - sizes_orginal = [] - - log_message(f'Segmenting image : {path_cyto.name}', callback_fun=callback_log) - - if callback_status: - callback_status(f'Segmenting image : {path_cyto.name}') - - if callback_progress: - progress = float((idx+1)/n_imgs) - callback_progress(progress) - - # DAPI image: existing? - path_nuclei = Path(str(path_cyto).replace(str_cyto, str_nuclei)) - if not path_nuclei.is_file(): - log_message(f'DAPI image not found : {path_nuclei}', callback_fun=callback_log) - continue - - # Read images - img_cyto = io.imread(str(path_cyto)) - if img_cyto.ndim != 2: - log_message(f'\nERROR\n Input image of cell has to be 2D. Current image is {img_cyto.ndim}D', callback_fun=callback_log) - continue - - img_nuclei = io.imread(str(path_nuclei)) - if img_nuclei.ndim != 2: - log_message(f'\nERROR\n Input image of cell has to be 2D. Current image is {img_nuclei.ndim}D', callback_fun=callback_log) - continue - - # Resize image before CellPose if specified - sizes_orginal.append(img_cyto.shape) - - # Resize - if new_size: - - # New size can also be defined as a scalar factor - if len(new_size) == 1: - scale_factor = new_size[0] - img_size = img_cyto.shape - new_size = tuple(int(ti/scale_factor) for ti in img_size) - - # IMPORTANT: CV2 resize is defined as (width, height) - dsize = (new_size[1], new_size[0]) - img_cyto = cv2.resize(img_cyto, dsize) - img_nuclei = cv2.resize(img_nuclei, dsize) - - img_zeros = np.zeros(img_cyto.shape) - - # For cell segmentation - img_3d = np.dstack([img_cyto, img_zeros, img_nuclei]) - imgs_cyto.append(img_3d) - files_cyto.append(path_cyto) - - # For nuclei segmentation - img_3d_dpi = np.dstack([img_zeros, img_zeros, img_nuclei]) - imgs_nuclei.append(img_3d_dpi) - files_nuclei.append(path_nuclei) - - # Create new output path if specified - if not isinstance(path_save, pathlib.PurePath): - path_save_results = create_output_path(path_cyto.parent, path_save_str_replace, subfolder='', create_path=True) - path_save_settings = path_save_results - - # >>> Call function for prediction of cell - data_cyto = {'imgs': imgs_cyto, - 'file_names': files_cyto, - 'sizes_orginal': sizes_orginal, - 'new_size': new_size, - 'channels': channels_cyto, - 'obj_name': 'cells'} - - cellpose_predict(data_cyto, config_cyto, path_save=path_save_results, callback_log=callback_log) - - # >>> Call function for prediction of nuclei - data_nuclei = {'imgs': imgs_nuclei, - 'file_names': files_nuclei, - 'channels': channels_nuclei, - 'obj_name': 'nuclei', - 'sizes_orginal': sizes_orginal, - 'new_size': new_size} - - cellpose_predict(data_nuclei, config_nuclei, path_save=path_save_results, callback_log=callback_log) - - # Save settings - if len(imgs_cyto) > 0: - fp = open(str(path_save_results / 'segmentation_settings__cells_nuclei.json'), "w") - json.dump(par_dict, fp, indent=4, sort_keys=True) - fp.close() - - log_message(f'\n BATCH SEGMENTATION finished', callback_fun=callback_log) - - -def resize_mask(mask_small, size_orginal): - """ Resize a label image. - Parameters - ---------- - mask_small : [type] - [description] - size_orginal : [type] - [description] - Returns - ------- - [type] - [description] - """ - - mask_full = np.zeros(size_orginal).astype('uint16') - maski_template = np.zeros(mask_small.shape).astype('uint8') - - ind_objs = np.unique(mask_small) - ind_objs = np.delete(ind_objs, np.where(ind_objs == 0)) - - if ind_objs.size > 0: - - for obj_int in np.nditer(ind_objs): - - # Create binary mask for current object and find contour - img_obj_loop = np.copy(maski_template) - img_obj_loop[mask_small == obj_int] = 1 - - # IMPORTANT: CV2 resize is defined as (width, height) - dsize = (size_orginal[1], size_orginal[0]) - img_obj_loop_large = cv2.resize(img_obj_loop, dsize).astype('bool') - mask_full[img_obj_loop_large] = obj_int - +# Imports of general libraries +import numpy as np +from tqdm import tqdm +import time +import matplotlib.pyplot as plt +import pathlib +from pathlib import Path +import json +import cv2 +from skimage.exposure import rescale_intensity + +# Imports of CellPose specific libraries +from cellpose import models, io, plot +from segwrap.utils_general import log_message, create_output_path + +# Call predict function +def cellpose_predict(data, config, path_save, callback_log=None): + """ Perform prediction with CellPose. + + Parameters + ---------- + data : dict + Contains data on which prediction should be performed. + config : dict + Configuration of CellPose prediction. + path_save : pathline Path object + Path where results will be saved. + """ + + # Get data + imgs = data['imgs'] + file_names = data['file_names'] + channels = data['channels'] + obj_name = data['obj_name'] + sizes_orginal = data['sizes_orginal'] + new_size = data['new_size'] + + # Get config + model_type = config['model_type'] + diameter = config['diameter'] + net_avg = config['net_avg'] + resample = config['resample'] + + log_message(f'\nPerforming segmentation of {obj_name}\n', callback_fun=callback_log) + + start_time = time.time() + + if not path_save.is_dir(): + path_save.mkdir() + + # Perform segmentation with CellPose + model = models.Cellpose(gpu=False, model_type=model_type) # model_type can be 'cyto' or 'nuclei' + masks, flows, styles, diams = model.eval(imgs, diameter=diameter, channels=channels, net_avg=net_avg, resample=resample) + + # Display and save results + log_message(f'\n Creating outputs ...\n', callback_fun=callback_log) + n_img = len(imgs) + + for idx in tqdm(range(n_img)): + + # Get images and file-name + file_name = file_names[idx] + maski = masks[idx] + flowi = flows[idx][0] + imgi = imgs[idx] + + # Rescale each channel separately + imgi_scaled = imgi.copy() + for idim in range(3): + imgdum = imgi[:, :, idim] + pa = np.percentile(imgdum, 0.5) + pb = np.percentile(imgdum, 99.5) + imgi_scaled[:, :, idim] = rescale_intensity(imgdum, in_range=(pa, pb),out_range=np.uint8) + + # Save flow + io.imsave(str(path_save / f'{file_name.stem}__flow__{obj_name}.png'), flowi) + + # Resize masks if necessary + if new_size: + mask_full = resize_mask(maski, sizes_orginal[idx]) + io.imsave(str(path_save / f'{file_name.stem}__mask__{obj_name}.png'), mask_full) + io.imsave(str(path_save / f'{file_name.stem}__mask_resize__{obj_name}.png'), maski) + + else: + io.imsave(str(path_save / f'{file_name.stem}__mask__{obj_name}.png'), maski) + + # Save overview image + fig = plt.figure(figsize=(12,3)) + plot.show_segmentation(fig, imgi_scaled, maski, flowi) + plt.tight_layout() + fig.savefig(str(path_save / f'{file_name.stem}__seg__{obj_name}.png'), dpi=300) + plt.close(fig) + + log_message(f"\nSegmentation of provided images finished ({(time.time() - start_time)}s)", callback_fun=callback_log) + + +def clean_par_dict(par_dict): + """ + Clean dictionary containing all parameters such that it can + be written into a json file. + """ + par_dict['path_scan'] = str(par_dict['path_scan']) + par_dict['path_save'] = str(par_dict['path_save']) + par_dict['callback_log'] = str(par_dict['callback_log']) + par_dict['callback_progress'] = str(par_dict['callback_progress']) + par_dict['callback_status'] = str(par_dict['callback_status']) + return par_dict + + +# Function to load and segment objects individually +def segment_obj_indiv(path_scan, obj_name, str_channel, img_ext, new_size, model_type, diameter, net_avg, resample, path_save, input_subfolder=None, callback_log=None, callback_status=None, callback_progress=None): + """ Will recursively search folder for images to be analyzed! + + Parameters + ---------- + path_scan : [type] + [description] + str_nuclei : [type] + [description] + img_ext : [type] + [description] + diameter : [type] + [description] + model_type : [type] + [description] + path_save : pathlib object or string + Path to save results, + - If Pathlib object, then this absolute path is used. + - If 'string' a replacement operation on the provided name of the data path will be applied (see create_output_path). + input_subfolder : str + Name of subfolder that contains results. If specified ONLY files in this folder will be processed. + callback_log : [type], optional + [description], by default None + callback_status : [type], optional + [description], by default None + callback_progress : [type], optional + [description], by default None + + Returns + ------- + [type] + [description] + """ + + # Print all input parameters + par_dict = locals() + par_dict = clean_par_dict(par_dict) + log_message(f"Function (segment_obj_indiv) called with: {str(par_dict)} ", callback_fun=callback_log) + + # Configurations + config = {'model_type': model_type, + 'diameter': diameter, + 'net_avg': net_avg, + 'resample': resample} + + channels = [0, 1] + + # Use provided absolute user-path to save images. + if isinstance(path_save, pathlib.PurePath): + path_save_results = path_save + if not path_save_results.is_dir(): + path_save_results.mkdir(parents=True) + + else: + path_save_str_replace = path_save + + if not path_scan.is_dir(): + log_message(f'Path {path_scan} does not exist.', callback_fun=callback_log) + return + + # Search for file to be analyzed + log_message(f'\nLoading images and segment them on the fly', callback_fun=callback_log) + files_proc = [] + for path_img in path_scan.rglob(f'*{str_channel}*{img_ext}'): + if input_subfolder: + if path_img.parts[-2] == input_subfolder: + files_proc.append(path_img) + else: + files_proc.append(path_img) + n_imgs = len(files_proc) + + if n_imgs == 0: + log_message(f'NO IMAGES FOUND. Check your settings.', callback_fun=callback_log) + return + + # Process files + for idx, path_img in enumerate(files_proc): + imgs = [] + files = [] + sizes_orginal = [] + + log_message(f'Segmenting image : {path_img.name}', callback_fun=callback_log) + + if callback_status: + callback_status(f'Segmenting image : {path_img.name}') + + if callback_progress: + progress = float((idx+1)/n_imgs) + callback_progress(progress) + + # Read images + img = io.imread(str(path_img)) + if img.ndim != 2: + log_message(f'\nERROR\n Input image has to be 2D. Current image is {img.ndim}D', callback_fun=callback_log) + continue + + + # IMPORTANT: CV2 resize is defined as (width, height) + print('>>> process file') + print(f'input file (size): {img.shape}') + + sizes_orginal.append(img.shape) + + # Resize + if new_size: + + # New size can also be defined as a scalar factor + if len(new_size) == 1: + scale_factor = new_size[0] + img_size = img.shape + new_size = tuple(int(ti/scale_factor) for ti in img_size) + + # IMPORTANT: CV2 resize is defined as (width, height) + dsize = (new_size[1], new_size[0]) + img = cv2.resize(img, dsize) + + print(f'resized file (size): {img.shape}') + + + # For object segmentation + img_zeros = np.zeros(img.shape) + img_3d_dpi = np.dstack([img_zeros, img_zeros, img]) + imgs.append(img_3d_dpi) + files.append(path_img) + + # >>> Call function for prediction + data = {'imgs': imgs, + 'file_names': files, + 'channels': channels, + 'obj_name': obj_name, + 'sizes_orginal': sizes_orginal, + 'new_size': new_size} + + # Create new output path if specified + if not isinstance(path_save, pathlib.PurePath): + path_save_results = create_output_path(path_img.parent, path_save_str_replace, subfolder='', create_path=True) + + cellpose_predict(data, config, path_save=path_save_results, callback_log=callback_log) + + # Save settings + if len(imgs) > 0: + fp = open(str(path_save_results / f'segmentation_settings__{obj_name}.json'), "w") + json.dump(par_dict, fp, indent=4, sort_keys=True) + fp.close() + + log_message(f'\n BATCH SEGMENTATION finished', callback_fun=callback_log) + + +# Function to load and segment cells and nuclei images individually +def segment_cells_nuclei_indiv(path_scan, str_channels, img_ext, new_size, model_types, diameters, net_avg, resample, path_save, input_subfolder=None, callback_log=None, callback_status=None, callback_progress=None): + """[summary] segment cells and nuclei in bulk, e.g. first all images are loaded and then segmented. + TODO: specify parameters + Parameters + ---------- + path_scan : [type] + [description] + strings : [type] + [description] + img_ext : [type] + [description] + new_size : tuple + Defines resizing of image. If two elements, new size of image. If one element, resizing factor. + If emtpy, no resizing. + sizes : [type] + [description] + models : [type] + [description] + path_save : pathlin object or string + Path to save results, + - If Pathlib object, then this absolute path is used. + - If 'string' a replacement operation on the provided name of the data path will be applied (see create_output_path). + And results will be stored in subfolder 'segmentation-input' + callback_log : [type], optional + [description], by default None + callback_status : [type], optional + [description], by default None + callback_progress : [type], optional + [description], by default None + """ + + par_dict = locals() + par_dict = clean_par_dict(par_dict) + log_message(f"Function (segment_obj_indiv) called with: {str(par_dict)} ", callback_fun=callback_log) + + # Get parameters + (str_cyto, str_nuclei) = str_channels + (diameter_cells, diameter_nuclei) = diameters + (model_type_cells, model_type_nuclei) = model_types + + # Use provided absolute user-path to save images. + if isinstance(path_save, pathlib.PurePath): + path_save_results = path_save + if not path_save_results.is_dir(): + path_save_results.mkdir(parents=True) + + else: + path_save_str_replace = path_save + + # Configurations + config_nuclei = {'model_type': model_type_nuclei, + 'diameter': diameter_nuclei, + 'net_avg': net_avg, + 'resample': resample} + + config_cyto = {'model_type': model_type_cells, + 'diameter': diameter_cells, + 'net_avg': net_avg, + 'resample': resample} + + channels_cyto = [1, 3] + channels_nuclei = [0, 1] + + # Loop over data + log_message(f'\nLoading image pairs and segment them on the fly', callback_fun=callback_log) + + if not path_scan.is_dir(): + log_message(f'Path {path_scan} does not exist.', callback_fun=callback_log) + return + + # Search for file to be analyzed + log_message(f'\nLoading images and segment them on the fly', callback_fun=callback_log) + files_proc = [] + for path_img in path_scan.rglob(f'*{str_cyto}*{img_ext}'): + if input_subfolder: + if path_img.parts[-2] == input_subfolder: + files_proc.append(path_img) + else: + files_proc.append(path_img) + n_imgs = len(files_proc) + + if n_imgs == 0: + log_message(f'NO IMAGES FOUND. Check your settings.', callback_fun=callback_log) + return + + # Process files + for idx, path_cyto in enumerate(files_proc): + imgs_cyto = [] + imgs_nuclei = [] + files_cyto = [] + files_nuclei = [] + sizes_orginal = [] + + log_message(f'Segmenting image : {path_cyto.name}', callback_fun=callback_log) + + if callback_status: + callback_status(f'Segmenting image : {path_cyto.name}') + + if callback_progress: + progress = float((idx+1)/n_imgs) + callback_progress(progress) + + # DAPI image: existing? + path_nuclei = Path(str(path_cyto).replace(str_cyto, str_nuclei)) + if not path_nuclei.is_file(): + log_message(f'DAPI image not found : {path_nuclei}', callback_fun=callback_log) + continue + + # Read images + img_cyto = io.imread(str(path_cyto)) + if img_cyto.ndim != 2: + log_message(f'\nERROR\n Input image of cell has to be 2D. Current image is {img_cyto.ndim}D', callback_fun=callback_log) + continue + + img_nuclei = io.imread(str(path_nuclei)) + if img_nuclei.ndim != 2: + log_message(f'\nERROR\n Input image of cell has to be 2D. Current image is {img_nuclei.ndim}D', callback_fun=callback_log) + continue + + # Resize image before CellPose if specified + sizes_orginal.append(img_cyto.shape) + + # Resize + if new_size: + + # New size can also be defined as a scalar factor + if len(new_size) == 1: + scale_factor = new_size[0] + img_size = img_cyto.shape + new_size = tuple(int(ti/scale_factor) for ti in img_size) + + # IMPORTANT: CV2 resize is defined as (width, height) + dsize = (new_size[1], new_size[0]) + img_cyto = cv2.resize(img_cyto, dsize) + img_nuclei = cv2.resize(img_nuclei, dsize) + + img_zeros = np.zeros(img_cyto.shape) + + # For cell segmentation + img_3d = np.dstack([img_cyto, img_zeros, img_nuclei]) + imgs_cyto.append(img_3d) + files_cyto.append(path_cyto) + + # For nuclei segmentation + img_3d_dpi = np.dstack([img_zeros, img_zeros, img_nuclei]) + imgs_nuclei.append(img_3d_dpi) + files_nuclei.append(path_nuclei) + + # Create new output path if specified + if not isinstance(path_save, pathlib.PurePath): + path_save_results = create_output_path(path_cyto.parent, path_save_str_replace, subfolder='', create_path=True) + path_save_settings = path_save_results + + # >>> Call function for prediction of cell + data_cyto = {'imgs': imgs_cyto, + 'file_names': files_cyto, + 'sizes_orginal': sizes_orginal, + 'new_size': new_size, + 'channels': channels_cyto, + 'obj_name': 'cells'} + + cellpose_predict(data_cyto, config_cyto, path_save=path_save_results, callback_log=callback_log) + + # >>> Call function for prediction of nuclei + data_nuclei = {'imgs': imgs_nuclei, + 'file_names': files_nuclei, + 'channels': channels_nuclei, + 'obj_name': 'nuclei', + 'sizes_orginal': sizes_orginal, + 'new_size': new_size} + + cellpose_predict(data_nuclei, config_nuclei, path_save=path_save_results, callback_log=callback_log) + + # Save settings + if len(imgs_cyto) > 0: + fp = open(str(path_save_results / 'segmentation_settings__cells_nuclei.json'), "w") + json.dump(par_dict, fp, indent=4, sort_keys=True) + fp.close() + + log_message(f'\n BATCH SEGMENTATION finished', callback_fun=callback_log) + + +def resize_mask(mask_small, size_orginal): + """ Resize a label image. + Parameters + ---------- + mask_small : [type] + [description] + size_orginal : [type] + [description] + Returns + ------- + [type] + [description] + """ + + mask_full = np.zeros(size_orginal).astype('uint16') + maski_template = np.zeros(mask_small.shape).astype('uint8') + + ind_objs = np.unique(mask_small) + ind_objs = np.delete(ind_objs, np.where(ind_objs == 0)) + + if ind_objs.size > 0: + + for obj_int in np.nditer(ind_objs): + + # Create binary mask for current object and find contour + img_obj_loop = np.copy(maski_template) + img_obj_loop[mask_small == obj_int] = 1 + + # IMPORTANT: CV2 resize is defined as (width, height) + dsize = (size_orginal[1], size_orginal[0]) + img_obj_loop_large = cv2.resize(img_obj_loop, dsize).astype('bool') + mask_full[img_obj_loop_large] = obj_int + return mask_full \ No newline at end of file diff --git a/segwrap/utils_general.py b/segwrap/utils_general.py index b224124..cfe49a8 100644 --- a/segwrap/utils_general.py +++ b/segwrap/utils_general.py @@ -1,71 +1,71 @@ -# Imports -from pathlib import Path -import re - - -# Log message -def log_message(msg, callback_fun=None): - """ Display log, either terminal or any callback accepting a string as input. - - Parameters - ---------- - msg : [string] - [description] - callback_fun : [type], optional - [description], by default None - """ - if callback_fun: - callback_fun(msg) - else: - print(msg) - - -# Create new output path -def create_output_path(path_orig, str_replace, subfolder=None, create_path=True, callback_log=None): - """ Allows to create new path object by replacing a string in a provided path object. - - Parameters - ---------- - path_orig : pathlib object - Original file-name. - str_replace : str - str defining the replacement operation: 'str_orig>>str_new', - where 'str_orig' is the orginal string, 'str_new' is the new string. - For example, 'acquisition>>analysis'. - subfolder : str or pathlib object - Subfolder that should be added to new file-name - create_path : bool - Create new path if it doesn't exist. - callback_log : str - Callback function to be used. If None, then system print will be used. - - Returns - ------- - pathlib object - New path. - """ - - log_message("Creating name to path to store data.", callback_fun=callback_log) - - if (re.search(">>", str_replace)): - str_orig = re.search(r'^(.*)>>(.*)$', str_replace).group(1) - str_rep = re.search(r'^(.*)>>(.*)$', str_replace).group(2) - - path_replace = Path(str(path_orig).replace(str_orig, str_rep)) - - if subfolder: - path_replace = path_replace / subfolder - - log_message(f'Replacement parameters found: original string: {str_orig}, replacement string: {str_rep}', callback_fun=callback_log) - log_message(f'Output path: {path_replace}', callback_fun=callback_log) - - else: - log_message("No match", callback_fun=callback_log) - return None - - # Create default folder to save data if none was defined by the user - if create_path: - if not path_replace.is_dir(): - path_replace.mkdir(parents=True) - +# Imports +from pathlib import Path +import re + + +# Log message +def log_message(msg, callback_fun=None): + """ Display log, either terminal or any callback accepting a string as input. + + Parameters + ---------- + msg : [string] + [description] + callback_fun : [type], optional + [description], by default None + """ + if callback_fun: + callback_fun(msg) + else: + print(msg) + + +# Create new output path +def create_output_path(path_orig, str_replace, subfolder=None, create_path=True, callback_log=None): + """ Allows to create new path object by replacing a string in a provided path object. + + Parameters + ---------- + path_orig : pathlib object + Original file-name. + str_replace : str + str defining the replacement operation: 'str_orig>>str_new', + where 'str_orig' is the orginal string, 'str_new' is the new string. + For example, 'acquisition>>analysis'. + subfolder : str or pathlib object + Subfolder that should be added to new file-name + create_path : bool + Create new path if it doesn't exist. + callback_log : str + Callback function to be used. If None, then system print will be used. + + Returns + ------- + pathlib object + New path. + """ + + log_message("Creating name to path to store data.", callback_fun=callback_log) + + if (re.search(">>", str_replace)): + str_orig = re.search(r'^(.*)>>(.*)$', str_replace).group(1) + str_rep = re.search(r'^(.*)>>(.*)$', str_replace).group(2) + + path_replace = Path(str(path_orig).replace(str_orig, str_rep)) + + if subfolder: + path_replace = path_replace / subfolder + + log_message(f'Replacement parameters found: original string: {str_orig}, replacement string: {str_rep}', callback_fun=callback_log) + log_message(f'Output path: {path_replace}', callback_fun=callback_log) + + else: + log_message("No match", callback_fun=callback_log) + return None + + # Create default folder to save data if none was defined by the user + if create_path: + if not path_replace.is_dir(): + path_replace.mkdir(parents=True) + return path_replace \ No newline at end of file diff --git a/segwrap/utils_masks.py b/segwrap/utils_masks.py index 3bf586b..e06cfce 100644 --- a/segwrap/utils_masks.py +++ b/segwrap/utils_masks.py @@ -1,117 +1,117 @@ -# Imports -from cellpose.io import imread, imsave -import numpy as np -from tqdm import tqdm -from scipy import ndimage -import pathlib - -from segwrap.utils_general import log_message, create_output_path - -# Calculate images summarizing distance to objects -def create_img_closest_obj(path_scan, str_label, strs_save, path_save=None, search_recursive=False, truncate_distance=None, callback_log=None, callback_status=None, callback_progress=None): - """ Function to process label images and facilitate assignment to closest segmented object. - Will create two 2D images with the same size as the label image. Pixel values in either image - encode - 1. Distance to the closted object, e.g. nuclei. - 2. Index of clostest object. - - Parameters - ---------- - path_scan : pathlib Path object - Path to scan for label images. - str_label : str - Unique string contained in label iamge to be saved. - strs_save : tuple of strings - Strings defining how to save the result images, either string will replace str_save. - path_save : pathlib Path object - Path to save results, - - If Pathlib object, then this absolute path is used. - - If 'string' a replacement operation path containing the analyzed mask will be applied (see create_output_path). - truncate_distance : int - Distance above which distances will be truncated. Using a value of 255 has the advantage - that the saved image is 8bit and thus small. - callback_log : callback, optional - Callback function to provide function log. If none, print will be used. - For more details see segwrap.utils_general.log_message - """ - - # Check scan directory - if not path_scan.is_dir(): - log_message(f'Path {path_scan} does not exist.', callback_fun=callback_log) - return - - # Path to save results - if isinstance(path_save, pathlib.PurePath): - path_save_results = path_save - if not path_save_results.is_dir(): - path_save_results.mkdir(parents=True) - - else: - path_save_str_replace = path_save - - # Search files: recursively or not - files_proc = [] - if search_recursive: - for path_mask in path_scan.rglob(f'*{str_label}*'): - files_proc.append(path_mask) - else: - for path_mask in path_scan.glob(f'*{str_label}*'): - files_proc.append(path_mask) - - # Process files - for idx, file_label in enumerate(files_proc): - - log_message(f'\n>>> Processing file:\n{file_label}', callback_fun=callback_status) - - # >>> Create path to save data if necessary - if not isinstance(path_save, pathlib.PurePath): - path_save_results = create_output_path(file_label.parent, path_save_str_replace, subfolder=None, create_path=True) - log_message(f'Results will be save here : {path_save_results}', callback_fun=callback_status) - - # >>>> Read label image - img_labels = imread(file_label) - props = regionprops(img_labels) - labels = np.array([prop.label for prop in props]) - n_objs = len(labels) - - # Loop over all nuclei and create create distance map - log_message(f' Creating distance maps for {n_objs} objects. This can take a while ...', callback_fun=callback_log) - dist_mat = np.zeros((img_labels.shape[0], img_labels.shape[1], n_objs), dtype=np.uint16) - mask_fill_indiv = np.zeros((img_labels.shape[0], img_labels.shape[1], n_objs), dtype=np.uint16) - - for indx, obj_int in enumerate(tqdm(np.nditer(labels), total=n_objs)): - - # Create binary mask for current object and find contour - img_label_loop = np.zeros((img_labels.shape[0], img_labels.shape[1])) - img_label_loop[img_labels == obj_int] = 1 - mask_fill_indiv[:, :, indx] = img_label_loop - - dist_obj = ndimage.distance_transform_edt(np.logical_not(img_label_loop)) - if truncate_distance: - dist_obj[dist_obj > truncate_distance] = truncate_distance - dist_mat[:, :, indx] = dist_obj.astype(np.uint16) - - # >>> Condense distmap in two matrixes: index and distance to closest object - dist_obj_ind_3D = np.argsort(dist_mat, axis=2) - dist_obj_dist_3D = np.take_along_axis(dist_mat, dist_obj_ind_3D, axis=2) - - # For index: replace Python matrix index with actual index from label image - ind_obj_closest = np.zeros((img_labels.shape[0], img_labels.shape[1])) - dist_obj_ind_2D = np.copy(dist_obj_ind_3D[:, :, 0]) - - for indx, obj_int in enumerate(np.nditer(labels)): - ind_obj_closest[dist_obj_ind_2D == indx] = obj_int - - # Save index of closest object - name_save_ind = path_save_results / f'{file_label.stem.replace(str_label, strs_save[0])}.png' - if str(name_save_ind) != str(file_label): - imsave(name_save_ind, ind_obj_closest.astype('uint16'), check_contrast=False) - else: - log_message(f'Name to save index matrix could not be established: {name_save_ind}', callback_fun=callback_log) - - # Save distances to closest object - name_save_dist = path_save_results / f'{file_label.stem.replace(str_label, strs_save[1])}.png' - if str(name_save_dist) != str(file_label): - imsave(name_save_dist, dist_obj_dist_3D[:, :, 0].astype('uint16'), check_contrast=False) - else: - log_message(f'Name to save index matrix could not be established: {name_save_dist}', callback_fun=callback_log) +# Imports +from cellpose.io import imread, imsave +import numpy as np +from tqdm import tqdm +from scipy import ndimage +import pathlib + +from segwrap.utils_general import log_message, create_output_path + +# Calculate images summarizing distance to objects +def create_img_closest_obj(path_scan, str_label, strs_save, path_save=None, search_recursive=False, truncate_distance=None, callback_log=None, callback_status=None, callback_progress=None): + """ Function to process label images and facilitate assignment to closest segmented object. + Will create two 2D images with the same size as the label image. Pixel values in either image + encode + 1. Distance to the closted object, e.g. nuclei. + 2. Index of clostest object. + + Parameters + ---------- + path_scan : pathlib Path object + Path to scan for label images. + str_label : str + Unique string contained in label iamge to be saved. + strs_save : tuple of strings + Strings defining how to save the result images, either string will replace str_save. + path_save : pathlib Path object + Path to save results, + - If Pathlib object, then this absolute path is used. + - If 'string' a replacement operation path containing the analyzed mask will be applied (see create_output_path). + truncate_distance : int + Distance above which distances will be truncated. Using a value of 255 has the advantage + that the saved image is 8bit and thus small. + callback_log : callback, optional + Callback function to provide function log. If none, print will be used. + For more details see segwrap.utils_general.log_message + """ + + # Check scan directory + if not path_scan.is_dir(): + log_message(f'Path {path_scan} does not exist.', callback_fun=callback_log) + return + + # Path to save results + if isinstance(path_save, pathlib.PurePath): + path_save_results = path_save + if not path_save_results.is_dir(): + path_save_results.mkdir(parents=True) + + else: + path_save_str_replace = path_save + + # Search files: recursively or not + files_proc = [] + if search_recursive: + for path_mask in path_scan.rglob(f'*{str_label}*'): + files_proc.append(path_mask) + else: + for path_mask in path_scan.glob(f'*{str_label}*'): + files_proc.append(path_mask) + + # Process files + for idx, file_label in enumerate(files_proc): + + log_message(f'\n>>> Processing file:\n{file_label}', callback_fun=callback_status) + + # >>> Create path to save data if necessary + if not isinstance(path_save, pathlib.PurePath): + path_save_results = create_output_path(file_label.parent, path_save_str_replace, subfolder=None, create_path=True) + log_message(f'Results will be save here : {path_save_results}', callback_fun=callback_status) + + # >>>> Read label image + img_labels = imread(file_label) + props = regionprops(img_labels) + labels = np.array([prop.label for prop in props]) + n_objs = len(labels) + + # Loop over all nuclei and create create distance map + log_message(f' Creating distance maps for {n_objs} objects. This can take a while ...', callback_fun=callback_log) + dist_mat = np.zeros((img_labels.shape[0], img_labels.shape[1], n_objs), dtype=np.uint16) + mask_fill_indiv = np.zeros((img_labels.shape[0], img_labels.shape[1], n_objs), dtype=np.uint16) + + for indx, obj_int in enumerate(tqdm(np.nditer(labels), total=n_objs)): + + # Create binary mask for current object and find contour + img_label_loop = np.zeros((img_labels.shape[0], img_labels.shape[1])) + img_label_loop[img_labels == obj_int] = 1 + mask_fill_indiv[:, :, indx] = img_label_loop + + dist_obj = ndimage.distance_transform_edt(np.logical_not(img_label_loop)) + if truncate_distance: + dist_obj[dist_obj > truncate_distance] = truncate_distance + dist_mat[:, :, indx] = dist_obj.astype(np.uint16) + + # >>> Condense distmap in two matrixes: index and distance to closest object + dist_obj_ind_3D = np.argsort(dist_mat, axis=2) + dist_obj_dist_3D = np.take_along_axis(dist_mat, dist_obj_ind_3D, axis=2) + + # For index: replace Python matrix index with actual index from label image + ind_obj_closest = np.zeros((img_labels.shape[0], img_labels.shape[1])) + dist_obj_ind_2D = np.copy(dist_obj_ind_3D[:, :, 0]) + + for indx, obj_int in enumerate(np.nditer(labels)): + ind_obj_closest[dist_obj_ind_2D == indx] = obj_int + + # Save index of closest object + name_save_ind = path_save_results / f'{file_label.stem.replace(str_label, strs_save[0])}.png' + if str(name_save_ind) != str(file_label): + imsave(name_save_ind, ind_obj_closest.astype('uint16'), check_contrast=False) + else: + log_message(f'Name to save index matrix could not be established: {name_save_ind}', callback_fun=callback_log) + + # Save distances to closest object + name_save_dist = path_save_results / f'{file_label.stem.replace(str_label, strs_save[1])}.png' + if str(name_save_dist) != str(file_label): + imsave(name_save_dist, dist_obj_dist_3D[:, :, 0].astype('uint16'), check_contrast=False) + else: + log_message(f'Name to save index matrix could not be established: {name_save_dist}', callback_fun=callback_log) diff --git a/segwrap/utils_segmentation.py b/segwrap/utils_segmentation.py index a8a5ea7..c799770 100644 --- a/segwrap/utils_segmentation.py +++ b/segwrap/utils_segmentation.py @@ -1,124 +1,124 @@ -# Imports -import pathlib -import json -#from skimage.io import imread, imsave -from cellpose.io import imread, imsave -from segwrap.utils_general import log_message, create_output_path - -# Functions -# TODO: allow multiple channel identifiers for segmentation of cells and nuclei (separate by ,) -def folder_prepare_prediction(path_process, channel_ident, img_ext, path_save, projection_type, subfolder=None, search_recursive=False, callback_log=None, callback_status=None, callback_progress=None): - """[summary] - - Parameters - ---------- - path_process : [type] - [description] - channel_ident : str - [description] - img_ext : str - Image extension - path_save : pathlin object or string - Path to save results, - - If Pathlib object, then this absolute path is used. - - If 'string' a replacement operation on the provided name of the data path will be applied (see create_output_path). - And results will be stored in subfolder 'segmentation-input' - projection_type : [type] - [description] - subfolder: str - subfolder where data should be stored. Will only be used when string replacement for path is used. - search_recursive : bool - Recursively search folder, default: false. - callback_log : [type], optional - [description], by default None - callback_status : [type], optional - [description], by default None - callback_progress : [type], optional - [description], by default None - """ - - # Print all input parameters - log_message(f"Function (segment_obj_indiv) called with: {str(locals())} ", callback_fun=callback_log) - - # Use provided absolute user-path to save images. - if isinstance(path_save, pathlib.PurePath): - path_save_results = path_save - if not path_save_results.is_dir(): - path_save_results.mkdir(parents=True) - path_save_settings = path_save_results - - else: - path_save_str_replace = path_save - - # How to look for files - files_proc = [] - if search_recursive: - for path_img in path_process.rglob(f'*{channel_ident}*{img_ext}'): - files_proc.append(path_img) - else: - for path_img in path_process.glob(f'*{channel_ident}*{img_ext}'): - files_proc.append(path_img) - - # Process files - n_files = len(files_proc) - for idx, file_proc in enumerate(files_proc): - - log_message(f'\n>>> Processing file: {file_proc}', callback_fun=callback_status) - - if callback_progress: - progress = float((idx+1)/n_files) - callback_progress(progress) - - name_base = file_proc.stem - - # Create new output path if specified - if not isinstance(path_save, pathlib.PurePath): - path_save_results = create_output_path(file_proc.parent, path_save_str_replace, subfolder=subfolder, create_path=True) - log_message(f'Results will be save here : {path_save_results}', callback_fun=callback_status) - path_save_settings = path_save_results - - # Create subfolder when processing individual images - if projection_type == 'indiv': - path_save_indiv = path_save_results / name_base - - if not path_save_indiv.is_dir(): - path_save_indiv.mkdir(parents=True) - path_save_settings = path_save_indiv - - # Open image - print(file_proc) - img = imread(str(file_proc)) - - img_properties = { "file_process": str(file_proc), - "img_name": file_proc.name, - "img_path": str(file_proc.parent), - "channel_ident": channel_ident, - "projection_type": projection_type} - - name_json = path_save_settings / f'img-prop__{name_base}.json' - with open(name_json, 'w') as fp: - json.dump(img_properties, fp, sort_keys=True, indent=4) - - # Process depending specified option - if projection_type == 'indiv': - - for i in range(img.shape[0]): - name_save = path_save_indiv / f'{name_base}_Z{str(i+1).zfill(3)}.png' - - if name_save.is_file(): - log_message(f'File already exists. Will be overwritten {name_save}', callback_fun=callback_log) - imsave(str(name_save), img[i, :, :]) - - else: - - if projection_type == 'mean': - img_proj = img.mean(axis=0) - - elif projection_type == 'max': - img_proj = img.max(axis=0) - - name_save = path_save_results / f'{name_base}.png' - - if name_save.is_file(): - log_message(f'File already exists. Will be overwritten {name_save}', callback_fun=callback_log) - imsave(str(name_save), img_proj.astype('uint16')) +# Imports +import pathlib +import json +#from skimage.io import imread, imsave +from cellpose.io import imread, imsave +from segwrap.utils_general import log_message, create_output_path + +# Functions +# TODO: allow multiple channel identifiers for segmentation of cells and nuclei (separate by ,) +def folder_prepare_prediction(path_process, channel_ident, img_ext, path_save, projection_type, subfolder=None, search_recursive=False, callback_log=None, callback_status=None, callback_progress=None): + """[summary] + + Parameters + ---------- + path_process : [type] + [description] + channel_ident : str + [description] + img_ext : str + Image extension + path_save : pathlin object or string + Path to save results, + - If Pathlib object, then this absolute path is used. + - If 'string' a replacement operation on the provided name of the data path will be applied (see create_output_path). + And results will be stored in subfolder 'segmentation-input' + projection_type : [type] + [description] + subfolder: str + subfolder where data should be stored. Will only be used when string replacement for path is used. + search_recursive : bool + Recursively search folder, default: false. + callback_log : [type], optional + [description], by default None + callback_status : [type], optional + [description], by default None + callback_progress : [type], optional + [description], by default None + """ + + # Print all input parameters + log_message(f"Function (segment_obj_indiv) called with: {str(locals())} ", callback_fun=callback_log) + + # Use provided absolute user-path to save images. + if isinstance(path_save, pathlib.PurePath): + path_save_results = path_save + if not path_save_results.is_dir(): + path_save_results.mkdir(parents=True) + path_save_settings = path_save_results + + else: + path_save_str_replace = path_save + + # How to look for files + files_proc = [] + if search_recursive: + for path_img in path_process.rglob(f'*{channel_ident}*{img_ext}'): + files_proc.append(path_img) + else: + for path_img in path_process.glob(f'*{channel_ident}*{img_ext}'): + files_proc.append(path_img) + + # Process files + n_files = len(files_proc) + for idx, file_proc in enumerate(files_proc): + + log_message(f'\n>>> Processing file: {file_proc}', callback_fun=callback_status) + + if callback_progress: + progress = float((idx+1)/n_files) + callback_progress(progress) + + name_base = file_proc.stem + + # Create new output path if specified + if not isinstance(path_save, pathlib.PurePath): + path_save_results = create_output_path(file_proc.parent, path_save_str_replace, subfolder=subfolder, create_path=True) + log_message(f'Results will be save here : {path_save_results}', callback_fun=callback_status) + path_save_settings = path_save_results + + # Create subfolder when processing individual images + if projection_type == 'indiv': + path_save_indiv = path_save_results / name_base + + if not path_save_indiv.is_dir(): + path_save_indiv.mkdir(parents=True) + path_save_settings = path_save_indiv + + # Open image + print(file_proc) + img = imread(str(file_proc)) + + img_properties = { "file_process": str(file_proc), + "img_name": file_proc.name, + "img_path": str(file_proc.parent), + "channel_ident": channel_ident, + "projection_type": projection_type} + + name_json = path_save_settings / f'img-prop__{name_base}.json' + with open(name_json, 'w') as fp: + json.dump(img_properties, fp, sort_keys=True, indent=4) + + # Process depending specified option + if projection_type == 'indiv': + + for i in range(img.shape[0]): + name_save = path_save_indiv / f'{name_base}_Z{str(i+1).zfill(3)}.png' + + if name_save.is_file(): + log_message(f'File already exists. Will be overwritten {name_save}', callback_fun=callback_log) + imsave(str(name_save), img[i, :, :]) + + else: + + if projection_type == 'mean': + img_proj = img.mean(axis=0) + + elif projection_type == 'max': + img_proj = img.max(axis=0) + + name_save = path_save_results / f'{name_base}.png' + + if name_save.is_file(): + log_message(f'File already exists. Will be overwritten {name_save}', callback_fun=callback_log) + imsave(str(name_save), img_proj.astype('uint16')) diff --git a/setup.py b/setup.py index db0e458..80b1002 100644 --- a/setup.py +++ b/setup.py @@ -1,34 +1,34 @@ -""" -Setup script. -""" - -import setuptools - -# package version -VERSION = None -with open('segwrap/__init__.py', encoding='utf-8') as f: - for row in f: - if row.startswith('__version__'): - VERSION = row.strip().split()[-1][1:-1] - break - -# package dependencies -with open("requirements.txt", encoding='utf-8') as f: - REQUIREMENTS = [l.strip() for l in f.readlines() if l] - -# setup -setuptools.setup( - name="segwrap", - version=VERSION, - author="Florian MUELLER", - author_email="muellerf.research@gmail.com", - description="wrapper package for cellpose", - url="https://github.com/fish-quant/fq-segmentation", - packages=setuptools.find_packages(), - install_requires=REQUIREMENTS, - include_package_data=True, - classifiers=( - "Programming Language :: Python :: 3", - "Operating System :: OS Independent", - ), -) +""" +Setup script. +""" + +import setuptools + +# package version +VERSION = None +with open('segwrap/__init__.py', encoding='utf-8') as f: + for row in f: + if row.startswith('__version__'): + VERSION = row.strip().split()[-1][1:-1] + break + +# package dependencies +with open("requirements.txt", encoding='utf-8') as f: + REQUIREMENTS = [l.strip() for l in f.readlines() if l] + +# setup +setuptools.setup( + name="segwrap", + version=VERSION, + author="Florian MUELLER", + author_email="muellerf.research@gmail.com", + description="wrapper package for cellpose", + url="https://github.com/fish-quant/fq-segmentation", + packages=setuptools.find_packages(), + install_requires=REQUIREMENTS, + include_package_data=True, + classifiers=( + "Programming Language :: Python :: 3", + "Operating System :: OS Independent", + ), +) diff --git a/update_manifest.js b/update_manifest.js index 17a5717..9485d1f 100644 --- a/update_manifest.js +++ b/update_manifest.js @@ -1,85 +1,85 @@ -var https = require('https'); -var fs = require('fs'); - -var childProcess = require('child_process'); - -function runScript(scriptPath, callback) { - // keep track of whether callback has been invoked to prevent multiple invocations - var invoked = false; - - var process = childProcess.fork(scriptPath); - - // listen for errors as they may prevent the exit event from firing - process.on('error', function (err) { - if (invoked) return; - invoked = true; - if(callback) callback(err); - }); - - // execute the callback once the process has finished running - process.on('exit', function (code) { - if (invoked) return; - invoked = true; - var err = code === 0 ? null : new Error('exit code ' + code); - if(callback) callback(err); - }); - -} - - -function downloadScripts(){ - return new Promise((resolve, reject)=>{ - https.get("https://raw.githubusercontent.com/oeway/ImJoy/master/web/src/pluginParser.js", (response)=>{ - if(response.statusCode == 200){ - var file = fs.createWriteStream( './pluginParser.js'); - var code = '' - response.on('data', (d) => { - code = code + d.toString() - }); - response.on('end', () => { - code = code.replace('export function', 'function') - code = code + '\nexports.parseComponent = parseComponent;' - file.write(code); - file.close(()=>{ - https.get("https://raw.githubusercontent.com/oeway/ImJoy/master/web/src/buildManifest.js", (response)=>{ - if(response.statusCode == 200){ - var code2 = '' - response.on('data', (d) => { - code2 = code2 + d.toString() - }); - response.on('end', () => { - var file = fs.createWriteStream( './buildManifest.js'); - file.write(code2); - file.close(resolve); - }) - } - else{ - reject(response.statusCode) - } - - }).on('error', function(err) { // Handle errors - reject(err.message); - }); - }); - }) - } - else{ - reject(response.statusCode) - } - - }).on('error', function(err) { // Handle errors - reject(err.message); - }); - }) -} - -downloadScripts().then(()=>{ - runScript('./buildManifest.js', ()=>{ - fs.unlink('./pluginParser.js', ()=>{}) - fs.unlink('./buildManifest.js', ()=>{}) - }) - -}).catch((err)=>{ - console.error(err) - runScript('./buildManifest.js') -}) +var https = require('https'); +var fs = require('fs'); + +var childProcess = require('child_process'); + +function runScript(scriptPath, callback) { + // keep track of whether callback has been invoked to prevent multiple invocations + var invoked = false; + + var process = childProcess.fork(scriptPath); + + // listen for errors as they may prevent the exit event from firing + process.on('error', function (err) { + if (invoked) return; + invoked = true; + if(callback) callback(err); + }); + + // execute the callback once the process has finished running + process.on('exit', function (code) { + if (invoked) return; + invoked = true; + var err = code === 0 ? null : new Error('exit code ' + code); + if(callback) callback(err); + }); + +} + + +function downloadScripts(){ + return new Promise((resolve, reject)=>{ + https.get("https://raw.githubusercontent.com/oeway/ImJoy/master/web/src/pluginParser.js", (response)=>{ + if(response.statusCode == 200){ + var file = fs.createWriteStream( './pluginParser.js'); + var code = '' + response.on('data', (d) => { + code = code + d.toString() + }); + response.on('end', () => { + code = code.replace('export function', 'function') + code = code + '\nexports.parseComponent = parseComponent;' + file.write(code); + file.close(()=>{ + https.get("https://raw.githubusercontent.com/oeway/ImJoy/master/web/src/buildManifest.js", (response)=>{ + if(response.statusCode == 200){ + var code2 = '' + response.on('data', (d) => { + code2 = code2 + d.toString() + }); + response.on('end', () => { + var file = fs.createWriteStream( './buildManifest.js'); + file.write(code2); + file.close(resolve); + }) + } + else{ + reject(response.statusCode) + } + + }).on('error', function(err) { // Handle errors + reject(err.message); + }); + }); + }) + } + else{ + reject(response.statusCode) + } + + }).on('error', function(err) { // Handle errors + reject(err.message); + }); + }) +} + +downloadScripts().then(()=>{ + runScript('./buildManifest.js', ()=>{ + fs.unlink('./pluginParser.js', ()=>{}) + fs.unlink('./buildManifest.js', ()=>{}) + }) + +}).catch((err)=>{ + console.error(err) + runScript('./buildManifest.js') +}) diff --git a/workflows/MacroBatchSplitChannel.ijm b/workflows/MacroBatchSplitChannel.ijm index 4d9f905..4ade76b 100644 --- a/workflows/MacroBatchSplitChannel.ijm +++ b/workflows/MacroBatchSplitChannel.ijm @@ -1,131 +1,131 @@ -// Split channels -// -// This macro batch processes all the files in a folder and any -// subfolders in that folder. It will split each image and save -// the different channels separately. -// -// WORKFLOW: -// 1. Scan recursively the specified folder for files ending in a specified suffix. -// 2. Images will be opened, split in different channels and maximum intensity projections (MIPs) created. -// 3. Results will be saved in a new folder -// a. Macro will replace specified string in original full file path by "acquisition", and create this folder to save the results. -// b. Will create additional subfolders 'mips' to store the MIPs. -/// -// PARAMETERS: -// - Last part of image name, by default 'ome.tif' -// - String contained in input folder which will be replaced, by default "multi_channel_stacks" - -suffix = "ome.tif" -folder_img = "multi_channel_stacks" - -setBatchMode(true); -dir = getDirectory("Choose a Directory"); -print('Processing directory: ' + dir); - -// Process files -n = 0; -processFolder(dir); - -function processFolder(dir) { - IJ.log("processing directory " + dir); - list = getFileList(dir); - - for (i = 0; i < list.length; i++) { - if(File.isDirectory(dir + list[i])) //if it's a directory, go to subfolder - processFolder("" + dir + list[i]); - - if(endsWith(list[i], suffix)) // if file ends with specified suffix, process it - print('Processing file'); - print(dir + list[i]); - processFile(dir, list[i]); - } -} - - -// Create multi-level directory -function createMultiLevelDirectory(path_create){ - - // Check if last part of path is the systems path separator. - // If not replace. This happens on windows machines, since - // getFileList returns directories with and "/". - - if (!endsWith(path_create, File.separator)){ - //print(path_create.replace("/",File.separator)); - path_create=replace(path_create,"/",File.separator); - print('PATH with bad last character. Modified: ' + path_create); - } - - parts = split(path_create, File.separator); - path_level = File.separator + parts[0] + File.separator + parts[1] + File.separator; - for(i=2; i