Git Product home page Git Product logo

ashlar's Introduction

ASHLAR: Alignment by Simultaneous Harmonization of Layer/Adjacency Registration

Whole-slide microscopy image stitching and registration in Python

Ashlar performs fast, high-quality stitching of microscopy images. It also co-registers multiple rounds of cyclic imaging for methods such as CyCIF and CODEX. Ashlar can read image data directly from BioFormats-supported microscope vendor file formats as well as a directory of plain TIFF files. Output is saved as pyramidal, tiled OME-TIFF.

Note that Ashlar requires unstitched individual "tile" images as input, so it is not suitable for microscopes or slide scanners that only provide pre-stitched images.

Visit labsyspharm.github.io/ashlar/ for the most up-to-date information on ASHLAR.

Usage

ashlar [-h] [-o PATH] [-c CHANNEL] [--flip-x] [--flip-y]
       [--flip-mosaic-x] [--flip-mosaic-y]
       [--output-channels CHANNEL [CHANNEL ...]] [-m SHIFT]
       [--stitch-alpha ALPHA] [--filter-sigma SIGMA]
       [--tile-size PIXELS] [--ffp FILE [FILE ...]]
       [--dfp FILE [FILE ...]] [--plates] [-q] [--version]
       FILE [FILE ...]

Stitch and align multi-tile cyclic microscope images

positional arguments:
  FILE                  Image file(s) to be processed, one per cycle

optional arguments:
  -h, --help            Show this help message and exit
  -o PATH, --output PATH
                        Output file. If PATH ends in .ome.tif a pyramidal OME-
                        TIFF will be written. If PATH ends in just .tif and
                        includes {cycle} and {channel} placeholders, a series
                        of single-channel plain TIFF files will be written. If
                        PATH starts with a relative or absolute path to
                        another directory, that directory must already exist.
                        (default: ashlar_output.ome.tif)
  -c CHANNEL, --align-channel CHANNEL
                        Reference channel number for image alignment.
                        Numbering starts at 0. (default: 0)
  --flip-x              Flip tile positions left-to-right
  --flip-y              Flip tile positions top-to-bottom
  --flip-mosaic-x       Flip output image left-to-right
  --flip-mosaic-y       Flip output image top-to-bottom
  --output-channels CHANNEL [CHANNEL ...]
                        Output only specified channels for each cycle.
                        Numbering starts at 0. (default: all channels)
  -m SHIFT, --maximum-shift SHIFT
                        Maximum allowed per-tile corrective shift in microns
                        (default: 15)
  --stitch-alpha ALPHA  Significance level for permutation testing during
                        alignment error quantification. Larger values include
                        more tile pairs in the spanning tree at the cost of
                        increased false positives. (default: 0.01)
  --filter-sigma SIGMA  Filter images before alignment using a Gaussian kernel
                        with s.d. of SIGMA pixels (default: no filtering)
  --tile-size PIXELS    Pyramid tile size for OME-TIFF output (default: 1024)
  --ffp FILE [FILE ...]
                        Perform flat field illumination correction using the
                        given profile image. Specify one common file for all
                        cycles or one file for every cycle. Channel counts
                        must match input files. (default: no flat field
                        correction)
  --dfp FILE [FILE ...]
                        Perform dark field illumination correction using the
                        given profile image. Specify one common file for all
                        cycles or one file for every cycle. Channel counts
                        must match input files. (default: no dark field
                        correction)
  --plates              Enable plate mode for HTS data
  -q, --quiet           Suppress progress display
  --version             Show program's version number and exit

Installation

Pip install

Ashlar can be installed in most Python environments using pip:

pip install ashlar

Using a conda environment

If you don't already have miniconda or Anaconda, download the python 3.x version and install. Then, run the following commands from a terminal (Linux/Mac) or command prompt (Windows):

Create a named conda environment with python 3.10:

conda create -y -n ashlar python=3.10

Activate the conda environment:

conda activate ashlar

In the activated environment, install dependencies and ashlar itself:

conda install -y -c conda-forge numpy scipy matplotlib networkx scikit-image=0.19 scikit-learn "tifffile>=2023.3.15" zarr pyjnius blessed
pip install ashlar

Docker image

The docker image of ashlar is on DockerHub at labsyspharm/ashlar which should be suitable for many use cases.

ashlar's People

Contributors

artemsokolov avatar dependabot[bot] avatar dpwrussell avatar jmuhlich avatar jteffthits avatar yu-anchen avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

ashlar's Issues

Allow second or later cycle to be used as the reference

A user reported their first cycle had some out-of-focus tiles and wanted to use cycle 2 as the reference cycle instead. For now they will just swap the order of the first two cycle filenames on the command line, but it would be better if we added an argument to select the reference cycle number.

ImportError: cannot import name '_fftpack'

Hi,

I installed ashlar in a conda environment. When I run ashlar -h I get the following error:

from . import scipy_fftpack
  File "...lib/python3.6/site-packages/pyfftw/interfaces/scipy_fftpack.py", line 65, in <module>
    from scipy.fftpack import (dct, idct, dst, idst, diff, tilbert, itilbert,
ImportError: cannot import name '_fftpack'

Scipy is installed. Running from scipy.fftpack import fft raises no error.

Helpful for any suggestions.

Thanks,
Mario

Help in using Ashlar for registering different rounds of hybridization

Hi! Thanks for this cool repo in stitching and aligning.

  1. I am trying to use it on 4 test images I have. There are 2 nd2 stacks per 2 rounds of hybridization (4 in total).
  2. 2 test nd2 stacks per each round of hybridization which are 2 different field of views and need to be stitched
  3. The 2 different hybridization round stacks correspond to each other and need to be registered
  4. Each nd2 stack has 5 channels and 150 z images. I am trying to register these 2 different rounds of hybridization and stitch the tiles within the same round

I want to figure out how Ashlar figures out which images to register and which images to stitch and how I should name my images accordingly, any feedback appreciated, thanks so much!

What I have done so far is

  1. I converted the nd2 files to tiff files for each image in zstack, so I have 150 images each with 5 channels. I have done this using imagej. Their naming looks something like below
    round2_z001.tif..round2_z150.tif
    round4_z00150.tif...round4_z00150.tif

  2. Using the notebook from this link, I am trying to register similarly but seems like all the 150 images are getting stitched which is not what I intend to do, I want to register the round2, round4. I think it might be that Ashlar doesn't work on pre-stitched images that this isn't working? I will add the stitchable images in the tiff files soon and try again
    #95

readers = []
for i in [2, 4]:
    readers.append(fileseries.FileSeriesReader(
        './data_to_test/',
        pattern='round'+str(i)+'_Z{series}.tiff',
        overlap=0.15,
        width=10,
        height=10,
        layout='snake',
        direction='horizontal',
        pixel_size=0.1625,
    ))


# check if filenames are indexed properly
print(
    '\n'.join(readers[0].metadata.filename(i, 0) for i in range(80, 120))
)
# it's very likely you'll want `flip_x=False, flip_y=True`
# try not to tweak here for now
# process_axis_flip(c1r, flip_x=False, flip_y=False)


# If using the third channel, pass `channel=2` (0-based indexing in python)
thumbnail_c1r = thumbnail.make_thumbnail(readers[0], channel=0)

plt.figure()
# doing log just for visualization
plt.imshow(np.log(thumbnail_c1r))

Clean up setup() description argument

The description should be a shorter bit of plain text, as it's displayed on pypi as-is. We can address this the next time we publish a new version.

Dockerfile dependency error

In the docker, pyjnius is looking for libjvm.so in the wrong place.

ashlar 'exemplar-001-cycle-01.ome.tiff' 'exemplar-001-cycle-02.ome.tiff' 'exemplar-001-cycle-03.ome.tiff' -m 30 --ffp exemplar-001-cycle-01-ffp.tif exemplar-001-cycle-02-ffp.tif exemplar-001-cycle-03-ffp.tif --dfp exemplar-001-cycle-01-dfp.tif exemplar-001-cycle-02-dfp.tif exemplar-001-cycle-03-dfp.tif --pyramid -f exemplar-001.ome.tif

  Traceback (most recent call last):
    File "/usr/local/bin/ashlar", line 5, in <module>
      from ashlar.scripts.ashlar import main
    File "/usr/local/lib/python3.7/dist-packages/ashlar/scripts/ashlar.py", line 8, in <module>
      from .. import reg
    File "/usr/local/lib/python3.7/dist-packages/ashlar/reg.py", line 37, in <module>
      import jnius
    File "/usr/local/lib/python3.7/dist-packages/jnius/__init__.py", line 42, in <module>
      from .reflect import *  # noqa
    File "/usr/local/lib/python3.7/dist-packages/jnius/reflect.py", line 20, in <module>
      class Class(with_metaclass(MetaJavaClass, JavaClass)):
    File "/usr/lib/python3/dist-packages/six.py", line 827, in __new__
      return meta(name, bases, d)
    File "jnius/jnius_export_class.pxi", line 119, in jnius.MetaJavaClass.__new__
    File "jnius/jnius_export_class.pxi", line 179, in jnius.MetaJavaClass.resolve_class
    File "jnius/jnius_env.pxi", line 11, in jnius.get_jnienv
    File "jnius/jnius_jvm_dlopen.pxi", line 134, in jnius.get_platform_jnienv
    File "jnius/jnius_jvm_dlopen.pxi", line 101, in jnius.create_jnienv
  SystemError: Error calling dlopen(b'/opt/ibm/jre/lib/server/libjvm.so': b'/opt/ibm/jre/lib/server/libjvm.so: cannot open shared object file: No such file or directory'

As a workaround, I added to the dockerfile

RUN mkdir -p /opt/ibm/jre/lib/server/ \
&& ln -s /usr/lib/jvm/java-11-openjdk-amd64/lib/server/libjvm.so /opt/ibm/jre/lib/server/libjvm.so

possibly related... kivy/pyjnius#428

Running Ashlar on sequentially stained whole slide brightfield images

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

How to make metadata when stitching jpg format tiles

Hello, i want to try ashlar to stitch jpg files into a whole slide image, but i don't know how to tell ashlar the location of each tiles.
my environment: win10 python3.7 ashlar 1.14.1
command:
ashlar 000_005.jpg 000_006.jpg 000_007.jpg --output-channels 0 1 2 --pyramid -f final.ome.tiff
input image:
image
output message:

Cycle 0:
    reading 000_005.jpg
WARNING: Stage coordinates undefined; falling back to (0, 0).
WARNING: Pixel size undefined; falling back to 1.0 μm.
    assembling thumbnail 1/1
    Channel 0:
        merging tile 1/1
WARNING: Pixel size undefined; falling back to 1.0 μm.
        writing to final.ome.tiff
    Channel 1:
        merging tile 1/1
        writing to final.ome.tiff
    Channel 2:
        merging tile 1/1
        writing to final.ome.tiff
Cycle 1:
    reading 000_006.jpg
WARNING: Stage coordinates undefined; falling back to (0, 0).
    assembling thumbnail 1/1
    estimated cycle offset [y x] = [515.  -8.]
    aligning tile 1/1
    Channel 0:
        merging tile 1/1
WARNING: Pixel size undefined; falling back to 1.0 μm.
        writing to final.ome.tiff
    Channel 1:
        merging tile 1/1
        writing to final.ome.tiff
    Channel 2:
        merging tile 1/1
        writing to final.ome.tiff
Cycle 2:
    reading 000_007.jpg
WARNING: Stage coordinates undefined; falling back to (0, 0).
    assembling thumbnail 1/1
    estimated cycle offset [y x] = [-81. -40.]
    aligning tile 1/1
    Channel 0:
        merging tile 1/1
WARNING: Pixel size undefined; falling back to 1.0 μm.
        writing to final.ome.tiff
    Channel 1:
        merging tile 1/1
        writing to final.ome.tiff
    Channel 2:
        merging tile 1/1
        writing to final.ome.tiff
Building pyramid
    Level 1:
        processing channel 9/9
    Level 2:
        processing channel 9/9

it seems ashlar need ome meta message to stitch, the output single tiff file only has one channel of first image
image
is there something wrong in my command, or lack of ome meta message?
if its the second reason, i have the coordinates and overlap of the tiles, how can i make the meta data to get ashlar works

Apply Image Correction before generating stitched images

I am imaging large areas with a spinning disk confocal microscope and want to stitch the images with ashlar. Before stitching I would like to normalize the ranges in each image to a range between 0 and 1 representing the 1-99% quantile of the signal in that image. Since I am working with several TB of data which I need to process its quite important for me that my code runs efficiently and quickly.

The images I obtain from the microscope are exported as individual .TIF files. I have gotten a stitching pipeline working as follows where the individual images are read from file.

#read data 
slide = filepattern.FilePatternReader(path = outdir_corrected, pattern = pattern, overlap = overlap)

#flip y-axis to comply with labeling generated by opera phenix
process_axis_flip(slide, flip_x=False, flip_y=True)

#perform actual alignment
aligner = reg.EdgeAligner(slide, channel='Alexa488', filter_sigma=1, verbose=True, do_make_thumbnail=False)
aligner.run()

#generate some QC plots
#reg.plot_edge_quality(aligner, img=aligner.reader.thumbnail)
reg.plot_edge_scatter(aligner)

#generate stitched file
mosaic_args = {}
mosaic_args['channels'] = lookup.label.tolist()
mosaic_args['verbose'] = True

mosaic = reg.Mosaic(aligner, 
                    aligner.mosaic_shape, 
                    SlideName + '_{channel}.tif',
                    **mosaic_args
                    )

#output result to array in python -> need to perform cropping
merged = mosaic.run(mode='return')
merged_array = np.array(merged)

Now I would like to somehow implement that before stitching my tiles I can apply the correction I described above to each of my tiles. I have a function which I implemented in numba which can apply this correction very quickly to stack of image tifs saved as an array in the form (N,C,W,H). Is there someway that I can apply this correction within ashlar after loading the images and before performing the stitching?
Alternatively is there a possibility for me to pass an array containing the images that should be stitched to ashlar instead of having ashlar read from a file?
In both situations I would end up having to only read and write my data to file once which would save me a lot of time as this is currently the most time-consuming bottle neck.
Many thanks!

Exception: Can't handle non-square pixels (0.293388, 0.293389)

Hi,

I am trying to run ashlar as part of the mcmicro pipeline with nextflow.
However, I get a Command error related to non-square pixels.

Command error:
  WARNING: Stage coordinates' measurement unit is undefined; assuming μm.
  Traceback (most recent call last):
    File "/usr/local/bin/ashlar", line 8, in <module>
      sys.exit(main())
    File "/usr/local/lib/python3.7/dist-packages/ashlar/scripts/ashlar.py", line 184, in main
      args.quiet
    File "/usr/local/lib/python3.7/dist-packages/ashlar/scripts/ashlar.py", line 213, in process_single
      process_axis_flip(reader, flip_x, flip_y)
    File "/usr/local/lib/python3.7/dist-packages/ashlar/scripts/ashlar.py", line 302, in process_axis_flip
      _ = metadata.positions
    File "/usr/local/lib/python3.7/dist-packages/ashlar/reg.py", line 177, in positions
      return Metadata.positions.fget(self)[self.active_series]
    File "/usr/local/lib/python3.7/dist-packages/ashlar/reg.py", line 94, in positions
      self.tile_position(i) for i in range(self._num_images)
    File "/usr/local/lib/python3.7/dist-packages/ashlar/reg.py", line 94, in <listcomp>
      self.tile_position(i) for i in range(self._num_images)
    File "/usr/local/lib/python3.7/dist-packages/ashlar/reg.py", line 375, in tile_position
      position_pixels = position_microns / self.pixel_size
    File "/usr/local/lib/python3.7/dist-packages/ashlar/reg.py", line 292, in pixel_size
      % tuple(values))
  Exception: Can't handle non-square pixels (0.293388, 0.293389)

Reading the Parameters with ImageJ, we have the following values:

Width: 3705.8078 µm (12631)
Height: 4720.6434 µm (16090)
Size: 194MB
Resolution: 3.4084 pixels per µm
Pixel size: 0.2934x0.2934 µm^2

I think it would be fair to assume that this is a precision problem and the pixels are somewhat square. The display precision in ImageJ is sub-nanometer, and I think this would be a good cutoff. I would therefore propose to round to 4 decimals here.

Happy to make a small pull request with a proposed solution in case.

mosaic error

On my first attempt to use ashlar on O2 I ran into this:

jc168@compute-a-16-69:~$ mosaic /n/scratch2/jc168/forZoltan/ZM_CYCIF1_051_Nicole3/
Scan 0:
Traceback (most recent call last):
  File "/n/groups/lsp/o2/apps/ashlar/1.0.3/venv/bin/mosaic", line 11, in <module>
    load_entry_point('ashlar==1.0.3', 'console_scripts', 'mosaic')()
  File "/n/groups/lsp/o2/apps/ashlar/1.0.3/venv/lib/python2.7/site-packages/ashlar/scripts/mosaic.py", line 18, in main
    print '    reading %s' % filepaths[0]
IndexError: list index out of range
jc168@compute-a-16-69:~$

Does the input require that specify more than the containing directory?

Output array size too large for JVM

Hi @jmuhlich

as per your suggestion in a different repo I I just gave this a spin. Trying to stitch a whole slide acquisition
in a single .nd2 file I run into errors with output size:

(/home/jovyan/shared_volker/ashlar) jovyan@43e3f12000b3:~/Desktop$ JAVA_TOOL_OPTIONS="-Xmx20G"  ashlar whole_slide_scan_large_image.nd2 -c 0
Picked up JAVA_TOOL_OPTIONS: -Xmx20G
Cycle 0:
    reading whole_slide_scan_large_image.nd2
WARNING: Stage coordinates' measurement unit is undefined; assuming μm.

    Channel 0:
        merging tile 1/1Traceback (most recent call last):
  File "/home/jovyan/shared_volker/ashlar/bin/ashlar", line 8, in <module>
    sys.exit(main())
  File "/home/jovyan/shared_volker/ashlar/lib/python3.7/site-packages/ashlar/scripts/ashlar.py", line 174, in main
    args.quiet
  File "/home/jovyan/shared_volker/ashlar/lib/python3.7/site-packages/ashlar/scripts/ashlar.py", line 219, in process_single
    mosaic.run()
  File "/home/jovyan/shared_volker/ashlar/lib/python3.7/site-packages/ashlar/reg.py", line 1085, in run
    tile_image = self.aligner.reader.read(c=channel, series=tile)
  File "/home/jovyan/shared_volker/ashlar/lib/python3.7/site-packages/ashlar/reg.py", line 420, in read
    img = self.reader.read(series, c)
  File "/home/jovyan/shared_volker/ashlar/lib/python3.7/site-packages/ashlar/reg.py", line 397, in read
    byte_array = self.metadata._reader.openBytes(index)
  File "jnius/jnius_export_class.pxi", line 1047, in jnius.JavaMultipleMethod.__call__
  File "jnius/jnius_export_class.pxi", line 769, in jnius.JavaMethod.__call__
  File "jnius/jnius_export_class.pxi", line 856, in jnius.JavaMethod.call_method
  File "jnius/jnius_utils.pxi", line 91, in jnius.check_exception
jnius.JavaException: JVM exception occurred: Array size too large: 70714 x 28428 x 2
(/home/jovyan/shared_volker/ashlar) jovyan@43e3f12000b3:~/Desktop$ 

The output array size seems quite realistic for this problem: 70714 x 28428 x 2
The machine has plenty of RAM (>64 Gbyte). Not sure whether I should be doing something differently or whether I am hitting a limtation here.

Assistance w/ usage

Hi. I'm experimenting with BaSiC correction and understand this repo can be used to apply corrections per ffp and dfp .tifs. Images are single scene, multi-channel CZIs and each has a corresponding multi channel ffp.tif, dfp.tif. I've run ashlar myimg.czi --ffp ffp.tif --dfp dfp.tif successfully though the output files are smaller than expected. Does all this sound about right? Thanks.

start guide to ashlar

hi!

I have many (tiff) image files containing field-of-view's that I would like to stitch together using ashlar. please, could you provide some samples of how I can use ashlar to do this. Either through the command line or python is fine!

thanks :)

Account for camera rotation when comparing shifts to max_shift in EdgeAligner

If the camera rotation is significant, I think this will amplify the actual pairwise shift. Users have to increase max_shift to compensate, which shouldn't be necessary. We should compensate for the camera angle so max_shift more accurately models stage position repeatability. The camera angle can be extracted from the linear model coefficients, but the max_shift comparison happens before the model fit...

Correct small amounts of tile rotation

When doing cyclic IF, it's often hard to entirely eliminate all differences in rotation from cycle to cycle, whether it's coming from the camera or the stage holder. Often these are only 0.5-1 degree of rotation, but with large fields of view this can still cause stitched edges to appear blurred and probably causes worse problems when scanning larger areas. I can correct very small rotation errors manually, but it would be nice to have this as a part of the alignment.

Output tile positions

I sadly wasn't able to find anything in the documentation, but hopefully you can quickly lead me in the correct direction.
I am using ashlar to stitch and align larger imaging datasets (3 channel imaging, ~2000 image tiles per project) using a python workflow. I then use the stitched images in a segmentation/classification pipeline. For my downstream analysis it would be useful to know which part of the stitched image came from which image tile so that I for example can eliminate cells that came from an out-of-focus tile. Is there some possibility to output this information while stitching?

5 channel images error

I have been testing ashlar to process (stich and register) multiple rounds of images from codex. After some trail and error i got to the point when i get satisfactory output (there seems to be some stitching artefacts in overlap area but i will tweak SHIFT and SIGMA values to work on that).
The problem i got stack on is an error below which i seems to get only when using 5 channel images. I created test set with 3 channels only which seems to work fine but when using generated side by side 5 channels set of images im getting below error.
For acquisition i use Dragonfly 200 confocal, i convert ims files (direct output from dragonfly, looks like ashlar doesnt have ims compactible reader) to ome.tif files using bfconvert command line tool, ashlar version 1.16.0

~/.local/lib/python3.8/site-packages/ashlar$ ashlar 'fileseries|/nfs/././test3|pattern=05242022_ashlar_test3_F{series}.ims.ome.tiff|width=6|height=20|pixel_size=0.1507|overlap=0.1|layout=snake|direction=vertical' --flip-y --flip-mosaic-y --pyramid --maximum-shift 30 -o /mnt/d/././.ome.tif
Stitching and registering input images
Cycle 0:
reading fileseries|/nfs/././test3|pattern=05242022_ashlar_test3_F{series}.ims.ome.tiff|width=6|height=20|pixel_size=0.1507|overlap=0.1|layout=snake|direction=vertical
WARNING: Some neighboring tiles have zero overlap.
Traceback (most recent call last):
File "/home/hdid/.local/bin/ashlar", line 8, in
sys.exit(main())
File "/home/hdid/.local/lib/python3.8/site-packages/ashlar/scripts/ashlar.py", line 212, in main
return process_single(
File "/home/hdid/.local/lib/python3.8/site-packages/ashlar/scripts/ashlar.py", line 243, in process_single
edge_aligner.run()
File "/home/hdid/.local/lib/python3.8/site-packages/ashlar/reg.py", line 485, in run
self.compute_threshold()
File "/home/hdid/.local/lib/python3.8/site-packages/ashlar/reg.py", line 550, in compute_threshold
o1, o2 = random_state.randint(max_offset, size=2)
File "mtrand.pyx", line 748, in numpy.random.mtrand.RandomState.randint
File "_bounded_integers.pyx", line 1247, in numpy.random._bounded_integers._rand_int64
ValueError: high <= 0

AttributeError: 'loci.formats.ome.OMEXMLMetadata'

Hi,

I am trying to register "normal" TIF images (no WSI or pyramidal TIF).
But I get the following error:

.../ashlar/reg.py", line 244, in _init_metadata
    xml_content = metadata.dumpXML()
AttributeError: 'loci.formats.ome.OMEXMLMetadata' object has no attribute 'dumpXML'

I tried with multichannel and greyscale versions, but run into the same issue.

Best regards,
Mario

No way to switch from combing to continuous merge when using the 'fileseries' option

Thank you for a great tool! I'm trying to migrate part of our analysis pipeline from MIST in ImageJ to Ashlar. Most things look positive but I have got stuck on a stopper. The image series we generate uses a "back and forth" paradigm so the first row is imaged left-to-right and the second row right-to-left. In MIST this is called "continuous" instead of "combing".

When I manually specify the "fileseries" and the correct width and height it merges but always uses the combing approach, resulting in an erroneous merge.

Is this possible to solve? Thanks'

Sparse tiles in output from CZI scans

Background

I'm attempting to use ASHLAR 1.15.2 on a couple Zeiss (CZI) 5-channel whole slide images. However, the results are showing strange tiling issues, basically sparse tiles with no data in between. I'd love some advice to troubleshoot this issue, or, if this is due to a bug in ASHLAR, I'm happy to help investigate.

Also, while running ASHLAR, I received some warnings ("WARNING: Stage coordinates' measurement unit is undefined; assuming μm."), and I'm wondering if that's the issue, and if there is a workaround. I'd also appreciate any additional explanations about those warnings. Full console output below.

Image output

Here's the zoomed-out output from running two whole slide images (screen clip is from Fiji, which can barely handle this gigantic image):
image

And here I'm using much smaller exported ROIs from the same images (screen clip is from ZEN, blue for the first image's DAPI channel and red for the second image's DAPI channel, though all channels from each image are contained within those respective rectangles):
image

Console output

Here's the full console output of my ASHLAR run on the exported ROIs that yielded the second image above. Both images have 5 channels and their last channel is DAPI, so I entered --align-channel 4 to reference that DAPI channel using ASHLAR's 0-based indexing.

D:\ashlar\output2>ashlar "c:\temp\ashlar\data\4420-cropped.czi" "c:\temp\ashlar\data\4610-cropped.czi" --align-channel 4
Stitching and registering input images
Cycle 0:
reading c:\temp\ashlar\data\4420-cropped.czi
WARNING: Stage coordinates' measurement unit is undefined; assuming μm.
assembling thumbnail 12/12
quantifying alignment error 1000/1000
aligning edge 3/3
Cycle 1:
reading c:\temp\ashlar\data\4610-cropped.czi
WARNING: Stage coordinates' measurement unit is undefined; assuming μm.
assembling thumbnail 12/12
estimated cycle offset [y x] = [-97.6009913 -95.       ]
aligning tile 12/12

Merging tiles and writing to ashlar-output.ome.tif
Cycle 0:
Channel 0:
merging tile 12/12
Channel 1:
merging tile 12/12
Channel 2:
merging tile 12/12
Channel 3:
merging tile 12/12
Channel 4:
merging tile 12/12
Cycle 1:
Channel 0:
merging tile 12/12
Channel 1:
merging tile 12/12
Channel 2:
merging tile 12/12
Channel 3:
merging tile 12/12
Channel 4:
merging tile 12/12
Generating pyramid
Level 1 (8229 x 7367)
processing channel 10/10
Level 2 (4115 x 3684)
processing channel 10/10
Level 3 (2058 x 1842)
processing channel 10/10
Level 4 (1029 x 921)
processing channel 10/10
Level 5 (515 x 461)
processing channel 10/10

Thanks for any assistance on this matter. I'm just taking off on vacation so I won't be able to get to responses right away, but I'll follow up on Monday, May 23rd.

Using PyramidWriter in python API

Thanks for all the great work on ashlar so far. The package has been working very well for our application and I wanted to update my workflow to output my results to ome.tiff using your newly added class PyramidWriter. Unfortunately I am having some difficulty in understanding the parameters I need to pass (specifically what the parameters "mosaics" refers to).

I modified my previous code as follows to run with the newest versions of each function and this part seems to be working ok so far.

#define file pattern for reading
pattern = "Row"+ str(RowID) + "_" + "Well" + str(WellID) + "_{channel}_r{row:03}_c{col:03}.tif"

slide = FilePatternReaderRescale(path = input_dir, pattern = pattern, overlap = overlap)
#flip y-axis to comply with labeling generated by opera phenix
process_axis_flip(slide, flip_x=False, flip_y=True)

aligner = reg.EdgeAligner(slide, channel=channel_id, filter_sigma=0, verbose=True, do_make_thumbnail=False)
aligner.run()
aligner.reader._cache = {}

mosaic_args = {}
mosaic_args['verbose'] = True
mosaic = reg.Mosaic(aligner, 
                    aligner.mosaic_shape, 
                    channels = set([0, 1, 2, 3]),
                    **mosaic_args
                    )

I then tried two different options of passing my aligned imaged to the PyramidWriter because I wasn't sure what the parameter "mosaics" refers to, but encountered errors with each approach.

Option 1:

writer = PyramidWriter(mosaic, "test_out.ome.tiff", scale=2, tile_size=1024, peak_size=1024, verbose=True)
writer.run()

This generated the following error message:

---------------------------------------------------------------------------
TypeError                                 Traceback (most recent call last)
Input In [36], in <cell line: 1>()
----> 1 writer = PyramidWriter(mosaic, "test_out.ome.tiff", scale=2, tile_size=1024, peak_size=1024, verbose=True)
      2 writer.run()

File ../ashlar/ashlar/reg.py:1110, in PyramidWriter.__init__(self, mosaics, path, scale, tile_size, peak_size, verbose)
   1107 def __init__(
   1108     self, mosaics, path, scale=2, tile_size=1024, peak_size=1024, verbose=False
   1109 ):
-> 1110     if any(m.shape != mosaics[0].shape for m in mosaics[1:]):
   1111         raise ValueError("mosaics must all have the same shape")
   1112     if tile_size % 16 != 0:

TypeError: 'Mosaic' object is not subscriptable

Option 2:

mosaics = []
for channel in tqdm(mosaic.channels):
    mosaics.append(mosaic.assemble_channel(channel = channel))

writer = PyramidWriter(mosaics, "test_out.ome.tiff", scale=2, tile_size=1024, peak_size=1024, verbose=True)
writer.run()

This generated the following error message:

---------------------------------------------------------------------------
AttributeError                            Traceback (most recent call last)
Input In [35], in <cell line: 1>()
----> 1 writer.run()

File .../ashlar/ashlar/reg.py:1210, in PyramidWriter.run(self)
   1209 def run(self):
-> 1210     dtype = self.ref_mosaic.aligner.metadata.pixel_dtype
   1211     pixel_size = self.ref_mosaic.aligner.metadata.pixel_size
   1212     resolution_cm = 10000 / pixel_size

AttributeError: 'numpy.ndarray' object has no attribute 'aligner'

I am guessing that work documenting the newly added functions is ongoing but if you could give me some insight into what the PyramidWriter is exactly expecting to be passed to it that would be great! Many thanks!

Make single-channel TIFF output files non-tiled by default

ImageJ (and probably other tools) can't read tiled TIFFs without explicitly invoking the BioFormats importer, which is annoying. The default for single-channel TIFFs should be non-tiled, since this format is meant for maximum compatibility after all.

--version argument by itself doesn't show version

Hi, thanks for maintaining this tool. This is a minor bug in Ashlar's CLI. It has a workaround (documented below).

Steps to Repro

When I run ashlar --version, I get the following output instead of a version number:

usage: ashlar [-h] [-o DIR] [-c CHANNEL] [--flip-x] [--flip-y]
              [--flip-mosaic-x] [--flip-mosaic-y]
              [--output-channels [CHANNEL [CHANNEL ...]]] [-m SHIFT]
              [--filter-sigma SIGMA] [-f FORMAT] [--pyramid]
              [--tile-size PIXELS] [--ffp [FILE [FILE ...]]]
              [--dfp [FILE [FILE ...]]] [--plates] [-q] [--version]
              FILE [FILE ...]
ashlar: error: the following arguments are required: FILE

Expected Behavior

I would expect --version to show the version number, much like how --help shows the help screen with no other arguments required.

Workaround

There is a workaround to get the version if placeholder text is entered for the FILE argument, like so:

> ashlar --version placeholdertext
ashlar 1.14.1

Slight tiling shift for subsequent rounds

Hello, great work on ashlar. I noticed a minor tiling shift for subsequent rounds, even if I used the same stack of images. Here is a gif of what I mean. The first image is the DAPI channel of the first round and is stitched pretty well, but the second image is the DAPI channel of the 'second' round (but still equal in values to the first).

original

I took a look through the code and I noticed that if I took out the call to this method, and I ran the code again, the results were as expected, with no shift (this is a gif!).

modified

Here is how I am generating the stitched images:

from pathlib import Path
from typing import List

from ashlar.scripts.ashlar import process_single


def register_cycles(paths: List[Path], dst_template: Path, verbose=True):
    aligner_args = dict(verbose=verbose, filter_sigma=2.0)
    mosaic_args = dict(verbose=verbose)

    process_single(
        [str(p) for p in paths],
        output_path_format=str(dst_template),
        flip_x=False,
        flip_y=False,
        ffp_paths=None,
        dfp_paths=None,
        aligner_args=aligner_args,
        mosaic_args=mosaic_args,
        pyramid=False,
        quiet=not verbose,
    )


def run():
    paths = [
        Path("images/test-stack.ome.tiff"),
        Path("images/test-stack1.ome.tiff"),
    ]
    # dst = Path("stitched") / "original-cycle-{cycle}-channel-{channel}.tif"
    dst = Path("stitched") / "modified-cycle-{cycle}-channel-{channel}.tif"
    dst.parent.mkdir(exist_ok=True, parents=True)
    register_cycles(paths, dst_template=dst)


if __name__ == "__main__":
    run()

I am using the master branch of ashlar, and changing filter_sigma to the default value did not change the result.

Question about FOV (tile) y coordinate

Thank you for this awesome tool! I have tried it with the mcmicro exemplar, and tried it on my own dataset. I could either specify the FOV locations in a grid (I saw that in your source code), or resave my dataset into OME-TIFF with FOV coordinates in the metadata. It seems that ashlar expects a certain orientation of the y FOV coordinate. So when I used BigStitcher on the mcmicro exemplar, the y FOV coordinates are flipped so the tile configuration does not display properly as small values of y is near the bottom while BigStitcher expects large values of y to be near the bottom. Conversely, for my OME-TIFF dataset, which was successfully stitched with BigStitcher, ashlar gave bad results. The grid method still worked. So for Bio-Formats metadata, is there a way to specify which way the y FOV coordinate should go?

Can't run on Ubuntu 20.04 and 18.04

Tried the ashlar on both Ubuntu 18.04 and 20.04 both failed with the exception

Cycle 0:
reading 1.jpg
Traceback (most recent call last):
File "/home/simon/.local/bin/ashlar", line 8, in
sys.exit(main())
File "/home/simon/.local/lib/python3.8/site-packages/ashlar/scripts/ashlar.py", line 171, in main
return process_single(
File "/home/simon/.local/lib/python3.8/site-packages/ashlar/scripts/ashlar.py", line 202, in process_single
reader = build_reader(filepaths[0], plate_well=plate_well)
File "/home/simon/.local/lib/python3.8/site-packages/ashlar/scripts/ashlar.py", line 328, in build_reader
reader = reader_class(path, **kwargs)
File "/home/simon/.local/lib/python3.8/site-packages/ashlar/reg.py", line 391, in init
self.metadata = BioformatsMetadata(self.path)
File "/home/simon/.local/lib/python3.8/site-packages/ashlar/reg.py", line 207, in init
self._init_metadata()
File "/home/simon/.local/lib/python3.8/site-packages/ashlar/reg.py", line 228, in _init_metadata
options.setBoolean('zeissczi.autostitch', False)
File "jnius/jnius_export_class.pxi", line 879, in jnius.JavaMethod.call
File "jnius/jnius_conversion.pxi", line 72, in jnius.populate_args
File "jnius/jnius_utils.pxi", line 205, in jnius.check_assignable_from_str
TypeError: Invalid instance of 'java/lang/Integer' passed for a 'java/lang/Boolean'

Testing command:
ashlar 1.jpg 2.jpg --align-channel 0 --maximum-shift 50 --filter-sigma 1 -f ashlar_output_cycle{cycle}_channel{channel}.ome.tiff

Any clue to fix this?

Use BioFormats 6 pyramid format

The --pyramid option should produce BioFormats 6 compatible OME-TIFF pyramids rather than the existing legacy pyramid format. tifffile has some simple example code for writing subresolutions that we can reference.

using ASHLAR for registering whole slide imaging data

Dear @Yu-AnChen,

based on your post below I just want to add another interested person in registering data from slide scanners. In particular we have an olympus vs200. Output format is vsi but can be converted to tif.
Happy to know more if progress is made on this, or to provide data to test it.
Alvaro

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?

Originally posted by @Yu-AnChen in #99 (comment)

Revisit handling of fractional stage position differences

As of 9ddafc8 we've dropped any accounting for the fractional part of stage position differences when aligning, both in EdgeAligner and LayerAligner. That commit dropped this code in EdgeAligner as part of a larger reworking of the math:

# Add fractional part of offset back in.
offset1, offset2, _ = self.intersection(t1, t2)
shift += np.modf(offset1 - offset2)[0]

We ought to develop a synthetic test case around this. Maybe one where two opposing something-point-9 stage positions add up to a noticeable extra shift of greater than 1 pixel.

Include installing openjdk in the installation

Not sure how common this would be for other users, but for me when trying to install ashlar into new conda environments there is an extra installation I have to do that is not mentioned, namely installing a java jdk. The following suffices:

conda install -c anaconda openjdk

Alternatives to linear blending

Hello,

Is there a way to use alternatives to linear blending when tiles overlap or is this not supported yet?

From the paper:

"Where neighboring image tiles overlap in the mosaic, they are combined with linear blending or one of several other user-selectable blending functions."

Boxes with 0 intensity pixels appear in only one channel after stitching

Hi,

I have been used ashlar to stitch my image (https://datacloud.helsinki.fi/index.php/apps/files/?dir=/Ada&fileid=19217901) and I suddenly realized that one of the channels has boxes with 0.000 intensity pixels in various points of the image, following some pattern. This happens just in the last channel of the last cycle, the rest of the channels in this and other cycles look normal.
ashlar_holes

The tiles do also look normal, you can see a comparison of the area with a tile from a non-affected channel and from the affected one, and these holes in the image are not appreciated.
tiles_119

This is an example on the command I write for the stitching. In this image´s case I did not include the cycle3.
image

Java memory issues

Hi there,

I'm a PhD student using ASHLAR for aligning multiple images generated using a cyclic immunofluorescence protocol on formalin-fixed paraffin-embedded sections. I'm finding that I'm able to align images at 5x resolution from 10+cycles. However, when I try to load in images at 10x resolution, I'm running into java memory issues. Is there a way to pass java options to ashlar to increase the heap size for memory? I should be able to run this on a HPC cluster- if I can increase the heap size, I may be able to load in the higher resolution files using the cluster.
Thanks!
Vinaya

Stitching result only has one stripe

Some of my MCMICRO processed image results are not complete. As one of the examples hta5_1180_1403 shown below, it only has the first column and is missing the rest of the mosaic. I also include some other examples in the screenshot that has horizontal stripe. I am guessing it is the Ashlar step that is failing but I am not sure. Have you ever experienced this before? Is there a way to fix this? Thank you!

Troubleshoot information:

  • I had success on very similar data before. They share the same imaging platform, configure.
  • I thought it might be the insufficient overlap between columns, but 10% overlap worked well on some other dataset.

Screen Shot 2021-07-26 at 12 41 44 PM

Code used:
Screen Shot 2021-07-26 at 1 27 20 PM

Error on mac and linux out of the blue

I have been testing ashlar on linux and was working fine, today I had this error (even trying to run the same thing i did yesterday). Then I installed ashlar on my mac and have the same error.

(ashlar) mac-microscopy1:stitching_registration alvarocrevenna$ ashlar “fileseries|/Users/alvarocrevenna/Documents/Data/2021/stitching_registration|pattern=test_{series}.tif|overlap=0.05|layout=raster|width=5|height=6” --output-channels 0 --maximum-shift 50 --filter-sigma 1 --pyramid -f ashlar_ouput_result.ome.tiff
-bash: /Users/alvarocrevenna/Documents/Data/2021/stitching_registration: is a directory
-bash: --output-channels: command not found
Traceback (most recent call last):
File "/opt/anaconda3/envs/ashlar/bin/ashlar", line 8, in
sys.exit(main())
File "/opt/anaconda3/envs/ashlar/lib/python3.7/site-packages/ashlar/scripts/ashlar.py", line 174, in main
args.quiet
File "/opt/anaconda3/envs/ashlar/lib/python3.7/site-packages/ashlar/scripts/ashlar.py", line 202, in process_single
reader = build_reader(filepaths[0], plate_well=plate_well)
File "/opt/anaconda3/envs/ashlar/lib/python3.7/site-packages/ashlar/scripts/ashlar.py", line 328, in build_reader
reader = reader_class(path, **kwargs)
File "/opt/anaconda3/envs/ashlar/lib/python3.7/site-packages/ashlar/reg.py", line 391, in init
self.metadata = BioformatsMetadata(self.path)
File "/opt/anaconda3/envs/ashlar/lib/python3.7/site-packages/ashlar/reg.py", line 207, in init
self._init_metadata()
File "/opt/anaconda3/envs/ashlar/lib/python3.7/site-packages/ashlar/reg.py", line 231, in _init_metadata
self._reader.setId(self.path)
File "jnius/jnius_export_class.pxi", line 769, in jnius.JavaMethod.call
File "jnius/jnius_export_class.pxi", line 863, in jnius.JavaMethod.call_method
File "jnius/jnius_utils.pxi", line 91, in jnius.check_exception
jnius.JavaException: JVM exception occurred: “fileseries (No such file or directory)
Exception ignored in: <_io.TextIOWrapper name='' mode='w' encoding='UTF-8'>
BrokenPipeError: [Errno 32] Broken pipe

Any idea?
thanks, Alvaro

Completely white image output; no data in output file

Hi,

I'm invoking ASHLAR on a 6x8 3-cycle 4-channel dataset made up of 32-bit single-channel TIFs named like so:

med_c0_s00_RAW_ch01.tif
...
med_c0_s47_RAW_ch03.tif

If I use this command:

ashlar "fileseries|./raw|pattern=med_c0_s{series:2}_RAW_ch{channel:2}.tif|overlap=0.2|width=6|height=8" --align-channel 0

I get output files of correct dimensions cycle_0_channel_0.tif but these files are 'empty', for lack of a better word. FIJI loads it as a 32-bit tiff with a value of 1.0 for each pixel. Inspecting with a hex editor shows that the file is indeed devoid of any data. What's going on?

EDIT: If i convert the images to 16-bit first, I get the expected output!

Migrate to 1-based indexing

We converged on 1-based indexing for all mcmicro tools.
Incorporate 1-based convention into --align-channel and --output-channels parameters.

Question regarding registration

ashlar/ashlar/utils.py

Lines 34 to 46 in 2587ea6

# At this point we may have a shift in the wrong quadrant since the FFT
# assumes the signal is periodic. We test all four possibilities and return
# the shift that gives the highest direct correlation (sum of products).
shape = np.array(img1.shape)
shift_pos = (shift + shape) % shape
shift_neg = shift_pos - shape
shifts = list(itertools.product(*zip(shift_pos, shift_neg)))
correlations = [
np.abs(np.sum(img1w * scipy.ndimage.shift(img2w, s, order=0)))
for s in shifts
]
idx = np.argmax(correlations)
shift = shifts[idx]

Hello, I have a question regarding the above code chunk.

I got erroneous results from ASHLAR's registration in my initial tests. ASHLAR did not report any errors but the output images were translated by large distances, much greater than the true offsets. This didn't happen with all the images but only some. Hence, I looked into the python scripts. The above code chunk is testing four possible offsets to account for cases with "shift in the wrong quadrant" as described in the comment. The tested shifts include large offsets. That seems to be the source of issue. Can you please check? For example, if shift = [2, 3], and img1.shape = [1080, 1080], running the lines 37-40 above gives:

>>> shifts
[(2, 3), (2, -1077), (-1078, 3), (-1078, -1077)]

Is this expected?

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.