---------------------------------------------------
---------------------------------------------------
How to run the codes and a sample run for the demo
---------------------------------------------------
---------------------------------------------------

Inputs to the pipeline
----------------------
----------------------

We assume that the sparse set of confocal slices are segmented and correspondences between these cell segments (sparse clustering) are already established. The 2D Watershed segmentation results for the image slices and and spatial tracking results on these segmented 2D cell slices, are thus the inputs to the system.

Input Variables and Data Structures
-----------------------------------

    sparse_2D_points :  A MATLAb cell with a dimension of (Nx1) where N is the number of sparse slices in the confocal stack. Each of these N elements is again a cell of c 2D matrices containing the 2D pixel-list of each of the cell segments, as obtained from Watershed segmentation, 'c' being the number of 2D segments on that particular SAM image slice.

    lineage          :  A 2D matrix with a dimension of (CXN), C being the total number of 3D cellular structures in the tissue (as obtained from a spatial tracker) and N, as before, is the number of sparsely z-sampled confocal image slices. The entry (i,j) of this matrix is the 2D slice/segment number of the cell i in the image slice j. If the cell i is not imaged in the z-slice j, the (i,j)th entry is 0. Note that the 2D cell slice numbers are obtained from a Watershed segmentation algorithm and the associations between these 2D cell slices are obtained by a spatial tracking algorithm. This input variable is termed as 'lineage' in analogy to the typical 'temporal' association results obtained by using a temporal cell tracker.

    For the demo on a 3D SAM image stack, the 2 inputs viz., sparse_2D_points and lineage are provided in the input data folder.  

    The raw confocal images are provided in 'Data/Raw Images/' folder.



Step-1
------
------

In this first step, we extract the pixels on the boundaries of the 2D contours of the sparsely sampled SAM.

    [sam_contours] = extract_2D_Boundaries(sparse_2D_points)


Input Variables and Data Structures
-----------------------------------

    sparse_2D_points : Explained before.
   
Output Variables and Data Structures
------------------------------------

    sam_contours : A MATLAB cell with a dimension of (NX1) where N is the number of sparse slices in the confocal stack. Each of the elements of it is a 2D matrix containing the list of 2D pixels on the extracted SAM contour as imaged in each slice.  


Step-2
------
------
In this step we fit a smooth 3D surface on the 2D SAM contours at various z depths, as obtained in the previous step.
 Please note that, this code is useful for reconstructing an open surface (such as a hemispheric surface of SAM, or a root meristem cut into half along the length), but the code needs to be modified for reconstructing a closed surface (such as a spherical / cylindrical surface).

    [dense_cloud_unclustered] = surface_reconstruction(sam_contours, num_gridpoints, ind_smoothness, z_for_slice_1, delta_x_y_z, min_z, flg_view3d)


Input Variables and Data Structures
-----------------------------------

    sam_contours     : Explained in Step-1.
    
    num_gridpoints   : Number of gridpoints used in the mesh generation step for the surface. It is either a scalar or a (1X2) row vector. The scalar value is specified if the grid resolutions required in both x and y are the same. For different resolutions along different axes, use the vector representation. 

    ind_smoothness   : An integer scalar or a row vector of length 2, index for smoothness of the estimated surface. Use scalar for same desired smoothness along x and y and use a vector otherwise. Can be any non-negative integer, higher the value, the smoother the resultant surface. Should be chosen judiciously to obtain a balance between the desired smoothness of the surface and the downside of losing finer details of the curved surface.

    z_for_slice_1    : Depth in negative microns for the topmost slice of the stack. 

    delta_x_y_z      : A real valued row vector of length 3 ([delta_x, delta_y, delta_z]), the elements being the sampling resolutions/voxel sizes along 3 dimensions (microns/superpixel).

    min_z            : The maximum depth upto which dense points would be sampled from within the surface. In our convention, the topmost point of the tissue corresponds to z=0 and z is negative for all the deeper portions of the tissue. Hence, min_z corresponds to the deepest point of reconstruction.

    flg_view3d       : A 1/0 flag to decide whether the estimated surface would be displayed.

Output Variables and Data Structures
------------------------------------

    dense_cloud_unclustered : A (DX3) 3D dense point cloud sampled from within the reconstructed SAM surface and yet to be partitioned into 3D cells. 

Sample run for the demo
-----------------------

    dense_cloud_unclustered = surface_reconstruction(sam_contours, 900, 150, -5*0.225, [0.2, 0.2, 5*0.225], -40*0.225, 1);



Step-3
------
------

In this step, the supplied 2D points in each 2D cell slice as obtained from the segmentation algorithm and the spatial correspondences between such 2D cell slices (obtained from a spatial tracker) are used to obtain a very z-sparse point cloud per cell.

    [cell_pts_sparse] = sparse_clustered_points_per_cell(sparse_2D_points, lineage, z_for_slice_1, del_xyz)

Input Variables and Data Structures
-----------------------------------
    
    sparse_2D_points   : Explained before.

    lineage            : Explained before.

    z_for_slice_1      : z value in micron for the topmost SAM contour (real scalar).

    del_xyz            : Explained in Step-2.
    
Output Variables and Data Structures
------------------------------------

    cell_pts_sparse    : A MATLAB cell of length C (total number of 3D cells in the tissue), where each cell contains a z-sparse 3D point cloud (A matrix of dimension (n_cX3), n_c being the number of sparse points on smapled sections of the c'th cell. 


Sample run for the demo
-----------------------

    [cell_pts_sparse] = sparse_clustered_points_per_cell(sparse_2D_points, lineage, 0,[0.2, 0.2, 5*0.225]);


Step-4 (Optional)
------
------

This is an optional step. In this step, the unclustered dense point cloud, generated in step-2, is further subsampled to avoid 'out of memory' issues. Downsampling can also speed up the execution of the code. In our implementation, we downsample the dense point cloud by a factor of 2 along both x and y directions.

    [sampled_points] = downsample(points, dimension, sampling_frequency)



Input Variables and Data Structures
-----------------------------------

    points             :   The dense point cloud that needs to be downsampled (similar data structure as Step-2 output)

    dimension          :   (1/2/3) indicating the axis along which downsampling would be performed (1 for X, 2 for Y, 3 for Z). Cascading is needed for multidimensional downsampling.

    sampling_frequency :   The factor by which the input cloud would be downsampled. A positive integer.


Output Variables and Data Structures
------------------------------------
    
    sampled_points     :   The downsampled 3D point cloud (Data structure same as 'points').


Sample run for the demo
-----------------------

    dense_cloud_downsampled = downsample(downsample(dense_cloud_unclustered,2,2), 1, 2);



Step-5
------
------

In this final step, the cell specific parameters for the quadratic distance metric are estimated from the sparse cell point clouds and the dense unclustered point cloud is tessellated using these distance metrics.

    [dense_cell_points_reconstructed] = dense_reconstruct(dense_cloud_downsampled, cell_pts_sparse, fl_view3D)

Input Variables and Data Structures
-----------------------------------

    dense_cloud_downsampled  :  Explained in Step-4.
    
    cell_pts_sparse          :  Explained in Step-3.

    fl_view3D                :  A 1/0 flag to decide whether the estimated cell resolution 3D reconstruction result would be displayed.


Output Variables and Data Structures
------------------------------------

    dense_cell_points_reconstructed : A MATLAB cell of length C (total number of 3D cells in the tissue), where each cell contains a dense 3D point cloud (A matrix of dimension (D_cX3), D_c being the number of dense points clustered within the c'th cell.


Sample run for the demo
-----------------------

    [dense_cell_points_reconstructed] = dense_reconstruct(dense_cloud_unclustered, cell_pts_sparse, 1);


Thus, a batch script for a fully automated run of the pipeline could be:

    %% Start of script%%

    clear all;
    
    load '../Data/sparse_2D_points';
    load '../Data/lineage';
    
    sam_contours = extract_2D_Boundaries(sparse_2D_points);
    
    dense_cloud_unclustered = surface_reconstruction(sam_contours, 900, 150, -5*0.225, [0.2, 0.2, 5*0.225], -40*0.225, 0);
    
    dense_cloud_downsampled = downsample(downsample(dense_cloud_unclustered,2,2), 1, 2); %% This runs fine on a machine with 8GB RAM. For less memory, comment this line and uncomment and use the next line instead.

    % dense_cloud_downsampled = downsample(downsample(dense_cloud_unclustered,2,4), 1, 4); %% Runs fine on 4 GB RAM
    
    clear dense_cloud_unclustered;
    
    cell_pts_sparse = sparse_clustered_points_per_cell(sparse_2D_points, lineage, -5*0.225, [0.2, 0.2, 5*0.225]);

    dense_cell_points_reconstructed = dense_reconstruct(dense_cloud_downsampled, cell_pts_sparse, 1); 

    %% End of script%%

    (The script is provided as a m file within the Code folder and should be run from within the Code folder.)



Please note that axes for MATLAB images are generally different from the axes of MATLAB plots. The images generally have their origin of pixels at top-left corner whereas the plots have the origin at the bottom left corner. Please be reminded that the final dense point clouds per cell as well as the input sparse 2D points are represented in the most common bottom left origin format (not in the top-left origin format as in MATLAB images). Also note that, the input 'sparse_2D_points' are in pixels whereas, the final output 'dense_cell_points_reconstructed' are in microns.









