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)

Visual Comparison

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
Downloads last month

-

Downloads are not tracked for this model. How to track
Inference Providers NEW
This model isn't deployed by any Inference Provider. 🙋 Ask for provider support