<?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 by John Kirkham</title>
  <updated>2026-03-05T15:05:19.850120+00:00</updated>
  <link href="https://blog.dask.org"/>
  <link href="https://blog.dask.org/blog/author/john-kirkham/atom.xml" rel="self"/>
  <generator uri="https://ablog.readthedocs.io/" version="0.11.12">ABlog</generator>
  <entry>
    <id>https://blog.dask.org/2019/08/09/image-itk/</id>
    <title>Dask and ITK for large scale image analysis</title>
    <updated>2019-08-09T00:00:00+00:00</updated>
    <author>
      <name>Matthew McCormick</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/2019/08/09/image-itk.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 post explores using the &lt;a class="reference external" href="https://www.itk.org"&gt;ITK&lt;/a&gt; suite of image processing utilities in parallel with Dask Array.&lt;/p&gt;
&lt;p&gt;We cover …&lt;/p&gt;
&lt;ol class="arabic simple"&gt;
&lt;li&gt;&lt;p&gt;A simple but common example of applying deconvolution across a stack of 3d images&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Tips on how to make these two libraries work well together&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Challenges that we ran into and opportunities for future improvements.&lt;/p&gt;&lt;/li&gt;
&lt;/ol&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/2019/08/09/image-itk.md&lt;/span&gt;, line 19)&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="a-worked-example"&gt;
&lt;h1&gt;A Worked Example&lt;/h1&gt;
&lt;p&gt;Let’s start with a full example applying Richardson Lucy deconvolution to a
stack of light sheet microscopy data. This is the same data that we showed how
to load in our &lt;a class="reference external" href="https://blog.dask.org/2019/06/20/load-image-data"&gt;last blogpost on image loading&lt;/a&gt;.
You can &lt;a class="reference external" href="https://drive.google.com/drive/folders/13mpIfqspKTIINkfoWbFsVtFF8D7jbTqJ"&gt;access the data as tiff files from google drive here&lt;/a&gt;, and the access the &lt;a class="reference external" href="https://drive.google.com/drive/folders/13udO-h9epItG5MNWBp0VxBkKCllYBLQF"&gt;corresponding point spread function images here&lt;/a&gt;.&lt;/p&gt;
&lt;div class="highlight-python notranslate"&gt;&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span class="c1"&gt;# Load our data from last time¶&lt;/span&gt;
&lt;span class="kn"&gt;import&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nn"&gt;dask.array&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;as&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nn"&gt;da&lt;/span&gt;
&lt;span class="n"&gt;imgs&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;da&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;from_zarr&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;AOLLSMData_m4_raw.zarr/&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s2"&gt;&amp;quot;data&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;table&gt;
&lt;tr&gt;
&lt;td&gt;
&lt;table&gt;  &lt;thead&gt;    &lt;tr&gt;&lt;td&gt; &lt;/td&gt;&lt;th&gt; Array &lt;/th&gt;&lt;th&gt; Chunk &lt;/th&gt;&lt;/tr&gt;
  &lt;/thead&gt;
  &lt;tbody&gt;
    &lt;tr&gt;&lt;th&gt; Bytes &lt;/th&gt;&lt;td&gt; 188.74 GB &lt;/td&gt; &lt;td&gt; 316.15 MB &lt;/td&gt;&lt;/tr&gt;
    &lt;tr&gt;&lt;th&gt; Shape &lt;/th&gt;&lt;td&gt; (3, 199, 201, 1024, 768) &lt;/td&gt; &lt;td&gt; (1, 1, 201, 1024, 768) &lt;/td&gt;&lt;/tr&gt;
    &lt;tr&gt;&lt;th&gt; Count &lt;/th&gt;&lt;td&gt; 598 Tasks &lt;/td&gt;&lt;td&gt; 597 Chunks &lt;/td&gt;&lt;/tr&gt;
    &lt;tr&gt;&lt;th&gt; Type &lt;/th&gt;&lt;td&gt; uint16 &lt;/td&gt;&lt;td&gt; numpy.ndarray &lt;/td&gt;&lt;/tr&gt;
  &lt;/tbody&gt;&lt;/table&gt;
&lt;/td&gt;
&lt;td&gt;
&lt;svg width="404" height="206" style="stroke:rgb(0,0,0);stroke-width:1" &gt;
  &lt;!-- Horizontal lines --&gt;
  &lt;line x1="0" y1="0" x2="45" y2="0" style="stroke-width:2" /&gt;
  &lt;line x1="0" y1="9" x2="45" y2="9" /&gt;
  &lt;line x1="0" y1="18" x2="45" y2="18" /&gt;
  &lt;line x1="0" y1="27" x2="45" y2="27" style="stroke-width:2" /&gt;
  &lt;!-- Vertical lines --&gt;
  &lt;line x1="0" y1="0" x2="0" y2="27" style="stroke-width:2" /&gt;
  &lt;line x1="0" y1="0" x2="0" y2="27" /&gt;
  &lt;line x1="0" y1="0" x2="0" y2="27" /&gt;
  &lt;line x1="0" y1="0" x2="0" y2="27" /&gt;
  &lt;line x1="0" y1="0" x2="0" y2="27" /&gt;
  &lt;line x1="1" y1="0" x2="1" y2="27" /&gt;
  &lt;line x1="1" y1="0" x2="1" y2="27" /&gt;
  &lt;line x1="1" y1="0" x2="1" y2="27" /&gt;
  &lt;line x1="1" y1="0" x2="1" y2="27" /&gt;
  &lt;line x1="2" y1="0" x2="2" y2="27" /&gt;
  &lt;line x1="2" y1="0" x2="2" y2="27" /&gt;
  &lt;line x1="2" y1="0" x2="2" y2="27" /&gt;
  &lt;line x1="2" y1="0" x2="2" y2="27" /&gt;
  &lt;line x1="2" y1="0" x2="2" y2="27" /&gt;
  &lt;line x1="3" y1="0" x2="3" y2="27" /&gt;
  &lt;line x1="3" y1="0" x2="3" y2="27" /&gt;
  &lt;line x1="3" y1="0" x2="3" y2="27" /&gt;
  &lt;line x1="3" y1="0" x2="3" y2="27" /&gt;
  &lt;line x1="4" y1="0" x2="4" y2="27" /&gt;
  &lt;line x1="4" y1="0" x2="4" y2="27" /&gt;
  &lt;line x1="4" y1="0" x2="4" y2="27" /&gt;
  &lt;line x1="4" y1="0" x2="4" y2="27" /&gt;
  &lt;line x1="5" y1="0" x2="5" y2="27" /&gt;
  &lt;line x1="5" y1="0" x2="5" y2="27" /&gt;
  &lt;line x1="5" y1="0" x2="5" y2="27" /&gt;
  &lt;line x1="5" y1="0" x2="5" y2="27" /&gt;
  &lt;line x1="5" y1="0" x2="5" y2="27" /&gt;
  &lt;line x1="6" y1="0" x2="6" y2="27" /&gt;
  &lt;line x1="6" y1="0" x2="6" y2="27" /&gt;
  &lt;line x1="6" y1="0" x2="6" y2="27" /&gt;
  &lt;line x1="6" y1="0" x2="6" y2="27" /&gt;
  &lt;line x1="7" y1="0" x2="7" y2="27" /&gt;
  &lt;line x1="7" y1="0" x2="7" y2="27" /&gt;
  &lt;line x1="7" y1="0" x2="7" y2="27" /&gt;
  &lt;line x1="7" y1="0" x2="7" y2="27" /&gt;
  &lt;line x1="7" y1="0" x2="7" y2="27" /&gt;
  &lt;line x1="8" y1="0" x2="8" y2="27" /&gt;
  &lt;line x1="8" y1="0" x2="8" y2="27" /&gt;
  &lt;line x1="8" y1="0" x2="8" y2="27" /&gt;
  &lt;line x1="8" y1="0" x2="8" y2="27" /&gt;
  &lt;line x1="9" y1="0" x2="9" y2="27" /&gt;
  &lt;line x1="9" y1="0" x2="9" y2="27" /&gt;
  &lt;line x1="9" y1="0" x2="9" y2="27" /&gt;
  &lt;line x1="9" y1="0" x2="9" y2="27" /&gt;
  &lt;line x1="10" y1="0" x2="10" y2="27" /&gt;
  &lt;line x1="10" y1="0" x2="10" y2="27" /&gt;
  &lt;line x1="10" y1="0" x2="10" y2="27" /&gt;
  &lt;line x1="10" y1="0" x2="10" y2="27" /&gt;
  &lt;line x1="10" y1="0" x2="10" y2="27" /&gt;
  &lt;line x1="11" y1="0" x2="11" y2="27" /&gt;
  &lt;line x1="11" y1="0" x2="11" y2="27" /&gt;
  &lt;line x1="11" y1="0" x2="11" y2="27" /&gt;
  &lt;line x1="11" y1="0" x2="11" y2="27" /&gt;
  &lt;line x1="12" y1="0" x2="12" y2="27" /&gt;
  &lt;line x1="12" y1="0" x2="12" y2="27" /&gt;
  &lt;line x1="12" y1="0" x2="12" y2="27" /&gt;
  &lt;line x1="12" y1="0" x2="12" y2="27" /&gt;
  &lt;line x1="12" y1="0" x2="12" y2="27" /&gt;
  &lt;line x1="13" y1="0" x2="13" y2="27" /&gt;
  &lt;line x1="13" y1="0" x2="13" y2="27" /&gt;
  &lt;line x1="13" y1="0" x2="13" y2="27" /&gt;
  &lt;line x1="13" y1="0" x2="13" y2="27" /&gt;
  &lt;line x1="14" y1="0" x2="14" y2="27" /&gt;
  &lt;line x1="14" y1="0" x2="14" y2="27" /&gt;
  &lt;line x1="14" y1="0" x2="14" y2="27" /&gt;
  &lt;line x1="14" y1="0" x2="14" y2="27" /&gt;
  &lt;line x1="15" y1="0" x2="15" y2="27" /&gt;
  &lt;line x1="15" y1="0" x2="15" y2="27" /&gt;
  &lt;line x1="15" y1="0" x2="15" y2="27" /&gt;
  &lt;line x1="15" y1="0" x2="15" y2="27" /&gt;
  &lt;line x1="15" y1="0" x2="15" y2="27" /&gt;
  &lt;line x1="16" y1="0" x2="16" y2="27" /&gt;
  &lt;line x1="16" y1="0" x2="16" y2="27" /&gt;
  &lt;line x1="16" y1="0" x2="16" y2="27" /&gt;
  &lt;line x1="16" y1="0" x2="16" y2="27" /&gt;
  &lt;line x1="17" y1="0" x2="17" y2="27" /&gt;
  &lt;line x1="17" y1="0" x2="17" y2="27" /&gt;
  &lt;line x1="17" y1="0" x2="17" y2="27" /&gt;
  &lt;line x1="17" y1="0" x2="17" y2="27" /&gt;
  &lt;line x1="18" y1="0" x2="18" y2="27" /&gt;
  &lt;line x1="18" y1="0" x2="18" y2="27" /&gt;
  &lt;line x1="18" y1="0" x2="18" y2="27" /&gt;
  &lt;line x1="18" y1="0" x2="18" y2="27" /&gt;
  &lt;line x1="18" y1="0" x2="18" y2="27" /&gt;
  &lt;line x1="19" y1="0" x2="19" y2="27" /&gt;
  &lt;line x1="19" y1="0" x2="19" y2="27" /&gt;
  &lt;line x1="19" y1="0" x2="19" y2="27" /&gt;
  &lt;line x1="19" y1="0" x2="19" y2="27" /&gt;
  &lt;line x1="20" y1="0" x2="20" y2="27" /&gt;
  &lt;line x1="20" y1="0" x2="20" y2="27" /&gt;
  &lt;line x1="20" y1="0" x2="20" y2="27" /&gt;
  &lt;line x1="20" y1="0" x2="20" y2="27" /&gt;
  &lt;line x1="20" y1="0" x2="20" y2="27" /&gt;
  &lt;line x1="21" y1="0" x2="21" y2="27" /&gt;
  &lt;line x1="21" y1="0" x2="21" y2="27" /&gt;
  &lt;line x1="21" y1="0" x2="21" y2="27" /&gt;
  &lt;line x1="21" y1="0" x2="21" y2="27" /&gt;
  &lt;line x1="22" y1="0" x2="22" y2="27" /&gt;
  &lt;line x1="22" y1="0" x2="22" y2="27" /&gt;
  &lt;line x1="22" y1="0" x2="22" y2="27" /&gt;
  &lt;line x1="22" y1="0" x2="22" y2="27" /&gt;
  &lt;line x1="23" y1="0" x2="23" y2="27" /&gt;
  &lt;line x1="23" y1="0" x2="23" y2="27" /&gt;
  &lt;line x1="23" y1="0" x2="23" y2="27" /&gt;
  &lt;line x1="23" y1="0" x2="23" y2="27" /&gt;
  &lt;line x1="23" y1="0" x2="23" y2="27" /&gt;
  &lt;line x1="24" y1="0" x2="24" y2="27" /&gt;
  &lt;line x1="24" y1="0" x2="24" y2="27" /&gt;
  &lt;line x1="24" y1="0" x2="24" y2="27" /&gt;
  &lt;line x1="24" y1="0" x2="24" y2="27" /&gt;
  &lt;line x1="25" y1="0" x2="25" y2="27" /&gt;
  &lt;line x1="25" y1="0" x2="25" y2="27" /&gt;
  &lt;line x1="25" y1="0" x2="25" y2="27" /&gt;
  &lt;line x1="25" y1="0" x2="25" y2="27" /&gt;
  &lt;line x1="25" y1="0" x2="25" y2="27" /&gt;
  &lt;line x1="26" y1="0" x2="26" y2="27" /&gt;
  &lt;line x1="26" y1="0" x2="26" y2="27" /&gt;
  &lt;line x1="26" y1="0" x2="26" y2="27" /&gt;
  &lt;line x1="26" y1="0" x2="26" y2="27" /&gt;
  &lt;line x1="27" y1="0" x2="27" y2="27" /&gt;
  &lt;line x1="27" y1="0" x2="27" y2="27" /&gt;
  &lt;line x1="27" y1="0" x2="27" y2="27" /&gt;
  &lt;line x1="27" y1="0" x2="27" y2="27" /&gt;
  &lt;line x1="28" y1="0" x2="28" y2="27" /&gt;
  &lt;line x1="28" y1="0" x2="28" y2="27" /&gt;
  &lt;line x1="28" y1="0" x2="28" y2="27" /&gt;
  &lt;line x1="28" y1="0" x2="28" y2="27" /&gt;
  &lt;line x1="28" y1="0" x2="28" y2="27" /&gt;
  &lt;line x1="29" y1="0" x2="29" y2="27" /&gt;
  &lt;line x1="29" y1="0" x2="29" y2="27" /&gt;
  &lt;line x1="29" y1="0" x2="29" y2="27" /&gt;
  &lt;line x1="29" y1="0" x2="29" y2="27" /&gt;
  &lt;line x1="30" y1="0" x2="30" y2="27" /&gt;
  &lt;line x1="30" y1="0" x2="30" y2="27" /&gt;
  &lt;line x1="30" y1="0" x2="30" y2="27" /&gt;
  &lt;line x1="30" y1="0" x2="30" y2="27" /&gt;
  &lt;line x1="31" y1="0" x2="31" y2="27" /&gt;
  &lt;line x1="31" y1="0" x2="31" y2="27" /&gt;
  &lt;line x1="31" y1="0" x2="31" y2="27" /&gt;
  &lt;line x1="31" y1="0" x2="31" y2="27" /&gt;
  &lt;line x1="31" y1="0" x2="31" y2="27" /&gt;
  &lt;line x1="32" y1="0" x2="32" y2="27" /&gt;
  &lt;line x1="32" y1="0" x2="32" y2="27" /&gt;
  &lt;line x1="32" y1="0" x2="32" y2="27" /&gt;
  &lt;line x1="32" y1="0" x2="32" y2="27" /&gt;
  &lt;line x1="33" y1="0" x2="33" y2="27" /&gt;
  &lt;line x1="33" y1="0" x2="33" y2="27" /&gt;
  &lt;line x1="33" y1="0" x2="33" y2="27" /&gt;
  &lt;line x1="33" y1="0" x2="33" y2="27" /&gt;
  &lt;line x1="33" y1="0" x2="33" y2="27" /&gt;
  &lt;line x1="34" y1="0" x2="34" y2="27" /&gt;
  &lt;line x1="34" y1="0" x2="34" y2="27" /&gt;
  &lt;line x1="34" y1="0" x2="34" y2="27" /&gt;
  &lt;line x1="34" y1="0" x2="34" y2="27" /&gt;
  &lt;line x1="35" y1="0" x2="35" y2="27" /&gt;
  &lt;line x1="35" y1="0" x2="35" y2="27" /&gt;
  &lt;line x1="35" y1="0" x2="35" y2="27" /&gt;
  &lt;line x1="35" y1="0" x2="35" y2="27" /&gt;
  &lt;line x1="36" y1="0" x2="36" y2="27" /&gt;
  &lt;line x1="36" y1="0" x2="36" y2="27" /&gt;
  &lt;line x1="36" y1="0" x2="36" y2="27" /&gt;
  &lt;line x1="36" y1="0" x2="36" y2="27" /&gt;
  &lt;line x1="36" y1="0" x2="36" y2="27" /&gt;
  &lt;line x1="37" y1="0" x2="37" y2="27" /&gt;
  &lt;line x1="37" y1="0" x2="37" y2="27" /&gt;
  &lt;line x1="37" y1="0" x2="37" y2="27" /&gt;
  &lt;line x1="37" y1="0" x2="37" y2="27" /&gt;
  &lt;line x1="38" y1="0" x2="38" y2="27" /&gt;
  &lt;line x1="38" y1="0" x2="38" y2="27" /&gt;
  &lt;line x1="38" y1="0" x2="38" y2="27" /&gt;
  &lt;line x1="38" y1="0" x2="38" y2="27" /&gt;
  &lt;line x1="38" y1="0" x2="38" y2="27" /&gt;
  &lt;line x1="39" y1="0" x2="39" y2="27" /&gt;
  &lt;line x1="39" y1="0" x2="39" y2="27" /&gt;
  &lt;line x1="39" y1="0" x2="39" y2="27" /&gt;
  &lt;line x1="39" y1="0" x2="39" y2="27" /&gt;
  &lt;line x1="40" y1="0" x2="40" y2="27" /&gt;
  &lt;line x1="40" y1="0" x2="40" y2="27" /&gt;
  &lt;line x1="40" y1="0" x2="40" y2="27" /&gt;
  &lt;line x1="40" y1="0" x2="40" y2="27" /&gt;
  &lt;line x1="41" y1="0" x2="41" y2="27" /&gt;
  &lt;line x1="41" y1="0" x2="41" y2="27" /&gt;
  &lt;line x1="41" y1="0" x2="41" y2="27" /&gt;
  &lt;line x1="41" y1="0" x2="41" y2="27" /&gt;
  &lt;line x1="41" y1="0" x2="41" y2="27" /&gt;
  &lt;line x1="42" y1="0" x2="42" y2="27" /&gt;
  &lt;line x1="42" y1="0" x2="42" y2="27" /&gt;
  &lt;line x1="42" y1="0" x2="42" y2="27" /&gt;
  &lt;line x1="42" y1="0" x2="42" y2="27" /&gt;
  &lt;line x1="43" y1="0" x2="43" y2="27" /&gt;
  &lt;line x1="43" y1="0" x2="43" y2="27" /&gt;
  &lt;line x1="43" y1="0" x2="43" y2="27" /&gt;
  &lt;line x1="43" y1="0" x2="43" y2="27" /&gt;
  &lt;line x1="44" y1="0" x2="44" y2="27" /&gt;
  &lt;line x1="44" y1="0" x2="44" y2="27" /&gt;
  &lt;line x1="44" y1="0" x2="44" y2="27" /&gt;
  &lt;line x1="44" y1="0" x2="44" y2="27" /&gt;
  &lt;line x1="44" y1="0" x2="44" y2="27" /&gt;
  &lt;line x1="45" y1="0" x2="45" y2="27" /&gt;
  &lt;line x1="45" y1="0" x2="45" y2="27" style="stroke-width:2" /&gt;
  &lt;!-- Colored Rectangle --&gt;
  &lt;polygon points="0.000000,0.000000 45.378219,0.000000 45.378219,27.530335 0.000000,27.530335" style="fill:#ECB172A0;stroke-width:0"/&gt;
  &lt;!-- Text --&gt;
&lt;p&gt;&lt;text x="22.689110" y="47.530335" font-size="1.0rem" font-weight="100" text-anchor="middle" &gt;199&lt;/text&gt;
&lt;text x="65.378219" y="13.765167" font-size="1.0rem" font-weight="100" text-anchor="middle" transform="rotate(0,65.378219,13.765167)"&gt;3&lt;/text&gt;&lt;/p&gt;
  &lt;!-- Horizontal lines --&gt;
  &lt;line x1="115" y1="0" x2="141" y2="26" style="stroke-width:2" /&gt;
  &lt;line x1="115" y1="130" x2="141" y2="156" style="stroke-width:2" /&gt;
  &lt;!-- Vertical lines --&gt;
  &lt;line x1="115" y1="0" x2="115" y2="130" style="stroke-width:2" /&gt;
  &lt;line x1="141" y1="26" x2="141" y2="156" style="stroke-width:2" /&gt;
  &lt;!-- Colored Rectangle --&gt;
  &lt;polygon points="115.000000,0.000000 141.720328,26.720328 141.720328,156.720328 115.000000,130.000000" style="fill:#ECB172A0;stroke-width:0"/&gt;
  &lt;!-- Horizontal lines --&gt;
  &lt;line x1="115" y1="0" x2="212" y2="0" style="stroke-width:2" /&gt;
  &lt;line x1="141" y1="26" x2="239" y2="26" style="stroke-width:2" /&gt;
  &lt;!-- Vertical lines --&gt;
  &lt;line x1="115" y1="0" x2="141" y2="26" style="stroke-width:2" /&gt;
  &lt;line x1="212" y1="0" x2="239" y2="26" style="stroke-width:2" /&gt;
  &lt;!-- Colored Rectangle --&gt;
  &lt;polygon points="115.000000,0.000000 212.500000,0.000000 239.220328,26.720328 141.720328,26.720328" style="fill:#ECB172A0;stroke-width:0"/&gt;
  &lt;!-- Horizontal lines --&gt;
  &lt;line x1="141" y1="26" x2="239" y2="26" style="stroke-width:2" /&gt;
  &lt;line x1="141" y1="156" x2="239" y2="156" style="stroke-width:2" /&gt;
  &lt;!-- Vertical lines --&gt;
  &lt;line x1="141" y1="26" x2="141" y2="156" style="stroke-width:2" /&gt;
  &lt;line x1="239" y1="26" x2="239" y2="156" style="stroke-width:2" /&gt;
  &lt;!-- Colored Rectangle --&gt;
  &lt;polygon points="141.720328,26.720328 239.220328,26.720328 239.220328,156.720328 141.720328,156.720328" style="fill:#ECB172A0;stroke-width:0"/&gt;
  &lt;!-- Text --&gt;
&lt;p&gt;&lt;text x="190.470328" y="176.720328" font-size="1.0rem" font-weight="100" text-anchor="middle" &gt;768&lt;/text&gt;
&lt;text x="259.220328" y="91.720328" font-size="1.0rem" font-weight="100" text-anchor="middle" transform="rotate(-90,259.220328,91.720328)"&gt;1024&lt;/text&gt;
&lt;text x="118.360164" y="163.360164" font-size="1.0rem" font-weight="100" text-anchor="middle" transform="rotate(45,118.360164,163.360164)"&gt;201&lt;/text&gt;
&lt;/svg&gt;&lt;/p&gt;
&lt;/td&gt;
&lt;/tr&gt;
&lt;/table&gt;
&lt;p&gt;This dataset has shape &lt;code class="docutils literal notranslate"&gt;&lt;span class="pre"&gt;(3,&lt;/span&gt; &lt;span class="pre"&gt;199,&lt;/span&gt; &lt;span class="pre"&gt;201,&lt;/span&gt; &lt;span class="pre"&gt;1024,&lt;/span&gt; &lt;span class="pre"&gt;768)&lt;/span&gt;&lt;/code&gt;:&lt;/p&gt;
&lt;ul class="simple"&gt;
&lt;li&gt;&lt;p&gt;3 fluorescence color channels,&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;199 time points,&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;201 z-slices,&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;1024 pixels in the y dimension, and&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;768 pixels in the x dimension.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;div class="highlight-python notranslate"&gt;&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span class="c1"&gt;# Load our Point Spread Function (PSF)&lt;/span&gt;
&lt;span class="kn"&gt;import&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nn"&gt;dask.array.image&lt;/span&gt;
&lt;span class="n"&gt;psf&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;dask&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;array&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;image&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;imread&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;AOLLSMData/m4/psfs_z0p1/*.tif&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;)[:,&lt;/span&gt; &lt;span class="kc"&gt;None&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="o"&gt;...&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;table&gt;
&lt;tr&gt;
&lt;td&gt;
&lt;table&gt;  &lt;thead&gt;    &lt;tr&gt;&lt;td&gt; &lt;/td&gt;&lt;th&gt; Array &lt;/th&gt;&lt;th&gt; Chunk &lt;/th&gt;&lt;/tr&gt;
  &lt;/thead&gt;
  &lt;tbody&gt;
    &lt;tr&gt;&lt;th&gt; Bytes &lt;/th&gt;&lt;td&gt; 2.48 MB &lt;/td&gt; &lt;td&gt; 827.39 kB &lt;/td&gt;&lt;/tr&gt;
    &lt;tr&gt;&lt;th&gt; Shape &lt;/th&gt;&lt;td&gt; (3, 1, 101, 64, 64) &lt;/td&gt; &lt;td&gt; (1, 1, 101, 64, 64) &lt;/td&gt;&lt;/tr&gt;
    &lt;tr&gt;&lt;th&gt; Count &lt;/th&gt;&lt;td&gt; 6 Tasks &lt;/td&gt;&lt;td&gt; 3 Chunks &lt;/td&gt;&lt;/tr&gt;
    &lt;tr&gt;&lt;th&gt; Type &lt;/th&gt;&lt;td&gt; uint16 &lt;/td&gt;&lt;td&gt; numpy.ndarray &lt;/td&gt;&lt;/tr&gt;
  &lt;/tbody&gt;&lt;/table&gt;
&lt;/td&gt;
&lt;td&gt;
&lt;svg width="402" height="208" style="stroke:rgb(0,0,0);stroke-width:1" &gt;
  &lt;!-- Horizontal lines --&gt;
  &lt;line x1="0" y1="0" x2="27" y2="0" style="stroke-width:2" /&gt;
  &lt;line x1="0" y1="11" x2="27" y2="11" /&gt;
  &lt;line x1="0" y1="22" x2="27" y2="22" /&gt;
  &lt;line x1="0" y1="33" x2="27" y2="33" style="stroke-width:2" /&gt;
  &lt;!-- Vertical lines --&gt;
  &lt;line x1="0" y1="0" x2="0" y2="33" style="stroke-width:2" /&gt;
  &lt;line x1="27" y1="0" x2="27" y2="33" style="stroke-width:2" /&gt;
  &lt;!-- Colored Rectangle --&gt;
  &lt;polygon points="0.000000,0.000000 27.530335,0.000000 27.530335,33.941765 0.000000,33.941765" style="fill:#ECB172A0;stroke-width:0"/&gt;
  &lt;!-- Text --&gt;
&lt;p&gt;&lt;text x="13.765167" y="53.941765" font-size="1.0rem" font-weight="100" text-anchor="middle" &gt;1&lt;/text&gt;
&lt;text x="47.530335" y="16.970882" font-size="1.0rem" font-weight="100" text-anchor="middle" transform="rotate(0,47.530335,16.970882)"&gt;3&lt;/text&gt;&lt;/p&gt;
  &lt;!-- Horizontal lines --&gt;
  &lt;line x1="97" y1="0" x2="173" y2="76" style="stroke-width:2" /&gt;
  &lt;line x1="97" y1="82" x2="173" y2="158" style="stroke-width:2" /&gt;
  &lt;!-- Vertical lines --&gt;
  &lt;line x1="97" y1="0" x2="97" y2="82" style="stroke-width:2" /&gt;
  &lt;line x1="173" y1="76" x2="173" y2="158" style="stroke-width:2" /&gt;
  &lt;!-- Colored Rectangle --&gt;
  &lt;polygon points="97.000000,0.000000 173.470588,76.470588 173.470588,158.846826 97.000000,82.376238" style="fill:#ECB172A0;stroke-width:0"/&gt;
  &lt;!-- Horizontal lines --&gt;
  &lt;line x1="97" y1="0" x2="179" y2="0" style="stroke-width:2" /&gt;
  &lt;line x1="173" y1="76" x2="255" y2="76" style="stroke-width:2" /&gt;
  &lt;!-- Vertical lines --&gt;
  &lt;line x1="97" y1="0" x2="173" y2="76" style="stroke-width:2" /&gt;
  &lt;line x1="179" y1="0" x2="255" y2="76" style="stroke-width:2" /&gt;
  &lt;!-- Colored Rectangle --&gt;
  &lt;polygon points="97.000000,0.000000 179.376238,0.000000 255.846826,76.470588 173.470588,76.470588" style="fill:#ECB172A0;stroke-width:0"/&gt;
  &lt;!-- Horizontal lines --&gt;
  &lt;line x1="173" y1="76" x2="255" y2="76" style="stroke-width:2" /&gt;
  &lt;line x1="173" y1="158" x2="255" y2="158" style="stroke-width:2" /&gt;
  &lt;!-- Vertical lines --&gt;
  &lt;line x1="173" y1="76" x2="173" y2="158" style="stroke-width:2" /&gt;
  &lt;line x1="255" y1="76" x2="255" y2="158" style="stroke-width:2" /&gt;
  &lt;!-- Colored Rectangle --&gt;
  &lt;polygon points="173.470588,76.470588 255.846826,76.470588 255.846826,158.846826 173.470588,158.846826" style="fill:#ECB172A0;stroke-width:0"/&gt;
  &lt;!-- Text --&gt;
&lt;p&gt;&lt;text x="214.658707" y="178.846826" font-size="1.0rem" font-weight="100" text-anchor="middle" &gt;64&lt;/text&gt;
&lt;text x="275.846826" y="117.658707" font-size="1.0rem" font-weight="100" text-anchor="middle" transform="rotate(0,275.846826,117.658707)"&gt;64&lt;/text&gt;
&lt;text x="125.235294" y="140.611532" font-size="1.0rem" font-weight="100" text-anchor="middle" transform="rotate(45,125.235294,140.611532)"&gt;101&lt;/text&gt;
&lt;/svg&gt;&lt;/p&gt;
&lt;/td&gt;
&lt;/tr&gt;
&lt;/table&gt;
&lt;div class="highlight-python notranslate"&gt;&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span class="c1"&gt;# Convert data to float32 for computation¶&lt;/span&gt;
&lt;span class="kn"&gt;import&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nn"&gt;numpy&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;as&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nn"&gt;np&lt;/span&gt;
&lt;span class="n"&gt;imgs&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;imgs&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;astype&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;np&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;float32&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="c1"&gt;# Note: the psf needs to be sampled with a voxel spacing&lt;/span&gt;
&lt;span class="c1"&gt;# consistent with the image&amp;#39;s sampling&lt;/span&gt;
&lt;span class="n"&gt;psf&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;psf&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;astype&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;np&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;float32&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;div class="highlight-python notranslate"&gt;&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span class="c1"&gt;# Apply Richardson-Lucy Deconvolution¶&lt;/span&gt;
&lt;span class="k"&gt;def&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nf"&gt;richardson_lucy_deconvolution&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;img&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;psf&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;iterations&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="sd"&gt;&amp;quot;&amp;quot;&amp;quot; Apply deconvolution to a single chunk of data &amp;quot;&amp;quot;&amp;quot;&lt;/span&gt;
    &lt;span class="kn"&gt;import&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nn"&gt;itk&lt;/span&gt;

    &lt;span class="n"&gt;img&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;img&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="o"&gt;...&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;  &lt;span class="c1"&gt;# remove leading two length-one dimensions&lt;/span&gt;
    &lt;span class="n"&gt;psf&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;psf&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="o"&gt;...&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;  &lt;span class="c1"&gt;# remove leading two length-one dimensions&lt;/span&gt;

    &lt;span class="n"&gt;image&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;itk&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;image_view_from_array&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;img&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;   &lt;span class="c1"&gt;# Convert to ITK object&lt;/span&gt;
    &lt;span class="n"&gt;kernel&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;itk&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;image_view_from_array&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;psf&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;  &lt;span class="c1"&gt;# Convert to ITK object&lt;/span&gt;

    &lt;span class="n"&gt;deconvolved&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;itk&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;richardson_lucy_deconvolution_image_filter&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
        &lt;span class="n"&gt;image&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="n"&gt;kernel_image&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;kernel&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="n"&gt;number_of_iterations&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;iterations&lt;/span&gt;
    &lt;span class="p"&gt;)&lt;/span&gt;

    &lt;span class="n"&gt;result&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;itk&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;array_from_image&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;deconvolved&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;  &lt;span class="c1"&gt;# Convert back to Numpy array&lt;/span&gt;
    &lt;span class="n"&gt;result&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;result&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="kc"&gt;None&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="kc"&gt;None&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="o"&gt;...&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;  &lt;span class="c1"&gt;# Add back the leading length-one dimensions&lt;/span&gt;

    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;result&lt;/span&gt;

&lt;span class="n"&gt;out&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;da&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;map_blocks&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;richardson_lucy_deconvolution&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;imgs&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;psf&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;dtype&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;np&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;float32&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;div class="highlight-python notranslate"&gt;&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span class="c1"&gt;# Create a local cluster of dask worker processes&lt;/span&gt;
&lt;span class="c1"&gt;# (this could also point to a distributed cluster if you have it)&lt;/span&gt;
&lt;span class="kn"&gt;from&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nn"&gt;dask.distributed&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;LocalCluster&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;Client&lt;/span&gt;
&lt;span class="n"&gt;cluster&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;LocalCluster&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;n_workers&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mi"&gt;20&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;threads_per_process&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="n"&gt;client&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;Client&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;cluster&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;  &lt;span class="c1"&gt;# now dask operations use this cluster by default&lt;/span&gt;

&lt;span class="c1"&gt;# Trigger computation and store&lt;/span&gt;
&lt;span class="n"&gt;out&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;to_zarr&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;AOLLSMData_m4_raw.zarr&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s2"&gt;&amp;quot;deconvolved&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;overwrite&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="kc"&gt;True&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;So in the example above we …&lt;/p&gt;
&lt;ol class="arabic simple"&gt;
&lt;li&gt;&lt;p&gt;Load data both from Zarr and TIFF files into multi-chunked Dask arrays&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Construct a function to apply an ITK routine onto each chunk&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Apply that function across the dask array with the &lt;a class="reference external" href="https://docs.dask.org/en/latest/array-api.html#dask.array.core.map_blocks"&gt;dask.array.map_blocks&lt;/a&gt; function.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Store the result back into Zarr format&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;From the perspective of an imaging scientist,
the new piece of technology here is the
&lt;a class="reference external" href="https://docs.dask.org/en/latest/array-api.html#dask.array.core.map_blocks"&gt;dask.array.map_blocks&lt;/a&gt; function.
Given a Dask array composed of many NumPy arrays and a function, &lt;code class="docutils literal notranslate"&gt;&lt;span class="pre"&gt;map_blocks&lt;/span&gt;&lt;/code&gt; applies that function across each block in parallel, returning a Dask array as a result.
It’s a great tool whenever you want to apply an operation across many blocks in a simple fashion.
Because Dask arrays are just made out of Numpy arrays it’s an easy way to
compose Dask with the rest of the Scientific Python ecosystem.&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/2019/08/09/image-itk.md&lt;/span&gt;, line 459)&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="building-the-right-function"&gt;
&lt;h1&gt;Building the right function&lt;/h1&gt;
&lt;p&gt;However in this case there are a few challenges to constructing the right Numpy
-&amp;gt; Numpy function, due to both idiosyncrasies in ITK and Dask Array. Let’s
look at our function again:&lt;/p&gt;
&lt;div class="highlight-python notranslate"&gt;&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span class="k"&gt;def&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nf"&gt;richardson_lucy_deconvolution&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;img&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;psf&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;iterations&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="sd"&gt;&amp;quot;&amp;quot;&amp;quot; Apply deconvolution to a single chunk of data &amp;quot;&amp;quot;&amp;quot;&lt;/span&gt;
    &lt;span class="kn"&gt;import&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nn"&gt;itk&lt;/span&gt;

    &lt;span class="n"&gt;img&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;img&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="o"&gt;...&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;  &lt;span class="c1"&gt;# remove leading two length-one dimensions&lt;/span&gt;
    &lt;span class="n"&gt;psf&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;psf&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="o"&gt;...&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;  &lt;span class="c1"&gt;# remove leading two length-one dimensions&lt;/span&gt;

    &lt;span class="n"&gt;image&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;itk&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;image_view_from_array&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;img&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;   &lt;span class="c1"&gt;# Convert to ITK object&lt;/span&gt;
    &lt;span class="n"&gt;kernel&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;itk&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;image_view_from_array&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;psf&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;  &lt;span class="c1"&gt;# Convert to ITK object&lt;/span&gt;

    &lt;span class="n"&gt;deconvolved&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;itk&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;richardson_lucy_deconvolution_image_filter&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
        &lt;span class="n"&gt;image&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="n"&gt;kernel_image&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;kernel&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="n"&gt;number_of_iterations&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;iterations&lt;/span&gt;
    &lt;span class="p"&gt;)&lt;/span&gt;

    &lt;span class="n"&gt;result&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;itk&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;array_from_image&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;deconvolved&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;  &lt;span class="c1"&gt;# Convert back to Numpy array&lt;/span&gt;
    &lt;span class="n"&gt;result&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;result&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="kc"&gt;None&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="kc"&gt;None&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="o"&gt;...&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;  &lt;span class="c1"&gt;# Add back the leading length-one dimensions&lt;/span&gt;

    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;result&lt;/span&gt;

&lt;span class="n"&gt;out&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;da&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;map_blocks&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;richardson_lucy_deconvolution&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;imgs&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;psf&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;dtype&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;np&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;float32&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;This is longer than we would like.
Instead, we would have preferred to just use the &lt;code class="docutils literal notranslate"&gt;&lt;span class="pre"&gt;itk&lt;/span&gt;&lt;/code&gt; function directly,
without all of the steps before and after.&lt;/p&gt;
&lt;div class="highlight-python notranslate"&gt;&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span class="n"&gt;deconvolved&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;da&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;map_blocks&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;itk&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;richardson_lucy_deconvolution_image_filter&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;imgs&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;psf&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;What were the extra steps in our function and why were they necessary?&lt;/p&gt;
&lt;ol class="arabic"&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Convert to and from ITK Image objects&lt;/strong&gt;: ITK functions don’t consume and
produce Numpy arrays, they consume and produce their own &lt;code class="docutils literal notranslate"&gt;&lt;span class="pre"&gt;Image&lt;/span&gt;&lt;/code&gt; data
structure. There are convenient functions to convert back and forth,
so handling this is straightforward, but it does need to be handled each
time. See &lt;a class="reference external" href="https://github.com/InsightSoftwareConsortium/ITK/issues/1136"&gt;ITK #1136&lt;/a&gt; for a
feature request that would remove the need for this step.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Unpack and pack singleton dimensions&lt;/strong&gt;: Our Dask arrays have shapes like
the following:&lt;/p&gt;
&lt;div class="highlight-default notranslate"&gt;&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span class="n"&gt;Array&lt;/span&gt; &lt;span class="n"&gt;Shape&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;3&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;199&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;201&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;1024&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;768&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="n"&gt;Chunk&lt;/span&gt; &lt;span class="n"&gt;Shape&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;   &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;201&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;1024&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;768&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;So our &lt;code class="docutils literal notranslate"&gt;&lt;span class="pre"&gt;map_blocks&lt;/span&gt;&lt;/code&gt; function gets NumPy arrays of the chunk size,
&lt;code class="docutils literal notranslate"&gt;&lt;span class="pre"&gt;(1,&lt;/span&gt; &lt;span class="pre"&gt;1,&lt;/span&gt; &lt;span class="pre"&gt;201,&lt;/span&gt; &lt;span class="pre"&gt;1024,&lt;/span&gt; &lt;span class="pre"&gt;768)&lt;/span&gt;&lt;/code&gt;.
However, our ITK functions are meant to work on 3d arrays, not 5d arrays,
so we need to remove those first two dimensions.&lt;/p&gt;
&lt;div class="highlight-python notranslate"&gt;&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span class="n"&gt;img&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;img&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="o"&gt;...&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;  &lt;span class="c1"&gt;# remove leading two length-one dimensions&lt;/span&gt;
&lt;span class="n"&gt;psf&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;psf&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="o"&gt;...&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;  &lt;span class="c1"&gt;# remove leading two length-one dimensions&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;And then when we’re done, Dask expects to get back 5d arrays like what it
provided, so we add these singleton dimensions back in&lt;/p&gt;
&lt;div class="highlight-python notranslate"&gt;&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span class="n"&gt;result&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;result&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="kc"&gt;None&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="kc"&gt;None&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="o"&gt;...&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;  &lt;span class="c1"&gt;# Add back the leading length-one dimensions&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;Again, this is straightforward for users who are accustomed to NumPy
slicing syntax, but does need to be done each time.
This adds some friction to our development process,
and is another step that can confuse users.&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;But if you’re comfortable working around things like this,
then ITK and &lt;code class="docutils literal notranslate"&gt;&lt;span class="pre"&gt;map_blocks&lt;/span&gt;&lt;/code&gt; can be a powerful combination
if you want to parallelize out ITK operations across a cluster.&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/2019/08/09/image-itk.md&lt;/span&gt;, line 541)&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="defining-a-dask-cluster"&gt;
&lt;h1&gt;Defining a Dask Cluster&lt;/h1&gt;
&lt;p&gt;Above we used &lt;code class="docutils literal notranslate"&gt;&lt;span class="pre"&gt;dask.distributed.LocalCluster&lt;/span&gt;&lt;/code&gt; to set up 20 single-threaded
workers on our local workstation:&lt;/p&gt;
&lt;div class="highlight-python notranslate"&gt;&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span class="kn"&gt;from&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nn"&gt;dask.distributed&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;LocalCluster&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;Client&lt;/span&gt;
&lt;span class="n"&gt;cluster&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;LocalCluster&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;n_workers&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mi"&gt;20&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;threads_per_process&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="n"&gt;client&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;Client&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;cluster&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;  &lt;span class="c1"&gt;# now dask operations use this cluster by default&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;If you had a distributed resource, this is where you would connect it.
You would swap out &lt;code class="docutils literal notranslate"&gt;&lt;span class="pre"&gt;LocalCluster&lt;/span&gt;&lt;/code&gt; with one of
&lt;a class="reference external" href="https://docs.dask.org/en/latest/setup.html"&gt;Dask’s other deployment options&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;Also, we found that we needed to use many single-threaded processes rather than
one multi-threaded process because ITK functions seem to still hold onto the
GIL. This is fine, we just need to be aware of it so that we set up our Dask
workers appropriately with one thread per process for maximum efficiency.
See &lt;a class="reference external" href="https://github.com/InsightSoftwareConsortium/ITK/issues/1134"&gt;ITK #1134&lt;/a&gt;
for an active Github issue on this topic.&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/2019/08/09/image-itk.md&lt;/span&gt;, line 563)&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="serialization"&gt;
&lt;h1&gt;Serialization&lt;/h1&gt;
&lt;p&gt;We had some difficulty when using the ITK library across multiple processes,
because the library itself didn’t serialize well. (If you don’t understand
what that means, don’t worry). We solved a bit of this in
&lt;a class="reference external" href="https://github.com/InsightSoftwareConsortium/ITK/pull/1090"&gt;ITK #1090&lt;/a&gt;,
but some issues still remain.&lt;/p&gt;
&lt;p&gt;We got around this by including the import in the function rather than outside
of it.&lt;/p&gt;
&lt;div class="highlight-python notranslate"&gt;&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span class="k"&gt;def&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nf"&gt;richardson_lucy_deconvolution&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;img&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;psf&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;iterations&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="kn"&gt;import&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nn"&gt;itk&lt;/span&gt;   &lt;span class="c1"&gt;# &amp;lt;--- we work around serialization issues by importing within the function&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;That way each task imports itk individually, and we sidestep this issue.&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/2019/08/09/image-itk.md&lt;/span&gt;, line 581)&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="trying-scikit-image"&gt;
&lt;h1&gt;Trying Scikit-Image&lt;/h1&gt;
&lt;p&gt;We also tried out the Richardson Lucy deconvolution operation in
&lt;a class="reference external" href="https://scikit-image.org/"&gt;Scikit-Image&lt;/a&gt;. Scikit-Image is known for being
more Scipy/Numpy native, but not always as fast as ITK. Our experience
confirmed this perception.&lt;/p&gt;
&lt;p&gt;First, we were glad to see that the scikit-image function worked with
&lt;code class="docutils literal notranslate"&gt;&lt;span class="pre"&gt;map_blocks&lt;/span&gt;&lt;/code&gt; immediately without any packing/unpacking, dimensionality, or
serialization issues:&lt;/p&gt;
&lt;div class="highlight-python notranslate"&gt;&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span class="kn"&gt;import&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nn"&gt;skimage.restoration&lt;/span&gt;

&lt;span class="n"&gt;out&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;da&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;map_blocks&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;skimage&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;restoration&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;richardson_lucy&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;imgs&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;psf&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;  &lt;span class="c1"&gt;# just works&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;So all of that converting to and from image objects or removing and adding
singleton dimensions isn’t necessary here.&lt;/p&gt;
&lt;p&gt;In terms of performance we were also happy to see that Scikit-Image released
the GIL, so we were able to get very high reported CPU utilization when using a
small number of multi-threaded processes. However, even though CPU utilization
was high, our parallel performance was poor enough that we stuck with the ITK
solution, warts and all. More information about this is available in
Github issue &lt;a class="reference external" href="https://github.com/scikit-image/scikit-image/issues/4083"&gt;scikit-image #4083&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;&lt;em&gt;Note: sequentially on a single chunk, ITK ran in around 2 minutes while
scikit-image ran in 3 minutes. It was only once we started parallelizing that
things became slow.&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;Regardless, our goal in this experiment was to see how well ITK and Dask
array played together. It was nice to see what smooth integration looks like,
if only to motivate future development in ITK+Dask relations.&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/2019/08/09/image-itk.md&lt;/span&gt;, line 616)&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="numba-gufuncs"&gt;
&lt;h1&gt;Numba GUFuncs&lt;/h1&gt;
&lt;p&gt;An alternative to &lt;code class="docutils literal notranslate"&gt;&lt;span class="pre"&gt;da.map_blocks&lt;/span&gt;&lt;/code&gt; are Generalized Universal Functions (gufuncs)
These are functions that have many magical properties, one of which is that
they operate equally well on both NumPy and Dask arrays. If libraries like
ITK or Scikit-Image make their functions into gufuncs then they work without
users having to do anything special.&lt;/p&gt;
&lt;p&gt;The easiest way to implement gufuncs today is with Numba. I did this on our
wrapped &lt;code class="docutils literal notranslate"&gt;&lt;span class="pre"&gt;richardson_lucy&lt;/span&gt;&lt;/code&gt; function, just to show how it could work, in case
other libraries want to take this on in the future.&lt;/p&gt;
&lt;div class="highlight-python notranslate"&gt;&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span class="kn"&gt;import&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nn"&gt;numba&lt;/span&gt;

&lt;span class="nd"&gt;@numba&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;guvectorize&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;float32[:,:,:], float32[:,:,:], float32[:,:,:]&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;  &lt;span class="c1"&gt;# we have to specify types&lt;/span&gt;
    &lt;span class="s2"&gt;&amp;quot;(i,j,k),(a,b,c)-&amp;gt;(i,j,k)&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;                          &lt;span class="c1"&gt;# and dimensionality explicitly&lt;/span&gt;
    &lt;span class="n"&gt;forceobj&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="kc"&gt;True&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="k"&gt;def&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nf"&gt;richardson_lucy_deconvolution&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;img&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;psf&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;out&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="c1"&gt;# &amp;lt;---- no dimension unpacking!&lt;/span&gt;
    &lt;span class="n"&gt;iterations&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;
    &lt;span class="n"&gt;image&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;itk&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;image_view_from_array&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;np&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;ascontiguousarray&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;img&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
    &lt;span class="n"&gt;kernel&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;itk&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;image_view_from_array&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;np&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;ascontiguousarray&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;psf&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;

    &lt;span class="n"&gt;deconvolved&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;itk&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;richardson_lucy_deconvolution_image_filter&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
        &lt;span class="n"&gt;image&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;kernel_image&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;kernel&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;number_of_iterations&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;iterations&lt;/span&gt;
    &lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;out&lt;/span&gt;&lt;span class="p"&gt;[:]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;itk&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;array_from_image&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;deconvolved&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="c1"&gt;# Now this function works natively on either NumPy or Dask arrays&lt;/span&gt;
&lt;span class="n"&gt;out&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;richardson_lucy_deconvolution&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;imgs&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;psf&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;  &lt;span class="c1"&gt;# &amp;lt;-- no map_blocks call!&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;Note that we’ve both lost the dimension unpacking and the &lt;code class="docutils literal notranslate"&gt;&lt;span class="pre"&gt;map_blocks&lt;/span&gt;&lt;/code&gt; call.
Our function now knows enough information about how it can broadcast that Dask
can do the parallelization without being told what to do explicitly.&lt;/p&gt;
&lt;p&gt;This adds some burden onto library maintainers,
but makes the user experience much more smooth.&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/2019/08/09/image-itk.md&lt;/span&gt;, line 658)&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="gpu-acceleration"&gt;
&lt;h1&gt;GPU Acceleration&lt;/h1&gt;
&lt;p&gt;When doing some user research on image processing and Dask, almost everyone we
interviewed said that they wanted faster deconvolution. This seemed to be a
major pain point. Now we know why. It’s both very common, and &lt;em&gt;very slow&lt;/em&gt;.&lt;/p&gt;
&lt;p&gt;Running deconvolution on a single chunk of this size takes around 2-4 minutes,
and we have hundreds of chunks in a single dataset. Multi-core parallelism can
help a bit here, but this problem may also be ripe for GPU acceleration.
Similar operations typically have 100x speedups on GPUs. This might be a more
pragmatic solution than scaling out to large distributed clusters.&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/2019/08/09/image-itk.md&lt;/span&gt;, line 670)&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="what-s-next"&gt;
&lt;h1&gt;What’s next?&lt;/h1&gt;
&lt;p&gt;This experiment both …&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Gives us an example&lt;/strong&gt; that other imaging scientists
can copy and modify to be effective with Dask and ITK together.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Highlights areas of improvement&lt;/strong&gt; where developers from the different
libraries can work to remove some of these rough interactions spots in the
future.&lt;/p&gt;
&lt;p&gt;It’s worth noting that Dask has done this with lots of libraries within the
Scipy ecosystem, including Pandas, Scikit-Image, Scikit-Learn, and others.&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;We’re also going to continue with our imaging experiment, while these technical
issues get worked out in the background. Next up, segmentation!&lt;/p&gt;
&lt;/section&gt;
</content>
    <link href="https://blog.dask.org/2019/08/09/image-itk/"/>
    <summary>Document headings start at H2, not H1 [myst.header]</summary>
    <category term="imaging" label="imaging"/>
    <published>2019-08-09T00:00:00+00:00</published>
  </entry>
  <entry>
    <id>https://blog.dask.org/2019/06/20/load-image-data/</id>
    <title>Load Large Image Data with Dask Array</title>
    <updated>2019-06-20T00:00:00+00:00</updated>
    <author>
      <name>John Kirkham</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/2019/06/20/load-image-data.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 post explores simple workflows to load large stacks of image data with Dask array.&lt;/p&gt;
&lt;p&gt;In particular, we start with a &lt;a class="reference external" href="https://drive.google.com/drive/folders/13mpIfqspKTIINkfoWbFsVtFF8D7jbTqJ"&gt;directory full of TIFF
files&lt;/a&gt;
of images like the following:&lt;/p&gt;
&lt;div class="highlight-default notranslate"&gt;&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;$ $ ls raw/ | head
ex6-2_CamA_ch1_CAM1_stack0000_560nm_0000000msec_0001291795msecAbs_000x_000y_000z_0000t.tif
ex6-2_CamA_ch1_CAM1_stack0001_560nm_0043748msec_0001335543msecAbs_000x_000y_000z_0000t.tif
ex6-2_CamA_ch1_CAM1_stack0002_560nm_0087497msec_0001379292msecAbs_000x_000y_000z_0000t.tif
ex6-2_CamA_ch1_CAM1_stack0003_560nm_0131245msec_0001423040msecAbs_000x_000y_000z_0000t.tif
ex6-2_CamA_ch1_CAM1_stack0004_560nm_0174993msec_0001466788msecAbs_000x_000y_000z_0000t.tif
&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;and show how to stitch these together into large lazy arrays
using the &lt;a class="reference external" href="https://image.dask.org/en/latest/"&gt;dask-image&lt;/a&gt; library&lt;/p&gt;
&lt;div class="highlight-python notranslate"&gt;&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span class="gp"&gt;&amp;gt;&amp;gt;&amp;gt; &lt;/span&gt;&lt;span class="kn"&gt;import&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nn"&gt;dask_image&lt;/span&gt;
&lt;span class="gp"&gt;&amp;gt;&amp;gt;&amp;gt; &lt;/span&gt;&lt;span class="n"&gt;x&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;dask_image&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;imread&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;imread&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;raw/*.tif&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;or by writing your own Dask delayed image reader function.&lt;/p&gt;
&lt;table&gt;
&lt;tr&gt;
&lt;td&gt;
&lt;table&gt;  &lt;thead&gt;    &lt;tr&gt;&lt;td&gt; &lt;/td&gt;&lt;th&gt; Array &lt;/th&gt;&lt;th&gt; Chunk &lt;/th&gt;&lt;/tr&gt;
  &lt;/thead&gt;
  &lt;tbody&gt;
    &lt;tr&gt;&lt;th&gt; Bytes &lt;/th&gt;&lt;td&gt; 3.16 GB &lt;/td&gt; &lt;td&gt; 316.15 MB &lt;/td&gt;&lt;/tr&gt;
    &lt;tr&gt;&lt;th&gt; Shape &lt;/th&gt;&lt;td&gt; (2010, 1024, 768) &lt;/td&gt; &lt;td&gt; (201, 1024, 768) &lt;/td&gt;&lt;/tr&gt;
    &lt;tr&gt;&lt;th&gt; Count &lt;/th&gt;&lt;td&gt; 30 Tasks &lt;/td&gt;&lt;td&gt; 10 Chunks &lt;/td&gt;&lt;/tr&gt;
    &lt;tr&gt;&lt;th&gt; Type &lt;/th&gt;&lt;td&gt; uint16 &lt;/td&gt;&lt;td&gt; numpy.ndarray &lt;/td&gt;&lt;/tr&gt;
  &lt;/tbody&gt;&lt;/table&gt;
&lt;/td&gt;
&lt;td&gt;
&lt;svg width="176" height="181" style="stroke:rgb(0,0,0);stroke-width:1" &gt;
  &lt;!-- Horizontal lines --&gt;
  &lt;line x1="10" y1="0" x2="80" y2="70" style="stroke-width:2" /&gt;
  &lt;line x1="10" y1="61" x2="80" y2="131" style="stroke-width:2" /&gt;
  &lt;!-- Vertical lines --&gt;
  &lt;line x1="10" y1="0" x2="10" y2="61" style="stroke-width:2" /&gt;
  &lt;line x1="17" y1="7" x2="17" y2="68" /&gt;
  &lt;line x1="24" y1="14" x2="24" y2="75" /&gt;
  &lt;line x1="31" y1="21" x2="31" y2="82" /&gt;
  &lt;line x1="38" y1="28" x2="38" y2="89" /&gt;
  &lt;line x1="45" y1="35" x2="45" y2="96" /&gt;
  &lt;line x1="52" y1="42" x2="52" y2="103" /&gt;
  &lt;line x1="59" y1="49" x2="59" y2="110" /&gt;
  &lt;line x1="66" y1="56" x2="66" y2="117" /&gt;
  &lt;line x1="73" y1="63" x2="73" y2="124" /&gt;
  &lt;line x1="80" y1="70" x2="80" y2="131" style="stroke-width:2" /&gt;
  &lt;!-- Colored Rectangle --&gt;
  &lt;polygon points="10.000000,0.000000 80.588235,70.588235 80.588235,131.722564 10.000000,61.134328" style="fill:#ECB172A0;stroke-width:0"/&gt;
  &lt;!-- Horizontal lines --&gt;
  &lt;line x1="10" y1="0" x2="55" y2="0" style="stroke-width:2" /&gt;
  &lt;line x1="17" y1="7" x2="62" y2="7" /&gt;
  &lt;line x1="24" y1="14" x2="69" y2="14" /&gt;
  &lt;line x1="31" y1="21" x2="77" y2="21" /&gt;
  &lt;line x1="38" y1="28" x2="84" y2="28" /&gt;
  &lt;line x1="45" y1="35" x2="91" y2="35" /&gt;
  &lt;line x1="52" y1="42" x2="98" y2="42" /&gt;
  &lt;line x1="59" y1="49" x2="105" y2="49" /&gt;
  &lt;line x1="66" y1="56" x2="112" y2="56" /&gt;
  &lt;line x1="73" y1="63" x2="119" y2="63" /&gt;
  &lt;line x1="80" y1="70" x2="126" y2="70" style="stroke-width:2" /&gt;
  &lt;!-- Vertical lines --&gt;
  &lt;line x1="10" y1="0" x2="80" y2="70" style="stroke-width:2" /&gt;
  &lt;line x1="55" y1="0" x2="126" y2="70" style="stroke-width:2" /&gt;
  &lt;!-- Colored Rectangle --&gt;
  &lt;polygon points="10.000000,0.000000 55.850746,0.000000 126.438982,70.588235 80.588235,70.588235" style="fill:#ECB172A0;stroke-width:0"/&gt;
  &lt;!-- Horizontal lines --&gt;
  &lt;line x1="80" y1="70" x2="126" y2="70" style="stroke-width:2" /&gt;
  &lt;line x1="80" y1="131" x2="126" y2="131" style="stroke-width:2" /&gt;
  &lt;!-- Vertical lines --&gt;
  &lt;line x1="80" y1="70" x2="80" y2="131" style="stroke-width:2" /&gt;
  &lt;line x1="126" y1="70" x2="126" y2="131" style="stroke-width:2" /&gt;
  &lt;!-- Colored Rectangle --&gt;
  &lt;polygon points="80.588235,70.588235 126.438982,70.588235 126.438982,131.722564 80.588235,131.722564" style="fill:#ECB172A0;stroke-width:0"/&gt;
  &lt;!-- Text --&gt;
&lt;p&gt;&lt;text x="103.513608" y="151.722564" font-size="1.0rem" font-weight="100" text-anchor="middle" &gt;768&lt;/text&gt;
&lt;text x="146.438982" y="101.155399" font-size="1.0rem" font-weight="100" text-anchor="middle" transform="rotate(-90,146.438982,101.155399)"&gt;1024&lt;/text&gt;
&lt;text x="35.294118" y="116.428446" font-size="1.0rem" font-weight="100" text-anchor="middle" transform="rotate(45,35.294118,116.428446)"&gt;2010&lt;/text&gt;
&lt;/svg&gt;&lt;/p&gt;
&lt;/td&gt;
&lt;/tr&gt;
&lt;/table&gt;
&lt;p&gt;Some day we’ll eventually be able to perform complex calculations on this dask array.&lt;/p&gt;
&lt;p&gt;&lt;img src="https://raw.githubusercontent.com/mrocklin/raw-host/gh-pages/images/aollsm-index-1.jpg"
     width="45%"
     alt="Light Microscopy data rendered with NVidia IndeX"&gt;
&lt;img src="https://raw.githubusercontent.com/mrocklin/raw-host/gh-pages/images/aollsm-index-2.jpg"
     width="45%"
     alt="Light Microscopy data rendered with NVidia IndeX"&gt;&lt;/p&gt;
&lt;p&gt;&lt;em&gt;Disclaimer: we’re not going to produce rendered images like the above in this
post. These were created with &lt;a class="reference external" href="https://developer.nvidia.com/index"&gt;NVidia
IndeX&lt;/a&gt;, a completely separate tool chain
from what is being discussed here. This post covers the first step of image
loading.&lt;/em&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/2019/06/20/load-image-data.md&lt;/span&gt;, line 128)&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="series-overview"&gt;
&lt;h1&gt;Series Overview&lt;/h1&gt;
&lt;p&gt;A common case in fields that acquire large amounts of imaging data is to write
out smaller acquisitions into many small files. These files can tile a larger
space, sub-sample from a larger time period, and may contain multiple channels.
The acquisition techniques themselves are often state of the art and constantly
pushing the envelope in term of how large a field of view can be acquired, at
what resolution, and what quality.&lt;/p&gt;
&lt;p&gt;Once acquired this data presents a number of challenges. Algorithms often
designed and tested to work on very small pieces of this data need to be scaled
up to work on the full dataset. It might not be clear at the outset what will
actually work and so exploration still plays a very big part of the whole
process.&lt;/p&gt;
&lt;p&gt;Historically this analytical process has involved a lot of custom code. Often
the analytical process is stitched together by a series of scripts possibly in
several different languages that write various intermediate results to disk.
Thanks to advances in modern tooling these process can be significantly
improved. In this series of blogposts, we will outline ways for image
scientists to leverage different tools to move towards a high level, friendly,
cohesive, interactive analytical pipeline.&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/2019/06/20/load-image-data.md&lt;/span&gt;, line 151)&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="post-overview"&gt;
&lt;h1&gt;Post Overview&lt;/h1&gt;
&lt;p&gt;This post in particular focuses on loading and managing large stacks of image
data in parallel from Python.&lt;/p&gt;
&lt;p&gt;Loading large image data can be a complex and often unique problem. Different
groups may choose to store this across many files on disk, a commodity or
custom database solution, or they may opt to store it in the cloud. Not all
datasets within the same group may be treated the same for a variety of
reasons. In short, this means loading data is a hard and expensive problem.&lt;/p&gt;
&lt;p&gt;Despite data being stored in many different ways, often groups want to reapply
the same analytical pipeline to these datasets. However if the data pipeline is
tightly coupled to a particular way of loading the data for later analytical
steps, it may be very difficult if not impossible to reuse an existing
pipeline. In other words, there is friction between the loading and analysis
steps, which frustrates efforts to make things reusable.&lt;/p&gt;
&lt;p&gt;Having a modular and general way to load data makes it easy to present data
stored differently in a standard way. Further having a standard way to present
data to analytical pipelines allows that part of the pipeline to focus on what
it does best, analysis! In general, this should decouple these to components in
a way that improves the experience of users involved in all parts of the
pipeline.&lt;/p&gt;
&lt;p&gt;We will use
&lt;a class="reference external" href="https://drive.google.com/drive/folders/13mpIfqspKTIINkfoWbFsVtFF8D7jbTqJ"&gt;image data&lt;/a&gt;
generously provided by
&lt;a class="reference external" href="https://scholar.google.com/citations?user=nxwNAEgAAAAJ&amp;amp;amp;hl=en"&gt;Gokul Upadhyayula&lt;/a&gt;
at the
&lt;a class="reference external" href="http://microscopy.berkeley.edu/"&gt;Advanced Bioimaging Center&lt;/a&gt;
at UC Berkeley and discussed in
&lt;a class="reference external" href="https://science.sciencemag.org/content/360/6386/eaaq1392"&gt;this paper&lt;/a&gt;
(&lt;a class="reference external" href="https://www.biorxiv.org/content/10.1101/243352v2"&gt;preprint&lt;/a&gt;),
though the workloads presented here should work for any kind of imaging data,
or array data generally.&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/2019/06/20/load-image-data.md&lt;/span&gt;, line 188)&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="load-image-data-with-dask"&gt;
&lt;h1&gt;Load image data with Dask&lt;/h1&gt;
&lt;p&gt;Let’s start again with our image data from the top of the post:&lt;/p&gt;
&lt;div class="highlight-default notranslate"&gt;&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;$ $ ls /path/to/files/raw/ | head
ex6-2_CamA_ch1_CAM1_stack0000_560nm_0000000msec_0001291795msecAbs_000x_000y_000z_0000t.tif
ex6-2_CamA_ch1_CAM1_stack0001_560nm_0043748msec_0001335543msecAbs_000x_000y_000z_0000t.tif
ex6-2_CamA_ch1_CAM1_stack0002_560nm_0087497msec_0001379292msecAbs_000x_000y_000z_0000t.tif
ex6-2_CamA_ch1_CAM1_stack0003_560nm_0131245msec_0001423040msecAbs_000x_000y_000z_0000t.tif
ex6-2_CamA_ch1_CAM1_stack0004_560nm_0174993msec_0001466788msecAbs_000x_000y_000z_0000t.tif
&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;section id="load-a-single-sample-image-with-scikit-image"&gt;
&lt;h2&gt;Load a single sample image with Scikit-Image&lt;/h2&gt;
&lt;p&gt;To load a single image, we use &lt;a class="reference external" href="https://scikit-image.org/"&gt;Scikit-Image&lt;/a&gt;:&lt;/p&gt;
&lt;div class="highlight-python notranslate"&gt;&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span class="gp"&gt;&amp;gt;&amp;gt;&amp;gt; &lt;/span&gt;&lt;span class="kn"&gt;import&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nn"&gt;glob&lt;/span&gt;
&lt;span class="gp"&gt;&amp;gt;&amp;gt;&amp;gt; &lt;/span&gt;&lt;span class="n"&gt;filenames&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;glob&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;glob&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;/path/to/files/raw/*.tif&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="gp"&gt;&amp;gt;&amp;gt;&amp;gt; &lt;/span&gt;&lt;span class="nb"&gt;len&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;filenames&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="go"&gt;597&lt;/span&gt;

&lt;span class="gp"&gt;&amp;gt;&amp;gt;&amp;gt; &lt;/span&gt;&lt;span class="kn"&gt;import&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nn"&gt;imageio&lt;/span&gt;
&lt;span class="gp"&gt;&amp;gt;&amp;gt;&amp;gt; &lt;/span&gt;&lt;span class="n"&gt;sample&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;imageio&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;imread&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;filenames&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;])&lt;/span&gt;
&lt;span class="gp"&gt;&amp;gt;&amp;gt;&amp;gt; &lt;/span&gt;&lt;span class="n"&gt;sample&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;shape&lt;/span&gt;
&lt;span class="go"&gt;(201, 1024, 768)&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;Each filename corresponds to some 3d chunk of a larger image. We can look at a
few 2d slices of this single 3d chunk to get some context.&lt;/p&gt;
&lt;div class="highlight-python notranslate"&gt;&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span class="kn"&gt;import&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nn"&gt;matplotlib.pyplot&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;as&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nn"&gt;plt&lt;/span&gt;
&lt;span class="kn"&gt;import&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nn"&gt;skimage.io&lt;/span&gt;
&lt;span class="n"&gt;plt&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;figure&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;figsize&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;10&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;10&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
&lt;span class="n"&gt;skimage&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;io&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;imshow&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;sample&lt;/span&gt;&lt;span class="p"&gt;[:,&lt;/span&gt; &lt;span class="p"&gt;:,&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;])&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;&lt;img src="https://raw.githubusercontent.com/mrocklin/raw-host/gh-pages/images/aollsm-sample-1.png"
     width="60%"&gt;&lt;/p&gt;
&lt;div class="highlight-python notranslate"&gt;&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span class="n"&gt;plt&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;figure&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;figsize&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;10&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;10&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
&lt;span class="n"&gt;skimage&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;io&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;imshow&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;sample&lt;/span&gt;&lt;span class="p"&gt;[:,&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;:])&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;&lt;img src="https://raw.githubusercontent.com/mrocklin/raw-host/gh-pages/images/aollsm-sample-2.png"
     width="60%"&gt;&lt;/p&gt;
&lt;div class="highlight-python notranslate"&gt;&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span class="n"&gt;plt&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;figure&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;figsize&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;10&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;10&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
&lt;span class="n"&gt;skimage&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;io&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;imshow&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;sample&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;:,&lt;/span&gt; &lt;span class="p"&gt;:])&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;&lt;img src="https://raw.githubusercontent.com/mrocklin/raw-host/gh-pages/images/aollsm-sample-3.png"
     width="60%"&gt;&lt;/p&gt;
&lt;/section&gt;
&lt;section id="investigate-filename-structure"&gt;
&lt;h2&gt;Investigate Filename Structure&lt;/h2&gt;
&lt;p&gt;These are slices from only one chunk of a much larger aggregate image.
Our interest here is combining the pieces into a large image stack.
It is common to see a naming structure in the filenames. Each
filename then may indicate a channel, time step, and spatial location with the
&lt;code class="docutils literal notranslate"&gt;&lt;span class="pre"&gt;&amp;lt;i&amp;gt;&lt;/span&gt;&lt;/code&gt; being some numeric values (possibly with units). Individual filenames may
have more or less information and may notate it differently than we have.&lt;/p&gt;
&lt;div class="highlight-default notranslate"&gt;&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span class="n"&gt;mydata_ch&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="n"&gt;_&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;j&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="n"&gt;t_&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;k&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="n"&gt;x_&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;l&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="n"&gt;y_&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;m&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="n"&gt;z&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;tif&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;In principle with NumPy we might allocate a giant array and then iteratively
load images and place them into the giant array.&lt;/p&gt;
&lt;div class="highlight-python notranslate"&gt;&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span class="n"&gt;full_array&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;np&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;empty&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="o"&gt;...&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="o"&gt;...&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="o"&gt;...&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="o"&gt;...&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="o"&gt;...&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt; &lt;span class="n"&gt;dtype&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;sample&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;dtype&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;fn&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;filenames&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
    &lt;span class="n"&gt;img&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;imageio&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;imread&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;fn&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;index&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;get_location_from_filename&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;fn&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;  &lt;span class="c1"&gt;# We need to write this function&lt;/span&gt;
    &lt;span class="n"&gt;full_array&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;index&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;:,&lt;/span&gt; &lt;span class="p"&gt;:,&lt;/span&gt; &lt;span class="p"&gt;:]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;img&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;However if our data is large then we can’t load it all into memory at once like
this into a single Numpy array, and instead we need to be a bit more clever to
handle it efficiently. One approach here is to use &lt;a class="reference external" href="https://dask.org"&gt;Dask&lt;/a&gt;,
which handles larger-than-memory workloads easily.&lt;/p&gt;
&lt;/section&gt;
&lt;section id="lazily-load-images-with-dask-array"&gt;
&lt;h2&gt;Lazily load images with Dask Array&lt;/h2&gt;
&lt;p&gt;Now we learn how to lazily load and stitch together image data with Dask array.
We’ll start with simple examples first and then move onto the full example with
this more complex dataset afterwards.&lt;/p&gt;
&lt;p&gt;We can delay the &lt;code class="docutils literal notranslate"&gt;&lt;span class="pre"&gt;imageio.imread&lt;/span&gt;&lt;/code&gt; calls with &lt;a class="reference external" href="https://docs.dassk.org/en/latest/delayed.html"&gt;Dask
Delayed&lt;/a&gt;.&lt;/p&gt;
&lt;div class="highlight-python notranslate"&gt;&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span class="kn"&gt;import&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nn"&gt;dask&lt;/span&gt;
&lt;span class="kn"&gt;import&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nn"&gt;dask.array&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;as&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nn"&gt;da&lt;/span&gt;

&lt;span class="n"&gt;lazy_arrays&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;dask&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;delayed&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;imageio&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;imread&lt;/span&gt;&lt;span class="p"&gt;)(&lt;/span&gt;&lt;span class="n"&gt;fn&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;fn&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;filenames&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
&lt;span class="n"&gt;lazy_arrays&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;da&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;from_delayed&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;x&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;shape&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;sample&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;shape&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;dtype&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;sample&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;dtype&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
               &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;x&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;lazy_arrays&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;&lt;em&gt;Note: here we’re assuming that all of the images have the same shape and dtype
as the sample file that we loaded above. This is not always the case. See the
&lt;code class="docutils literal notranslate"&gt;&lt;span class="pre"&gt;dask_image&lt;/span&gt;&lt;/code&gt; note below in the Future Work section for an alternative.&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;We haven’t yet stitched these together. We have hundreds of single-chunk Dask
arrays, each of which lazily loads a single 3d chunk of data from disk. Lets look at a single array.&lt;/p&gt;
&lt;div class="highlight-python notranslate"&gt;&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span class="gp"&gt;&amp;gt;&amp;gt;&amp;gt; &lt;/span&gt;&lt;span class="n"&gt;lazy_arrays&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;table&gt;
&lt;tr&gt;
&lt;td&gt;
&lt;table&gt;  &lt;thead&gt;    &lt;tr&gt;&lt;td&gt; &lt;/td&gt;&lt;th&gt; Array &lt;/th&gt;&lt;th&gt; Chunk &lt;/th&gt;&lt;/tr&gt;
  &lt;/thead&gt;
  &lt;tbody&gt;
    &lt;tr&gt;&lt;th&gt; Bytes &lt;/th&gt;&lt;td&gt; 316.15 MB &lt;/td&gt; &lt;td&gt; 316.15 MB &lt;/td&gt;&lt;/tr&gt;
    &lt;tr&gt;&lt;th&gt; Shape &lt;/th&gt;&lt;td&gt; (201, 1024, 768) &lt;/td&gt; &lt;td&gt; (201, 1024, 768) &lt;/td&gt;&lt;/tr&gt;
    &lt;tr&gt;&lt;th&gt; Count &lt;/th&gt;&lt;td&gt; 2 Tasks &lt;/td&gt;&lt;td&gt; 1 Chunks &lt;/td&gt;&lt;/tr&gt;
    &lt;tr&gt;&lt;th&gt; Type &lt;/th&gt;&lt;td&gt; uint16 &lt;/td&gt;&lt;td&gt; numpy.ndarray &lt;/td&gt;&lt;/tr&gt;
  &lt;/tbody&gt;&lt;/table&gt;
&lt;/td&gt;
&lt;td&gt;
&lt;svg width="174" height="194" style="stroke:rgb(0,0,0);stroke-width:1" &gt;
  &lt;!-- Horizontal lines --&gt;
  &lt;line x1="10" y1="0" x2="34" y2="24" style="stroke-width:2" /&gt;
  &lt;line x1="10" y1="120" x2="34" y2="144" style="stroke-width:2" /&gt;
  &lt;!-- Vertical lines --&gt;
  &lt;line x1="10" y1="0" x2="10" y2="120" style="stroke-width:2" /&gt;
  &lt;line x1="34" y1="24" x2="34" y2="144" style="stroke-width:2" /&gt;
  &lt;!-- Colored Rectangle --&gt;
  &lt;polygon points="10.000000,0.000000 34.664918,24.664918 34.664918,144.664918 10.000000,120.000000" style="fill:#ECB172A0;stroke-width:0"/&gt;
  &lt;!-- Horizontal lines --&gt;
  &lt;line x1="10" y1="0" x2="100" y2="0" style="stroke-width:2" /&gt;
  &lt;line x1="34" y1="24" x2="124" y2="24" style="stroke-width:2" /&gt;
  &lt;!-- Vertical lines --&gt;
  &lt;line x1="10" y1="0" x2="34" y2="24" style="stroke-width:2" /&gt;
  &lt;line x1="100" y1="0" x2="124" y2="24" style="stroke-width:2" /&gt;
  &lt;!-- Colored Rectangle --&gt;
  &lt;polygon points="10.000000,0.000000 100.000000,0.000000 124.664918,24.664918 34.664918,24.664918" style="fill:#ECB172A0;stroke-width:0"/&gt;
  &lt;!-- Horizontal lines --&gt;
  &lt;line x1="34" y1="24" x2="124" y2="24" style="stroke-width:2" /&gt;
  &lt;line x1="34" y1="144" x2="124" y2="144" style="stroke-width:2" /&gt;
  &lt;!-- Vertical lines --&gt;
  &lt;line x1="34" y1="24" x2="34" y2="144" style="stroke-width:2" /&gt;
  &lt;line x1="124" y1="24" x2="124" y2="144" style="stroke-width:2" /&gt;
  &lt;!-- Colored Rectangle --&gt;
  &lt;polygon points="34.664918,24.664918 124.664918,24.664918 124.664918,144.664918 34.664918,144.664918" style="fill:#ECB172A0;stroke-width:0"/&gt;
  &lt;!-- Text --&gt;
&lt;p&gt;&lt;text x="79.664918" y="164.664918" font-size="1.0rem" font-weight="100" text-anchor="middle" &gt;768&lt;/text&gt;
&lt;text x="144.664918" y="84.664918" font-size="1.0rem" font-weight="100" text-anchor="middle" transform="rotate(-90,144.664918,84.664918)"&gt;1024&lt;/text&gt;
&lt;text x="12.332459" y="152.332459" font-size="1.0rem" font-weight="100" text-anchor="middle" transform="rotate(45,12.332459,152.332459)"&gt;201&lt;/text&gt;
&lt;/svg&gt;&lt;/p&gt;
&lt;/td&gt;
&lt;/tr&gt;
&lt;/table&gt;
&lt;p&gt;This is a lazy 3-dimensional Dask array of a &lt;em&gt;single&lt;/em&gt; 300MB chunk of data.
That chunk is created by loading in a particular TIFF file. Normally Dask
arrays are composed of &lt;em&gt;many&lt;/em&gt; chunks. We can concatenate many of these
single-chunked Dask arrays into a multi-chunked Dask array with functions like
&lt;a class="reference external" href="https://docs.dask.org/en/latest/array-api.html#dask.array.concatenate"&gt;da.concatenate&lt;/a&gt;
and
&lt;a class="reference external" href="https://docs.dask.org/en/latest/array-api.html#dask.array.stack"&gt;da.stack&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;Here we concatenate the first ten Dask arrays along a few axes, to get an
easier-to-understand picture of how this looks. Take a look both at how the
shape changes as we change the &lt;code class="docutils literal notranslate"&gt;&lt;span class="pre"&gt;axis=&lt;/span&gt;&lt;/code&gt; parameter both in the table on the left
and the image on the right.&lt;/p&gt;
&lt;div class="highlight-python notranslate"&gt;&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span class="n"&gt;da&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;concatenate&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;lazy_arrays&lt;/span&gt;&lt;span class="p"&gt;[:&lt;/span&gt;&lt;span class="mi"&gt;10&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt; &lt;span class="n"&gt;axis&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;table&gt;
&lt;tr&gt;
&lt;td&gt;
&lt;table&gt;  &lt;thead&gt;    &lt;tr&gt;&lt;td&gt; &lt;/td&gt;&lt;th&gt; Array &lt;/th&gt;&lt;th&gt; Chunk &lt;/th&gt;&lt;/tr&gt;
  &lt;/thead&gt;
  &lt;tbody&gt;
    &lt;tr&gt;&lt;th&gt; Bytes &lt;/th&gt;&lt;td&gt; 3.16 GB &lt;/td&gt; &lt;td&gt; 316.15 MB &lt;/td&gt;&lt;/tr&gt;
    &lt;tr&gt;&lt;th&gt; Shape &lt;/th&gt;&lt;td&gt; (2010, 1024, 768) &lt;/td&gt; &lt;td&gt; (201, 1024, 768) &lt;/td&gt;&lt;/tr&gt;
    &lt;tr&gt;&lt;th&gt; Count &lt;/th&gt;&lt;td&gt; 30 Tasks &lt;/td&gt;&lt;td&gt; 10 Chunks &lt;/td&gt;&lt;/tr&gt;
    &lt;tr&gt;&lt;th&gt; Type &lt;/th&gt;&lt;td&gt; uint16 &lt;/td&gt;&lt;td&gt; numpy.ndarray &lt;/td&gt;&lt;/tr&gt;
  &lt;/tbody&gt;&lt;/table&gt;
&lt;/td&gt;
&lt;td&gt;
&lt;svg width="176" height="181" style="stroke:rgb(0,0,0);stroke-width:1" &gt;
  &lt;!-- Horizontal lines --&gt;
  &lt;line x1="10" y1="0" x2="80" y2="70" style="stroke-width:2" /&gt;
  &lt;line x1="10" y1="61" x2="80" y2="131" style="stroke-width:2" /&gt;
  &lt;!-- Vertical lines --&gt;
  &lt;line x1="10" y1="0" x2="10" y2="61" style="stroke-width:2" /&gt;
  &lt;line x1="17" y1="7" x2="17" y2="68" /&gt;
  &lt;line x1="24" y1="14" x2="24" y2="75" /&gt;
  &lt;line x1="31" y1="21" x2="31" y2="82" /&gt;
  &lt;line x1="38" y1="28" x2="38" y2="89" /&gt;
  &lt;line x1="45" y1="35" x2="45" y2="96" /&gt;
  &lt;line x1="52" y1="42" x2="52" y2="103" /&gt;
  &lt;line x1="59" y1="49" x2="59" y2="110" /&gt;
  &lt;line x1="66" y1="56" x2="66" y2="117" /&gt;
  &lt;line x1="73" y1="63" x2="73" y2="124" /&gt;
  &lt;line x1="80" y1="70" x2="80" y2="131" style="stroke-width:2" /&gt;
  &lt;!-- Colored Rectangle --&gt;
  &lt;polygon points="10.000000,0.000000 80.588235,70.588235 80.588235,131.722564 10.000000,61.134328" style="fill:#ECB172A0;stroke-width:0"/&gt;
  &lt;!-- Horizontal lines --&gt;
  &lt;line x1="10" y1="0" x2="55" y2="0" style="stroke-width:2" /&gt;
  &lt;line x1="17" y1="7" x2="62" y2="7" /&gt;
  &lt;line x1="24" y1="14" x2="69" y2="14" /&gt;
  &lt;line x1="31" y1="21" x2="77" y2="21" /&gt;
  &lt;line x1="38" y1="28" x2="84" y2="28" /&gt;
  &lt;line x1="45" y1="35" x2="91" y2="35" /&gt;
  &lt;line x1="52" y1="42" x2="98" y2="42" /&gt;
  &lt;line x1="59" y1="49" x2="105" y2="49" /&gt;
  &lt;line x1="66" y1="56" x2="112" y2="56" /&gt;
  &lt;line x1="73" y1="63" x2="119" y2="63" /&gt;
  &lt;line x1="80" y1="70" x2="126" y2="70" style="stroke-width:2" /&gt;
  &lt;!-- Vertical lines --&gt;
  &lt;line x1="10" y1="0" x2="80" y2="70" style="stroke-width:2" /&gt;
  &lt;line x1="55" y1="0" x2="126" y2="70" style="stroke-width:2" /&gt;
  &lt;!-- Colored Rectangle --&gt;
  &lt;polygon points="10.000000,0.000000 55.850746,0.000000 126.438982,70.588235 80.588235,70.588235" style="fill:#ECB172A0;stroke-width:0"/&gt;
  &lt;!-- Horizontal lines --&gt;
  &lt;line x1="80" y1="70" x2="126" y2="70" style="stroke-width:2" /&gt;
  &lt;line x1="80" y1="131" x2="126" y2="131" style="stroke-width:2" /&gt;
  &lt;!-- Vertical lines --&gt;
  &lt;line x1="80" y1="70" x2="80" y2="131" style="stroke-width:2" /&gt;
  &lt;line x1="126" y1="70" x2="126" y2="131" style="stroke-width:2" /&gt;
  &lt;!-- Colored Rectangle --&gt;
  &lt;polygon points="80.588235,70.588235 126.438982,70.588235 126.438982,131.722564 80.588235,131.722564" style="fill:#ECB172A0;stroke-width:0"/&gt;
  &lt;!-- Text --&gt;
&lt;p&gt;&lt;text x="103.513608" y="151.722564" font-size="1.0rem" font-weight="100" text-anchor="middle" &gt;768&lt;/text&gt;
&lt;text x="146.438982" y="101.155399" font-size="1.0rem" font-weight="100" text-anchor="middle" transform="rotate(-90,146.438982,101.155399)"&gt;1024&lt;/text&gt;
&lt;text x="35.294118" y="116.428446" font-size="1.0rem" font-weight="100" text-anchor="middle" transform="rotate(45,35.294118,116.428446)"&gt;2010&lt;/text&gt;
&lt;/svg&gt;&lt;/p&gt;
&lt;/td&gt;
&lt;/tr&gt;
&lt;/table&gt;
&lt;div class="highlight-python notranslate"&gt;&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span class="n"&gt;da&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;concatenate&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;lazy_arrays&lt;/span&gt;&lt;span class="p"&gt;[:&lt;/span&gt;&lt;span class="mi"&gt;10&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt; &lt;span class="n"&gt;axis&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;table&gt;
&lt;tr&gt;
&lt;td&gt;
&lt;table&gt;  &lt;thead&gt;    &lt;tr&gt;&lt;td&gt; &lt;/td&gt;&lt;th&gt; Array &lt;/th&gt;&lt;th&gt; Chunk &lt;/th&gt;&lt;/tr&gt;
  &lt;/thead&gt;
  &lt;tbody&gt;
    &lt;tr&gt;&lt;th&gt; Bytes &lt;/th&gt;&lt;td&gt; 3.16 GB &lt;/td&gt; &lt;td&gt; 316.15 MB &lt;/td&gt;&lt;/tr&gt;
    &lt;tr&gt;&lt;th&gt; Shape &lt;/th&gt;&lt;td&gt; (201, 10240, 768) &lt;/td&gt; &lt;td&gt; (201, 1024, 768) &lt;/td&gt;&lt;/tr&gt;
    &lt;tr&gt;&lt;th&gt; Count &lt;/th&gt;&lt;td&gt; 30 Tasks &lt;/td&gt;&lt;td&gt; 10 Chunks &lt;/td&gt;&lt;/tr&gt;
    &lt;tr&gt;&lt;th&gt; Type &lt;/th&gt;&lt;td&gt; uint16 &lt;/td&gt;&lt;td&gt; numpy.ndarray &lt;/td&gt;&lt;/tr&gt;
  &lt;/tbody&gt;&lt;/table&gt;
&lt;/td&gt;
&lt;td&gt;
&lt;svg width="113" height="187" style="stroke:rgb(0,0,0);stroke-width:1" &gt;
  &lt;!-- Horizontal lines --&gt;
  &lt;line x1="10" y1="0" x2="27" y2="17" style="stroke-width:2" /&gt;
  &lt;line x1="10" y1="12" x2="27" y2="29" /&gt;
  &lt;line x1="10" y1="24" x2="27" y2="41" /&gt;
  &lt;line x1="10" y1="36" x2="27" y2="53" /&gt;
  &lt;line x1="10" y1="48" x2="27" y2="65" /&gt;
  &lt;line x1="10" y1="60" x2="27" y2="77" /&gt;
  &lt;line x1="10" y1="72" x2="27" y2="89" /&gt;
  &lt;line x1="10" y1="84" x2="27" y2="101" /&gt;
  &lt;line x1="10" y1="96" x2="27" y2="113" /&gt;
  &lt;line x1="10" y1="108" x2="27" y2="125" /&gt;
  &lt;line x1="10" y1="120" x2="27" y2="137" style="stroke-width:2" /&gt;
  &lt;!-- Vertical lines --&gt;
  &lt;line x1="10" y1="0" x2="10" y2="120" style="stroke-width:2" /&gt;
  &lt;line x1="27" y1="17" x2="27" y2="137" style="stroke-width:2" /&gt;
  &lt;!-- Colored Rectangle --&gt;
  &lt;polygon points="10.000000,0.000000 27.014952,17.014952 27.014952,137.014952 10.000000,120.000000" style="fill:#ECB172A0;stroke-width:0"/&gt;
  &lt;!-- Horizontal lines --&gt;
  &lt;line x1="10" y1="0" x2="46" y2="0" style="stroke-width:2" /&gt;
  &lt;line x1="27" y1="17" x2="63" y2="17" style="stroke-width:2" /&gt;
  &lt;!-- Vertical lines --&gt;
  &lt;line x1="10" y1="0" x2="27" y2="17" style="stroke-width:2" /&gt;
  &lt;line x1="46" y1="0" x2="63" y2="17" style="stroke-width:2" /&gt;
  &lt;!-- Colored Rectangle --&gt;
  &lt;polygon points="10.000000,0.000000 46.948234,0.000000 63.963186,17.014952 27.014952,17.014952" style="fill:#ECB172A0;stroke-width:0"/&gt;
  &lt;!-- Horizontal lines --&gt;
  &lt;line x1="27" y1="17" x2="63" y2="17" style="stroke-width:2" /&gt;
  &lt;line x1="27" y1="29" x2="63" y2="29" /&gt;
  &lt;line x1="27" y1="41" x2="63" y2="41" /&gt;
  &lt;line x1="27" y1="53" x2="63" y2="53" /&gt;
  &lt;line x1="27" y1="65" x2="63" y2="65" /&gt;
  &lt;line x1="27" y1="77" x2="63" y2="77" /&gt;
  &lt;line x1="27" y1="89" x2="63" y2="89" /&gt;
  &lt;line x1="27" y1="101" x2="63" y2="101" /&gt;
  &lt;line x1="27" y1="113" x2="63" y2="113" /&gt;
  &lt;line x1="27" y1="125" x2="63" y2="125" /&gt;
  &lt;line x1="27" y1="137" x2="63" y2="137" style="stroke-width:2" /&gt;
  &lt;!-- Vertical lines --&gt;
  &lt;line x1="27" y1="17" x2="27" y2="137" style="stroke-width:2" /&gt;
  &lt;line x1="63" y1="17" x2="63" y2="137" style="stroke-width:2" /&gt;
  &lt;!-- Colored Rectangle --&gt;
  &lt;polygon points="27.014952,17.014952 63.963186,17.014952 63.963186,137.014952 27.014952,137.014952" style="fill:#ECB172A0;stroke-width:0"/&gt;
  &lt;!-- Text --&gt;
&lt;p&gt;&lt;text x="45.489069" y="157.014952" font-size="1.0rem" font-weight="100" text-anchor="middle" &gt;768&lt;/text&gt;
&lt;text x="83.963186" y="77.014952" font-size="1.0rem" font-weight="100" text-anchor="middle" transform="rotate(-90,83.963186,77.014952)"&gt;10240&lt;/text&gt;
&lt;text x="8.507476" y="148.507476" font-size="1.0rem" font-weight="100" text-anchor="middle" transform="rotate(45,8.507476,148.507476)"&gt;201&lt;/text&gt;
&lt;/svg&gt;&lt;/p&gt;
&lt;/td&gt;
&lt;/tr&gt;
&lt;/table&gt;
&lt;div class="highlight-python notranslate"&gt;&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span class="n"&gt;da&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;concatenate&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;lazy_arrays&lt;/span&gt;&lt;span class="p"&gt;[:&lt;/span&gt;&lt;span class="mi"&gt;10&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt; &lt;span class="n"&gt;axis&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;table&gt;
&lt;tr&gt;
&lt;td&gt;
&lt;table&gt;  &lt;thead&gt;    &lt;tr&gt;&lt;td&gt; &lt;/td&gt;&lt;th&gt; Array &lt;/th&gt;&lt;th&gt; Chunk &lt;/th&gt;&lt;/tr&gt;
  &lt;/thead&gt;
  &lt;tbody&gt;
    &lt;tr&gt;&lt;th&gt; Bytes &lt;/th&gt;&lt;td&gt; 3.16 GB &lt;/td&gt; &lt;td&gt; 316.15 MB &lt;/td&gt;&lt;/tr&gt;
    &lt;tr&gt;&lt;th&gt; Shape &lt;/th&gt;&lt;td&gt; (201, 1024, 7680) &lt;/td&gt; &lt;td&gt; (201, 1024, 768) &lt;/td&gt;&lt;/tr&gt;
    &lt;tr&gt;&lt;th&gt; Count &lt;/th&gt;&lt;td&gt; 30 Tasks &lt;/td&gt;&lt;td&gt; 10 Chunks &lt;/td&gt;&lt;/tr&gt;
    &lt;tr&gt;&lt;th&gt; Type &lt;/th&gt;&lt;td&gt; uint16 &lt;/td&gt;&lt;td&gt; numpy.ndarray &lt;/td&gt;&lt;/tr&gt;
  &lt;/tbody&gt;&lt;/table&gt;
&lt;/td&gt;
&lt;td&gt;
&lt;svg width="197" height="108" style="stroke:rgb(0,0,0);stroke-width:1" &gt;
  &lt;!-- Horizontal lines --&gt;
  &lt;line x1="10" y1="0" x2="27" y2="17" style="stroke-width:2" /&gt;
  &lt;line x1="10" y1="40" x2="27" y2="58" style="stroke-width:2" /&gt;
  &lt;!-- Vertical lines --&gt;
  &lt;line x1="10" y1="0" x2="10" y2="40" style="stroke-width:2" /&gt;
  &lt;line x1="27" y1="17" x2="27" y2="58" style="stroke-width:2" /&gt;
  &lt;!-- Colored Rectangle --&gt;
  &lt;polygon points="10.000000,0.000000 27.988258,17.988258 27.988258,58.112379 10.000000,40.124121" style="fill:#ECB172A0;stroke-width:0"/&gt;
  &lt;!-- Horizontal lines --&gt;
  &lt;line x1="10" y1="0" x2="130" y2="0" style="stroke-width:2" /&gt;
  &lt;line x1="27" y1="17" x2="147" y2="17" style="stroke-width:2" /&gt;
  &lt;!-- Vertical lines --&gt;
  &lt;line x1="10" y1="0" x2="27" y2="17" style="stroke-width:2" /&gt;
  &lt;line x1="22" y1="0" x2="39" y2="17" /&gt;
  &lt;line x1="34" y1="0" x2="51" y2="17" /&gt;
  &lt;line x1="46" y1="0" x2="63" y2="17" /&gt;
  &lt;line x1="58" y1="0" x2="75" y2="17" /&gt;
  &lt;line x1="70" y1="0" x2="87" y2="17" /&gt;
  &lt;line x1="82" y1="0" x2="99" y2="17" /&gt;
  &lt;line x1="94" y1="0" x2="111" y2="17" /&gt;
  &lt;line x1="106" y1="0" x2="123" y2="17" /&gt;
  &lt;line x1="118" y1="0" x2="135" y2="17" /&gt;
  &lt;line x1="130" y1="0" x2="147" y2="17" style="stroke-width:2" /&gt;
  &lt;!-- Colored Rectangle --&gt;
  &lt;polygon points="10.000000,0.000000 130.000000,0.000000 147.988258,17.988258 27.988258,17.988258" style="fill:#ECB172A0;stroke-width:0"/&gt;
  &lt;!-- Horizontal lines --&gt;
  &lt;line x1="27" y1="17" x2="147" y2="17" style="stroke-width:2" /&gt;
  &lt;line x1="27" y1="58" x2="147" y2="58" style="stroke-width:2" /&gt;
  &lt;!-- Vertical lines --&gt;
  &lt;line x1="27" y1="17" x2="27" y2="58" style="stroke-width:2" /&gt;
  &lt;line x1="39" y1="17" x2="39" y2="58" /&gt;
  &lt;line x1="51" y1="17" x2="51" y2="58" /&gt;
  &lt;line x1="63" y1="17" x2="63" y2="58" /&gt;
  &lt;line x1="75" y1="17" x2="75" y2="58" /&gt;
  &lt;line x1="87" y1="17" x2="87" y2="58" /&gt;
  &lt;line x1="99" y1="17" x2="99" y2="58" /&gt;
  &lt;line x1="111" y1="17" x2="111" y2="58" /&gt;
  &lt;line x1="123" y1="17" x2="123" y2="58" /&gt;
  &lt;line x1="135" y1="17" x2="135" y2="58" /&gt;
  &lt;line x1="147" y1="17" x2="147" y2="58" style="stroke-width:2" /&gt;
  &lt;!-- Colored Rectangle --&gt;
  &lt;polygon points="27.988258,17.988258 147.988258,17.988258 147.988258,58.112379 27.988258,58.112379" style="fill:#ECB172A0;stroke-width:0"/&gt;
  &lt;!-- Text --&gt;
&lt;p&gt;&lt;text x="87.988258" y="78.112379" font-size="1.0rem" font-weight="100" text-anchor="middle" &gt;7680&lt;/text&gt;
&lt;text x="167.988258" y="38.050318" font-size="1.0rem" font-weight="100" text-anchor="middle" transform="rotate(-90,167.988258,38.050318)"&gt;1024&lt;/text&gt;
&lt;text x="8.994129" y="69.118250" font-size="1.0rem" font-weight="100" text-anchor="middle" transform="rotate(45,8.994129,69.118250)"&gt;201&lt;/text&gt;
&lt;/svg&gt;&lt;/p&gt;
&lt;/td&gt;
&lt;/tr&gt;
&lt;/table&gt;
&lt;p&gt;Or, if we wanted to make a new dimension, we would use &lt;code class="docutils literal notranslate"&gt;&lt;span class="pre"&gt;da.stack&lt;/span&gt;&lt;/code&gt;. In this
case note that we’ve run out of easily visible dimensions, so you should take
note of the listed shape in the table input on the left more than the picture
on the right. Notice that we’ve stacked these 3d images into a 4d image.&lt;/p&gt;
&lt;div class="highlight-python notranslate"&gt;&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span class="n"&gt;da&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;stack&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;lazy_arrays&lt;/span&gt;&lt;span class="p"&gt;[:&lt;/span&gt;&lt;span class="mi"&gt;10&lt;/span&gt;&lt;span class="p"&gt;])&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;table&gt;
&lt;tr&gt;
&lt;td&gt;
&lt;table&gt;  &lt;thead&gt;    &lt;tr&gt;&lt;td&gt; &lt;/td&gt;&lt;th&gt; Array &lt;/th&gt;&lt;th&gt; Chunk &lt;/th&gt;&lt;/tr&gt;
  &lt;/thead&gt;
  &lt;tbody&gt;
    &lt;tr&gt;&lt;th&gt; Bytes &lt;/th&gt;&lt;td&gt; 3.16 GB &lt;/td&gt; &lt;td&gt; 316.15 MB &lt;/td&gt;&lt;/tr&gt;
    &lt;tr&gt;&lt;th&gt; Shape &lt;/th&gt;&lt;td&gt; (10, 201, 1024, 768) &lt;/td&gt; &lt;td&gt; (1, 201, 1024, 768) &lt;/td&gt;&lt;/tr&gt;
    &lt;tr&gt;&lt;th&gt; Count &lt;/th&gt;&lt;td&gt; 30 Tasks &lt;/td&gt;&lt;td&gt; 10 Chunks &lt;/td&gt;&lt;/tr&gt;
    &lt;tr&gt;&lt;th&gt; Type &lt;/th&gt;&lt;td&gt; uint16 &lt;/td&gt;&lt;td&gt; numpy.ndarray &lt;/td&gt;&lt;/tr&gt;
  &lt;/tbody&gt;&lt;/table&gt;
&lt;/td&gt;
&lt;td&gt;
&lt;svg width="354" height="194" style="stroke:rgb(0,0,0);stroke-width:1" &gt;
  &lt;!-- Horizontal lines --&gt;
  &lt;line x1="0" y1="0" x2="25" y2="0" style="stroke-width:2" /&gt;
  &lt;line x1="0" y1="25" x2="25" y2="25" style="stroke-width:2" /&gt;
  &lt;!-- Vertical lines --&gt;
  &lt;line x1="0" y1="0" x2="0" y2="25" style="stroke-width:2" /&gt;
  &lt;line x1="2" y1="0" x2="2" y2="25" /&gt;
  &lt;line x1="5" y1="0" x2="5" y2="25" /&gt;
  &lt;line x1="7" y1="0" x2="7" y2="25" /&gt;
  &lt;line x1="10" y1="0" x2="10" y2="25" /&gt;
  &lt;line x1="12" y1="0" x2="12" y2="25" /&gt;
  &lt;line x1="15" y1="0" x2="15" y2="25" /&gt;
  &lt;line x1="17" y1="0" x2="17" y2="25" /&gt;
  &lt;line x1="20" y1="0" x2="20" y2="25" /&gt;
  &lt;line x1="22" y1="0" x2="22" y2="25" /&gt;
  &lt;line x1="25" y1="0" x2="25" y2="25" style="stroke-width:2" /&gt;
  &lt;!-- Colored Rectangle --&gt;
  &lt;polygon points="0.000000,0.000000 25.412617,0.000000 25.412617,25.412617 0.000000,25.412617" style="fill:#ECB172A0;stroke-width:0"/&gt;
  &lt;!-- Text --&gt;
&lt;p&gt;&lt;text x="12.706308" y="45.412617" font-size="1.0rem" font-weight="100" text-anchor="middle" &gt;10&lt;/text&gt;
&lt;text x="45.412617" y="12.706308" font-size="1.0rem" font-weight="100" text-anchor="middle" transform="rotate(0,45.412617,12.706308)"&gt;1&lt;/text&gt;&lt;/p&gt;
  &lt;!-- Horizontal lines --&gt;
  &lt;line x1="95" y1="0" x2="119" y2="24" style="stroke-width:2" /&gt;
  &lt;line x1="95" y1="120" x2="119" y2="144" style="stroke-width:2" /&gt;
  &lt;!-- Vertical lines --&gt;
  &lt;line x1="95" y1="0" x2="95" y2="120" style="stroke-width:2" /&gt;
  &lt;line x1="119" y1="24" x2="119" y2="144" style="stroke-width:2" /&gt;
  &lt;!-- Colored Rectangle --&gt;
  &lt;polygon points="95.000000,0.000000 119.664918,24.664918 119.664918,144.664918 95.000000,120.000000" style="fill:#ECB172A0;stroke-width:0"/&gt;
  &lt;!-- Horizontal lines --&gt;
  &lt;line x1="95" y1="0" x2="185" y2="0" style="stroke-width:2" /&gt;
  &lt;line x1="119" y1="24" x2="209" y2="24" style="stroke-width:2" /&gt;
  &lt;!-- Vertical lines --&gt;
  &lt;line x1="95" y1="0" x2="119" y2="24" style="stroke-width:2" /&gt;
  &lt;line x1="185" y1="0" x2="209" y2="24" style="stroke-width:2" /&gt;
  &lt;!-- Colored Rectangle --&gt;
  &lt;polygon points="95.000000,0.000000 185.000000,0.000000 209.664918,24.664918 119.664918,24.664918" style="fill:#ECB172A0;stroke-width:0"/&gt;
  &lt;!-- Horizontal lines --&gt;
  &lt;line x1="119" y1="24" x2="209" y2="24" style="stroke-width:2" /&gt;
  &lt;line x1="119" y1="144" x2="209" y2="144" style="stroke-width:2" /&gt;
  &lt;!-- Vertical lines --&gt;
  &lt;line x1="119" y1="24" x2="119" y2="144" style="stroke-width:2" /&gt;
  &lt;line x1="209" y1="24" x2="209" y2="144" style="stroke-width:2" /&gt;
  &lt;!-- Colored Rectangle --&gt;
  &lt;polygon points="119.664918,24.664918 209.664918,24.664918 209.664918,144.664918 119.664918,144.664918" style="fill:#ECB172A0;stroke-width:0"/&gt;
  &lt;!-- Text --&gt;
&lt;p&gt;&lt;text x="164.664918" y="164.664918" font-size="1.0rem" font-weight="100" text-anchor="middle" &gt;768&lt;/text&gt;
&lt;text x="229.664918" y="84.664918" font-size="1.0rem" font-weight="100" text-anchor="middle" transform="rotate(-90,229.664918,84.664918)"&gt;1024&lt;/text&gt;
&lt;text x="97.332459" y="152.332459" font-size="1.0rem" font-weight="100" text-anchor="middle" transform="rotate(45,97.332459,152.332459)"&gt;201&lt;/text&gt;
&lt;/svg&gt;&lt;/p&gt;
&lt;/td&gt;
&lt;/tr&gt;
&lt;/table&gt;
&lt;p&gt;These are the common case situations, where you have a single axis along which
you want to stitch images together.&lt;/p&gt;
&lt;/section&gt;
&lt;section id="full-example"&gt;
&lt;h2&gt;Full example&lt;/h2&gt;
&lt;p&gt;This works fine for combining along a single axis. However if we need to
combine across multiple we need to perform multiple concatenate steps.
Fortunately there is a simpler option &lt;a class="reference external" href="https://docs.dask.org/en/latest/array-api.html#dask.array.block"&gt;da.block&lt;/a&gt;, which can
concatenate along multiple axes at once if you give it a nested list of dask
arrays.&lt;/p&gt;
&lt;div class="highlight-python notranslate"&gt;&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span class="n"&gt;a&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;da&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;block&lt;/span&gt;&lt;span class="p"&gt;([[&lt;/span&gt;&lt;span class="n"&gt;laxy_array_00&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;lazy_array_01&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;
              &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;lazy_array_10&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;lazy_array_11&lt;/span&gt;&lt;span class="p"&gt;]])&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;We now do the following:&lt;/p&gt;
&lt;ul class="simple"&gt;
&lt;li&gt;&lt;p&gt;Parse each filename to learn where it should live in the larger array&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;See how many files are in each of our relevant dimensions&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Allocate a NumPy object-dtype array of the appropriate size, where each
element of this array will hold a single-chunk Dask array&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Go through our filenames and insert the proper Dask array into the right
position&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Call &lt;code class="docutils literal notranslate"&gt;&lt;span class="pre"&gt;da.block&lt;/span&gt;&lt;/code&gt; on the result&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;This code is a bit complex, but shows what this looks like in a real-world
setting&lt;/p&gt;
&lt;div class="highlight-python notranslate"&gt;&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span class="c1"&gt;# Get various dimensions&lt;/span&gt;

&lt;span class="n"&gt;fn_comp_sets&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;dict&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;fn&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;filenames&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
    &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;comp&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="nb"&gt;enumerate&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;os&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;path&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;splitext&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;fn&lt;/span&gt;&lt;span class="p"&gt;)[&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;split&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;_&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;)):&lt;/span&gt;
        &lt;span class="n"&gt;fn_comp_sets&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;setdefault&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nb"&gt;set&lt;/span&gt;&lt;span class="p"&gt;())&lt;/span&gt;
        &lt;span class="n"&gt;fn_comp_sets&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;add&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;comp&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="n"&gt;fn_comp_sets&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;list&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;map&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;sorted&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;fn_comp_sets&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;values&lt;/span&gt;&lt;span class="p"&gt;()))&lt;/span&gt;

&lt;span class="n"&gt;remap_comps&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;
    &lt;span class="nb"&gt;dict&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;map&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;reversed&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nb"&gt;enumerate&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;fn_comp_sets&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;]))),&lt;/span&gt;
    &lt;span class="nb"&gt;dict&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;map&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;reversed&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nb"&gt;enumerate&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;fn_comp_sets&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;4&lt;/span&gt;&lt;span class="p"&gt;])))&lt;/span&gt;
&lt;span class="p"&gt;]&lt;/span&gt;

&lt;span class="c1"&gt;# Create an empty object array to organize each chunk that loads a TIFF&lt;/span&gt;
&lt;span class="n"&gt;a&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;np&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;empty&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;tuple&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;map&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;len&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;remap_comps&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt; &lt;span class="n"&gt;dtype&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="nb"&gt;object&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;fn&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;x&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="nb"&gt;zip&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;filenames&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;lazy_arrays&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="n"&gt;channel&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;int&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;fn&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;fn&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;index&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;_ch&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="mi"&gt;3&lt;/span&gt;&lt;span class="p"&gt;:]&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;split&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;_&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;)[&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;])&lt;/span&gt;
    &lt;span class="n"&gt;stack&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;int&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;fn&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;fn&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;index&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;_stack&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="mi"&gt;6&lt;/span&gt;&lt;span class="p"&gt;:]&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;split&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;_&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;)[&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;])&lt;/span&gt;

    &lt;span class="n"&gt;a&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;channel&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;stack&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;x&lt;/span&gt;

&lt;span class="c1"&gt;# Stitch together the many blocks into a single array&lt;/span&gt;
&lt;span class="n"&gt;a&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;da&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;block&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;a&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;tolist&lt;/span&gt;&lt;span class="p"&gt;())&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;table&gt;
&lt;tr&gt;
&lt;td&gt;
&lt;table&gt;  &lt;thead&gt;    &lt;tr&gt;&lt;td&gt; &lt;/td&gt;&lt;th&gt; Array &lt;/th&gt;&lt;th&gt; Chunk &lt;/th&gt;&lt;/tr&gt;
  &lt;/thead&gt;
  &lt;tbody&gt;
    &lt;tr&gt;&lt;th&gt; Bytes &lt;/th&gt;&lt;td&gt; 188.74 GB &lt;/td&gt; &lt;td&gt; 316.15 MB &lt;/td&gt;&lt;/tr&gt;
    &lt;tr&gt;&lt;th&gt; Shape &lt;/th&gt;&lt;td&gt; (3, 199, 201, 1024, 768) &lt;/td&gt; &lt;td&gt; (1, 1, 201, 1024, 768) &lt;/td&gt;&lt;/tr&gt;
    &lt;tr&gt;&lt;th&gt; Count &lt;/th&gt;&lt;td&gt; 2985 Tasks &lt;/td&gt;&lt;td&gt; 597 Chunks &lt;/td&gt;&lt;/tr&gt;
    &lt;tr&gt;&lt;th&gt; Type &lt;/th&gt;&lt;td&gt; uint16 &lt;/td&gt;&lt;td&gt; numpy.ndarray &lt;/td&gt;&lt;/tr&gt;
  &lt;/tbody&gt;&lt;/table&gt;
&lt;/td&gt;
&lt;td&gt;
&lt;svg width="386" height="194" style="stroke:rgb(0,0,0);stroke-width:1" &gt;
  &lt;!-- Horizontal lines --&gt;
  &lt;line x1="0" y1="0" x2="41" y2="0" style="stroke-width:2" /&gt;
  &lt;line x1="0" y1="8" x2="41" y2="8" /&gt;
  &lt;line x1="0" y1="16" x2="41" y2="16" /&gt;
  &lt;line x1="0" y1="25" x2="41" y2="25" style="stroke-width:2" /&gt;
  &lt;!-- Vertical lines --&gt;
  &lt;line x1="0" y1="0" x2="0" y2="25" style="stroke-width:2" /&gt;
  &lt;line x1="0" y1="0" x2="0" y2="25" /&gt;
  &lt;line x1="0" y1="0" x2="0" y2="25" /&gt;
  &lt;line x1="0" y1="0" x2="0" y2="25" /&gt;
  &lt;line x1="0" y1="0" x2="0" y2="25" /&gt;
  &lt;line x1="1" y1="0" x2="1" y2="25" /&gt;
  &lt;line x1="1" y1="0" x2="1" y2="25" /&gt;
  &lt;line x1="1" y1="0" x2="1" y2="25" /&gt;
  &lt;line x1="1" y1="0" x2="1" y2="25" /&gt;
  &lt;line x1="1" y1="0" x2="1" y2="25" /&gt;
  &lt;line x1="2" y1="0" x2="2" y2="25" /&gt;
  &lt;line x1="2" y1="0" x2="2" y2="25" /&gt;
  &lt;line x1="2" y1="0" x2="2" y2="25" /&gt;
  &lt;line x1="2" y1="0" x2="2" y2="25" /&gt;
  &lt;line x1="2" y1="0" x2="2" y2="25" /&gt;
  &lt;line x1="3" y1="0" x2="3" y2="25" /&gt;
  &lt;line x1="3" y1="0" x2="3" y2="25" /&gt;
  &lt;line x1="3" y1="0" x2="3" y2="25" /&gt;
  &lt;line x1="3" y1="0" x2="3" y2="25" /&gt;
  &lt;line x1="3" y1="0" x2="3" y2="25" /&gt;
  &lt;line x1="4" y1="0" x2="4" y2="25" /&gt;
  &lt;line x1="4" y1="0" x2="4" y2="25" /&gt;
  &lt;line x1="4" y1="0" x2="4" y2="25" /&gt;
  &lt;line x1="4" y1="0" x2="4" y2="25" /&gt;
  &lt;line x1="5" y1="0" x2="5" y2="25" /&gt;
  &lt;line x1="5" y1="0" x2="5" y2="25" /&gt;
  &lt;line x1="5" y1="0" x2="5" y2="25" /&gt;
  &lt;line x1="5" y1="0" x2="5" y2="25" /&gt;
  &lt;line x1="5" y1="0" x2="5" y2="25" /&gt;
  &lt;line x1="6" y1="0" x2="6" y2="25" /&gt;
  &lt;line x1="6" y1="0" x2="6" y2="25" /&gt;
  &lt;line x1="6" y1="0" x2="6" y2="25" /&gt;
  &lt;line x1="6" y1="0" x2="6" y2="25" /&gt;
  &lt;line x1="6" y1="0" x2="6" y2="25" /&gt;
  &lt;line x1="7" y1="0" x2="7" y2="25" /&gt;
  &lt;line x1="7" y1="0" x2="7" y2="25" /&gt;
  &lt;line x1="7" y1="0" x2="7" y2="25" /&gt;
  &lt;line x1="7" y1="0" x2="7" y2="25" /&gt;
  &lt;line x1="7" y1="0" x2="7" y2="25" /&gt;
  &lt;line x1="8" y1="0" x2="8" y2="25" /&gt;
  &lt;line x1="8" y1="0" x2="8" y2="25" /&gt;
  &lt;line x1="8" y1="0" x2="8" y2="25" /&gt;
  &lt;line x1="8" y1="0" x2="8" y2="25" /&gt;
  &lt;line x1="9" y1="0" x2="9" y2="25" /&gt;
  &lt;line x1="9" y1="0" x2="9" y2="25" /&gt;
  &lt;line x1="9" y1="0" x2="9" y2="25" /&gt;
  &lt;line x1="9" y1="0" x2="9" y2="25" /&gt;
  &lt;line x1="9" y1="0" x2="9" y2="25" /&gt;
  &lt;line x1="10" y1="0" x2="10" y2="25" /&gt;
  &lt;line x1="10" y1="0" x2="10" y2="25" /&gt;
  &lt;line x1="10" y1="0" x2="10" y2="25" /&gt;
  &lt;line x1="10" y1="0" x2="10" y2="25" /&gt;
  &lt;line x1="10" y1="0" x2="10" y2="25" /&gt;
  &lt;line x1="11" y1="0" x2="11" y2="25" /&gt;
  &lt;line x1="11" y1="0" x2="11" y2="25" /&gt;
  &lt;line x1="11" y1="0" x2="11" y2="25" /&gt;
  &lt;line x1="11" y1="0" x2="11" y2="25" /&gt;
  &lt;line x1="11" y1="0" x2="11" y2="25" /&gt;
  &lt;line x1="12" y1="0" x2="12" y2="25" /&gt;
  &lt;line x1="12" y1="0" x2="12" y2="25" /&gt;
  &lt;line x1="12" y1="0" x2="12" y2="25" /&gt;
  &lt;line x1="12" y1="0" x2="12" y2="25" /&gt;
  &lt;line x1="13" y1="0" x2="13" y2="25" /&gt;
  &lt;line x1="13" y1="0" x2="13" y2="25" /&gt;
  &lt;line x1="13" y1="0" x2="13" y2="25" /&gt;
  &lt;line x1="13" y1="0" x2="13" y2="25" /&gt;
  &lt;line x1="13" y1="0" x2="13" y2="25" /&gt;
  &lt;line x1="14" y1="0" x2="14" y2="25" /&gt;
  &lt;line x1="14" y1="0" x2="14" y2="25" /&gt;
  &lt;line x1="14" y1="0" x2="14" y2="25" /&gt;
  &lt;line x1="14" y1="0" x2="14" y2="25" /&gt;
  &lt;line x1="14" y1="0" x2="14" y2="25" /&gt;
  &lt;line x1="15" y1="0" x2="15" y2="25" /&gt;
  &lt;line x1="15" y1="0" x2="15" y2="25" /&gt;
  &lt;line x1="15" y1="0" x2="15" y2="25" /&gt;
  &lt;line x1="15" y1="0" x2="15" y2="25" /&gt;
  &lt;line x1="15" y1="0" x2="15" y2="25" /&gt;
  &lt;line x1="16" y1="0" x2="16" y2="25" /&gt;
  &lt;line x1="16" y1="0" x2="16" y2="25" /&gt;
  &lt;line x1="16" y1="0" x2="16" y2="25" /&gt;
  &lt;line x1="16" y1="0" x2="16" y2="25" /&gt;
  &lt;line x1="17" y1="0" x2="17" y2="25" /&gt;
  &lt;line x1="17" y1="0" x2="17" y2="25" /&gt;
  &lt;line x1="17" y1="0" x2="17" y2="25" /&gt;
  &lt;line x1="17" y1="0" x2="17" y2="25" /&gt;
  &lt;line x1="17" y1="0" x2="17" y2="25" /&gt;
  &lt;line x1="18" y1="0" x2="18" y2="25" /&gt;
  &lt;line x1="18" y1="0" x2="18" y2="25" /&gt;
  &lt;line x1="18" y1="0" x2="18" y2="25" /&gt;
  &lt;line x1="18" y1="0" x2="18" y2="25" /&gt;
  &lt;line x1="18" y1="0" x2="18" y2="25" /&gt;
  &lt;line x1="19" y1="0" x2="19" y2="25" /&gt;
  &lt;line x1="19" y1="0" x2="19" y2="25" /&gt;
  &lt;line x1="19" y1="0" x2="19" y2="25" /&gt;
  &lt;line x1="19" y1="0" x2="19" y2="25" /&gt;
  &lt;line x1="19" y1="0" x2="19" y2="25" /&gt;
  &lt;line x1="20" y1="0" x2="20" y2="25" /&gt;
  &lt;line x1="20" y1="0" x2="20" y2="25" /&gt;
  &lt;line x1="20" y1="0" x2="20" y2="25" /&gt;
  &lt;line x1="20" y1="0" x2="20" y2="25" /&gt;
  &lt;line x1="21" y1="0" x2="21" y2="25" /&gt;
  &lt;line x1="21" y1="0" x2="21" y2="25" /&gt;
  &lt;line x1="21" y1="0" x2="21" y2="25" /&gt;
  &lt;line x1="21" y1="0" x2="21" y2="25" /&gt;
  &lt;line x1="21" y1="0" x2="21" y2="25" /&gt;
  &lt;line x1="22" y1="0" x2="22" y2="25" /&gt;
  &lt;line x1="22" y1="0" x2="22" y2="25" /&gt;
  &lt;line x1="22" y1="0" x2="22" y2="25" /&gt;
  &lt;line x1="22" y1="0" x2="22" y2="25" /&gt;
  &lt;line x1="22" y1="0" x2="22" y2="25" /&gt;
  &lt;line x1="23" y1="0" x2="23" y2="25" /&gt;
  &lt;line x1="23" y1="0" x2="23" y2="25" /&gt;
  &lt;line x1="23" y1="0" x2="23" y2="25" /&gt;
  &lt;line x1="23" y1="0" x2="23" y2="25" /&gt;
  &lt;line x1="23" y1="0" x2="23" y2="25" /&gt;
  &lt;line x1="24" y1="0" x2="24" y2="25" /&gt;
  &lt;line x1="24" y1="0" x2="24" y2="25" /&gt;
  &lt;line x1="24" y1="0" x2="24" y2="25" /&gt;
  &lt;line x1="24" y1="0" x2="24" y2="25" /&gt;
  &lt;line x1="25" y1="0" x2="25" y2="25" /&gt;
  &lt;line x1="25" y1="0" x2="25" y2="25" /&gt;
  &lt;line x1="25" y1="0" x2="25" y2="25" /&gt;
  &lt;line x1="25" y1="0" x2="25" y2="25" /&gt;
  &lt;line x1="25" y1="0" x2="25" y2="25" /&gt;
  &lt;line x1="26" y1="0" x2="26" y2="25" /&gt;
  &lt;line x1="26" y1="0" x2="26" y2="25" /&gt;
  &lt;line x1="26" y1="0" x2="26" y2="25" /&gt;
  &lt;line x1="26" y1="0" x2="26" y2="25" /&gt;
  &lt;line x1="26" y1="0" x2="26" y2="25" /&gt;
  &lt;line x1="27" y1="0" x2="27" y2="25" /&gt;
  &lt;line x1="27" y1="0" x2="27" y2="25" /&gt;
  &lt;line x1="27" y1="0" x2="27" y2="25" /&gt;
  &lt;line x1="27" y1="0" x2="27" y2="25" /&gt;
  &lt;line x1="27" y1="0" x2="27" y2="25" /&gt;
  &lt;line x1="28" y1="0" x2="28" y2="25" /&gt;
  &lt;line x1="28" y1="0" x2="28" y2="25" /&gt;
  &lt;line x1="28" y1="0" x2="28" y2="25" /&gt;
  &lt;line x1="28" y1="0" x2="28" y2="25" /&gt;
  &lt;line x1="29" y1="0" x2="29" y2="25" /&gt;
  &lt;line x1="29" y1="0" x2="29" y2="25" /&gt;
  &lt;line x1="29" y1="0" x2="29" y2="25" /&gt;
  &lt;line x1="29" y1="0" x2="29" y2="25" /&gt;
  &lt;line x1="29" y1="0" x2="29" y2="25" /&gt;
  &lt;line x1="30" y1="0" x2="30" y2="25" /&gt;
  &lt;line x1="30" y1="0" x2="30" y2="25" /&gt;
  &lt;line x1="30" y1="0" x2="30" y2="25" /&gt;
  &lt;line x1="30" y1="0" x2="30" y2="25" /&gt;
  &lt;line x1="30" y1="0" x2="30" y2="25" /&gt;
  &lt;line x1="31" y1="0" x2="31" y2="25" /&gt;
  &lt;line x1="31" y1="0" x2="31" y2="25" /&gt;
  &lt;line x1="31" y1="0" x2="31" y2="25" /&gt;
  &lt;line x1="31" y1="0" x2="31" y2="25" /&gt;
  &lt;line x1="31" y1="0" x2="31" y2="25" /&gt;
  &lt;line x1="32" y1="0" x2="32" y2="25" /&gt;
  &lt;line x1="32" y1="0" x2="32" y2="25" /&gt;
  &lt;line x1="32" y1="0" x2="32" y2="25" /&gt;
  &lt;line x1="32" y1="0" x2="32" y2="25" /&gt;
  &lt;line x1="33" y1="0" x2="33" y2="25" /&gt;
  &lt;line x1="33" y1="0" x2="33" y2="25" /&gt;
  &lt;line x1="33" y1="0" x2="33" y2="25" /&gt;
  &lt;line x1="33" y1="0" x2="33" y2="25" /&gt;
  &lt;line x1="33" y1="0" x2="33" y2="25" /&gt;
  &lt;line x1="34" y1="0" x2="34" y2="25" /&gt;
  &lt;line x1="34" y1="0" x2="34" y2="25" /&gt;
  &lt;line x1="34" y1="0" x2="34" y2="25" /&gt;
  &lt;line x1="34" y1="0" x2="34" y2="25" /&gt;
  &lt;line x1="34" y1="0" x2="34" y2="25" /&gt;
  &lt;line x1="35" y1="0" x2="35" y2="25" /&gt;
  &lt;line x1="35" y1="0" x2="35" y2="25" /&gt;
  &lt;line x1="35" y1="0" x2="35" y2="25" /&gt;
  &lt;line x1="35" y1="0" x2="35" y2="25" /&gt;
  &lt;line x1="35" y1="0" x2="35" y2="25" /&gt;
  &lt;line x1="36" y1="0" x2="36" y2="25" /&gt;
  &lt;line x1="36" y1="0" x2="36" y2="25" /&gt;
  &lt;line x1="36" y1="0" x2="36" y2="25" /&gt;
  &lt;line x1="36" y1="0" x2="36" y2="25" /&gt;
  &lt;line x1="37" y1="0" x2="37" y2="25" /&gt;
  &lt;line x1="37" y1="0" x2="37" y2="25" /&gt;
  &lt;line x1="37" y1="0" x2="37" y2="25" /&gt;
  &lt;line x1="37" y1="0" x2="37" y2="25" /&gt;
  &lt;line x1="37" y1="0" x2="37" y2="25" /&gt;
  &lt;line x1="38" y1="0" x2="38" y2="25" /&gt;
  &lt;line x1="38" y1="0" x2="38" y2="25" /&gt;
  &lt;line x1="38" y1="0" x2="38" y2="25" /&gt;
  &lt;line x1="38" y1="0" x2="38" y2="25" /&gt;
  &lt;line x1="38" y1="0" x2="38" y2="25" /&gt;
  &lt;line x1="39" y1="0" x2="39" y2="25" /&gt;
  &lt;line x1="39" y1="0" x2="39" y2="25" /&gt;
  &lt;line x1="39" y1="0" x2="39" y2="25" /&gt;
  &lt;line x1="39" y1="0" x2="39" y2="25" /&gt;
  &lt;line x1="39" y1="0" x2="39" y2="25" /&gt;
  &lt;line x1="40" y1="0" x2="40" y2="25" /&gt;
  &lt;line x1="40" y1="0" x2="40" y2="25" /&gt;
  &lt;line x1="40" y1="0" x2="40" y2="25" /&gt;
  &lt;line x1="40" y1="0" x2="40" y2="25" /&gt;
  &lt;line x1="41" y1="0" x2="41" y2="25" /&gt;
  &lt;line x1="41" y1="0" x2="41" y2="25" /&gt;
  &lt;line x1="41" y1="0" x2="41" y2="25" /&gt;
  &lt;line x1="41" y1="0" x2="41" y2="25" /&gt;
  &lt;line x1="41" y1="0" x2="41" y2="25" style="stroke-width:2" /&gt;
  &lt;!-- Colored Rectangle --&gt;
  &lt;polygon points="0.000000,0.000000 41.887587,0.000000 41.887587,25.412617 0.000000,25.412617" style="fill:#ECB172A0;stroke-width:0"/&gt;
  &lt;!-- Text --&gt;
&lt;p&gt;&lt;text x="20.943793" y="45.412617" font-size="1.0rem" font-weight="100" text-anchor="middle" &gt;199&lt;/text&gt;
&lt;text x="61.887587" y="12.706308" font-size="1.0rem" font-weight="100" text-anchor="middle" transform="rotate(0,61.887587,12.706308)"&gt;3&lt;/text&gt;&lt;/p&gt;
  &lt;!-- Horizontal lines --&gt;
  &lt;line x1="111" y1="0" x2="135" y2="24" style="stroke-width:2" /&gt;
  &lt;line x1="111" y1="120" x2="135" y2="144" style="stroke-width:2" /&gt;
  &lt;!-- Vertical lines --&gt;
  &lt;line x1="111" y1="0" x2="111" y2="120" style="stroke-width:2" /&gt;
  &lt;line x1="135" y1="24" x2="135" y2="144" style="stroke-width:2" /&gt;
  &lt;!-- Colored Rectangle --&gt;
  &lt;polygon points="111.000000,0.000000 135.664918,24.664918 135.664918,144.664918 111.000000,120.000000" style="fill:#ECB172A0;stroke-width:0"/&gt;
  &lt;!-- Horizontal lines --&gt;
  &lt;line x1="111" y1="0" x2="201" y2="0" style="stroke-width:2" /&gt;
  &lt;line x1="135" y1="24" x2="225" y2="24" style="stroke-width:2" /&gt;
  &lt;!-- Vertical lines --&gt;
  &lt;line x1="111" y1="0" x2="135" y2="24" style="stroke-width:2" /&gt;
  &lt;line x1="201" y1="0" x2="225" y2="24" style="stroke-width:2" /&gt;
  &lt;!-- Colored Rectangle --&gt;
  &lt;polygon points="111.000000,0.000000 201.000000,0.000000 225.664918,24.664918 135.664918,24.664918" style="fill:#ECB172A0;stroke-width:0"/&gt;
  &lt;!-- Horizontal lines --&gt;
  &lt;line x1="135" y1="24" x2="225" y2="24" style="stroke-width:2" /&gt;
  &lt;line x1="135" y1="144" x2="225" y2="144" style="stroke-width:2" /&gt;
  &lt;!-- Vertical lines --&gt;
  &lt;line x1="135" y1="24" x2="135" y2="144" style="stroke-width:2" /&gt;
  &lt;line x1="225" y1="24" x2="225" y2="144" style="stroke-width:2" /&gt;
  &lt;!-- Colored Rectangle --&gt;
  &lt;polygon points="135.664918,24.664918 225.664918,24.664918 225.664918,144.664918 135.664918,144.664918" style="fill:#ECB172A0;stroke-width:0"/&gt;
  &lt;!-- Text --&gt;
&lt;p&gt;&lt;text x="180.664918" y="164.664918" font-size="1.0rem" font-weight="100" text-anchor="middle" &gt;768&lt;/text&gt;
&lt;text x="245.664918" y="84.664918" font-size="1.0rem" font-weight="100" text-anchor="middle" transform="rotate(-90,245.664918,84.664918)"&gt;1024&lt;/text&gt;
&lt;text x="113.332459" y="152.332459" font-size="1.0rem" font-weight="100" text-anchor="middle" transform="rotate(45,113.332459,152.332459)"&gt;201&lt;/text&gt;
&lt;/svg&gt;&lt;/p&gt;
&lt;/td&gt;
&lt;/tr&gt;
&lt;/table&gt;
&lt;p&gt;That’s a 180 GB logical array, composed of around 600 chunks, each of size 300
MB. We can now do normal NumPy like computations on this array using &lt;a class="reference external" href="https://docs.dask.org/en/latest/array.html"&gt;Dask
Array&lt;/a&gt;, but we’ll save that for a
future post.&lt;/p&gt;
&lt;div class="highlight-python notranslate"&gt;&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span class="gp"&gt;&amp;gt;&amp;gt;&amp;gt; &lt;/span&gt;&lt;span class="c1"&gt;# array computations would work fine, and would run in low memory&lt;/span&gt;
&lt;span class="gp"&gt;&amp;gt;&amp;gt;&amp;gt; &lt;/span&gt;&lt;span class="c1"&gt;# but we&amp;#39;ll save actual computation for future posts&lt;/span&gt;
&lt;span class="gp"&gt;&amp;gt;&amp;gt;&amp;gt; &lt;/span&gt;&lt;span class="n"&gt;a&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;sum&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;compute&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;
&lt;/div&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/2019/06/20/load-image-data.md&lt;/span&gt;, line 1056)&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="save-data"&gt;
&lt;h1&gt;Save Data&lt;/h1&gt;
&lt;p&gt;To simplify data loading in the future, we store this in a large chunked
array format like &lt;a class="reference external" href="https://zarr.readthedocs.io/"&gt;Zarr&lt;/a&gt; using the &lt;a class="reference external" href="https://docs.dask.org/en/latest/array-api.html#dask.array.Array.to_zarr"&gt;to_zarr&lt;/a&gt;
method.&lt;/p&gt;
&lt;div class="highlight-python notranslate"&gt;&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span class="n"&gt;a&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;to_zarr&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;mydata.zarr&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;We may add additional information about the image data as &lt;a class="reference external" href="https://zarr.readthedocs.io/en/stable/tutorial.html#user-attributes"&gt;attributes&lt;/a&gt;. This
both makes things simpler for future users (they can read the full dataset with
a single line using &lt;a class="reference external" href="http://docs.dask.org/en/latest/array-api.html#dask.array.from_zarr"&gt;da.from_zarr&lt;/a&gt;) and much
more performant because Zarr is an &lt;em&gt;analysis ready format&lt;/em&gt; that is efficiently
encoded for computation.&lt;/p&gt;
&lt;p&gt;Zarr uses the &lt;a class="reference external" href="http://blosc.org/"&gt;Blosc&lt;/a&gt; library for compression by default.
For scientific imaging data, we can optionally pass compression options that provide
a good compression ratio to speed tradeoff and optimize compression
performance.&lt;/p&gt;
&lt;div class="highlight-python notranslate"&gt;&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span class="kn"&gt;from&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nn"&gt;numcodecs&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;Blosc&lt;/span&gt;
&lt;span class="n"&gt;a&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;to_zarr&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;mydata.zarr&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;compressor&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;Blosc&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;cname&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;zstd&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;clevel&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mi"&gt;3&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;shuffle&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;Blosc&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;BITSHUFFLE&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;
&lt;/div&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/2019/06/20/load-image-data.md&lt;/span&gt;, line 1082)&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="future-work"&gt;
&lt;h1&gt;Future Work&lt;/h1&gt;
&lt;p&gt;The workload above is generic and straightforward. It works well in simple
cases and also extends well to more complex cases, providing you’re willing to
write some for-loops and parsing code around your custom logic. It works on a
single small-scale laptop as well as a large HPC or Cloud cluster. If you have
a function that turns a filename into a NumPy array, you can generate large
lazy Dask array using that function, &lt;a class="reference external" href="https://docs.dask.org/en/latest/delayed.html"&gt;Dask
Delayed&lt;/a&gt; and &lt;a class="reference external" href="https://docs.dask.org/en/latest/array.html"&gt;Dask
Array&lt;/a&gt;.&lt;/p&gt;
&lt;section id="dask-image"&gt;
&lt;h2&gt;Dask Image&lt;/h2&gt;
&lt;p&gt;However, we can make things a bit easier for users if we specialize a bit. For
example the &lt;a class="reference external" href="https://image.dask.org/en/latest/"&gt;Dask Image&lt;/a&gt; library has a
parallel image reader function, which automates much of our work above in the
simple case.&lt;/p&gt;
&lt;div class="highlight-python notranslate"&gt;&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span class="gp"&gt;&amp;gt;&amp;gt;&amp;gt; &lt;/span&gt;&lt;span class="kn"&gt;import&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nn"&gt;dask_image&lt;/span&gt;
&lt;span class="gp"&gt;&amp;gt;&amp;gt;&amp;gt; &lt;/span&gt;&lt;span class="n"&gt;x&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;dask_image&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;imread&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;imread&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;raw/*.tif&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;Similarly libraries like &lt;a class="reference external" href="https://xarray.pydata.org/en/stable/"&gt;Xarray&lt;/a&gt; have
readers for other file formats, like GeoTIFF.&lt;/p&gt;
&lt;p&gt;As domains do more and more work like what we did above they tend to write down
common patterns into domain-specific libraries, which then increases the
accessibility and user base of these tools.&lt;/p&gt;
&lt;/section&gt;
&lt;section id="gpus"&gt;
&lt;h2&gt;GPUs&lt;/h2&gt;
&lt;p&gt;If we have special hardware lying around like a few GPUs, we can move the data
over to it and perform computations with a library like CuPy, which mimics
NumPy very closely. Thus benefiting from the same operations listed above, but
with the added performance of GPUs behind them.&lt;/p&gt;
&lt;div class="highlight-python notranslate"&gt;&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span class="kn"&gt;import&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nn"&gt;cupy&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;as&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nn"&gt;cp&lt;/span&gt;
&lt;span class="n"&gt;a_gpu&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;a&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;map_blocks&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;cp&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;asarray&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;/section&gt;
&lt;section id="computation"&gt;
&lt;h2&gt;Computation&lt;/h2&gt;
&lt;p&gt;Finally, in future blogposts we plan to talk about how to compute on our large
Dask arrays using common image-processing workloads like overlapping stencil
functions, segmentation and deconvolution, and integrating with other libraries
like ITK.&lt;/p&gt;
&lt;/section&gt;
&lt;/section&gt;
</content>
    <link href="https://blog.dask.org/2019/06/20/load-image-data/"/>
    <summary>Document headings start at H2, not H1 [myst.header]</summary>
    <category term="dask-image" label="dask-image"/>
    <category term="python" label="python"/>
    <category term="scikit-image" label="scikit-image"/>
    <category term="scipy" label="scipy"/>
    <published>2019-06-20T00:00:00+00:00</published>
  </entry>
</feed>
