Stitch single channel data

import paprica
import matplotlib.pyplot as plt
/opt/hostedtoolcache/Python/3.8.17/x64/lib/python3.8/site-packages/numpy/core/getlimits.py:500: UserWarning: The value of the smallest subnormal for <class 'numpy.float32'> type is zero.
  setattr(self, word, getattr(machar, word).flat[0])
/opt/hostedtoolcache/Python/3.8.17/x64/lib/python3.8/site-packages/numpy/core/getlimits.py:89: UserWarning: The value of the smallest subnormal for <class 'numpy.float32'> type is zero.
  return self._float_to_str(self.smallest_subnormal)
/opt/hostedtoolcache/Python/3.8.17/x64/lib/python3.8/site-packages/numpy/core/getlimits.py:500: UserWarning: The value of the smallest subnormal for <class 'numpy.float64'> type is zero.
  setattr(self, word, getattr(machar, word).flat[0])
/opt/hostedtoolcache/Python/3.8.17/x64/lib/python3.8/site-packages/numpy/core/getlimits.py:89: UserWarning: The value of the smallest subnormal for <class 'numpy.float64'> type is zero.
  return self._float_to_str(self.smallest_subnormal)

Let’s start by parsing a data-set:

path = '../../../tests/data/apr'
tiles = paprica.tileParser(path=path, ftype='apr', frame_size=512)
**********  PARSING DATA **********
../../../tests/data/apr
Tiles are of type apr.
13 tiles were detected.
4 rows and 4 columns.
***********************************

The data-set can then be quickly displayed by using the stitcher module using the expected tile position given the overlap and confirm that the data was parsed correctly.

stitcher_expected = paprica.tileStitcher(tiles, overlap_h=25, overlap_v=25)
stitcher_expected.compute_expected_registration()

To do so, we provide a lazy reconstructor with the stitcher to display a cross-section (or a max projection) of stitched data-set along any given dimension:

_ = stitcher_expected.reconstruct_slice(color=True, n_proj=10, progress_bar=False)

# The code below is only used to format the output image correctly for this tutorial and is not needed if used on your own machine
fig = plt.gcf()
fig.set_figheight(20)
fig.set_figwidth(20)
Error reading APR file: particle dataset 'particles' doesn't exist
---------------------------------------------------------------------------
ValueError                                Traceback (most recent call last)
Cell In[4], line 1
----> 1 _ = stitcher_expected.reconstruct_slice(color=True, n_proj=10, progress_bar=False)
      3 # The code below is only used to format the output image correctly for this tutorial and is not needed if used on your own machine
      4 fig = plt.gcf()

File /opt/hostedtoolcache/Python/3.8.17/x64/lib/python3.8/site-packages/paprica/stitcher.py:635, in baseStitcher.reconstruct_slice(self, loc, n_proj, dim, downsample, color, debug, plot, seg, progress_bar)
    604 """
    605 Reconstruct whole sample 2D section at the given location and in a given dimension. This function can also
    606 reconstruct a maximum intensity projection if `n_proj>0`.
   (...)
    631     Array containing the reconstructed data.
    632 """
    634 if dim == 0:
--> 635     return self._reconstruct_z_slice(z=loc, n_proj=n_proj, downsample=downsample, color=color,
    636                                      debug=debug, plot=plot, seg=seg, progress_bar=progress_bar)
    637 elif dim == 1:
    638     return self._reconstruct_y_slice(y=loc, n_proj=n_proj, downsample=downsample, color=color,
    639                                      debug=debug, plot=plot, progress_bar=progress_bar)

File /opt/hostedtoolcache/Python/3.8.17/x64/lib/python3.8/site-packages/paprica/stitcher.py:785, in baseStitcher._reconstruct_z_slice(self, z, n_proj, downsample, color, debug, plot, seg, progress_bar)
    782 level_delta = int(-np.sign(downsample) * np.log2(np.abs(downsample)))
    784 tile = self.tiles[0]
--> 785 tile.lazy_load_tile(level_delta=level_delta)
    786 if seg:
    787     tile.lazy_load_segmentation(level_delta=level_delta)

File /opt/hostedtoolcache/Python/3.8.17/x64/lib/python3.8/site-packages/paprica/loader.py:201, in tileLoader.lazy_load_tile(self, level_delta)
    198 if self.type != 'apr':
    199     raise TypeError('Error: lazy loading is only supported for APR data.')
--> 201 self.lazy_data = pyapr.reconstruction.LazySlicer(self.path, level_delta=level_delta, parts_name='particles',
    202                                                   tree_parts_name='particles')
    203 self.is_loaded = True

File /opt/hostedtoolcache/Python/3.8.17/x64/lib/python3.8/site-packages/pyapr/reconstruction/LazySlicer.py:72, in LazySlicer.__init__(self, file_path, level_delta, mode, parts_name, tree_parts_name, t, channel_name)
     70 tree_parts_name = tree_parts_name or get_particle_names(self.path, t=t, channel_name=channel_name, tree=True)[0]
     71 tree_parts_type = get_particle_type(self.path, t=t, channel_name=channel_name, parts_name=tree_parts_name, tree=True)
---> 72 self.tree_parts = type_to_lazy_particles(tree_parts_type)
     73 self.tree_parts.init_tree(self.aprfile, tree_parts_name, t, channel_name)
     74 self.tree_parts.open()

File /opt/hostedtoolcache/Python/3.8.17/x64/lib/python3.8/site-packages/pyapr/utils/types.py:63, in type_to_lazy_particles(typespec)
     61 if typespec in ('uint64', np.uint64):
     62     return LazyDataLong()
---> 63 raise ValueError(f'Type {typespec} is currently not supported. Valid types are \'uint8\', \'uint16\', '
     64                  f'\'uint64\' and \'float\' (\'float32\')')

ValueError: Type  is currently not supported. Valid types are 'uint8', 'uint16', 'uint64' and 'float' ('float32')

As you can see on the image above, there are doubling artifacts arising from tiles misalignment. To actively counteract these misalignments, the registration between tiles can be computed:

stitcher = paprica.tileStitcher(tiles, overlap_h=25, overlap_v=25)
stitcher.set_overlap_margin(10)
stitcher.compute_registration(progress_bar=False)

_ = stitcher.reconstruct_slice(color=True, n_proj=10, progress_bar=False)

# The code below is only used to format the output image correctly for this tutorial and is not needed if used on your own machine
fig = plt.gcf()
fig.set_figheight(20)
fig.set_figwidth(20)
Computing max. proj.: 100%|██████████| 13/13 [00:00<00:00, 27.44it/s]
Effective horizontal overlap: 25.29%
Effective vertical overlap: 24.71%
../_images/f649840c0180c7ff12c36ff329b46f7ad2ad5aca398d12a36132cbe798801035.png

On the image above, the doubling artifacts are corrected. It is then possible to see the correct tile placement and save it. The ´database´ object is used by the rest of the pipeline by the viewer, merger and the segmenter to place tiles correctly.

print(stitcher.database)
# stitcher.save_database('path to saving location')
                               path  row  col    dH    dV   dD   ABS_H  \
0   ../../../tests/data/apr/0_2.apr    0    2   0.0   0.0  0.0   768.0   
1   ../../../tests/data/apr/0_3.apr    0    3   3.0   0.0  0.0  1143.0   
2   ../../../tests/data/apr/1_0.apr    1    0 -24.0  15.0  0.0     0.0   
3   ../../../tests/data/apr/1_1.apr    1    1 -10.0  23.0  0.0   386.0   
4   ../../../tests/data/apr/1_2.apr    1    2  -6.0  12.0  0.0   762.0   
5   ../../../tests/data/apr/1_3.apr    1    3   8.0  12.0  0.0  1148.0   
6   ../../../tests/data/apr/2_0.apr    2    0 -24.0  18.0  0.0     0.0   
7   ../../../tests/data/apr/2_1.apr    2    1 -20.0  23.0  0.0   376.0   
8   ../../../tests/data/apr/2_3.apr    2    3   9.0  21.0  0.0  1149.0   
9   ../../../tests/data/apr/3_0.apr    3    0 -21.0  33.0  0.0     3.0   
10  ../../../tests/data/apr/3_1.apr    3    1 -14.0  35.0  0.0   382.0   
11  ../../../tests/data/apr/3_2.apr    3    2  -1.0  43.0  0.0   767.0   
12  ../../../tests/data/apr/3_3.apr    3    3   9.0  30.0  0.0  1149.0   

     ABS_V  ABS_D  
0      0.0    0.0  
1      0.0    0.0  
2    387.0    0.0  
3    395.0    0.0  
4    384.0    0.0  
5    384.0    0.0  
6    762.0    0.0  
7    767.0    0.0  
8    765.0    0.0  
9   1149.0    0.0  
10  1151.0    0.0  
11  1159.0    0.0  
12  1146.0    0.0  

Comparison of stitched and unstitched data

The cross sections can also be computed in other dimension (still using lazy loading) and compared between the stitched and unstitched data.

Before Stitching

_ = stitcher_expected.reconstruct_slice(dim=1, loc=650, color=True, n_proj=10, progress_bar=False)

# The code below is only used to format the output image correctly for this tutorial and is not needed if used on your own machine
fig = plt.gcf()
fig.set_figheight(20)
fig.set_figwidth(20)
Merging: 100%|██████████| 4/4 [00:00<00:00, 32.53it/s]
../_images/bce26a7799b30fd2d0e009757f808ef6f7fb28d4d11e72d379e60cdd4b3bd41b.png

After Stitching

_ = stitcher.reconstruct_slice(dim=1, loc=650, color=True, n_proj=10, progress_bar=False)

# The code below is only used to format the output image correctly for this tutorial and is not needed if used on your own machine
fig = plt.gcf()
fig.set_figheight(20)
fig.set_figwidth(20)
Merging: 100%|██████████| 4/4 [00:00<00:00, 30.70it/s]
../_images/d040d12bd036bc1a7a35cc7518c115bb65b4a3319a34308c8c975886602a98cf.png

Before stitching

_ = stitcher_expected.reconstruct_slice(dim=2, loc=800, color=True, n_proj=10, progress_bar=False)

# The code below is only used to format the output image correctly for this tutorial and is not needed if used on your own machine
fig = plt.gcf()
fig.set_figheight(20)
fig.set_figwidth(20)
Merging: 100%|██████████| 6/6 [00:00<00:00, 53.54it/s]
../_images/1e1c22f971986ad50bef9e2b672e297e34758778ac8c7b06edba4c73e8acb4b2.png

After Stitching

_ = stitcher.reconstruct_slice(dim=2, loc=800, color=True, n_proj=10, progress_bar=False)

# The code below is only used to format the output image correctly for this tutorial and is not needed if used on your own machine
fig = plt.gcf()
fig.set_figheight(20)
fig.set_figwidth(20)
Merging: 100%|██████████| 6/6 [00:00<00:00, 47.24it/s]
../_images/7a88e5d939708bd39ed97fb2fb84a9c589215523f1334105699781a6757838a0.png

Color depth projection

It is also possible to display a color depth projection:

_ = stitcher.reconstruct_z_color(n_proj=50, progress_bar=False)

# The code below is only used to format the output image correctly for this tutorial and is not needed if used on your own machine
fig = plt.gcf()
fig.set_figheight(20)
fig.set_figwidth(20)
Merging: 100%|██████████| 13/13 [00:00<00:00, 23.34it/s]
../_images/63ed657d08c7534ec5d64411f004b6553a1fe6fa1fb3356c413c2c44112d91d6.png