1. Introduction

This report demonstrates the antspymm.blind_image_assessment function for performing automated, no-reference Quality Control on medical images. We will first simulate a set of images with varying characteristics (noise, smoothness, etc.) and then run the QC analysis on them. The results are presented in interactive and static tables.

This script is designed to be fully portable and self-contained. It creates temporary files in a system-appropriate location and cleans up after itself upon completion.

2. Simulating Images for QC

First, we set up a Python environment and generate several test images. A temporary directory is created to store these images, ensuring the script does not leave files on the system.

# --- Python Environment and Image Simulation ---
import siq
import ants
import antspymm
import os
import tempfile
import shutil
import pandas as pd

# Create a single, system-agnostic temporary directory for all output files.
# This makes the script portable (works on Linux, macOS, Windows).
temp_dir = tempfile.mkdtemp()
print(f"Using temporary directory: {temp_dir}")
## Using temporary directory: /tmp/tmp0lt08_m8
# List to hold the paths of all generated files for processing.
generated_files = []

# --- Image 1: Baseline Simulated Image ---
print("Simulating baseline image...")
## Simulating baseline image...
eximg = siq.simulate_image()
exfn_base = os.path.join(temp_dir, 'baseline.nii.gz')
ants.image_write(eximg, exfn_base)
ants.plot( eximg )

generated_files.append(exfn_base)

# --- Image 2: Additive Gaussian Noise ---
print("Simulating image with Gaussian noise...")
## Simulating image with Gaussian noise...
img_gauss = siq.simulate_image().add_noise_to_image('additivegaussian', [0, 1])
exfn_gauss = os.path.join(temp_dir, 'noise_gaussian.nii.gz')
ants.image_write(img_gauss, exfn_gauss)
ants.plot( img_gauss )

generated_files.append(exfn_gauss)

# --- Image 3: Salt & Pepper Noise ---
print("Simulating image with Salt & Pepper noise...")
## Simulating image with Salt & Pepper noise...
img_sp = siq.simulate_image()
img_sp = ants.add_noise_to_image(img_sp, 'saltandpepper', [0.2, -1, 1])
exfn_sp = os.path.join(temp_dir, 'noise_saltpepper.nii.gz')
ants.image_write(img_sp, exfn_sp)
ants.plot( img_sp )

generated_files.append(exfn_sp)

# --- Image 4: Smoothed Image ---
print("Simulating a smoothed image...")
## Simulating a smoothed image...
img_smooth = siq.simulate_image().smooth_image(3)
exfn_smooth = os.path.join(temp_dir, 'smooth.nii.gz')
ants.image_write(img_smooth, exfn_smooth)
ants.plot( img_smooth )

generated_files.append(exfn_smooth)

# --- Image 5: Time Series Image ---
print("Simulating a 4D time-series image...")
## Simulating a 4D time-series image...
img_ts = siq.simulate_image([16, 16, 16, 4])
exfn_ts = os.path.join(temp_dir, 'timeseries.nii.gz')
ants.image_write(img_ts, exfn_ts)
generated_files.append(exfn_ts)

print(f"\nGenerated {len(generated_files)} files for analysis.")
## 
## Generated 5 files for analysis.

3. Running Batch QC Analysis

Now we loop through the generated images and run blind_image_assessment on each. The results are collected into a single Pandas DataFrame.

# --- Batch QC Processing ---
# A more efficient way to build a DataFrame is to append dictionaries to a
# list and then call the DataFrame constructor once.
qc_results = []
for f in generated_files:
    print(f"Running QC on: {os.path.basename(f)}...")
    myqc = antspymm.blind_image_assessment(f)
    qc_results.append(myqc)
## Running QC on: baseline.nii.gz...
## Running QC on: noise_gaussian.nii.gz...
## Running QC on: noise_saltpepper.nii.gz...
## Running QC on: smooth.nii.gz...
## Running QC on: timeseries.nii.gz...

# Concatenate all results into a single DataFrame.
qcdf = pd.concat(qc_results, axis=0)

# The 'qcdf' DataFrame is now automatically available to R via reticulate as py$qcdf
# No need to write to a temporary CSV file.

4. QC Results

The following tables display the QC metrics for all simulated images.

4.1. Interactive QC Data Table

This table is sortable and searchable, which is useful for exploring the results dynamically.

## Warning in py_to_r.pandas.core.frame.DataFrame(x): index contains duplicated
## values: row names not set

4.2. Static QC Data Table

This is a clean, static view of the same data, suitable for printing or including in a non-interactive document.

Static table of blind QC metrics.
filename dimensionality noise snr cnr psnr ssim mi reflection_err EVR msk_vol spc0 spc1 spc2 org0 org1 org2 dimx dimy dimz dimt slice modality mriseries mrimfg mrimodel mriMagneticFieldStrength mriSAR mriPixelBandwidth mriPixelBandwidthPE dti_bvalueMax dti_bvecnorm
baseline 3 0.03687 25.65 20.98 23.16 0.9421 -1.023 0.1575 0.6699 32494 1 1 1 0 0 0 32 32 32 1 0 unknown NA NA NA NA NA NA NA NA NA
noise_gaussian 3 0.09391 NA NA 17.13 0.6415 -0.2906 0.137 NA 0 1 1 1 0 0 0 32 32 32 1 0 unknown NA NA NA NA NA NA NA NA NA
noise_saltpepper 3 0.07676 Inf Inf 14.12 0.5467 -0.7279 0.2088 0.834 32767 1 1 1 0 0 0 32 32 32 1 0 unknown NA NA NA NA NA NA NA NA NA
smooth 3 0.03274 13.09 11.16 34.76 0.9956 -1.893 0.2581 0.02344 31356 1 1 1 0 0 0 32 32 32 1 0 unknown NA NA NA NA NA NA NA NA NA
timeseries 4 0.08569 32222380 22635400 21.9 0.9365 -1.184 0.1029 0.6025 4052 1 1 1 0 0 0 16 16 16 4 0 unknown NA NA NA NA NA NA NA NA NA

5. QC Metric Definitions

The metrics reported in the tables above are defined as follows:

fn
The filename of the processed image.
noise
Estimated noise level, calculated as the mean absolute difference between the original image and a smoothed version of it.
snr
Signal-to-Noise Ratio. Defined from automatically generated foreground (fg) and background (bg) masks as: mean(fg) / std(bg).
cnr
Contrast-to-Noise Ratio. Defined as: (mean(fg) - mean(bg)) / std(bg).
psnr
Peak Signal-to-Noise Ratio. Calculated between the original and a smoothed version of the image.
ssim
Structural Similarity. Measures the similarity between the original and a smoothed version of the image. Higher values indicate greater similarity.
mi
Mutual Information. Measures the statistical dependency between the original and smoothed image.
reflection_error
Mean absolute error between the original image and a version reflected across the mid-sagittal plane. Useful for detecting severe spatial artifacts or asymmetries.
EVR
Eigenvalue Ratio. A measure of image texture and complexity. Values near 0 suggest very smooth images, while values near 1 suggest pure noise. Typical medical images fall in the 0.6-0.7 range.
msk_vol
The volume of the automatically detected foreground mask, in cubic millimeters.
spc*
The voxel spacing (e.g., spcx, spcy, spcz).
org*
The image origin coordinates.
dim*
The image dimensions (number of voxels along each axis).
slice
The slice index, primarily used for 4D time-series data.
modality
Inferred image modality, typically based on the filename.
mriseries, mrimfg, mrimodel
Metadata fields (series description, manufacturer, model) read from a sidecar JSON file, if available.