Skip to main content

Piecewise alignment for layers of mosaics

Project description

palom
Piecewise alignment for layers of mosaics

Palom started as a tool for registering whole-slide images of the same FFPE section with different IHC stainings.


Installation

Installing palom in a fresh conda environment is recommended. Instruction for installing miniconda

Step 1

Create a named conda environment - palom, in the following example, and activate the environment.

conda create -n palom python=3.7 pip -c conda-forge
conda activate palom

Step 2

Install openslide in the conda environment.

conda install openslide -c sdvillal

Step 3

Install palom from pypi in the conda environment.

python -m pip install palom

CLI usage

Configuration YAML file

Palom CLI tool merges multiple SVS files into a pyramidal OME-TIFF file, with the option to perform preset stain separation (5 modes are available - output mode: hematoxylin, aec, dab, grayscale, color)

A user-defined configuration YAML file is required for the run. A configuration example can be printed to the console by running

palom-svs show example
input dir: Y:\user\me\projects\data\mihc
output full path: Y:\user\me\projects\analysis\mihc\2021\skin-case-356.ome.tif

reference image:
    filename: 20210111/skin_case_356_HEM_C11R3_HEM.svs
    output mode: hematoxylin
    channel name: Hematoxylin

moving images:
- filename: 20210101/skin_case_356_HEM_C01R1_PD1.svs
  output mode: aec
  channel name: PD-1
- filename: 20210101/skin_case_356_HEM_C01R2_PDL1.svs
  output mode: aec
  channel name: PD-L1

To show the configuration schema, run the following command

palom-svs show schema

Use the helper script to generate the configuration file

A helper script is included showing how to automatically generate the configuration file if the SVS files are organized and have specific naming pattern.

Here's an example directory containing many SVS files

Y:\DATA\SARDANA\MIHC\768473\RAW
    CBB_SARDANA_768473_C04R1_CD8.svs
    KB_SARDANA_768473_C01R1_PD1.svs
    KB_SARDANA_768473_C01R2_PDL1.svs
    KB_SARDANA_768473_C01R3_Hem.svs
    KB_SARDANA_768473_C02R1_CD4.svs
    KB_SARDANA_768473_C03R1_CD3.svs
    KB_SARDANA_768473_C03R3_DCLAMP.svs

Running the following command to generate the configuration file

palom-svs-helper -i "Y:\DATA\SARDANA\MIHC\768473\RAW" -n "*Hem*" -o "Y:\DATA\SARDANA\MIHC\768473\RAW\palom\768473.ome.tif" -c "Y:\DATA\SARDANA\MIHC\768473\768473.yml"

And the resulting Y:\DATA\SARDANA\MIHC\768473\768473.yml file

input dir: Y:\DATA\SARDANA\MIHC\768473\RAW
output full path: Y:\DATA\SARDANA\MIHC\768473\RAW\palom\768473.ome.tif
reference image:
  filename: .\KB_SARDANA_768473_C01R3_Hem.svs
  output mode: hematoxylin
  channel name: Hem-C01R3
moving images:
- filename: .\KB_SARDANA_768473_C01R1_PD1.svs
  output mode: aec
  channel name: PD1-C01R1
- filename: .\KB_SARDANA_768473_C01R2_PDL1.svs
  output mode: aec
  channel name: PDL1-C01R2
- filename: .\KB_SARDANA_768473_C02R1_CD4.svs
  output mode: aec
  channel name: CD4-C02R1
- filename: .\KB_SARDANA_768473_C03R1_CD3.svs
  output mode: aec
  channel name: CD3-C03R1
- filename: .\KB_SARDANA_768473_C03R3_DCLAMP.svs
  output mode: aec
  channel name: DCLAMP-C03R3
- filename: .\CBB_SARDANA_768473_C04R1_CD8.svs
  output mode: aec
  channel name: CD8-C04R1

After reviewing the configuration file, process those SVS files by running

palom-svs run -c "Y:\DATA\SARDANA\MIHC\768473\768473.yml"

When the process is finished, a pyramidal OME-TIFF file will be generated along with PNG files showing the feature-based registration results and a log file.

Y:\DATA\SARDANA\MIHC\768473\RAW
│   CBB_SARDANA_768473_C04R1_CD8.svs
│   KB_SARDANA_768473_C01R1_PD1.svs
│   KB_SARDANA_768473_C01R2_PDL1.svs
│   KB_SARDANA_768473_C01R3_Hem.svs
│   KB_SARDANA_768473_C02R1_CD4.svs
│   KB_SARDANA_768473_C03R1_CD3.svs
│   KB_SARDANA_768473_C03R3_DCLAMP.svs
│
└───palom
    │   768473.ome.tif
    │
    └───qc
            01-KB_SARDANA_768473_C01R1_PD1.svs.png
            02-KB_SARDANA_768473_C01R2_PDL1.svs.png
            03-KB_SARDANA_768473_C02R1_CD4.svs.png
            04-KB_SARDANA_768473_C03R1_CD3.svs.png
            05-KB_SARDANA_768473_C03R3_DCLAMP.svs.png
            06-CBB_SARDANA_768473_C04R1_CD8.svs.png
            768473.ome.tif.log

Scripting

WARNING API may change in the future

For SVS files

import palom

c1r = palom.reader.SvsReader(r'Y:\DATA\SARDANA\MIHC\75684\GG_TNP_75684_D21_C11R3_HEM.svs')
c2r = palom.reader.SvsReader(r'Y:\DATA\SARDANA\MIHC\75684\GG_TNP_75684_D23_C01R1_PD1.svs')

LEVEL = 1
THUMBNAIL_LEVEL = 2

c1rp = palom.color.PyramidHaxProcessor(c1r.pyramid, thumbnail_level=THUMBNAIL_LEVEL)
c2rp = palom.color.PyramidHaxProcessor(c2r.pyramid, thumbnail_level=THUMBNAIL_LEVEL)

c21l = palom.align.Aligner(
    c1rp.get_processed_color(LEVEL), 
    c2rp.get_processed_color(LEVEL),
    ref_thumbnail=c1rp.get_processed_color(THUMBNAIL_LEVEL).compute(),
    moving_thumbnail=c2rp.get_processed_color(THUMBNAIL_LEVEL).compute(),
    ref_thumbnail_down_factor=c1r.level_downsamples[THUMBNAIL_LEVEL] / c1r.level_downsamples[LEVEL],
    moving_thumbnail_down_factor=c2r.level_downsamples[THUMBNAIL_LEVEL] / c2r.level_downsamples[LEVEL]
)

c21l.coarse_register_affine()
c21l.compute_shifts()
c21l.constrain_shifts()

c21l.block_affine_matrices_da

c2m = palom.align.block_affine_transformed_moving_img(
    c1rp.get_processed_color(LEVEL),
    c2rp.get_processed_color(LEVEL, 'aec'),
    mxs=c21l.block_affine_matrices_da
)

palom.pyramid.write_pyramid(
    palom.pyramid.normalize_mosaics([c2m]),
    r"Y:\DATA\SARDANA\MIHC\75684\mosaic.ome.tif",
    pixel_size=c1r.pixel_size*c1r.level_downsamples[LEVEL],
)

For TIFF and OME-TIFF files

import palom

# reference image is a multichannel immunofluoroscence imaging
c1r = palom.reader.OmePyramidReader(r"Z:\P37_Pilot2\P37_S12_Full.ome.tiff")
# moving image is a brightfield imaging (H&E staining) of the same tissue
# section as the reference image
c2r = palom.reader.OmePyramidReader(r"Z:\P37_Pilot2\HE\P37_S12_E033_93_HE.ome.tiff")

# use second-to-the-bottom pyramid level for a quick test; set `LEVEL = 0` for
# processing lowest level pyramid (full resolution)
LEVEL = 1
# choose thumbnail pyramid level for feature-based affine registration as
# initial coarse alignment
# `THUMBNAIL_LEVEL = c1r.get_thumbnail_level_of_size(2000)` might be a good
# starting point
THUMBNAIL_LEVEL = 3

c21l = palom.align.Aligner(
    # use the first channel (Hoechst staining) in the reference image as the
    # registration reference
    ref_img=c1r.read_level_channels(LEVEL, 0),
    # use the second channel (G channel) in the moving image, it usually has
    # better contrast
    moving_img=c2r.read_level_channels(LEVEL, 1),
    # select the same channels for the thumbnail images
    ref_thumbnail=c1r.read_level_channels(THUMBNAIL_LEVEL, 0).compute(),
    moving_thumbnail=c2r.read_level_channels(THUMBNAIL_LEVEL, 1).compute(),
    # specify the downsizing factors so that the affine matrix can be scaled to
    # match the registration reference
    ref_thumbnail_down_factor=c1r.level_downsamples[THUMBNAIL_LEVEL] / c1r.level_downsamples[LEVEL],
    moving_thumbnail_down_factor=c2r.level_downsamples[THUMBNAIL_LEVEL] / c2r.level_downsamples[LEVEL]
)

# run feature-based affine registration using thumbnails
c21l.coarse_register_affine(n_keypoints=4000)
# after coarsly affine registered, run phase correlation on each of the
# corresponding chunks (blocks/pieces) to refine translations
c21l.compute_shifts()
# discard incorrect shifts which is usually due to low contrast in the
# background regions; this is needed for WSI but maybe not for ROI images
c21l.constrain_shifts()

# configure the transformation of aligning the moving image to the registration
# reference
c2m = palom.align.block_affine_transformed_moving_img(
    ref_img=c1r.read_level_channels(LEVEL, 0),
    # select all the three channels (RGB) in moving image to transform
    moving_img=c2r.pyramid[LEVEL],
    mxs=c21l.block_affine_matrices_da
)

# write the registered images to a pyramidal ome-tiff
palom.pyramid.write_pyramid(
    mosaics=palom.pyramid.normalize_mosaics([
        # select only the first three channels in referece image to be written
        # to the output ome-tiff; for writing all channels, use
        # `c1r.pyramid[LEVEL]` instead
        c1r.read_level_channels(LEVEL, [0, 1, 2]),
        c2m
    ]),
    output_path=r"Z:\P37_Pilot2\mosaic.ome.tif",
    pixel_size=c1r.pixel_size*c1r.level_downsamples[LEVEL]
)

Project details


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

palom-2022.3.3.tar.gz (20.5 kB view details)

Uploaded Source

Built Distribution

palom-2022.3.3-py3-none-any.whl (22.6 kB view details)

Uploaded Python 3

File details

Details for the file palom-2022.3.3.tar.gz.

File metadata

  • Download URL: palom-2022.3.3.tar.gz
  • Upload date:
  • Size: 20.5 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? No
  • Uploaded via: poetry/1.2.0a2 CPython/3.8.12 Windows/10

File hashes

Hashes for palom-2022.3.3.tar.gz
Algorithm Hash digest
SHA256 30131a3da6299a572fcf3fe9144dabddbc6f39204f82318196642f600714b463
MD5 d1cdff4961bc306bd8c1f4a7cd1114a8
BLAKE2b-256 86494bd198cc841e4e1c015b7c199ed94a90608944682077249d11a7ca2ab5b1

See more details on using hashes here.

File details

Details for the file palom-2022.3.3-py3-none-any.whl.

File metadata

  • Download URL: palom-2022.3.3-py3-none-any.whl
  • Upload date:
  • Size: 22.6 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? No
  • Uploaded via: poetry/1.2.0a2 CPython/3.8.12 Windows/10

File hashes

Hashes for palom-2022.3.3-py3-none-any.whl
Algorithm Hash digest
SHA256 96b9698008721d1cb1766bb40cc6b169eb0ec4564c2eeb9fd3147e34ccbab2d5
MD5 e15660d693a71889d1baa07dcb844b70
BLAKE2b-256 85f7ce6f91084c40dc21505df8857c97c86107ddb7f1a96d0cf3225b6276b79f

See more details on using hashes here.

Supported by

AWS AWS Cloud computing and Security Sponsor Datadog Datadog Monitoring Fastly Fastly CDN Google Google Download Analytics Microsoft Microsoft PSF Sponsor Pingdom Pingdom Monitoring Sentry Sentry Error logging StatusPage StatusPage Status page