labsyspharm / ashlar

ASHLAR: Alignment by Simultaneous Harmonization of Layer/Adjacency Registration
https://labsyspharm.github.io/ashlar/
MIT License
117 stars 41 forks source link

Running Ashlar on sequentially stained whole slide brightfield images #99

Open kaizen89 opened 2 years ago

kaizen89 commented 2 years ago

Hi, I have 10 images, each with hematoxylin and a DAB staining for different markers on the same slide that were stained sequentially. Now I would like to align and register the images based on the hematoxylin staining using a reference image. Can I use Ashlar for this purpose? If yes, how should I input all the image files at once in the command? Thank you

jmuhlich commented 2 years ago

Can you explain the experimental protocol a bit more? Do you strip the DAB-labeled antibody and re-stain each time?

kaizen89 commented 2 years ago

Exactly. Scan, strip and restain again. aaf6925-f1

Yu-AnChen commented 2 years ago

Hi @kaizen89, we need a bit more info - what are your imaging data files? Do you know whether each scan outputs field-of-views or a stitched image?

kaizen89 commented 2 years ago

I would say a stitched image, the instrument scans the whole slide but there is no alignement needed inside each image. The only alignment that is needed is between different images /markers. I can send example images if it would help.

Yu-AnChen commented 2 years ago

Thanks, having the example images would be helpful! ASHLAR is designed for stitching and registering imaging data that are not stitched. However, we recently took the idea in ASHLAR and started another module that hopefully works with pre-stitched images. Do you know what scanner was used and what type of files can it export? Like .tif .czi?

jmuhlich commented 2 years ago

Most brightfield slide scanners/microscopes emit pre-stitched images which are generally impossible to register accurately down to the single-cell level across the entire image. See Figure 5 in our preprint and the associated section of the text for more (imagine your scanner's internal stitching algorithm in place of the MIST algorithm we used in our comparison) : https://www.biorxiv.org/content/10.1101/2021.04.20.440625v1.full . You can try non-rigid or piecewise-rigid registration on the pre-stitched images, but there will always be "local deformations" as described by the MICSSS paper you cited. Depending on what you want to get out of the registered images, this loss may be acceptable. The tool @Yu-AnChen mentioned uses piecwise-rigid registration.

We did learn that some Aperio histology-focused microscopes and scanners do have an undocumented option to emit all the unstitched tile images instead of a single stitched image, but this only configurable at scan time (i.e. you can't "fix" an existing scan). It's possibly other vendors have similar support but we haven't been able to identify any others yet. One other microscope vendor we are aware of (Zeiss) generates files that appear pre-stitched but do actually contain the raw tiles.

kaizen89 commented 2 years ago

The scanner is a Hamamatsu and exports ndpi images. What we currently do is to export ROIs that are relatively big 10x10mm2 as ome.tif file and then launch an alignment process that we adapted from scripts found on forums to align 10-13 images each stained with a different marker. The alignement quality is fairly good allowing cell level measurements. However the process is time and RAM consuming, especially if we want to align the whole slide and not just an ROI, and in this cas the process usually fails to align correctly. We also know that HALO software can register those images (Whole slide) with good quality and in short amount of time, unfortunately this software is costly and does not allow to export the final composite image.

kaizen89 commented 2 years ago

Here's a link to access example images. The ndpi images are the original ones and ome.tif are exported ROIs that we were able to align. Ideally we would like to align the whole slide and then select ROI to analyze on the composite images with all the markers.

Yu-AnChen commented 2 years ago

Thanks for sharing the files, I did a quick run using palom. The result is here, you can toggle on/off channels on the top or in the left panel. What color separation you are using? The current method in palom isn't working well for your image, as you see in the 4th and 8th channel.

Here's the script I used

import palom

c1r = palom.reader.SvsReader('B11_CD3_PanelLymphoid_25287_6.ndpi')
c2r = palom.reader.SvsReader('B11_PanCK_PanelLymphoid_25287_6.ndpi')

LEVEL = 0
THUMBNAIL_LEVEL = 4

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()

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
)

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

palom.pyramid.write_pyramid(
    palom.pyramid.normalize_mosaics([
        c1rp.get_processed_color(LEVEL, 'color'),
        c1rp.get_processed_color(LEVEL, 'aec'),
        c2m_color,
        c2m
    ]),
    r"PanelLymphoid_25287-CD3_PanCK.ome.tif",
    pixel_size=c1r.pixel_size*c1r.level_downsamples[LEVEL],
    channel_names=['CD3_color', 'CD3', 'PanCK_color', 'PanCK']
)
kaizen89 commented 2 years ago

Thanks for doing the test. Palom seems to be very suited to my use case but it seems that there is something weird in the color deconvolution. What I use in Fiji is:

run("RGB Color"); 
run("Colour Deconvolution", "vectors=[H DAB]");

And then save channel 1 (hematox) and Channel 2 (marker staining) for each image. After alignment the final stack will have all the marker stainings and only one hematox (ref image).

Yu-AnChen commented 2 years ago

Cool, thanks for the info on the color deconvolution. Looks like the vector ([H DAB]) is the same in scikit-image. It was easy to add that to palom and here's what it looks like with the H DAB vector. I'll probably update the release shortly, happy to learn about what you think.

kaizen89 commented 2 years ago

It looks really great. Did you use the CD3 hematox as a reference or the panCK? Could you please share the script that you used with the H DAB deconvolution. I have lots of samples with 13 different markers to align, looking forward to try the updated release. One final thought, In order to reduce image composite size I was thinking to use an autothresholding estimator to convert to NaN every pixel with a value below this threshold. What do you think about this? Thanks a lot!

Yu-AnChen commented 2 years ago

I have updated the release (v2021.12.0). Please try to follow along with the README for installation and running. With the latest release, I now can use the following configuration (as config.yml) to run the two images you provided -

input dir: Y:\data\YC-20211201-ashlar-ndpi-files
output full path: Y:\data\YC-20211201-ashlar-ndpi-files\palom-test.ome.tif

reference image:
    filename: B11_CD3_PanelLymphoid_25287_6.ndpi
    output mode: hematoxylin
    channel name: Hematoxylin

moving images:
- filename: B11_CD3_PanelLymphoid_25287_6.ndpi
  output mode: dab
  channel name: CD3
- filename: B11_PanCK_PanelLymphoid_25287_6.ndpi
  output mode: dab
  channel name: PanCK

and run palom with the command

palom-svs run -c config.yml

The above config will write out the color-deconvoled images, resulting in a 3-channel image. If you have additional palom usage questions and issues, happy to discuss them there!