A high-performance BM3D denoising library for neutron imaging, optimized for streak/ring artifact removal from sinograms.
The BM3D algorithm was originally proposed by K. Dabov, A. Foi, V. Katkovnik, and K. Egiazarian in the paper "Image Denoising by Sparse 3D Transform-Domain Collaborative Filtering" (2007).
BM3D ORNL provides a Python API with a Rust backend for efficient, parallel processing of tomography data. Key features:
- Streak/Ring Artifact Removal: Specialized mode for removing vertical streak artifacts common in neutron and X-ray imaging
- Multi-Scale Processing: True multi-scale BM3D for handling wide streaks that single-scale cannot capture (based on Mäkinen et al. 2021)
- Fourier-SVD Method: Alternative fast algorithm (~2.6x faster than BM3D) combining FFT-based energy detection with rank-1 SVD
- Stack Processing: Efficient batched processing of 3D sinogram stacks
- High Performance: Rust backend with optimized block matching (integral images, early termination) and transforms (Hadamard, FFT)
Using Pip
# Core library only
pip install bm3dornl
# With GUI application
pip install bm3dornl[gui]Supported Platforms
| Platform | Architecture | Library | GUI |
|---|---|---|---|
| Linux | x86_64 | ✅ | ✅ |
| macOS | ARM64 (Apple Silicon) | ✅ | ✅ |
Using Pixi (Development)
pixi install
pixi run buildfrom bm3dornl import bm3d_ring_artifact_removal
import numpy as np
# Load sinogram data - 2D (H, W) or 3D stack (N, H, W)
sinogram = np.load("sinogram.npy")
# Standard BM3D denoising (generic white noise)
denoised = bm3d_ring_artifact_removal(sinogram, mode="generic", sigma_random=0.1)
# Streak artifact removal (recommended for ring artifacts)
denoised = bm3d_ring_artifact_removal(sinogram, mode="streak", sigma_random=0.1)
# With custom parameters (all parameters are flat, no dict wrapping)
denoised = bm3d_ring_artifact_removal(
sinogram,
mode="streak",
sigma_random=0.1,
patch_size=8, # Patch size (7 or 8 recommended)
step_size=4, # Step size for patch extraction
search_window=40, # Max search distance
max_matches=64, # Similar patches per 3D group
batch_size=32, # Batch size for stack processing
)
# Multi-scale BM3D for wide streaks (v0.7.0+)
denoised = bm3d_ring_artifact_removal(
sinogram,
mode="streak",
multiscale=True, # Enable multi-scale pyramid processing
num_scales=None, # Auto-detect (or set explicitly)
filter_strength=1.0, # Filtering intensity multiplier
)For faster processing with excellent results on many datasets:
from bm3dornl.fourier_svd import fourier_svd_removal
# Fast streak removal (~2.6x faster than BM3D)
denoised = fourier_svd_removal(
sinogram,
fft_alpha=1.0, # FFT-guided trust factor (0.0 disables FFT guidance)
notch_width=2.0, # Gaussian notch filter width
)The Rust backend provides high performance for tomography stacks:
| Metric | Value |
|---|---|
| Speed | ~0.63s per frame (512×512) on Apple Silicon |
| Memory | >50% reduction via chunked processing |
| Parallelism | Zero-overhead parallel processing via Rayon |
Key optimizations:
- Integral image pre-screening for fast block matching
- Early termination in distance calculations
- Pre-computed FFT plans
- Fast Walsh-Hadamard transform for 8×8 patches
We use pixi for development environment management.
- Clone repo.
- Run
pixi run buildto compile the Rust backend and install in editable mode. - Run
pixi run testto run tests. - Run
pixi run benchto run performance benchmarks.
git clone https://github.com/ornlneutronimaging/bm3dornl.git
cd bm3dornl
pixi run build
pixi run testBM3DORNL includes a standalone GUI application for interactive ring artifact removal.
pip install bm3dornl[gui]Or install the GUI separately:
pip install bm3dornl-guibm3dornl-gui- Load HDF5 files with tree browser for dataset selection
- Interactive slice viewer with histogram
- Side-by-side comparison of original and processed images
- Real-time parameter adjustment
- ROI selection for histogram (Shift+drag to select region)
- Export processed data to TIFF or HDF5
| Shortcut | Action |
|---|---|
| Shift+Drag | Select ROI for histogram |
| Scroll | Zoom in/out on image |
| Drag | Pan image |
| Parameter | Default | Description |
|---|---|---|
mode |
"streak" |
"generic" for white noise, "streak" for ring artifacts |
sigma_random |
0.1 |
Noise standard deviation |
patch_size |
8 |
Patch size (7 or 8 recommended) |
step_size |
3 |
Step size for patch extraction |
search_window |
39 |
Maximum search distance for similar patches |
max_matches |
16 |
Maximum similar patches per 3D group |
batch_size |
32 |
Batch size for stack processing |
streak_sigma_smooth |
1.0 |
Smoothing for streak mode (streak mode only) |
multiscale |
False |
Enable multi-scale processing for wide streaks |
num_scales |
None |
Number of scales (auto-detected if None) |
filter_strength |
1.0 |
Filtering strength multiplier for multi-scale |
debin_iterations |
30 |
Debinning iterations for multi-scale |
| Parameter | Default | Description |
|---|---|---|
fft_alpha |
1.0 |
FFT-guided trust factor (0.0 disables FFT guidance) |
notch_width |
2.0 |
Gaussian notch filter width in frequency domain |