{
 "cells": [
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "# Getting Started with Segmentations"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## Before you start!\n",
    "\n",
    "- This notebook assumes that shapeworks conda environment has been activated using `conda activate shapeworks` on the terminal.\n",
    "- See [Getting Started with Notebooks](getting-started-with-notebooks.ipynb) for information on setting up your environment and notebook shortcuts. \n",
    "- Note example output was generated on Linux/Mac environment and may look different on Windows.\n",
    "\n",
    "\n",
    "## In this notebook, you will learn:\n",
    "\n",
    "1. How to define your dataset location and explore what is available in it\n",
    "2. How to load a single segmentation \n",
    "3. How to convert `shapeworks` image to `vtk` image for visualization\n",
    "4. How to visualize a single segmentation and multiple segmentations using `pyvista`\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "import shapeworks as sw"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## 1. Defining and exploring your dataset\n",
    "\n",
    "### Defining dataset location\n",
    "\n",
    "You can download exemplar datasets from [ShapeWorks data portal](https://girder.shapeworks-cloud.org) after you login. For new users, you can [register](https://girder.shapeworks-cloud.org#?dialog=register) an account for free. Please do not use an important password.\n",
    "\n",
    "After you login, click `Collections` on the left panel and then `use-case-data-v2`. Select the dataset you would like to download by clicking on the checkbox on the left of the dataset name. See the video below.\n",
    "After you download the dataset zip file, make sure you unzip/extract the contents in the appropriate location.\n",
    "\n",
    "**This notebook assumes that you have downloaded `ellipsoid_1mode` and you have placed the unzipped folder `ellipsoid_1mode` in `Examples/Python/Data`.** Feel free to use your own dataset.  \n",
    "\n",
    "\n",
    "<p><video src=\"https://sci.utah.edu/~shapeworks/doc-resources/mp4s/portal_data_download.mp4\" autoplay muted loop controls style=\"width:100%\"></p>\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "import os \n",
    "\n",
    "# dataset name is the folder name for your dataset\n",
    "datasetName  = 'ellipsoid_1mode'\n",
    "\n",
    "# path to the dataset where we can find shape data \n",
    "# here we assume shape data are given as binary segmentations\n",
    "shapeDir      = '../../Data/' + datasetName + '/segmentations/'\n",
    "\n",
    "print('Dataset Name:     ' + datasetName)\n",
    "print('Shape Directory:  ' + shapeDir)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### What is available in the dataset?\n",
    "\n",
    "First let's see how many shapes we have in the dataset.\n",
    "\n",
    "**File formats:** For binary segmentations, all [itk-supported image formats](https://insightsoftwareconsortium.github.io/itk-js/docs/image_formats.html) can be used."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "import glob \n",
    "from pathlib import Path \n",
    "\n",
    "\n",
    "shapeExtention = '.nrrd'\n",
    "\n",
    "# let's get a list of files for available segmentations in this dataset\n",
    "# * here is a wild character used to retrieve all filenames \n",
    "# in the shape directory with the file extensnion\n",
    "\n",
    "shapeFilenames = sorted(glob.glob(shapeDir + '*' + shapeExtention)) \n",
    "\n",
    "print ('Number of shapes: ' + str(len(shapeFilenames)))\n",
    "print('Shape files found:')\n",
    "for shapeFilename in shapeFilenames:\n",
    "    shapeFilename = Path(shapeFilename)\n",
    "    print(shapeFilename)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## 2. Loading a single segmentation\n",
    "\n",
    "We will select one segmentation to explore for now. We will then use shapeworks Image class to load this segmentation and print out its header information that includes image dimensions (rows, columns and slices), physical origin, physical size, and voxel spacing (in physical units)."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "# select a shape by setting the shape index (in the filenames list)\n",
    "shapeIdx       = 1\n",
    "\n",
    "# the filename for the selected shape\n",
    "shapeFilename  = shapeFilenames[shapeIdx]\n",
    "\n",
    "# since segmentation is just an image data, we will use shapeworks Image class to load it\n",
    "print('Loading: ' + shapeFilename)\n",
    "shapeSeg = sw.Image(shapeFilename)\n",
    "\n",
    "# let's print out header information of this segmentation \n",
    "print('Header information: ')\n",
    "print(shapeSeg)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## 3. Converting `shapeworks` image to `vtk` image for visualization\n",
    "\n",
    "We use python library [`pyvista`](https://docs.pyvista.org/index.html) for interactive 3D visualization. This library support, among others, `vtk` data structures for images and meshes. Hence, to visualize our `shapeworks` image, we need first to convert it to a `vtk` data structure.\n",
    "\n",
    "This conversion can be performed by first extracting a numpy array from the `shapeworks` image, then constructing a `vtk` image from this array. `pyvista`'s `wrap` function makes this easy.\n",
    "\n",
    "In the ShapeWorks python module, we have the `sw2vtkImage` function for this conversion to `vtk` image."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "#from the shapeworks python module use the conversion function\n",
    "shapeSeg_vtk = sw.sw2vtkImage(shapeSeg)\n",
    "\n",
    "# print header info of both images, please note that the wrap function\n",
    "# only wraps the numpy array, which is oblivous to image spacing and origin\n",
    "print('shapeworks image header information: \\n')\n",
    "print(shapeSeg)\n",
    "\n",
    "print('\\nvtk image header information: \\n')\n",
    "print(shapeSeg_vtk)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## 4. Visualizing segmentation using `pyvista`\n",
    "\n",
    "[`pyvista`](https://docs.pyvista.org/index.html) python library is built on top of `vtk` and brings a paraview-like visualizations to notebooks. It also supports multiple rendering windows that can be linked. This feature is very useful when visualizing multiple samples from your dataset side-by-side and making them share the same camera view.\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "import pyvista as pv\n",
    "\n",
    "notebook = False # True will bring the renderings inline\n",
    "# click r to reset the view after zooming\n",
    "shapeSeg_vtk.plot(volume     = True,     # volume render\n",
    "                  shade      = True,\n",
    "                  notebook = notebook)     # enable shading"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "<p><video src=\"https://sci.utah.edu/~shapeworks/doc-resources/mp4s/nb-seg-pv-vol.mp4\" autoplay muted loop controls style=\"width:100%\"></p>"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## 5. Visualizing two segmentations side-by-side using `pyvista`\n",
    "\n",
    "When exploring datasets and results of different grooming (data preprocessing) steps, it is important to simultaneously visualize multiple shape samples. Here, we will learn how to visualize two segmentations side-by-side and link their views using `pyvista`. This linking is useful to make all rendering windows share the same camera view.  "
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### Loading the second segmentation and convert it to `vtk` image\n",
    "\n",
    "First, let's select another segmentation and load it."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "# select a shape by setting the shape index (in the filenames list)\n",
    "shapeIdx2       = 2\n",
    "\n",
    "# the filename for the selected shape\n",
    "shapeFilename2  = shapeFilenames[shapeIdx2]\n",
    "\n",
    "# since segmentation is just an image data, we will use shapeworks Image class to load it\n",
    "print('Loading: ' + shapeFilename2)\n",
    "shapeSeg2 = sw.Image(shapeFilename2)\n",
    "\n",
    "# let's print out header information of this segmentation \n",
    "print('Header information: ')\n",
    "print(shapeSeg2)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Then, let's convert this `shapeworks` image to a `vtk` image for visualization."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "# sw to vtk\n",
    "shapeSeg2_vtk = sw.sw2vtkImage(shapeSeg2)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### Defining `pyvista` plotter\n",
    "\n",
    "Next, we will define a `pyvista` plotter to render multiple windows, each with a single segmentation. The multiple rendering windows will be visualized as a grid of plots. Since, we have only two segmentations, the grid size will be one row and two columns.\n",
    "\n",
    "The plotter also enable use to specify a color map."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "\n",
    "# define parameters that controls the plotter\n",
    "notebook       = False  # True will bring the renderings inline in the notebook\n",
    "show_borders   = True  # show borders for each rendering window\n",
    "shade_volumes  = True  # use shading when performing volume rendering\n",
    "color_map      = \"coolwarm\" # color map for volume rendering, e.g., 'bone', 'coolwarm', 'cool', 'viridis', 'magma'\n",
    "show_axes      = True  # show a vtk axes widget for each rendering window\n",
    "show_bounds    = False # show volume bounding box\n",
    "show_all_edges = True  # add an unlabeled and unticked box at the boundaries of plot. \n",
    "font_size      = 10    # text font size for windows\n",
    "link_views     = True  # link all rendering windows so that they share same camera and axes boundaries\n",
    "\n",
    "\n",
    "#extract the shape name for display\n",
    "segFilename = shapeFilenames[shapeIdx].split('/')[-1] \n",
    "shapeName   = segFilename[:-len(shapeExtention)]\n",
    "segFilename2 = shapeFilenames[shapeIdx2].split('/')[-1] \n",
    "shapeName2   = segFilename2[:-len(shapeExtention)]\n",
    "shapeSegList = [shapeSeg_vtk,shapeSeg2_vtk]\n",
    "shapeNames = [shapeName,shapeName2]\n",
    "\n"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Let's use the `plot_volumes` function from Shapeworks python module for adding segmentations to the pyvista plotter"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "\n",
    "sw.plot_volumes(shapeSegList,    \n",
    "             volumeNames     = shapeNames, \n",
    "             notebook = notebook, \n",
    "             show_borders   = show_borders,  \n",
    "             shade_volumes  = shade_volumes,  \n",
    "             show_axes      = show_axes,  \n",
    "             show_bounds    = show_bounds,\n",
    "             show_all_edges = show_all_edges, \n",
    "             font_size      = font_size,   \n",
    "             link_views     = True )"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "<p><img src=\"https://sci.utah.edu/~shapeworks/doc-resources/pngs/segs_two_windows.png\"></p>"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## 6. Visualizing two segmentations in the same rendering window\n",
    "\n",
    "This type of visualization is useful when exploring differences between more than one segmentations, e.g., when inspecting the impact of a grooming/preprocessing step or the spatial relation of multiple samples. This is also useful if your shape data contains multiple domains (or compartments) such as anatomical joints.\n",
    "\n",
    "Note that, since we have a single rendering window (view), linking views is not necessary. But, if this multi-surface visualization is used in conjuction with multiple rendering windows, linking views should be considered. "
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "\n",
    "\n",
    "# define parameters that controls the plotter\n",
    "\n",
    "use_same_window = True"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "\n",
    "sw.plot_volumes(shapeSegList,    \n",
    "             color_map=color_map,\n",
    "             notebook = notebook, \n",
    "             show_borders   = show_borders,  \n",
    "             shade_volumes  = shade_volumes,  \n",
    "             show_axes      = show_axes,  \n",
    "             show_bounds    = show_bounds,\n",
    "             show_all_edges = show_all_edges, \n",
    "             font_size      = font_size, \n",
    "             use_same_window = use_same_window,\n",
    "             link_views     = True )"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "<p><img src=\"https://sci.utah.edu/~shapeworks/doc-resources/pngs/segs_one_window.png\"></p>"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": []
  }
 ],
 "metadata": {
  "kernelspec": {
   "display_name": "Python 3",
   "language": "python",
   "name": "python3"
  },
  "language_info": {
   "codemirror_mode": {
    "name": "ipython",
    "version": 3
   },
   "file_extension": ".py",
   "mimetype": "text/x-python",
   "name": "python",
   "nbconvert_exporter": "python",
   "pygments_lexer": "ipython3",
   "version": "3.7.8"
  },
  "toc": {
   "base_numbering": 1,
   "nav_menu": {},
   "number_sections": false,
   "sideBar": true,
   "skip_h1_title": true,
   "title_cell": "Table of Contents",
   "title_sidebar": "Contents",
   "toc_cell": false,
   "toc_position": {},
   "toc_section_display": true,
   "toc_window_display": false
  }
 },
 "nbformat": 4,
 "nbformat_minor": 4
}
