Skip to main content

bm3d-triton

简体中文 · Installation · API · Algorithm · Benchmark

BM3D Triton implements block matching and collaborative image filtering as Triton GPU kernels. It provides a PyTorch tensor API, an inference-only nn.Module, and a command-line image tool.

The implementation combines 8×8 DCT, a Hadamard group transform, and Kaiser-weighted aggregation. Choose hard-threshold filtering on its own or add Wiener refinement. Kernels are compiled by Triton on first use; there are no pretrained weights or project-specific C++/CUDA extensions to build.

Capability What you get
Tensor API NCHW input, batch support, arbitrary independently filtered channels
Two processing modes Hard thresholding, or hard thresholding + Wiener refinement
Image CLI 8-bit grayscale, RGB and RGBA; alpha preserved; lossless PNG output
Integration Float32 output on the input CUDA device; no ComfyUI dependency
Inspectable implementation Triton source, independent numerical reference tests, benchmark tools

Qualitative illustration

Clean reference, synthetic noisy input and actual BM3D Triton output

Figure 1. (a) Reference image, (b) synthetic Gaussian noise with sigma=25/255, and (c) two-stage BM3D reconstruction. Boxes indicate the common region shown below. No sharpening or learned postprocessing is applied.

Inspect the same detail crop

Identical detail crops: reference, noisy input and BM3D reconstruction

Figure 2. Identical crops from Figure 1, displayed with nearest-neighbor sampling. All figures are generated by Python/Matplotlib; PNG, vector PDF and diagram SVG exports are available in assets/, with source attribution and the reproduction command. No benchmark scores are included.

Get started

Use Python 3.10+ with an NVIDIA GPU and a compatible CUDA-enabled PyTorch build. Install PyTorch using its installation selector, then run this from the checkout:

python -m pip install -e ".[cuda,cli]"

If PyTorch already supplies a compatible Triton version, .[cli] is sufficient. Linux is the primary execution environment; Windows with triton-windows is experimental. Keep Triton compatible with the installed PyTorch version. Check torch.cuda.is_available() before use; the first call includes JIT compilation.

Python

import torch
from bm3d_triton import denoise

# Replace with your own floating-point NCHW image, normalized to [0, 1].
image = torch.rand(1, 3, 256, 256, device="cuda")
restored = denoise(image, sigma=25 / 255, two_step=True)

Python sigma is a standard deviation in normalized units. An 8-bit sigma of 25 means 25/255, not 25. For an existing variance or a module interface:

from bm3d_triton import BM3D, denoise_variance

restored = denoise_variance(image, variance=(25 / 255) ** 2)
restored = BM3D(sigma=25 / 255)(image)

The output has the input shape and device, with contiguous float32 storage. Input and default output are clipped to [0,1]; clamp=False keeps reconstruction overshoot. Images smaller than 8×8 are replicate-padded and cropped back.

Inputs must have nonempty NCHW dimensions and floating-point dtype. sigma and variance are finite nonnegative Python scalars. Zero noise returns a clipped float32 copy. The tensor API filters every channel, including alpha; only the CLI preserves alpha separately. BM3D has no parameters and its settings are ordinary attributes, not serialized by state_dict().

Command line

bm3d-triton noisy.png restored.png --sigma 25
bm3d-triton noisy.png single-stage.png --sigma 25 --single-stage
bm3d-triton noisy.png restored.png --sigma 15 --device cuda:0 --overwrite

The CLI uses 8-bit sigma units. It accepts 8-bit L/RGB/RGBA input, applies EXIF orientation and preserves alpha. Output is PNG; existing files require --overwrite. Metadata and ICC profiles are not copied. High-bit-depth and color-managed workflows should perform their own explicit conversion.

How it works

BM3D data flow from noisy input through hard filtering and Wiener refinement

Figure 3. Two-stage computation. Solid arrows denote signal flow; dashed arrows denote basic-estimate guidance for matching and Wiener gain estimation.

Similar patches are gathered into groups so their repeated structure can be filtered jointly in the transform domain. The first stage constructs a basic estimate. The second uses that estimate to guide patch matching and Wiener gains, while filtering patches from the original noisy image. Overlapping patches are combined with a Kaiser window and group-dependent weights.

This is a DCT/Hadamard BM3D variant with independently processed channels. It is not the official BM3D reference implementation or joint-color CBM3D.

Parameter Hard threshold Wiener refinement
Patch size 8×8 8×8
Reference stride / search radius 3 / 19 pixels 3 / 19 pixels
Maximum group size, including reference 16 32
Matching threshold, mean squared distance in 8-bit units 2500 400
Kaiser window beta 2.0 2.0

Groups are rounded down to a power of two. Each patch undergoes orthonormal DCT, followed by an unnormalized Hadamard transform along the group dimension. For group size m and noise variance v, the hard threshold is 2.7*sqrt(m*v). In the Wiener stage, basic-estimate coefficients b determine gains (b*b/m)/(b*b/m + v). Inverse Hadamard transforms divide by m; filtered patches are accumulated with group weights and a Kaiser window.

Matching uses float32 distances. Reference positions include right/bottom boundaries. Location/count buffers process at most 4096 groups per chunk; image-level aggregation memory still grows with resolution. The input and basic estimate are retained for the second stage.

Run your own benchmarks

The repository provides benchmark tools and measurement instructions rather than published timing tables, quality scores or hardware-specific speed claims.

# Warm GPU timings; sizes are HxW.
python benchmarks/benchmark.py --sizes 256x256 512x512 1080x1920 --warmup 3 --repeats 10

# Evaluate local images and generate comparison crops.
python -m pip install -e ".[eval]"
python benchmarks/evaluate.py /path/to/image.png --sigma 10 25 50 --seeds 123 456 789

Timing measures synchronized GPU-resident inference after warmup. Evaluation adds reproducible Gaussian noise and computes PSNR/SSIM against the source. Outputs stay in ignored benchmark-output/ and quality-output/ directories. Timing excludes initial JIT, CPU/GPU transfers, image I/O and output clipping; it includes in-call allocation and dispatch (clamp=False). Wall-clock and CUDA event samples are saved locally. Report cold-start costs separately.

Evaluation center-crops local 8-bit L/RGB images to at most 512×512 without resizing, adds seeded Gaussian noise and clips inputs/outputs. SSIM uses an 11-pixel Gaussian window, sigma 1.5, population covariance and data_range=1, averaged across color channels. It also saves local comparison crops. No datasets are downloaded. Review textures and edges alongside metrics.

Both scripts accept --reference-module and --reference-path for an external comparator exposing forward(contiguous_HW_float32, normalized_variance, two_step) -> HW_float32 on CUDA. No reference extension is bundled. Use --help for options; keep hardware load, input, precision and sigma consistent when comparing implementations.

Development

python -m pip install -e ".[dev,cli]"
ruff check .
ruff format --check .
pytest -m "not cuda"  # API and image-I/O tests
pytest               # includes GPU tests when available
python -m build
python -m twine check dist/*

GPU tests compare actual kernels against an independent dense-matrix reference. CPU CI covers import, API, file I/O and packaging; GPU CI is manually triggered on a configured NVIDIA runner. Test coverage, contribution conventions and release steps are consolidated in CONTRIBUTING.md.

src/bm3d_triton/   Public API, CLI and Triton kernels
assets/           README images, pipeline diagram and attribution
tools/            Matplotlib documentation-figure generator
benchmarks/       Timing and image-quality evaluation tools
tests/            CPU contracts and GPU numerical tests
.github/          CPU and manually triggered GPU workflows

Scope and limitations

The denoiser assumes a single scalar noise level and finite floating-point images. It does not estimate noise or implement joint-color, temporal, HDR, spatially varying or learned denoising. High noise levels can smooth fine textures. CPU, MPS and ROCm execution are not supported.

This is inference-only: gradients are not provided. First calls incur JIT latency, and batch/channel items are dispatched sequentially. Float32 atomics and near-tie rematching can cause small run-to-run differences. Exact determinism, CUDA graph capture and torch.compile support are not promised.

License and credits

BSD-2-Clause. See LICENSE and NOTICE for the BM3D paper and bm3d-gpu attribution. Documentation photographs have separate provenance in assets/README.md. Community and reporting policies: Contributing · Security.

Publishing

Version tags automatically build and publish to PyPI after CI passes. See RELEASING.md for one-time Trusted Publisher setup and release steps.

Metadata

Release files for bm3d-triton 0.1.1

For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.

Source distribution (sdist)

Source distribution for bm3d-triton 0.1.1
File Size Uploaded
bm3d_triton-0.1.1.tar.gz 4.3 MB Details

Built distribution (wheel)

Table of built distributions (wheels) for bm3d-triton 0.1.1
File Interpreter ABI Platform
bm3d_triton-0.1.1-py3-none-any.whl Python 3 none any Details

Total release size: 4.3 MB

Release files / bm3d_triton-0.1.1.tar.gz

Download URL bm3d_triton-0.1.1.tar.gz
Size 4.3 MB
Tags Source
SHA-256 checksum
How to use checksums
c1cb8ccdd50ecd770a480c7949f33de0d6950a33f397fe67b0821f2fba165829
BLAKE2b-256 checksum
How to use checksums
041d67d0d0c01746147520ca38f882a6e0aee26013b0a531e671001195df8ba9
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/7.0.0 CPython/3.13.14

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Oct 15, 2026.

Transparency log

Release files / bm3d_triton-0.1.1-py3-none-any.whl

Download URL bm3d_triton-0.1.1-py3-none-any.whl
Size 14.9 kB
Tags Python 3
SHA-256 checksum
How to use checksums
19d83e7309a1d39bf65b556245559c6b5a85f2a70c8f088d0b937a57e5dc7068
BLAKE2b-256 checksum
How to use checksums
9d0060375990098dad82589c3d0cb6d14b28374c0a9d2d14d1f39845fdc81ec5
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/7.0.0 CPython/3.13.14

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Oct 15, 2026.

Transparency log

Release history Release notifications | RSS feed

This release

0.1.1 This release

2 release files

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page