Skip to main content

Documentation Index

Fetch the complete documentation index at: https://mintlify.com/Rubick65/dcemapper/llms.txt

Use this file to discover all available pages before exploring further.

Region of interest (ROI) tools in DCEMapper allow you to restrict analysis to specific anatomical structures or lesions. By drawing a mask directly on the main canvas, you can exclude background, normal tissue, or motion-corrupted voxels from the semi-quantitative pipeline. Masks are stored as 3-D NIfTI files, making them fully reproducible across sessions.

Activating ROI Mode

The ROI toolbar becomes active after a preprocessed file is loaded. DCEMapper checks for the _preproc suffix in the current filename: when it is present, the ROI selection buttons in the NiftiToolbar are enabled. Three ROI shapes are available (defined in roi_actions_dict in src/utils/misc.py):

Rectangle

Draw a rectangular bounding box by clicking and dragging. Shortcut: Ctrl+R

Elliptical

Draw an ellipse fitted between click and release points. Shortcut: Ctrl+E

Polygonal

Define a freeform shape by clicking a series of vertices. Shortcut: Ctrl+P
ROI tools only activate after a preprocessed _preproc.nii.gz file has been loaded into the viewer — either by running the preprocessing pipeline or by opening an existing preprocessed file directly via File → Open → Open NIfTI File.

Drawing an ROI

Rectangle

Activate rectangle mode (Ctrl+R or toolbar button). A RectangleSelector widget is created on the matplotlib axes. Click and drag on the canvas to define the bounding box; the selection is drawn with a cyan outline. Release the mouse button to finalise the coordinates — DCEMapper stores them as (x1, y1, x2, y2) in roi_coords.

Ellipse

Activate ellipse mode (Ctrl+E or toolbar button). An EllipseSelector widget is created on the matplotlib axes. Click and drag to set the axis-aligned extents of the ellipse. On release, DCEMapper computes the centre (xc, yc) and semi-axes (a, b) from the click and release coordinates:
xc = (x1 + x2) / 2
yc = (y1 + y2) / 2
a  = abs(x2 - x1) / 2
b  = abs(y2 - y1) / 2

Polygon

Activate polygon mode (Ctrl+P or toolbar button). A PolygonSelector widget is created on the matplotlib axes. Click successive points on the canvas to place vertices; a cyan line connects them. Close the polygon by clicking near the first vertex. DCEMapper stores the vertex list in vertices.

Confirming, Cancelling, and Undoing

ActionKeyEffect
Confirm ROITabApplies the drawn shape as a mask to the current slice (z_index) and updates the canvas.
Cancel ROIEscapeClears the current selection widget without modifying the mask.
Undo last maskCtrl+ZCalls restar_mask(), resetting full_mask[:, :, z_index] to 1.0 (no mask) for the current slice only.

ROI Mask Internals

Masks are stored internally as a 3-D NumPy array named full_mask with shape (X, Y, Z), initialised to all ones when a file is first loaded. Each slice can have an independent mask. When you confirm an ROI, the appropriate function in src/roi/roi_creation.py is called for the current z_index:
  1. A blank float32 array of shape (X, Y) is created.
  2. The corner coordinates are floor-divided to integer pixel indices and clipped to image bounds.
  3. The interior rectangle is filled with 1.0.
  4. A Gaussian blur with sigma=0.5 is applied to produce sub-pixel smooth edges.
  5. The result is combined with the existing slice mask using np.minimum — this means successive ROIs intersect rather than union.
smooth_mask = ndimage.gaussian_filter(new_selection, sigma=0.5)
full_mask[:, :, z_index] = np.minimum(full_mask[:, :, z_index], smooth_mask)
  1. For every pixel (x, y), the ellipse equation ((x-xc)²/a²) + ((y-yc)²/b²) ≤ 1 is evaluated over a meshgrid.
  2. The boolean result is cast to float32.
  3. A Gaussian blur with sigma=1.0 is applied to smooth the boundary.
  4. Combined with the existing slice mask using np.minimum.
  1. The polygon is drawn at 4× super-resolution using skimage.draw.polygon to avoid aliasing.
  2. The high-resolution mask is downsampled back to image resolution using skimage.transform.resize with order=1 and anti_aliasing=True.
  3. Combined with the existing slice mask using np.minimum.
Once the mask is confirmed, the displayed data is recomputed as:
data = original_data * full_mask[:, :, :, np.newaxis]
This masks every time frame uniformly using the same spatial mask, preserving the temporal dimension for the intensity curve widget and semi-quantitative processing.

Saving and Loading Masks

Save a mask: Go to File → Mask → Save current Mask. A directory picker appears; DCEMapper saves the current full_mask array as a NIfTI file (e.g., <subject>_mask.nii.gz) in the selected folder, using the affine from the loaded image to preserve spatial registration. Load a saved mask: Go to File → Mask → Open mask. Select the NIfTI mask file in the file dialog. DCEMapper validates the filename for a mask suffix, loads the array into full_mask, and immediately applies it to the currently loaded volume by recomputing data = original_data * full_mask[:, :, :, np.newaxis].
A loaded mask must match the spatial dimensions of the currently loaded volume. DCEMapper validates the mask filename but does not currently enforce shape checking at runtime — ensure you load a mask that was generated from data of identical matrix size and number of slices.

Build docs developers (and LLMs) love