<?xml version='1.0' encoding='UTF-8'?>
<feed xmlns="http://www.w3.org/2005/Atom" xml:lang="en">
  <id>https://blog.dask.org</id>
  <title>Dask Working Notes - Posts tagged image analysis</title>
  <updated>2026-03-05T15:05:26.402401+00:00</updated>
  <link href="https://blog.dask.org"/>
  <link href="https://blog.dask.org/blog/tag/image-analysis/atom.xml" rel="self"/>
  <generator uri="https://ablog.readthedocs.io/" version="0.11.12">ABlog</generator>
  <entry>
    <id>https://blog.dask.org/2021/12/01/mosaic-fusion/</id>
    <title>Mosaic Image Fusion</title>
    <updated>2021-12-01T00:00:00+00:00</updated>
    <author>
      <name>and Genevieve Buckley</name>
    </author>
    <content type="html">&lt;aside class="system-message"&gt;
&lt;p class="system-message-title"&gt;System Message: WARNING/2 (&lt;span class="docutils literal"&gt;/opt/build/repo/2021/12/01/mosaic-fusion.md&lt;/span&gt;, line 9)&lt;/p&gt;
&lt;p&gt;Document headings start at H2, not H1 [myst.header]&lt;/p&gt;
&lt;/aside&gt;
&lt;section id="executive-summary"&gt;

&lt;p&gt;This blogpost shows a case study where a researcher uses Dask for mosaic image fusion.
Mosaic image fusion is when you combine multiple smaller images taken at known locations and stitch them together into a single image with a very large field of view. Full code examples are available on GitHub from the &lt;a class="reference external" href="https://github.com/VolkerH/DaskFusion"&gt;&lt;code class="docutils literal notranslate"&gt;&lt;span class="pre"&gt;DaskFusion&lt;/span&gt;&lt;/code&gt;&lt;/a&gt; repository:
&lt;a class="github reference external" href="https://github.com/VolkerH/DaskFusion"&gt;VolkerH/DaskFusion&lt;/a&gt;&lt;/p&gt;
&lt;aside class="system-message"&gt;
&lt;p class="system-message-title"&gt;System Message: WARNING/2 (&lt;span class="docutils literal"&gt;/opt/build/repo/2021/12/01/mosaic-fusion.md&lt;/span&gt;, line 15)&lt;/p&gt;
&lt;p&gt;Document headings start at H2, not H1 [myst.header]&lt;/p&gt;
&lt;/aside&gt;
&lt;/section&gt;
&lt;section id="the-problem"&gt;
&lt;h1&gt;The problem&lt;/h1&gt;
&lt;section id="image-mosaicing-in-microscopy"&gt;
&lt;h2&gt;Image mosaicing in microscopy&lt;/h2&gt;
&lt;p&gt;In optical microscopy, a single field of view captured with a 20x objective typically
has a diagonal on the order of a few 100 μm (exact dimensions depend on other
parts of the optical system, including the size of the camera chip). A typical
sample slide has a size of 25mm by 75mm.
Therefore, when imaging a whole slide, one has to acquire hundreds of images, typically
with some overlap between individual tiles. With increasing magnification,
the required number of images increases accordingly.&lt;/p&gt;
&lt;p&gt;To obtain an overview one has to fuse this large number of individual
image tiles into a large mosaic image. Here, we assume that the information required for
positioning and alignment of the individual image tiles is known. In the example presented here,
this information is available as metadata recorded by the microscope, namely the microscope stage
position and the pixel scale. Alternatively, this
information could also be derived from the image data directly, e.g. through a
registration step that matches corresponding image features in the areas where tiles overlap.&lt;/p&gt;
&lt;aside class="system-message"&gt;
&lt;p class="system-message-title"&gt;System Message: WARNING/2 (&lt;span class="docutils literal"&gt;/opt/build/repo/2021/12/01/mosaic-fusion.md&lt;/span&gt;, line 35)&lt;/p&gt;
&lt;p&gt;Document headings start at H2, not H1 [myst.header]&lt;/p&gt;
&lt;/aside&gt;
&lt;/section&gt;
&lt;/section&gt;
&lt;section id="the-solution"&gt;
&lt;h1&gt;The solution&lt;/h1&gt;
&lt;p&gt;The array that can hold the resulting mosaic image will often have a size that is too large
to fit in RAM, therefore we will use Dask arrays and the &lt;a class="reference external" href="https://docs.dask.org/en/latest/generated/dask.array.map_blocks.html"&gt;&lt;code class="docutils literal notranslate"&gt;&lt;span class="pre"&gt;map_blocks&lt;/span&gt;&lt;/code&gt;&lt;/a&gt; function to enable
out-of-core processing. The &lt;a class="reference external" href="https://docs.dask.org/en/latest/generated/dask.array.map_blocks.html"&gt;&lt;code class="docutils literal notranslate"&gt;&lt;span class="pre"&gt;map_blocks&lt;/span&gt;&lt;/code&gt;&lt;/a&gt;
function will process smaller blocks (a.k.a chunks) of the output array individually, thus eliminating the need to
hold the whole output array in memory. If sufficient resources are available, dask will also distribute the processing of blocks across several workers,
thus we also get parallel processing for free, which can help speed up the fusion process.&lt;/p&gt;
&lt;p&gt;Typically whenever we want to join Dask arrays, we use &lt;a class="reference external" href="https://docs.dask.org/en/latest/array-stack.html"&gt;Stack, Concatenate, and Block&lt;/a&gt;. However, these are not good tools for mosaic image fusion, because:&lt;/p&gt;
&lt;ol class="arabic simple"&gt;
&lt;li&gt;&lt;p&gt;The image tiles will be be overlapping,&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Tiles may not be positioned on an exact grid and will typically also have slight rotations as the alignment of stage and camera is not perfect. In the most general case, for example in panaromic photo mosaics,
individual image tiles could be arbitrarily rotated or skewed.&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;The starting point for this mosaic prototype was some code that reads in the stage metadate for all tiles and calculates an affine transformation for each tile that would place it at the correct location
in the output array.&lt;/p&gt;
&lt;p&gt;The image below shows preliminary work placing mosaic image tiles into the correct positions using the napari image viewer.
Shown here is a small example with 63 image tiles.&lt;/p&gt;
&lt;img src="/images/mosaic-fusion/NapariMosaics.png" alt="Mosaic fusion images in the napari image viewer" width="700" height="265"&gt;
&lt;p&gt;And here is an animation of placing the individual tiles.&lt;/p&gt;
&lt;img src="/images/mosaic-fusion/Lama_whole_slide.gif" alt="Animation of whole slide mosaic fusion images" width="700" height="361"&gt;
&lt;p&gt;To leverage processing with Dask we created a &lt;code class="docutils literal notranslate"&gt;&lt;span class="pre"&gt;fuse&lt;/span&gt;&lt;/code&gt; function that generates a small block of the final mosaic and is invoked by &lt;code class="docutils literal notranslate"&gt;&lt;span class="pre"&gt;map_blocks&lt;/span&gt;&lt;/code&gt; for each chunk of the output array.
On each invocation of the &lt;code class="docutils literal notranslate"&gt;&lt;span class="pre"&gt;fuse&lt;/span&gt;&lt;/code&gt; function &lt;code class="docutils literal notranslate"&gt;&lt;span class="pre"&gt;map_blocks&lt;/span&gt;&lt;/code&gt; passes a dictionary (&lt;code class="docutils literal notranslate"&gt;&lt;span class="pre"&gt;block_info&lt;/span&gt;&lt;/code&gt;). From the &lt;a class="reference external" href="https://docs.dask.org/en/latest/generated/dask.array.map_blocks.html?highlight=block_info#dask.array.map_blocks"&gt;Dask documentation&lt;/a&gt;:&lt;/p&gt;
&lt;blockquote&gt;
&lt;div&gt;&lt;p&gt;Your block function gets information about where it is in the array by accepting a special &lt;code class="docutils literal notranslate"&gt;&lt;span class="pre"&gt;block_info&lt;/span&gt;&lt;/code&gt; or &lt;code class="docutils literal notranslate"&gt;&lt;span class="pre"&gt;block_id&lt;/span&gt;&lt;/code&gt; keyword argument.&lt;/p&gt;
&lt;/div&gt;&lt;/blockquote&gt;
&lt;p&gt;The basic outline of the &lt;code class="docutils literal notranslate"&gt;&lt;span class="pre"&gt;fuse&lt;/span&gt;&lt;/code&gt; function of the mosaic workflow is as follows.
For each chunk of the output array:&lt;/p&gt;
&lt;ol class="arabic simple"&gt;
&lt;li&gt;&lt;p&gt;Determine which source image tiles intersect with the chunk.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Adjust the image tiles’ affine transformations to take the offset of the chunk within the array into account.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Load all intersectiong image tiles and apply their respective adjusted affine transformation to map them into the chunk.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Blend the tiles using a simple maximum projection.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Return the blended chunk.&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;Using a maximum projection to blend areas with overlapping tiles can lead to artifacts such as ghost images and visible tile
seams, so you would typically want to use something more sophisticated in production.&lt;/p&gt;
&lt;section id="results"&gt;
&lt;h2&gt;Results&lt;/h2&gt;
&lt;p&gt;For datasets with many image tiles (~500-1000 tiles), we could speed up the mosaic generation from several hours to tens of minutes using this Dask based method
(compared to a previous workflow using ImageJ plugins runnning on the same workstation).
Due to Dask’s ability to handle data out-of-core and chunked array storage using zarr it is also possible to run the
fusion on hardware with limited RAM.&lt;/p&gt;
&lt;p&gt;Finally, we have the final mosaic fusion result.&lt;/p&gt;
&lt;img src="/images/mosaic-fusion/final-mosaic-fusion-result.png" alt="Final mosaic fusion result" width="700" height="486"&gt;
&lt;/section&gt;
&lt;section id="code"&gt;
&lt;h2&gt;Code&lt;/h2&gt;
&lt;p&gt;Code relatiing to this mosaic image fusion project can be found in the &lt;a class="reference external" href="https://github.com/VolkerH/DaskFusion"&gt;&lt;code class="docutils literal notranslate"&gt;&lt;span class="pre"&gt;DaskFusion&lt;/span&gt;&lt;/code&gt;&lt;/a&gt; GitHub repository here:
&lt;a class="github reference external" href="https://github.com/VolkerH/DaskFusion"&gt;VolkerH/DaskFusion&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;There is a self-contained example available in &lt;a class="reference external" href="https://github.com/VolkerH/DaskFusion/blob/main/DaskFusion_Example.ipynb"&gt;this notebook&lt;/a&gt;, which downloads reduced-size example data to demonstrate the process.&lt;/p&gt;
&lt;aside class="system-message"&gt;
&lt;p class="system-message-title"&gt;System Message: WARNING/2 (&lt;span class="docutils literal"&gt;/opt/build/repo/2021/12/01/mosaic-fusion.md&lt;/span&gt;, line 97)&lt;/p&gt;
&lt;p&gt;Document headings start at H2, not H1 [myst.header]&lt;/p&gt;
&lt;/aside&gt;
&lt;/section&gt;
&lt;/section&gt;
&lt;section id="what-s-next"&gt;
&lt;h1&gt;What’s next?&lt;/h1&gt;
&lt;p&gt;Currently, the DaskFusion code is a proof of concept for single-channel 2D images and simple maximum projection for blending the tiles in overlapping areas, it is not production code.
However, the same principle can be used for fusing multi-channel image volumes,
such as from Light-Sheet data if the tile chunk intersection calculation is extended to higher-dimensional arrays.
Such even larger datasets will benefit even more from leveraging dask,
as the processing can be distributed across multiple nodes of a HPC cluster using &lt;a class="reference external" href="http://jobqueue.dask.org/en/latest/"&gt;dask jobqueue&lt;/a&gt;.&lt;/p&gt;
&lt;section id="also-see"&gt;
&lt;h2&gt;Also see&lt;/h2&gt;
&lt;p&gt;Marvin’s lightning talk on multi-view image fusion:
&lt;a class="reference external" href="https://www.youtube.com/watch?v=YIblUvonMvo&amp;amp;amp;list=PLJ0vO2F_f6OBAY6hjRHM_mIQ9yh32mWr0&amp;amp;amp;index=10"&gt;15 minute video available here on YouTube&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;The GitHub repository &lt;a class="reference external" href="https://github.com/m-albert/MVRegFus"&gt;MVRegFus&lt;/a&gt; that Marvin talks about in the video is available here:
&lt;a class="github reference external" href="https://github.com/m-albert/MVRegFus"&gt;m-albert/MVRegFus&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;The &lt;a class="reference external" href="https://github.com/manzt/napari-lazy-openslide"&gt;napari-lazy-openslide&lt;/a&gt; visualization plugin by &lt;a class="reference external" href="https://github.com/manzt"&gt;Trevor Manz&lt;/a&gt;: &lt;em&gt;“An experimental plugin to lazily load multiscale whole-slide tiff images with openslide and dask.”&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;For further information on alternative approaches to image stitching:&lt;/p&gt;
&lt;ul class="simple"&gt;
&lt;li&gt;&lt;p&gt;ASHLAR: Alignment by Simultaneous Harmonization of Layer / Adjacency Registration&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;p&gt;&lt;a class="reference external" href="https://labsyspharm.github.io/ashlar/"&gt;ASHLAR homepage&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;a class="reference external" href="https://github.com/labsyspharm/ashlar"&gt;ASHLAR GitHub repository&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;a class="reference external" href="https://doi.org/10.1101/2021.04.20.440625"&gt;ASHLAR biorxiv pre-print&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Microscopy Image Stitching Tool (MIST)&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;p&gt;&lt;a class="reference external" href="https://pages.nist.gov/MIST/"&gt;MIST homepage&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;a class="reference external" href="https://github.com/usnistgov/MIST"&gt;MIST GitHub repository&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;a class="reference external" href="https://raw.githubusercontent.com/wiki/USNISTGOV/MIST/assets/mist-algorithm-documentation.pdf"&gt;MIST algorithm documentation (PDF)&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;The &lt;a class="reference external" href="https://github.com/yfukai/m2stitch"&gt;m2stitch&lt;/a&gt; python package by &lt;a class="reference external" href="https://github.com/yfukai"&gt;Yohsuke T. Fukai&lt;/a&gt;: &lt;em&gt;“Provides robust stitching of tiled microscope images on a regular grid”&lt;/em&gt; (based on the MIST algorithm)&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;aside class="system-message"&gt;
&lt;p class="system-message-title"&gt;System Message: WARNING/2 (&lt;span class="docutils literal"&gt;/opt/build/repo/2021/12/01/mosaic-fusion.md&lt;/span&gt;, line 127)&lt;/p&gt;
&lt;p&gt;Document headings start at H2, not H1 [myst.header]&lt;/p&gt;
&lt;/aside&gt;
&lt;/section&gt;
&lt;/section&gt;
&lt;section id="acknowledgements"&gt;
&lt;h1&gt;Acknowledgements&lt;/h1&gt;
&lt;p&gt;This computational work was done by Volker Hilsenstein, in conjunction with Marvin Albert.
Volker Hilsenstein is a scientific software developer at &lt;a class="reference external" href="https://www.embl.org/groups/alexandrov/"&gt;EMBL in Theodore Alexandrov’s lab&lt;/a&gt; with a focus on spatial metabolomics and bio-image analysis.&lt;/p&gt;
&lt;p&gt;The sample images were prepared and imaged by Mohammed Shahraz from the Alexandrov lab at EMBL Heidelberg.&lt;/p&gt;
&lt;p&gt;Genevieve Buckley and Volker Hilsenstein wrote this blogpost.&lt;/p&gt;
&lt;/section&gt;
</content>
    <link href="https://blog.dask.org/2021/12/01/mosaic-fusion/"/>
    <summary>Document headings start at H2, not H1 [myst.header]</summary>
    <category term="imageanalysis" label="image analysis"/>
    <category term="lifescience" label="life science"/>
    <published>2021-12-01T00:00:00+00:00</published>
  </entry>
</feed>
