https://github.com/ornlneutronimaging/bm3dornl
Rust-based bm3d algorithm for ring artifact removal in normalized sinogram with Python Bindings
https://github.com/ornlneutronimaging/bm3dornl
bm3d neutron-imaging python ring-artifact-reduction rust sinogram
Last synced: 3 months ago
JSON representation
Rust-based bm3d algorithm for ring artifact removal in normalized sinogram with Python Bindings
- Host: GitHub
- URL: https://github.com/ornlneutronimaging/bm3dornl
- Owner: ornlneutronimaging
- License: mit
- Created: 2024-04-29T14:02:44.000Z (about 2 years ago)
- Default Branch: next
- Last Pushed: 2026-01-12T17:25:35.000Z (5 months ago)
- Last Synced: 2026-01-12T18:39:38.197Z (5 months ago)
- Topics: bm3d, neutron-imaging, python, ring-artifact-reduction, rust, sinogram
- Language: Jupyter Notebook
- Homepage: https://bm3dornl.readthedocs.io/en/latest/
- Size: 90.5 MB
- Stars: 5
- Watchers: 2
- Forks: 2
- Open Issues: 1
-
Metadata Files:
- Readme: README.md
- Contributing: CONTRIBUTING.md
- License: LICENSE
- Code of conduct: CODE_OF_CONDUCT.md
Awesome Lists containing this project
README
[](https://github.com/ornlneutronimaging/bm3dornl/actions/workflows/test.yml?query=branch?next)
[](https://www.bestpractices.dev/projects/11811)
[](https://bm3dornl.readthedocs.io/en/latest/?badge=latest)
[](https://pypi.org/project/bm3dornl/)
[](https://crates.io/crates/bm3d_core)
[](https://doi.org/10.5281/zenodo.18276016)
BM3D ORNL
=========
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)
How to install
--------------
**Using Pip**
```bash
# 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)**
```bash
pixi install
pixi run build
```
Usage
-----
```python
from 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
)
```
### Fourier-SVD Method (v0.7.0+)
For faster processing with excellent results on many datasets:
```python
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
)
```
Performance
-----------
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
Development
-----------
We use [pixi](https://prefix.dev) for development environment management.
1. Clone repo.
2. Run `pixi run build` to compile the Rust backend and install in editable mode.
3. Run `pixi run test` to run tests.
4. Run `pixi run bench` to run performance benchmarks.
```bash
git clone https://github.com/ornlneutronimaging/bm3dornl.git
cd bm3dornl
pixi run build
pixi run test
```
GUI Application
---------------
BM3DORNL includes a standalone GUI application for interactive ring artifact removal.
### Installation
```bash
pip install bm3dornl[gui]
```
Or install the GUI separately:
```bash
pip install bm3dornl-gui
```
### Launching
```bash
bm3dornl-gui
```
### Features
- 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
### Keyboard Shortcuts
| Shortcut | Action |
|----------|--------|
| Shift+Drag | Select ROI for histogram |
| Scroll | Zoom in/out on image |
| Drag | Pan image |
Parameter Reference
-------------------
| 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 |
### Fourier-SVD Parameters
| 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 |