Task 01 — Slice Extraction and Display

1 Introduction

Medical imaging modalities such as CT (Computed Tomography) and MRI (Magnetic Resonance Imaging) produce volumetric data — three-dimensional grids of scalar values (voxels) that encode tissue density, signal intensity, or other physical quantities. A fundamental task in visualization is slice extraction: selecting a two-dimensional cross-section from the 3D volume along one of the three anatomical planes (axial, coronal, sagittal) and mapping its voxel intensities to displayable pixel values.

This report covers the theoretical and practical foundations of a volumetric slice viewer. 2 introduces the tensor abstraction that underlies multidimensional data storage and slicing. 3 presents the intensity transformations (linear stretching and window/level) used to map raw voxel values to the display range. 4 describes colormap application. 5 reviews medical image coordinate conventions (LPS, RAS) and the radiologist/neuroradiologist viewing perspectives. Finally, 6 embeds an interactive WebAssembly-based viewer, and the appendices summarize the code architecture and the WASM/Emscripten build.

2 Tensors, Strides, Views, and Slices

2.1 Tensor Definition

An $N$-dimensional tensor $T$ is defined by:

The total number of elements is $\prod_{i=0}^{N-1} d_i$, and the buffer occupies $\prod_{i} d_i \cdot \text{sizeof}(\texttt{type})$ bytes.

2.2 Memory Layout and Strides

Elements are stored contiguously with the first index varying fastest (column-major / Fortran-order). The strides $s_i$ determine how many elements to skip when advancing one step along dimension $i$:

$$s_0 = 1, \quad s_i = \prod_{j=0}^{i-1} d_j \quad \text{for } i \geq 1. \tag{2.1}$$

The linear (flat) index of an element at position $(x_0, x_1, \ldots, x_{N-1})$ is:

$$p = \sum_{i=0}^{N-1} x_i \cdot s_i. \tag{2.2}$$

For a 3D tensor with shape $(X, Y, Z)$, this gives $p = x + y \cdot X + z \cdot X \cdot Y$.

2.3 Element Access

Algorithm 1: \textsc{ElementAccess}$(T, x_0, x_1, \ldots, x_{N-1})$

\STATE $p \gets 0$
\FOR{$i = 0$ \TO $N - 1$}
    \STATE $p \gets p + x_i \cdot s_i$
\ENDFOR
\RETURN $T.\text{data}[p]$

2.4 Slice Extraction

Slicing selects a lower-dimensional subtensor by fixing one or more indices. Given a 3D tensor $T$ with shape $(X, Y, Z)$ and strides $(1, X, XY)$, fixing dimension $k$ at index $c$ produces a 2D tensor whose elements are gathered from:

$$p = \text{base} + \sum_{\substack{i=0 \\ i \neq k}}^{2} x_i \cdot s_i, \quad \text{base} = c \cdot s_k. \tag{2.3}$$

For instance, tensor[all, all, z] extracts the axial slice at depth $z$:

Algorithm 2: \textsc{CopySlice}$(T, \text{base}, \text{shape}, \text{strides})$

\STATE $n_\text{free} \gets |\text{shape}|$ \COMMENT{\textit{Number of free dimensions}}
\STATE $\text{total} \gets \prod_{d=0}^{n_\text{free}-1} \text{shape}[d]$
\STATE Allocate output buffer $O$ of size $\text{total}$
\FOR{$i = 0$ \TO $\text{total} - 1$}
    \STATE $\text{src\_idx} \gets \text{base}$; $\text{rem} \gets i$
    \FOR{$d = 0$ \TO $n_\text{free} - 1$}
        \STATE $\text{src\_idx} \gets \text{src\_idx} + (\text{rem} \bmod \text{shape}[d]) \cdot \text{strides}[d]$
        \STATE $\text{rem} \gets \lfloor \text{rem} / \text{shape}[d] \rfloor$
    \ENDFOR
    \STATE $O[i] \gets T.\text{data}[\text{src\_idx}]$
\ENDFOR
\RETURN $O$

2.5 The All Sentinel

In the implementation, slicing is expressed via C++23’s multidimensional operator[] with an All sentinel type. Each argument is either all (a free dimension) or an integer (a fixed index). The number of All arguments determines the output dimensionality:

3 Linear Stretching and Window/Level

3.1 Linear Stretching

Raw voxel values span an arbitrary range $[l_1, l_2]$ determined by the imaging modality. Linear stretching maps this input range to a display range $[k_1, k_2]$ (typically $[0, 255]$ for 8-bit display):

$$o(v) = k_1 + \frac{(v - l_1)(k_2 - k_1)}{l_2 - l_1}, \quad v \in [l_1, l_2]. \tag{3.1}$$

Values below $l_1$ are clamped to $k_1$; values at or above $l_2$ are clamped to $k_2$.

3.2 Window/Level

The window/level (W/L) adjustment is the standard clinical tool for controlling contrast and brightness. Given the global intensity range $[v_{\min}, v_{\max}]$:

$$W = w_p \cdot (v_{\max} - v_{\min}), \qquad L = l_p \cdot v_{\max}, \tag{3.2}$$

where $w_p$ and $l_p$ are user-controlled percentages ($w_p \in (0, 1]$, $l_p \in [0, 1]$). The input range boundaries are:

$$l_1 = \operatorname{max}\left(L - \tfrac{W}{2},\; v_{\min}\right), \qquad l_2 = \operatorname{min}\left(L + \tfrac{W}{2},\; v_{\max}\right). \tag{3.3}$$

Linear stretching is then applied with these bounds, mapping $[l_1, l_2] \to [0, 255]$.

Narrowing the window increases contrast within the selected range; shifting the level moves the center of the visible range across the full intensity spectrum.

4 Colormaps

4.1 Grayscale

The simplest colormap maps each intensity value $v$ to the gray triple $(v, v, v)$.

4.2 Viridis Colormap

The viridis colormap is a perceptually uniform, colorblind-friendly palette. Each RGB channel is approximated by a degree-6 polynomial in the normalized intensity $t = v/255$:

$$C(t) = c_0 + c_1 t + c_2 t^2 + c_3 t^3 + c_4 t^4 + c_5 t^5 + c_6 t^6, \tag{4.1}$$

evaluated via Horner’s method. The coefficients for the R, G, B channels are given by:

Coeff R G B
$c_0$ $0.278$ $0.005$ $0.334$
$c_1$ $0.105$ $1.405$ $1.749$
$c_2$ $-0.331$ $0.215$ $0.095$
$c_3$ $-4.634$ $-5.799$ $-19.332$
$c_4$ $6.228$ $14.180$ $56.690$
$c_5$ $4.776$ $-13.745$ $-65.353$
$c_6$ $-5.435$ $4.646$ $26.312$

The output is clamped to $[0, 1]$ and scaled to $[0, 255]$. The same polynomial structure is used for the magma colormap with different coefficients.

4.3 Blue-to-Red Colormap

A smooth blue $\to$ cyan $\to$ green $\to$ yellow $\to$ red gradient defined by piecewise linear functions of $V = 4t + 1$ ($t \in [0,1]$):

$$\begin{aligned} R(V) &= 255 \cdot \operatorname{max}\left(0,\; \tfrac{3 - |V-4| - |V-5|}{2}\right) \\ G(V) &= 255 \cdot \operatorname{max}\left(0,\; \tfrac{4 - |V-2| - |V-4|}{2}\right) \\ B(V) &= 255 \cdot \operatorname{max}\left(0,\; \tfrac{3 - |V-1| - |V-2|}{2}\right) \end{aligned} \tag{4.2}$$

Each colormap maps a normalized intensity $t = v/255$ directly to an RGB triple. The colormaps are precomputed into 256-entry lookup tables for efficient per-pixel application.

5 Medical Image Coordinates

5.1 Coordinate Systems

Medical images use body-relative coordinate systems. The two primary conventions are:

RAS is obtained from LPS by negating the X and Y axes.

5.2 Anatomical Planes

The three orthogonal planes correspond to fixing one tensor axis:

Plane Fixed axis Free axes View
Axial (transverse) Z X, Y Top-down
Coronal Y X, Z Front view
Sagittal X Y, Z Side view

5.3 Radiologist vs. Neuroradiologist Convention

The two standard viewing conventions differ in the orientation of the displayed slices:

Radiologist convention. The viewer faces the patient as if the patient stands in front of them. The patient’s left appears on the right side of the screen. Slices are navigated:

Neuroradiologist convention. The anatomical left of the patient appears on the left side of the screen. All slice navigation directions are reversed relative to the radiologist convention.

In the implementation, switching between conventions is achieved by (1) reversing the slice position index and (2) applying a horizontal flip to the extracted slice.

6 Interactive Viewer

The viewer below is a WebAssembly-based application that loads .scn volumetric files and displays the three orthogonal slices in real time. It supports window/level adjustment, perspective switching, and colormap selection — all the concepts described in the preceding sections.

A hosted sample volume is available at brain.scn.gz. The original course page, MO815 - Visualization of Volumetric Images, taught by Alexandre Xavier Falcao, also provides other volumetric images.

Volume Slice Viewer

Drop a .scn file here or click to browse

100
50
Axial
Z 0
Coronal
Y 0
Sagittal
X 0
Interactive viewer for .scn volumetric data. Drop a file to visualize axial, coronal, and sagittal slices with adjustable window/level, viewpoint, and colormap.

7 Appendix A: Code Architecture

7.1 tinytensor

A minimal, header-only C++ library for N-dimensional tensors:

7.2 vbox

The volume visualization library built on tinytensor:

8 Appendix B: WASM and Emscripten

The viewer runs C++ code in the browser via WebAssembly (WASM), compiled with Emscripten.

Why WASM: near-native performance for compute-heavy operations (slice extraction, type conversion, colormap application) without requiring a server backend.

Emscripten embind exposes five C++ functions to JavaScript:

Memory management: WASM heap views (typed_memory_view) become invalid when the underlying C++ vector is destroyed. The solution is to immediately copy into a JS-owned Uint8ClampedArray.

Build flags: -O1 (avoids binaryen version mismatch), -s ALLOW_MEMORY_GROWTH=1 (dynamic heap for large volumes), -s MODULARIZE=1 -s EXPORT_NAME=createVboxModule (factory function pattern).