<jupyter_start><jupyter_text>Demo: Training data generation for isotropic reconstruction of Zebrafish retinaThis notebook demonstrates training data generation for an isotropic reconstruction task, where the anisotropic distortions along the undersampled Z axis are simulated from isotropic 2D slices.Note that training data can be created from existing acquisitions.We will use a single Retina stack for training data generation, whereas in your application you should aim to use stacks from different developmental timepoints to ensure a well trained model. More documentation is available at http://csbdeep.bioimagecomputing.com/doc/.<jupyter_code>from __future__ import print_function, unicode_literals, absolute_import, division
import numpy as np
import matplotlib.pyplot as plt
%matplotlib inline
%config InlineBackend.figure_format = 'retina'

from tifffile import imread
from csbdeep.utils import download_and_extract_zip_file, plot_some, axes_dict
from csbdeep.io import save_training_data
from csbdeep.data import RawData, create_patches
from csbdeep.data.transform import anisotropic_distortions<jupyter_output><empty_output><jupyter_text>Download example dataFirst we download some example data, consisting of a single 3D Zebrafish retina stack.<jupyter_code>download_and_extract_zip_file (
    url       = 'http://csbdeep.bioimagecomputing.com/example_data/retina.zip',
    targetdir = 'data',
)<jupyter_output><empty_output><jupyter_text>We plot XY and XZ slices of the training stack:<jupyter_code>x = imread('data/retina/cropped_farred_RFP_GFP_2109175_2color_sub_10.20.tif')
subsample = 10.2
print('image size         =', x.shape)
print('Z subsample factor =', subsample)

plt.figure(figsize=(16,15))
plot_some(np.moveaxis(x,1,-1)[[5,-5]],
          title_list=[['XY slice','XY slice']],
          pmin=2,pmax=99.8);

plt.figure(figsize=(16,15))
plot_some(np.moveaxis(np.moveaxis(x,1,-1)[:,[50,-50]],1,0),
          title_list=[['XZ slice','XZ slice']],
          pmin=2,pmax=99.8, aspect=subsample);<jupyter_output><empty_output><jupyter_text>Generate training data for isotropic CAREWe first need to create a `RawData` object, which defines how to get pairs of images and the semantics of each axis (e.g. which one is considered a color channel, etc.).In contrast to the standard CARE approach (e.g. [3D denoising](../denoising3D/1_datagen.ipynb)), we don't have pairs of low/high-SNR images here, just a single image.Nevertheless, we can use `RawData.from_folder` and simply indicate the same folder as both source and target.  We also set `axes = 'ZCYX'` to indicate the semantic order of the image axes.<jupyter_code>raw_data = RawData.from_folder (
    basepath    = 'data',
    source_dirs = ['retina'],
    target_dir  = 'retina',
    axes        = 'ZCYX',
)<jupyter_output><empty_output><jupyter_text>Furthermore, we must define how to modify XY slices to mimic the axial distortions of a real microscope as closely as possible. To that end, we define a `Transform` object that will take our `RawData` as input and return the modified image. Here, we use `anisotropic_distortions` to accomplish this.The most important parameters are the subsampling factor along Z of the raw data and the PSF of the microscope that should mimic the optical abberations along Z, but now applied to the lateral X axis.<jupyter_code>anisotropic_transform = anisotropic_distortions (
    subsample = 10.2,
    psf       = np.ones((3,3))/9, # use the actual PSF here
    psf_axes  = 'YX',
)<jupyter_output><empty_output><jupyter_text>From the raw image stack and its synthetically distorted copy, we now generate corresponding patches. As a general rule, use a patch size that is a power of two along XYZT, or at least divisible by 8.  Typically, you should use more patches the more trainings stacks you have. By default, patches are sampled from non-background regions (i.e. that are above a relative threshold), see the documentation of `create_patches` for details.Note that returned values `(X, Y, XY_axes)` by `create_patches` are not to be confused with the image axes X and Y.  By convention, the variable name `X` (or `x`) refers to an input variable for a machine learning model, whereas `Y` (or `y`) indicates an output variable.<jupyter_code>X, Y, XY_axes = create_patches (
    raw_data            = raw_data,
    patch_size          = (1,2,128,128),
    n_patches_per_image = 512,
    transforms          = [anisotropic_transform],
)
assert X.shape == Y.shape
print("shape of X,Y =", X.shape)
print("axes  of X,Y =", XY_axes)<jupyter_output><empty_output><jupyter_text>Since the isotropic CARE model operates on 2D (+ channel) images, we need to remove the (singleton) Z axis before saving the training data.<jupyter_code>z = axes_dict(XY_axes)['Z']
X = np.take(X,0,axis=z)
Y = np.take(Y,0,axis=z)
XY_axes = XY_axes.replace('Z','')
assert X.shape == Y.shape
print("shape of X,Y =", X.shape)
print("axes  of X,Y =", XY_axes)
save_training_data('data/my_training_data.npz', X, Y, XY_axes)<jupyter_output><empty_output><jupyter_text>ShowThis shows some of the generated patch pairs (even rows: *source*, odd rows: *target*)<jupyter_code>for i in range(2):
    plt.figure(figsize=(16,4))
    sl = slice(8*i, 8*(i+1))
    plot_some(np.moveaxis(X[sl],1,-1),np.moveaxis(Y[sl],1,-1),title_list=[np.arange(sl.start,sl.stop)])
    plt.show()
None;<jupyter_output><empty_output>
{'fraction_non_alphanumeric': 0.09840326773115485, 'fraction_numerical': 0.014853323431117713, 'mean_word_length': 5.093891402714932, 'pattern_counts': {'":': 0, '<': 33, '<?xml version=': 0, '>': 33, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 4, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'chain_length': '8', 'dir': 'jupyter-structured-clean-dedup', 'id': '320570', 'license': 'BSD-3-Clause', 'n_tokens_mistral': 1798, 'n_tokens_neox': 1674, 'n_words': 570, 'path': 'examples/isotropic_reconstruction/1_datagen.ipynb', 'repo_name': 'kapoorlab/CSBDeep', 'size': '5386'}