RCAN-Large: Low-Light Denoising and 4x Super-Resolution
This repository hosts the Flagship RCAN-Large model for joint low-light image enhancement, noise suppression, and 4x super-resolution.
Achieved 39.72 dB PSNR on the competitive evaluation benchmark.
Visual Comparison (Input vs Prediction vs Ground Truth)
Left: Low-light noisy input (4x bicubic upsampled) | Middle: RCAN-Large 4x enhanced output | Right: Ground truth clean high-resolution image.
Model Architecture: RCAN-Large
- Trunk: Residual in Residual (RIR) structure with 8 Residual Groups $\times$ 8 RCAB blocks = 64 Channel Attention Blocks (~5.43M parameters).
- Attention: Channel Attention (CALayer) adaptively recalibrates channel-wise feature responses, filtering dark sensor noise while boosting clear signal.
- Upsampling: Sub-pixel convolution (4x PixelShuffle).
- Skip Connection: Long skip global residual adding 4x bicubic-upsampled base.
- Trained on: 1,372 paired low-light/normal images using Pure L1 + Luminance Loss (weight=2.0) matching the ITU-R BT.601 grading standard ($0.2989R + 0.5870G + 0.1140B$).
Quickstart & Inference
import torch
import numpy as np
from PIL import Image
from model import get_model
# 1. Initialize Model
device = torch.device('cuda' if torch.cuda.is_available() else 'cpu')
model = get_model(scale=4, num_groups=8, num_blocks=8).to(device)
# 2. Load Weights
weights_path = 'rcan_large_4x.pth'
state_dict = torch.load(weights_path, map_location=device)
if 'state_dict' in state_dict:
state_dict = state_dict['state_dict']
clean_sd = {k.replace('module.', ''): v for k, v in state_dict.items()}
model.load_state_dict(clean_sd)
model.eval()
# 3. Enhance Low-Light Image
image = Image.open('input_lowlight.png').convert('RGB')
input_tensor = torch.from_numpy(np.array(image).astype(np.float32) / 255.0).permute(2, 0, 1).unsqueeze(0).to(device)
with torch.no_grad():
enhanced_tensor = model(input_tensor).clamp(0.0, 1.0)
enhanced_np = (enhanced_tensor[0].cpu().permute(1, 2, 0).numpy() * 255.0).round().astype(np.uint8)
enhanced_image = Image.fromarray(enhanced_np)
enhanced_image.save('output_enhanced_4x.png')
print("Restored 4x high-resolution image saved to output_enhanced_4x.png!")
Performance Summary
| Model | Setup | Kaggle PSNR |
|---|---|---|
| Baseline (Stage 1) | 64x64 patches, 30 blocks | 39.25 dB |
| Stage 2 | 96x96 patches | 39.36 dB |
| Stage 3 | Luminance Loss + All Data | 39.43 dB |
| RCAN-Large (Stage 4) | 128x128 patches, 64 blocks, Lum Loss, 8x TTA | 39.718 dB |
