Skip to content
New issue

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

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

Already on GitHub? Sign in to your account

Update README and sample contribution #440

Merged
merged 14 commits into from
Oct 6, 2023
35 changes: 25 additions & 10 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,28 +4,36 @@
[![Python package index](https://img.shields.io/pypi/v/recOrder-napari.svg)](https://pypi.org/project/recOrder-napari)
[![Development Status](https://img.shields.io/pypi/status/napari.svg)](https://en.wikipedia.org/wiki/Software_release_life_cycle#Alpha)

`recOrder` is a napari plugin and command-line tool for quantitative label-free microscopy that depends on a computational optics library, [`waveorder`](https://github.com/mehta-lab/waveorder), and an I/O library, [`iohub`](https://github.com/czbiohub-sf/iohub).
`recOrder` is a collection of computational imaging methods. It currently provides QLIPP (quantitative label-free imaging with phase and polarization), phase from defocus, and fluorescence deconvolution.

In this repository you will find python tools and a napari plugin that allow the user to calibrate microscope hardware, acquire multi-modal data, reconstruct density and anisotropy, and visualize the results.
[![Unveiling the invisible](./docs/images/comms_video_screenshot.png)](https://www.youtube.com/watch?v=JEZAaPeZhck)

The acquisition, calibration, background correction, reconstruction, and applications of QLIPP (quantitative label-free imaging with phase and polarization) are described in the following [E-Life Paper](https://elifesciences.org/articles/55502):
Acquisition, calibration, background correction, reconstruction, and applications of QLIPP are described in the following [E-Life Paper](https://elifesciences.org/articles/55502):

```bibtex
Syuan-Ming Guo, Li-Hao Yeh, Jenny Folkesson, Ivan E Ivanov, Anitha P Krishnan, Matthew G Keefe, Ezzat Hashemi, David Shin, Bryant B Chhun, Nathan H Cho, Manuel D Leonetti, May H Han, Tomasz J Nowakowski, Shalin B Mehta, "Revealing architectural order with quantitative label-free imaging and deep learning," eLife 2020;9:e55502 DOI: 10.7554/eLife.55502 (2020).
```

`recOrder` is to be used alongside a conventional widefield microscope fitted with a universal polarizer (Panel A below). The universal polarizer allows for the collection of label-free information including the intrinsic anisotropy of the sample and its relative phase (density). These measurements are collected by acquiring data under calibrated, polarization-diverse illumination followed by a computational reconstruction. The overall structure of `recOrder` is shown in Panel B, highlighting the structure of the graphical user interface (GUI) through a napari plugin.
These are the kinds of data you can acquire with `recOrder` and QLIPP:

![Flow Chart](https://github.com/mehta-lab/recOrder/blob/main/docs/images/recOrder_Fig1_Overview.png?raw=true)
https://user-images.githubusercontent.com/9554101/271128301-cc71da57-df6f-401b-a955-796750a96d88.mov

## Dataset
https://user-images.githubusercontent.com/9554101/271128510-aa2180af-607f-4c0c-912c-c18dc4f29432.mp4

[Slides](https://doi.org/10.5281/zenodo.5135889) and a [dataset](https://doi.org/10.5281/zenodo.5178487) shared during a workshop on QLIPP and recOrder can be found on Zenodo.
## What do I need to use `recOrder`
`recOrder` is to be used alongside a conventional widefield microscope. For QLIPP, the microscope must be fitted with an analyzer and a universal polarizer:

[![DOI](https://zenodo.org/badge/DOI/10.5281/zenodo.5178487.svg)](https://doi.org/10.5281/zenodo.5178487)
[![DOI](https://zenodo.org/badge/DOI/10.5281/zenodo.5135889.svg)](https://doi.org/10.5281/zenodo.5135889)
https://user-images.githubusercontent.com/9554101/273073475-70afb05a-1eb7-4019-9c42-af3e07bef723.mp4

For phase-from-defocus or fluorescence deconvolution methods, the universal polarizer is optional.

The overall structure of `recOrder` is shown in Panel B, highlighting the structure of the graphical user interface (GUI) through a napari plugin and the command-line interface (CLI) that allows users to perform reconstructions.

![Flow Chart](https://github.com/mehta-lab/recOrder/blob/main/docs/images/recOrder_Fig1_Overview.png?raw=true)

## Quick Start


## Software Quick Start

(Optional but recommended) install [anaconda](https://www.anaconda.com/products/distribution) and create a virtual environment:

Expand All @@ -48,3 +56,10 @@ napari -w recOrder-napari

For more help, see [`recOrder`'s documentation](https://github.com/mehta-lab/recOrder/tree/main/docs). To install `recOrder`
on a microscope, see the [microscope installation guide](https://github.com/mehta-lab/recOrder/blob/main/docs/microscope-installation-guide.md).

## Dataset

[Slides](https://doi.org/10.5281/zenodo.5135889) and a [dataset](https://doi.org/10.5281/zenodo.5178487) shared during a workshop on QLIPP and recOrder can be found on Zenodo, and the napari plugin's sample contributions (`File > Open Sample > recOrder-napari` in napari).

[![DOI](https://zenodo.org/badge/DOI/10.5281/zenodo.5178487.svg)](https://doi.org/10.5281/zenodo.5178487)
[![DOI](https://zenodo.org/badge/DOI/10.5281/zenodo.5135889.svg)](https://doi.org/10.5281/zenodo.5135889)
Binary file added docs/images/comms_video_screenshot.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
10 changes: 8 additions & 2 deletions recOrder/napari.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,9 @@ contributions:
- id: recOrder-napari.polarization_target_reconstruction
title: Polarization Target Data
python_name: recOrder.scripts.samples:read_polarization_target_reconstruction
- id: recOrder-napari.zebrafish_embryo_reconstruction
title: Zebrafish Embryo Reconstruction
python_name: recOrder.scripts.samples:read_zebrafish_embryo_reconstruction
readers:
- command: recOrder-napari.get_reader
accepts_directories: true
Expand All @@ -24,8 +27,11 @@ contributions:
sample_data:
- command: recOrder-napari.polarization_target_data
key: polarization-target-data
display_name: Polarization Target Data
display_name: Polarization Target Data (10 MB)
- command: recOrder-napari.polarization_target_reconstruction
key: polarization-target-reconstruction
display_name: Polarization Target Reconstruction
display_name: Polarization Target Reconstruction (10 MB)
- command: recOrder-napari.zebrafish_embryo_reconstruction
key: zebrafish-embryo-reconstruction
display_name: Zebrafish Embryo Reconstruction (92 MB)

70 changes: 44 additions & 26 deletions recOrder/scripts/samples.py
Original file line number Diff line number Diff line change
@@ -1,29 +1,59 @@
import shutil
from pathlib import Path

from typing import Literal
from iohub import open_ome_zarr
from iohub.ngff import Plate
from napari.utils.notifications import show_warning
from platformdirs import user_data_dir
from wget import download


def download_and_unzip() -> tuple[Path]:
def _build_layer_list(dataset: Plate, layer_names: list[str]):
layer_list = []
ziw-liu marked this conversation as resolved.
Show resolved Hide resolved
for channel_name in layer_names:
channel_index = dataset.channel_names.index(channel_name)
position = dataset["0/0/0"]
data = (position["0"][:, channel_index],)
layer_dict = {"name": channel_name, "scale": position.scale[3:]}
layer_list.append((data, layer_dict))

return layer_list


def download_and_unzip(data_type: Literal["target", "embryo"]) -> tuple[Path]:
"""Downloads sample data .zip from zenodo, unzips, and returns Paths to the .zarr datasets.

Skips the download if the files already exist.

Uses platformdirs.user_data_dir to store data.
"""
temp_dirpath = Path(user_data_dir("recOrder-sample-v1.4"))

# Delete old data
old_data_dirs = ["recOrder-sample-v1.4"]
for old_data_dir in old_data_dirs:
old_data_path = Path(user_data_dir(old_data_dir))
if old_data_path.exists():
shutil.rmtree(str(old_data_path))

temp_dirpath = Path(user_data_dir("recOrder-sample-v1.5"))
temp_dirpath.mkdir(exist_ok=True, parents=True)
data_dirpath = temp_dirpath / "sample_contribution"

if data_type == "target":
data_dirpath = temp_dirpath / "sample_contribution"
data_size = "10 MB"
data_url = "https://zenodo.org/record/8386856/files/sample_contribution.zip?download=1"
elif data_type == "embryo":
data_dirpath = temp_dirpath / "sample_contribution_embryo"
data_size = "92 MB"
data_url = "https://zenodo.org/record/8386856/files/sample_contribution_embryo.zip?download=1"

if not data_dirpath.with_suffix(".zip").exists():
show_warning(
"Downloading 10 MB sample contribution. This might take a moment..."
f"Downloading {data_size} sample contribution. This might take a moment..."
ziw-liu marked this conversation as resolved.
Show resolved Hide resolved
)
data_url = "https://zenodo.org/record/8280720/files/sample_contribution.zip?download=1"
download(data_url, out=str(temp_dirpath))

if not data_dirpath.exists():
shutil.unpack_archive(
data_dirpath.with_suffix(".zip"), extract_dir=temp_dirpath
Expand All @@ -36,32 +66,20 @@ def download_and_unzip() -> tuple[Path]:

def read_polarization_target_data():
"""Returns the polarization data sample contribution"""
data_path, _ = download_and_unzip()

data_path, _ = download_and_unzip("target")
dataset = open_ome_zarr(data_path)
layer_list = []
for channel_index, channel_name in enumerate(dataset.channel_names):
position = dataset["0/0/0"]
data = (position["0"][0, channel_index],)
layer_dict = {"name": channel_name, "scale": position.scale[3:]}
layer_list.append((data, layer_dict))

return layer_list
return _build_layer_list(dataset, dataset.channel_names)


def read_polarization_target_reconstruction():
"""Returns the polarization target reconstruction sample contribution"""

_, recon_path = download_and_unzip()
_, recon_path = download_and_unzip("target")
dataset = open_ome_zarr(recon_path)
return _build_layer_list(dataset, ["Phase3D", "Retardance", "Orientation"])

layer_list = []
for channel_index, channel_name in enumerate(
["Retardance", "Orientation"]
):
position = dataset["0/0/0"]
data = (position["0"][0, channel_index],)
layer_dict = {"name": channel_name, "scale": position.scale[3:]}
layer_list.append((data, layer_dict))

return layer_list
def read_zebrafish_embryo_reconstruction():
"""Returns the embryo reconstruction sample contribution"""
_, recon_path = download_and_unzip("embryo")
dataset = open_ome_zarr(recon_path)
return _build_layer_list(dataset, ["Retardance", "Orientation"])
Loading