vivoficator-img
A small photo-restoration CNN fine-tuned on processed Vivo phone photos. It cleans up noise and emphasizes edges in soft phone images, particularly distant buildings, roof tiles, windows and foliage. Input and output have the same pixel dimensions.
The starting point was simple: can a tiny pretrained network learn some of the crisp, cleaned-up appearance of Vivo's zoom processing? This release is the early zoom-oriented experiment, resize-10k, which was preferred over later texture-focused variants in our visual comparisons.
It is still an experiment. Fine fur and dark foliage can become too smooth, and stronger-looking edges do not mean the model has recovered the original physical detail.
Top row: Google Camera input and official pretrained FFDNet. Bottom row: vivoficator-img and a separately captured Vivo camera image aligned for comparison. Identical 192 × 192 source coordinates, displayed at 2× with nearest-neighbor scaling; see the alignment limitations below.
At a glance
| Property | Value |
|---|---|
| Architecture | KAIR FFDNet Color |
| Parameters | 852,108 |
| Layers / feature channels | 12 convolution layers / 96 channels |
| Checkpoint | resize-10k/best.pth, exported without changing tensor values |
| Input / output | RGB, identical width and height |
| Recommended conditioning | sigma = 0.03 |
| Inference | FP32, tiled at 256 px with a 32 px halo |
| File format | Safetensors |
| Task | Same-resolution photo restoration; no upscaling |
| Training target | Processed phone photos, rather than RAW or noise-free ground truth |
“Vivo-style” refers to the visual goal. This is an independent FFDNet adaptation, with no affiliation with Vivo, Google, Apple or GSMArena. It does not contain or reproduce Vivo's proprietary camera pipeline.
Quick start
This repository uses a small custom PyTorch inference script. It is not a Transformers or Diffusers pipeline, and a hosted inference endpoint is not included.
Download the repository files, then run:
python -m pip install -r requirements.txt
python inference.py input.jpg output.png --device cuda
For CPU inference:
python inference.py input.jpg output.png --device cpu
The default checkpoint is model.safetensors next to inference.py. Keep the models/ directory with the script. The script applies EXIF orientation, converts to RGB, divides pixel values by 255, runs tiled inference, clips to [0, 1], and writes a lossless PNG. It does not copy EXIF metadata or perform an additional resize, sharpening pass or color correction. Explicit ICC profile conversion and RAW processing are not implemented.
sigma is a network conditioning value, not a measured sensor noise level or ISO setting. The default 0.03 matches the non-identity degradation branch used during zoom adaptation and the examples below. Changing it is experimental; lower values do not guarantee a proportional change in restoration strength.
Real-photo examples
All examples below were used for inference only, with no additional synthetic damage applied to their inputs. There is no paired clean ground truth for these real photographs. They illustrate appearance and failure modes; they do not establish a general camera-quality improvement.
Baseline and zoom protocol
The baseline is the original official KAIR FFDNet Color checkpoint, before either fine-tuning stage. Its SHA256 is 286f04f7e3a20254c067ba95efb5d3339f4fc8a09a365a93cd469184d4cdb279. It receives exactly the same decoded RGB input as vivoficator-img, with sigma 0.03, FP32, 256 px tiles and a 32 px halo. It is a Gaussian-denoising baseline, not a separate sharpening or super-resolution model. The unchanged input is shown alongside it.
The tighter figures use 192 × 192 source crops displayed at 2× with nearest-neighbor scaling. The model itself still outputs the original image dimensions. All columns use identical crop coordinates and display scaling; no extra sharpening, color matching or synthetic input damage is applied. Unscaled individual crops are included under assets/zoom/, and crop coordinates and baseline settings/timings are recorded. Full-frame views and broader crops remain below for context.
Google Camera → model → Vivo
Two user-supplied Google Camera / Vivo pairs show distant buildings, foliage and roofs. The model receives only the Google Camera image.
Google images are 964 × 1280; Vivo images are 720 × 1280 and have different framing. For the figures, Vivo is warped into Google coordinates using a homography fitted to static architecture with SIFT/RANSAC. Median inlier reprojection errors are 0.476 px and 0.533 px. Vivo's interpolation, camera processing, parallax and moving leaves affect the comparison. No color or exposure matching was applied. Vivo is a visual reference, not a pixelwise training or evaluation target.
The model makes some contours more distinct. Vivo's rendering remains stronger and differs in contrast and color.
More zoomed baseline comparisons and broader scene contextZoomed figures: input / official FFDNet on the top row; vivoficator-img / aligned Vivo on the bottom row. The broader context figures below retain their original Google / model / Vivo layout.
iPhone SE (2020), low light
Four user-supplied PNG copies of photographs from GSMArena's iPhone SE (2020) camera review, by the GSMArena team, 1 May 2020.
These copies are approximately 1 MP: 1165 × 873, 1170 × 876, 1167 × 874 and 1172 × 876. They are not the camera's original full-resolution JPEGs. Their alpha channels are fully opaque; removing alpha preserves the input RGB values. Source hashes and crop coordinates are recorded in evidence/gsmarena-provenance.json.
Left: supplied input. Center: official pretrained FFDNet. Right: vivoficator-img. A 192 × 192 crop is displayed at 2×. The architecture and vehicle edges look clearer; shadow texture can still be lost.
All four low-light examples, including full viewsTighter three-column figures: input / official FFDNet / vivoficator-img. Full-width context figures: input / vivoficator-img only. On the hotel facade, visible grain is reduced. In dark foliage, some texture is smoothed away. No actual Vivo rendering of these scenes is available.
Training
The private collection contains 504 source JPEGs, described by the user as Vivo X200 Pro photographs. They are already processed phone photos, not linear RAW captures or noise-free targets. The training dataset is not included in this repository.
Scene grouping uses capture-time proximity and perceptual similarity. The split is 401 training / 52 validation / 51 test source images; all cached crops from one group stay in the same split. Automatic grouping is imperfect and may miss related views. Each image contributes eight cached 128 px crops, alternating native-scale crops and crops from a view resized to at most 1024 px. Rotation and flip augmentation are used during training.
The selected model was trained in two stages:
| Stage | Initialization | Steps | Batch | Learning rate | Loss |
|---|---|---|---|---|---|
| pilot-mixed-5k | Official KAIR FFDNet Color checkpoint | 5,000 | 16 | 1e-5 | L1 |
| resize-10k, this release | Best pilot-mixed-5k checkpoint | 10,000 | 16 | 3e-5 | L1 |
Adam optimizer; seed 42; PyTorch 2.8.0; NVIDIA L4. Training uses FP16 autocast and gradient scaling. The best checkpoint is selected by synthetic validation PSNR. No GAN or perceptual loss is used in this release. Later perceptual and SCUNet experiments are separate models and are not included here.
The zoom stage uses 12% exact clean/identity inputs, conditioned with sigma 0. The remaining branch uses:
- A sampled resize factor from 0.35 to 0.65, followed by return to the original crop dimensions.
- A randomly chosen bilinear, bicubic or Lanczos downsampling filter; bicubic upsampling.
- Optional Gaussian blur, radius 0.15–0.65 px, probability 0.4.
- Additive Gaussian RGB noise with a sampled standard deviation from 0 to 6/255.
- Optional JPEG compression, quality 45–90, probability 0.65.
- Fixed conditioning sigma 0.03 for this degradation branch.
There is no explicit brightness or color augmentation. The model is nevertheless free to change color and brightness: neither is mathematically constrained. The synthetic degradation is an approximation, not a physical model of a camera sensor or ISP.
Reproducing this release
The repository includes training code and a step-by-step recipe, machine-readable settings, the scene-group split and hashes of the original crop cache. Both training stages, Adam settings, seeds, augmentation, checkpoint selection and evaluation are documented.
Inference is reproducible from the provided weights. Full training reproduction requires the private crop images, which are not uploaded. A substitute dataset can repeat the method but will not reproduce this checkpoint or its PSNR. GPU kernel determinism was not enforced, so the seed does not promise bit-identical retraining.
The selected PyTorch checkpoint was exported to Safetensors without changing tensor values. Export verification records strict reload, odd-sized tiled inference and an exact pixel comparison between the shipped CLI and the reference output. Source/model SHA256 values are documented in the training recipe.
Quantitative evaluation
The table reports 96 deterministic synthetic test patches, drawn from the held-out source-image split under the zoom degradation above. PSNR is calculated from the mean RGB MSE across those patches, rather than averaging per-image PSNR.
| Same synthetic test | PSNR |
|---|---|
| Degraded input | 27.831 dB |
| Preceding mixed-noise/JPEG pilot | 27.942 dB |
| vivoficator-img, selected zoom checkpoint | 29.109 dB |
The gain over the preceding pilot is 1.167 dB under this particular synthetic test. These values do not measure performance on the real Google Camera or GSMArena images. No real-photo PSNR, SSIM, blind-quality ranking or user preference study is claimed.
Detailed experiment numbers are included in evidence/training-summary.json. Synthetic validation PSNR was used for model selection; test patches were not used for checkpoint selection.
Measured compute
The zoom training loop, including evaluation, checkpoints and a synthetic inference benchmark, took 237.63 seconds on one NVIDIA L4. This excludes environment setup, image building, data upload and the preceding 5k-step pilot.
On the four supplied approximately 1 MP iPhone SE PNG copies, the main checkpoint took about 0.042 seconds per image after the first inference on L4. The first image took 0.602 seconds. This is GPU inference timing, including synchronization, excluding decode/encode, model load, cloud cold start and network transfer.
These numbers are observations for the recorded workload, not an end-to-end service latency promise. Mobile inference has not been benchmarked.
Limitations and intended use
Use it for experimentation with ordinary RGB phone photos where noise, interpolation softness and compressed detail are visible. Judge the output alongside the original at native scale.
- Texture loss: fur, hair, grass and dark foliage may be flattened.
- Artifacts: edges can develop halos or become unnaturally crisp; JPEG blocks and grain may survive or be emphasized.
- Color: there is no exact color, luminance or exposure preservation guarantee.
- Missing detail: downsampling and blur destroy information. This model estimates an output; it cannot establish what an unreadable sign, face or fine texture originally contained.
- Domain gap: training on processed Vivo targets can transfer their smoothing or sharpening habits. Other phones, lighting, crops and codecs may behave differently.
- Small evaluation: the real examples are a small, selected qualitative set. There is no broad independent benchmark.
- Scope: single RGB images only. RAW processing, video consistency, HDR fusion, multi-frame super-resolution and mobile deployment are not provided.
Do not use restored detail as evidence in identity, forensic or measurement decisions. Keep the original.
Provenance and licensing
The architecture and initial weights come from KAIR, pinned at commit fc1732f4a4514e42ce15e5b3a1e18c828af47a1e. The initial checkpoint was ffdnet_color.pth. Upstream FFDNet code and its copyright notice are retained in LICENSE.
The model and included inference code are distributed under MIT. Example photographs have separate provenance and rights: GSMArena photos belong to their respective rights holders; the other examples were supplied by the project owner. The model/software license does not relicense the photos or the private training collection.
This repository contains the selected early zoom model and its reproducibility materials. It does not contain the private training dataset, service credentials or later experimental checkpoints. This README describes the selected early zoom checkpoint only.
References
- Zhang, Zuo and Zhang, FFDNet: Toward a Fast and Flexible Solution for CNN-Based Image Denoising, IEEE TIP, 2018.
- KAIR source and pretrained checkpoint.
- GSMArena iPhone SE (2020) camera review.