I noticed that QR codes often fail to scan when they're low resolution, blurry, or have noise. This happens a lot in real-world scenarios:
- Logistics packages with damaged labels
- Healthcare wristbands scanned quickly
- Digital QR codes screenshot and re-shared multiple times
I wanted to see if I could build a neural network that upscales these degraded QR codes back to scannable quality. And I wanted to compare two approaches: a GAN (Generative Adversarial Network) vs a simpler CNN.
Built two models in PyTorch:
1. GAN-based Model (PaperGen)
- Generator with PixelShuffle upsampling
- Discriminator to adversarially train the generator
- Content loss (MSE) + adversarial loss
2. Simple CNN (AdvancedSimpleQR)
- Residual blocks with skip connections
- No discriminator, pure MSE loss
- Faster training, simpler architecture
Dataset: Generated synthetic QR codes, then degraded them:
- Blur: Gaussian blur with random kernel sizes (3-11) and sigma (1.1-1.6)
- Noise: Gaussian noise with sigma (0.7-1.2)
- Low-res: 64x64 input, 256x256 target
Training Strategy:
- Blur: 3 epochs (converges fast)
- Noise: 10 epochs (harder to denoise)
- Batch size 16, LR 0.0002 for generator
- Saved comparison images every 50 batches to visually track progress
(Left to Right: Original High Quality | GAN Model Output | Advanced CNN Output | Degraded Low Quality Input)
Both models can upscale degraded QR codes:
- GAN produces sharper outputs but takes longer to train
- CNN trains faster and is more stable
- Both achieve scannable results from heavily degraded inputs
Key metrics tracked:
- Pixel accuracy (MSE)
- QR code scannability rate
- Inference time
# Setup
python -m venv venv
source venv/bin/activate # Windows: venv\Scripts\activate
pip install -r requirements.txt
# Generate synthetic QR code dataset first
# (Put your QR images in data/qr_codes/)
# Train models
python src/qrtrain.py
# Test and compare
python src/qrtest.pySuperResolutionForQRCodeImages/
├── src/
│ ├── dataset.py # QR dataset with degradation
│ ├── model.py # GAN generator, discriminator, CNN
│ ├── qrtrain.py # Training loop for both models
│ └── qrtest.py # Evaluation and comparison
├── src/images/ # Training output samples
├── src/saved_models_qr/ # Saved model checkpoints
├── requirements.txt # Pinned dependencies
└── README.md # This file
GAN Training:
- Discriminator loss needs to stay balanced with generator loss
- PixelShuffle works better than transposed convolutions for upsampling
- Saving samples during training is essential - numbers don't tell the whole story
CNN vs GAN Trade-offs:
- GAN: Better perceptual quality, but training is unstable
- CNN: Faster, more reliable, good enough for QR codes
- For QR codes, pixel accuracy matters more than perceptual realism
QR Code Specifics:
- QR codes are binary (black/white) so grayscale conversion is fine
- The position markers need to be preserved accurately for scanning
- Heavy blur is harder to recover than noise
- Real QR Dataset: Test on real degraded QR codes, not just synthetic
- Scanning Metrics: Integrate actual QR decoder (pyzbar) to measure scannability, not just pixel MSE
- Mobile Optimization: Quantize and convert to ONNX for mobile deployment
- Binary Output: Add post-processing to threshold to pure black/white
- Python 3.8+
- PyTorch 2.0+
- PIL, torchvision
- pandas (for results)
See requirements.txt for pinned versions.
Student project - feel free to use for your own super-resolution experiments.