{ "cells": [ { "cell_type": "markdown", "metadata": {}, "source": [ "# Convert Scanco Volumes to Open Standards\n", "\n", "This notebook illustrates how to convert Scanco microCT images into open standard file formats while preserving critical image metadata." ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "### Install notebook dependencies" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "import sys\n", "!{sys.executable} -m pip install itk-ioscanco xarray zarr tqdm requests itkwidgets" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "### Imports" ] }, { "cell_type": "code", "execution_count": 2, "metadata": {}, "outputs": [], "source": [ "import requests\n", "from tqdm.notebook import tqdm\n", "import os\n", "\n", "from itkwidgets import view\n", "\n", "import itk\n", "import numpy as np\n", "import xarray as xr\n", "import zarr" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "### Download example data" ] }, { "cell_type": "code", "execution_count": 3, "metadata": {}, "outputs": [], "source": [ "def download_data(url, filename):\n", " if not os.path.exists(filename):\n", " chunk_size = 32 * 1024\n", " r = requests.get(url, stream=True)\n", " total_size = int(r.headers.get('content-length', 0))\n", " pbar = tqdm(unit=\"B\", unit_scale=True, total=int(total_size))\n", " with open(filename, 'wb') as f:\n", " for chunk in r.iter_content(chunk_size=chunk_size): \n", " if chunk: # filter out keep-alive new chunks\n", " pbar.update(len(chunk))\n", " f.write(chunk)\n", " \n", "file_name = 'C0004255.ISQ'\n", "file_url = 'https://data.kitware.com/api/v1/file/591e56178d777f16d01e0d20/download'\n", "download_data(file_url, file_name)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "### Read in the Scanco image file, *.ISQ* or *.AIM*." ] }, { "cell_type": "code", "execution_count": 4, "metadata": {}, "outputs": [], "source": [ "imageio = itk.ScancoImageIO.New()\n", "image = itk.imread(file_name, imageio=imageio)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "The type of the image is an `itk.Image`." ] }, { "cell_type": "code", "execution_count": 5, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "True\n", "\n" ] } ], "source": [ "print(isinstance(image, itk.Image))\n", "print(type(image))" ] }, { "cell_type": "code", "execution_count": 6, "metadata": {}, "outputs": [ { "data": { "application/vnd.jupyter.widget-view+json": { "model_id": "1e1e184334524c68903caeec8f6ce966", "version_major": 2, "version_minor": 0 }, "text/plain": [ "Viewer(geometries=[], gradient_opacity=0.22, point_sets=[], rendered_image=\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "
<xarray.DataArray (z: 51, y: 1024, x: 1024)>\n",
       "array([[[-1000, -1000, -1000, ..., -1000, -1000, -1000],\n",
       "        [-1000, -1000, -1000, ..., -1000, -1000, -1000],\n",
       "        [-1000, -1000, -1000, ..., -1000, -1000, -1000],\n",
       "        ...,\n",
       "        [-1000, -1000, -1000, ..., -1000, -1000, -1000],\n",
       "        [-1000, -1000, -1000, ..., -1000, -1000, -1000],\n",
       "        [-1000, -1000, -1000, ..., -1000, -1000, -1000]],\n",
       "\n",
       "       [[-1000, -1000, -1000, ..., -1000, -1000, -1000],\n",
       "        [-1000, -1000, -1000, ..., -1000, -1000, -1000],\n",
       "        [-1000, -1000, -1000, ..., -1000, -1000, -1000],\n",
       "        ...,\n",
       "        [-1000, -1000, -1000, ..., -1000, -1000, -1000],\n",
       "        [-1000, -1000, -1000, ..., -1000, -1000, -1000],\n",
       "        [-1000, -1000, -1000, ..., -1000, -1000, -1000]],\n",
       "\n",
       "       [[-1000, -1000, -1000, ..., -1000, -1000, -1000],\n",
       "        [-1000, -1000, -1000, ..., -1000, -1000, -1000],\n",
       "        [-1000, -1000, -1000, ..., -1000, -1000, -1000],\n",
       "        ...,\n",
       "...\n",
       "        ...,\n",
       "        [-1000, -1000, -1000, ..., -1000, -1000, -1000],\n",
       "        [-1000, -1000, -1000, ..., -1000, -1000, -1000],\n",
       "        [-1000, -1000, -1000, ..., -1000, -1000, -1000]],\n",
       "\n",
       "       [[-1000, -1000, -1000, ..., -1000, -1000, -1000],\n",
       "        [-1000, -1000, -1000, ..., -1000, -1000, -1000],\n",
       "        [-1000, -1000, -1000, ..., -1000, -1000, -1000],\n",
       "        ...,\n",
       "        [-1000, -1000, -1000, ..., -1000, -1000, -1000],\n",
       "        [-1000, -1000, -1000, ..., -1000, -1000, -1000],\n",
       "        [-1000, -1000, -1000, ..., -1000, -1000, -1000]],\n",
       "\n",
       "       [[-1000, -1000, -1000, ..., -1000, -1000, -1000],\n",
       "        [-1000, -1000, -1000, ..., -1000, -1000, -1000],\n",
       "        [-1000, -1000, -1000, ..., -1000, -1000, -1000],\n",
       "        ...,\n",
       "        [-1000, -1000, -1000, ..., -1000, -1000, -1000],\n",
       "        [-1000, -1000, -1000, ..., -1000, -1000, -1000],\n",
       "        [-1000, -1000, -1000, ..., -1000, -1000, -1000]]], dtype=int16)\n",
       "Coordinates:\n",
       "  * x        (x) float64 0.0 0.036 0.072 0.108 0.144 ... 36.72 36.76 36.79 36.83\n",
       "  * y        (y) float64 0.0 0.036 0.072 0.108 0.144 ... 36.72 36.76 36.79 36.83\n",
       "  * z        (z) float64 0.0 0.036 0.072 0.108 0.144 ... 1.692 1.728 1.764 1.8\n",
       "Attributes: (12/28)\n",
       "    direction:            [[1. 0. 0.]\\n [0. 1. 0.]\\n [0. 0. 1.]]\n",
       "    CalibrationData:      45 kVp, 0.5mm Al, BH: 1200mg HA/ccm, Scaling 4096\n",
       "    CreationDate:         5-JUN-2015 11:09:18.880\n",
       "    DataRange:            (-2813.0, 32767.0)\n",
       "    Energy:               45.0\n",
       "    Intensity:            0.177\n",
       "    ...                   ...\n",
       "    ScannerID:            2135\n",
       "    ScannerType:          10\n",
       "    Site:                 5\n",
       "    SliceIncrement:       0.036000000000000004\n",
       "    SliceThickness:       0.036000000000000004\n",
       "    Version:              CTDATA-HEADER_V1
" ], "text/plain": [ "\n", "array([[[-1000, -1000, -1000, ..., -1000, -1000, -1000],\n", " [-1000, -1000, -1000, ..., -1000, -1000, -1000],\n", " [-1000, -1000, -1000, ..., -1000, -1000, -1000],\n", " ...,\n", " [-1000, -1000, -1000, ..., -1000, -1000, -1000],\n", " [-1000, -1000, -1000, ..., -1000, -1000, -1000],\n", " [-1000, -1000, -1000, ..., -1000, -1000, -1000]],\n", "\n", " [[-1000, -1000, -1000, ..., -1000, -1000, -1000],\n", " [-1000, -1000, -1000, ..., -1000, -1000, -1000],\n", " [-1000, -1000, -1000, ..., -1000, -1000, -1000],\n", " ...,\n", " [-1000, -1000, -1000, ..., -1000, -1000, -1000],\n", " [-1000, -1000, -1000, ..., -1000, -1000, -1000],\n", " [-1000, -1000, -1000, ..., -1000, -1000, -1000]],\n", "\n", " [[-1000, -1000, -1000, ..., -1000, -1000, -1000],\n", " [-1000, -1000, -1000, ..., -1000, -1000, -1000],\n", " [-1000, -1000, -1000, ..., -1000, -1000, -1000],\n", " ...,\n", "...\n", " ...,\n", " [-1000, -1000, -1000, ..., -1000, -1000, -1000],\n", " [-1000, -1000, -1000, ..., -1000, -1000, -1000],\n", " [-1000, -1000, -1000, ..., -1000, -1000, -1000]],\n", "\n", " [[-1000, -1000, -1000, ..., -1000, -1000, -1000],\n", " [-1000, -1000, -1000, ..., -1000, -1000, -1000],\n", " [-1000, -1000, -1000, ..., -1000, -1000, -1000],\n", " ...,\n", " [-1000, -1000, -1000, ..., -1000, -1000, -1000],\n", " [-1000, -1000, -1000, ..., -1000, -1000, -1000],\n", " [-1000, -1000, -1000, ..., -1000, -1000, -1000]],\n", "\n", " [[-1000, -1000, -1000, ..., -1000, -1000, -1000],\n", " [-1000, -1000, -1000, ..., -1000, -1000, -1000],\n", " [-1000, -1000, -1000, ..., -1000, -1000, -1000],\n", " ...,\n", " [-1000, -1000, -1000, ..., -1000, -1000, -1000],\n", " [-1000, -1000, -1000, ..., -1000, -1000, -1000],\n", " [-1000, -1000, -1000, ..., -1000, -1000, -1000]]], dtype=int16)\n", "Coordinates:\n", " * x (x) float64 0.0 0.036 0.072 0.108 0.144 ... 36.72 36.76 36.79 36.83\n", " * y (y) float64 0.0 0.036 0.072 0.108 0.144 ... 36.72 36.76 36.79 36.83\n", " * z (z) float64 0.0 0.036 0.072 0.108 0.144 ... 1.692 1.728 1.764 1.8\n", "Attributes: (12/28)\n", " direction: [[1. 0. 0.]\\n [0. 1. 0.]\\n [0. 0. 1.]]\n", " CalibrationData: 45 kVp, 0.5mm Al, BH: 1200mg HA/ccm, Scaling 4096\n", " CreationDate: 5-JUN-2015 11:09:18.880\n", " DataRange: (-2813.0, 32767.0)\n", " Energy: 45.0\n", " Intensity: 0.177\n", " ... ...\n", " ScannerID: 2135\n", " ScannerType: 10\n", " Site: 5\n", " SliceIncrement: 0.036000000000000004\n", " SliceThickness: 0.036000000000000004\n", " Version: CTDATA-HEADER_V1" ] }, "execution_count": 13, "metadata": {}, "output_type": "execute_result" } ], "source": [ "image_da = itk.xarray_from_image(image)\n", "image_da" ] }, { "cell_type": "code", "execution_count": 14, "metadata": {}, "outputs": [], "source": [ "image_ds = image_da.to_dataset(name='image')\n", "with zarr.storage.ZipStore('image.zarr.zip', mode='w', compression=0) as store:\n", " image_ds.to_zarr(store, mode='w', compute=True)" ] }, { "cell_type": "code", "execution_count": 15, "metadata": {}, "outputs": [], "source": [ "image_ds = xr.open_zarr('image.zarr.zip')" ] }, { "cell_type": "code", "execution_count": 16, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "{'CalibrationData': '45 kVp, 0.5mm Al, BH: 1200mg HA/ccm, Scaling 4096',\n", " 'CreationDate': '5-JUN-2015 11:09:18.880',\n", " 'Energy': 45.0,\n", " 'Intensity': 0.1770000010728836,\n", " 'MeasurementIndex': 4937,\n", " 'ModificationDate': '5-JUN-2015 11:09:18.880',\n", " 'MuScaling': 4096.0,\n", " 'MuWater': 0.7032999992370605,\n", " 'NumberOfProjections': 500,\n", " 'NumberOfSamples': 1024,\n", " 'PatientIndex': 78,\n", " 'PatientName': 'COLE-BPBP',\n", " 'ReconstructionAlg': 3,\n", " 'ReferenceLine': 0.0,\n", " 'RescaleIntercept': -1000.0,\n", " 'RescaleSlope': 0.3471358120441437,\n", " 'RescaleType': 2,\n", " 'RescaleUnits': 'mg HA/ccm',\n", " 'SampleTime': 400.0,\n", " 'ScanDistance': 36.86399841308594,\n", " 'ScannerID': 2135,\n", " 'ScannerType': 10,\n", " 'Site': 5,\n", " 'SliceIncrement': 0.035999998450279236,\n", " 'SliceThickness': 0.035999998450279236,\n", " 'Version': 'CTDATA-HEADER_V1',\n", " 'origin': array([0., 0., 0.]),\n", " 'spacing': array([0.036, 0.036, 0.036]),\n", " 'direction': array([[1., 0., 0.],\n", " [0., 1., 0.],\n", " [0., 0., 1.]])}" ] }, "execution_count": 16, "metadata": {}, "output_type": "execute_result" } ], "source": [ "image_zarr = itk.image_from_xarray(image_ds.image)\n", "dict(image_zarr)" ] } ], "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.9.2" } }, "nbformat": 4, "nbformat_minor": 2 }