{ "cells": [ { "cell_type": "code", "execution_count": null, "metadata": { "collapsed": false }, "outputs": [], "source": [ "%matplotlib inline" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "\n# Tractography Clustering with QuickBundles\n\nThis example explains how we can use QuickBundles [Garyfallidis12]_ to\nsimplify/cluster streamlines.\n\nFirst import the necessary modules.\n" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "collapsed": false }, "outputs": [], "source": [ "import numpy as np\nfrom dipy.io.streamline import load_tractogram\nfrom dipy.segment.clustering import QuickBundles\nfrom dipy.io.pickles import save_pickle\nfrom dipy.data import get_fnames\nfrom dipy.viz import window, actor, colormap" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "For educational purposes we will try to cluster a small streamline bundle known\nfrom neuroanatomy as the fornix.\n\n" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "collapsed": false }, "outputs": [], "source": [ "fname = get_fnames('fornix')" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Load fornix streamlines.\n\n" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "collapsed": false }, "outputs": [], "source": [ "fornix = load_tractogram(fname, 'same', bbox_valid_check=False)\nstreamlines = fornix.streamlines" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Perform QuickBundles clustering using the MDF metric and a 10mm distance\nthreshold. Keep in mind that since the MDF metric requires streamlines to have\nthe same number of points, the clustering algorithm will internally use a\nrepresentation of streamlines that have been automatically downsampled/upsampled\nso they have only 12 points (To set manually the number of points,\nsee `clustering-examples-ResampleFeature`).\n\n" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "collapsed": false }, "outputs": [], "source": [ "qb = QuickBundles(threshold=10.)\nclusters = qb.cluster(streamlines)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "`clusters` is a `ClusterMap` object which contains attributes that\nprovide information about the clustering result.\n\n" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "collapsed": false }, "outputs": [], "source": [ "print(\"Nb. clusters:\", len(clusters))\nprint(\"Cluster sizes:\", map(len, clusters))\nprint(\"Small clusters:\", clusters < 10)\nprint(\"Streamlines indices of the first cluster:\\n\", clusters[0].indices)\nprint(\"Centroid of the last cluster:\\n\", clusters[-1].centroid)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "::\n\n Nb. clusters: 4\n\n Cluster sizes: [64, 191, 47, 1]\n\n Small clusters: array([False, False, False, True], dtype=bool)\n\n Streamlines indices of the first cluster:\n [0, 7, 8, 10, 11, 12, 13, 14, 15, 18, 26, 30, 33, 35, 41, 65, 66, 85, 100,\n 101, 105, 115, 116, 119, 122, 123, 124, 125, 126, 128, 129, 135, 139, 142,\n 143, 144, 148, 151, 159, 167, 175, 180, 181, 185, 200, 208, 210, 224, 237,\n 246, 249, 251, 256, 267, 270, 280, 284, 293, 296, 297, 299]\n\n Centroid of the last cluster:\n array([[ 84.83773804, 117.92590332, 77.32278442],\n [ 86.10850525, 115.84362793, 81.91885376],\n [ 86.40357208, 112.25676727, 85.72930145],\n [ 86.48336792, 107.60327911, 88.13782501],\n [ 86.23897552, 102.5100708 , 89.29447174],\n [ 85.04563904, 97.46020508, 88.54240417],\n [ 82.60240173, 93.14851379, 86.84208679],\n [ 78.98937225, 89.57682037, 85.63652039],\n [ 74.72344208, 86.60827637, 84.9391861 ],\n [ 70.40846252, 85.15874481, 82.4484024 ],\n [ 66.74534607, 86.00262451, 78.82582092],\n [ 64.02451324, 88.43942261, 75.0697403 ]], dtype=float32)\n\n\n`clusters` also has attributes such as `centroids` (cluster representatives), and\nmethods like `add`, `remove`, and `clear` to modify the clustering result.\n\nLet's first show the initial dataset.\n\n" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "collapsed": false }, "outputs": [], "source": [ "# Enables/disables interactive visualization\ninteractive = False\n\nscene = window.Scene()\nscene.SetBackground(1, 1, 1)\nscene.add(actor.streamtube(streamlines, window.colors.white))\nwindow.record(scene, out_path='fornix_initial.png', size=(600, 600))\nif interactive:\n window.show(scene)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ ".. figure:: fornix_initial.png\n :align: center\n\n Initial Fornix dataset.\n\nShow the centroids of the fornix after clustering (with random colors):\n\n" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "collapsed": false }, "outputs": [], "source": [ "colormap = colormap.create_colormap(np.arange(len(clusters)))\n\nscene.clear()\nscene.SetBackground(1, 1, 1)\nscene.add(actor.streamtube(streamlines, window.colors.white, opacity=0.05))\nscene.add(actor.streamtube(clusters.centroids, colormap, linewidth=0.4))\nwindow.record(scene, out_path='fornix_centroids.png', size=(600, 600))\nif interactive:\n window.show(scene)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ ".. figure:: fornix_centroids.png\n :align: center\n\n Showing the different QuickBundles centroids with random colors.\n\nShow the labeled fornix (colors from centroids).\n\n" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "collapsed": false }, "outputs": [], "source": [ "colormap_full = np.ones((len(streamlines), 3))\nfor cluster, color in zip(clusters, colormap):\n colormap_full[cluster.indices] = color\n\nscene.clear()\nscene.SetBackground(1, 1, 1)\nscene.add(actor.streamtube(streamlines, colormap_full))\nwindow.record(scene, out_path='fornix_clusters.png', size=(600, 600))\nif interactive:\n window.show(scene)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ ".. figure:: fornix_clusters.png\n :align: center\n\n Showing the different clusters.\n\nIt is also possible to save the complete `ClusterMap` object with pickling.\n\n" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "collapsed": false }, "outputs": [], "source": [ "save_pickle('QB.pkl', clusters)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Finally, here is a video of QuickBundles applied on a larger dataset.\n\n.. raw:: html\n\n \n\n.. include:: ../links_names.inc\n\n## References\n\n.. [Garyfallidis12] Garyfallidis E. et al., QuickBundles a method for\n tractography simplification, Frontiers in Neuroscience, vol\n 6, no 175, 2012.\n\n\n" ] } ], "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.13" } }, "nbformat": 4, "nbformat_minor": 0 }