1. Image Assembly#

Raw ScanImage .tiff files are saved to disk in an interleaved manner. The general workflow is as follows:

  • Set up filepaths.

  • Initialize a scanreader object to read in raw .tiff files.

  • Save the assembled image or individual ROIs to disk.

%load_ext autoreload
%autoreload 2

from pathlib import Path
import numpy as np
import tifffile

import fastplotlib as fpl

import matplotlib.pyplot as plt
import lbm_caiman_python as lcp
WGPU: enumerate_adapters() is deprecated, use enumerate_adapters_sync() instead.
WGPU: request_adapter() is deprecated, use request_adapter_sync() instead.
Available devices:
ValidDeviceTypeBackendDriver
✅ (default) NVIDIA RTX A4000DiscreteGPUVulkan560.94
NVIDIA RTX A4000DiscreteGPUD3D12
❗ limitedMicrosoft Basic Render DriverCPUD3D12
NVIDIA RTX A4000DiscreteGPUD3D12
NVIDIA RTX A4000/PCIe/SSE2UnknownOpenGL4.6.0 NVIDIA 560.94

1.1. Input data: Path to your raw .tiff file(s)#

Before processing, ensure:

  • Put all raw .tiff files, from a single imaging session, into a directory.

    • Here, we name that directory raw

  • No other .tiff files reside in this directory

There are a few ways to pass your raw files into the scanreader.

  1. A string containing a wildcard pattern for files to gather:

  2. A list of strings containing all files in that directory.

1.2. Initialize a scanreader object#

(Option 1). Simply pass a string containing a wildcard pattern for files to gather

files = "C:/Users/RBO/caiman_data/raw/*.
scan = sr.read_scan(files, join_contiguous=True)

(Option 2). Manually gather a list of strings containing all .tiff files in that directory

parent_dir = Path().home() / 'caiman_data' / 'raw'
raw_tiff_files = [str(x) for x in parent_dir.glob("*.tif*")]
scan = sr.read_scan(raw_tiff_files, join_contiguous=True)
data_path = r"C:\Users\RBO\lbm_data\raw\MH70_0p6mm_FOV_50_550um_depth_som_stim_199mW_3min"
files = lcp.get_files_ext(data_path, str_contains='tif', max_depth=1)

1.3. scanreader object#

When indexing the scanreader, a numpy array is returned with dimensions [field, T, z, y, x]

  • If join_contiguous=True, the scanreader object will have only 1 field, as all ROIs are joined into a single field.

  • If join_contiguous=False, the scanreader object will have multiple fields, each corresponding to a single ROI.

This example does not cover the case where you separate your image by ROI.

scan = lcp.read_scan(files, join_contiguous=True)
print(f'Planes: {scan.num_channels}')
print(f'Frames: {scan.num_frames}')
print(f'ROIs: {scan.num_rois}')
print(f'Fields: {scan.num_fields}')  # 1, because join_contiguous=True
Planes: 30
Frames: 1730
ROIs: 4
Fields: 1

You can use the scan object as if it were a numpy array

array = scan[:100, 0, :, :]
# 4 fields (join_contiguous=False), one for each ROI
print(f'[T, y, x]: {array.shape} (with the first 100 frames')
[T, y, x]: (100, 600, 576) (with the first 100 frames
array = scan[:100, 1:3, :, :]
# 4 fields (join_contiguous=False), one for each ROI
print(f'[T, z, y, x]: {array.shape} (with the first 100 frames')
[T, z, y, x]: (100, 2, 600, 576) (with the first 100 frames
del array

1.3.1. View a single z-plane timeseries#

You can pass in the scan object to preview your data before saving it to disk.

Warning

Make sure you set histogram_widget=False or you will get an index error.

image_widget = fpl.ImageWidget(scan, histogram_widget=False,  figure_kwargs={"size": (900, 560)},)
image_widget.figure[0, 0].auto_scale()
image_widget.show()
image_widget.close()

1.3.2. Include more z-planes for a 4D graphic#

1.4. Path to save your files#

We can save the assembled image or individual ROIs to disk. The currently supported file extensions are .tiff (for now).

Note

For .zarr files to be compatible with caiman, we need to control the filenames.

Each z-plane sent through caiman needs a .zarr extension, and to be further compatible with caiman locating the dataset we need to further add a mov subdirectory to mimic compatibility hdf5 groups.

This is a CaImAn specific quirk, and we suggest sticking with .tiff to avoid any future incompatibilities with CaImAn updates.

save_path = r"C:\Users\RBO\lbm_data\processed"

We pass our scan object, along with the save path into lbm_caiman_python.save_as()

Important

If you initialize the scanreader with join_contiguous=False, filename structure will be plane_{plane}_roi_{roi}{str}.tiff If you initialize the scanreader with join_contiguous=True, filename structure will be plane_{plane}{str}.tiff … where str is the paramter append_str

# We recommend discarding the first frame if it contains extra flyback lines.
# this can be a list, numpy array, or slice
# you can do the same thing with planes = [0:28]
frames_to_save = np.arange(1, scan.num_frames)
lcp.save_as(scan, save_path, frames=frames_to_save, overwrite=True, append_str="_assembled", ext='.tiff')
Reading tiff series data...
Reading tiff pages...
Raw tiff fully read.
Saving 30 planes.
Saving planes: 100%|██████████████████████████████| 30/30 [06:14<00:00, 12.49s/it]
Data successfully saved to C:\Users\RBO\lbm_data\processed.

1.4.1. Read back in your file to make sure it saved properly#

make sure you include the append_str from the save_as() function.

img = tifffile.memmap(Path(save_path) / 'plane_1_assembled.tiff')
img.shape
(1729, 600, 576)
image_widget = fpl.ImageWidget(img, figure_kwargs={"size":(1200, 800)})
image_widget.show()
image_widget.close()

1.4.2. Preview raw traces#

We can also preview the raw traces of the assembled image.

Click on a pixel to view the raw trace for that pixel over time.

from ipywidgets import VBox
iw_movie = fpl.ImageWidget(img, cmap="viridis", figure_kwargs={"size": (900, 560)},)

tfig = fpl.Figure()

raw_trace = tfig[0, 0].add_line(np.zeros(img.shape[0]))

@iw_movie.managed_graphics[0].add_event_handler("click")
def pixel_clicked(ev):
    col, row = ev.pick_info["index"]
    raw_trace.data[:, 1] =  iw_movie.data[0][:, row, col]
    tfig[0, 0].auto_scale(maintain_aspect=False)

VBox([iw_movie.show(), tfig.show()])