Unbiased and Nonlocal Linear Regression for Video Denoising under Multiplicative Noise
PyTorch implementation of the paper:
Unbiased and Nonlocal Linear Regression for Video Denoising under Multiplicative Noise
Zipei Yan¹, Ting Wang², Chao Wang²*, Jizhou Li¹*
¹ The Chinese University of Hong Kong ² Southern University of Science and Technology
Journal of Mathematical Imaging and Vision (JMIV), 2026
NL-LMURE is a distribution-agnostic nonlocal patch-based framework for video denoising under multiplicative noise
-
Distribution-agnostic: Applicable to any multiplicative noise satisfying
$\mathbb{E}[w]=1$ ,$\mathrm{Var}(w)=\tau^2$ — including Gamma, Normal, Lognormal, Wald, and Beta Prime (Table 1 in the paper) - Closed-form optimization: No iterative solver needed; the optimal regression weights admit a direct matrix solution
- Unbiased patch matching: A dedicated matching criterion (Theorem 1) that correctly recovers pairwise patch similarity under multiplicative noise (Fig. 9 in the paper)
-
Built-in variance estimation: Estimates
$\tau^2$ from the noisy observation via RANSAC-regularized linear regression (Section 4.5, Eq. 15) - Two-step internal adaptation: A pilot estimate refines a second pass using only the matching indices, suppressing residual noise without new parameter tuning (Section 4.6)
- Installation
- Project Structure
- Quick Start
- Method
- Supported Noise Distributions
- Hyperparameters
- Citation
- Acknowledgments
- Contact
git clone https://github.com/TISGroup/NL-LMURE.git
cd NL-LMURE
conda create -n nl_lmure python=3.10
conda activate nl_lmure
pip install -r requirements.txtCore dependencies: PyTorch, scikit-image, scikit-learn, einops, NumPy, SciPy, gdown.
NL-LMURE/
├── denoise.py # Core algorithm (block matching, LMURE, aggregation)
├── demo.py # Demo with PSNR/SSIM evaluation
├── simulate_noisy_data.py # Multiplicative noise simulator (5 distributions)
├── download_data.py # GoPro 540p dataset downloader
├── requirements.txt
├── README.md
└── data/
├── clean/ # Clean video frames (.tif)
└── noisy/
└── gamma/
├── v=0.01/ # τ = 0.1 (L = 100 looks)
├── v=0.04/ # τ = 0.2 (L = 25 looks)
├── v=0.25/ # τ = 0.5 (L = 4 looks)
└── v=1/ # τ = 1.0 (L = 1 look)
We use the GoPro 540p dataset (from FastDVDnet), consisting of 4 RGB video sequences: hypersmooth, motorbike, rafting, snowboard.
python download_data.pyClean data is saved as multi-frame .tif stacks in ./data/clean/.
The noise simulator supports all five multiplicative distributions studied in the paper (Section 5.1, Table 1). By default it generates Gamma noise at four noise levels:
corresponding to
python simulate_noisy_data.pyTo switch noise types, edit noise_type in simulate_noisy_data.py to any of
"gamma", "normal", "lognormal", "wald", or "beta_prime".
Noisy data is saved to ./data/noisy/{noise_type}/v={v}/noisy.tif.
python demo.pyThe demo loads a clean/noisy pair, runs the full two-step NL-LMURE pipeline, and reports frame-wise PSNR and SSIM before and after denoising. Hyperparameters are pre-configured per noise level (see Hyperparameters below).
NL-LMURE operates within the nonlocal framework organized into four steps (Section 3.2 of the paper):
We first select the
Within each
where $\mathbf{D} = \mathrm{diag}(\Vert\mathbf{Y}{:,1}|^2, \ldots, |\mathbf{Y}{:,k}\Vert^2)$. This is derived by minimizing the unbiased risk estimator (Corollary 3.1, Eq. 11) that accurately estimates $\mathbb{E}|\mathbf{X} - \hat{\mathbf{X}}|F^2$ without ground truth. Patches are aggregated via weighted-average reprojection with weights $w_j = 1 / \Vert\mathbf{\Theta}{:,j}\Vert^2$ (Section 3.2).
Following the two-step design in NL-Means, BM3D, and NL-Ridge, we re-apply the pipeline using the Step 1 output
The full pipeline is summarized in Algorithm 1 of the paper.
All noise models follow the multiplicative form
| Distribution | noise_type |
Parameter mapping | |
|---|---|---|---|
| Gamma | "gamma" |
||
| Gaussian | "normal" |
||
| Log-normal | "lognormal" |
||
| Wald (Inv. Gaussian) | "wald" |
||
| Beta Prime | "beta_prime" |
The Gamma case is particularly relevant for coherent imaging (SAR, ultrasound, OCT), where
Hyperparameters follow Table 2 of the paper. The spatial block size is fixed at
| Parameter | Description | Paper notation | Typical |
|---|---|---|---|
temp_depth |
Temporal depth (similar frames per block) | 2–4 | |
block_size |
Spatial search window (odd) | 37 | |
patch_size1 |
Patch size for Step 1 matching | 7–9 | |
topk1 |
Number of similar patches in Step 1 | 16–22 | |
patch_size2 |
Patch size for Step 2 matching | 5–7 | |
topk2 |
Number of similar patches in Step 2 | 22 | |
variance |
Noise variance None to auto-estimate) |
0.01–1.0 |
Preset configurations used in demo.py (matching the paper's experiments):
|
|
|||||||
|---|---|---|---|---|---|---|---|
| 0.01 | 0.1 | 100 | 4 | 7 | 22 | 5 | 22 |
| 0.04 | 0.2 | 25 | 3 | 7 | 22 | 5 | 22 |
| 0.25 | 0.5 | 4 | 2 | 9 | 16 | 7 | 22 |
| 1.0 | 1.0 | 1 | 2 | 9 | 16 | 7 | 22 |
If you find this work useful, please cite:
@article{yan2026nl_lmure,
title = {Unbiased and Nonlocal Linear Regression for Video Denoising under Multiplicative Noise},
author = {Yan, Zipei and Wang, Ting and Wang, Chao and Li, Jizhou},
journal = {Journal of Mathematical Imaging and Vision},
year = {2026},
}This code builds upon the NL-Ridge framework (Herbreteau & Kervrann, SIAM J. Imaging Sci., 2025). The GoPro dataset comes from FastDVDnet (Tassano et al., CVPR 2020).
For questions, please contact: jzli AT ee DOT cuhk DOT edu DOT hk