Retro-Diffusion/pixel-art-fixer
GitHub: Retro-Diffusion/pixel-art-fixer
Pixel Art Fixer 通过多检测器共识与两阶段重建 pipeline,将网格漂移、模糊失真的「伪像素画」精准还原为真正的原始分辨率像素艺术。
Stars: 106 | Forks: 10
# Pixel Art Fixer

将虚假的“像素画”转换为真正的、网格对齐的像素画。仅需图像处理,无需模型。
### ➜ [**在 Retro Diffusion 上体验 Pixel Art Fixer**](https://retrodiffusion.ai/pixel-art-fixer)
无需安装,无需设置。在浏览器中放入图片,即可免费获得真正的像素画。

图像生成器、放大算法和有损 pipeline 很容易生成*看起来*像像素画但实际上并不是的图片。这些“像素”偏离了网格,与相邻像素模糊在一起,呈现出尴尬的非整数尺寸,并且文件以艺术内容实际分辨率的 10 倍进行存储。Pixel Art Fixer 能够恢复这些图像所依赖的伪像素网格,并将每个单元格精确地重建为一个真正的像素,还原为艺术作品原本应有的原始分辨率。
它由 [Retro Diffusion](https://retrodiffusion.ai) 构建和维护,这是一个由专业像素艺术家设计的 AI 像素画生成器。
## 问题所在
一幅“真正的”像素画是由刻意手工放置的像素组成的微小网格。而“虚假”的像素画则是任何只模仿了外观而缺乏这种结构的图像:
- **脱离网格的单元格。** 隐含的像素无法对齐到干净的网格上,并且网格的缩放比例通常会在整个图像中发生漂移。
- **非整数单元格尺寸。** 一个单元格的宽度可能是 6.38 像素,而不是 6,因此简单的整数降采样无法适配它。
- **模糊与抗锯齿。** 单元格的边缘因双线性重采样而变得模糊、抖动或涂抹,因此没有清晰的边界可供对齐。
- **错误的分辨率。** 一个 32x32 的 sprite 以 1024x1024 的 PNG 形式出现,包含数千种近乎重复的颜色,且没有干净的 alpha 通道。
- **压缩损坏。** JPEG 的 8x8 区块网格与真实的艺术网格相互冲突。
在这些图像被转换回真正的像素之前,它们都无法进行平铺、调色板替换、动画处理或逐像素编辑。
## 为什么现有工具仍有不足
- **朴素最近邻或固定整数降采样** 假设存在一个全局的、整数尺寸的单元格以及相位为 0 的原点。但真实的伪像素画违反了所有这三个假设,因此固定的网格会直接切开单元格。
- **“像素对齐”工具** 只能检测出一个主要的周期并以此对齐。但这个周期通常是*内容*的尺度(如 sprite、纹理、人脸),而不是像素的尺度,而且往往相差一个八度(是真实值的 2 倍或 1/2,其得分几乎与真实值一样高)。
- **单一启发式检测器** 非常脆弱:无论它们依赖哪种线索(边缘、自相关、FFT 峰值),都会在另一类图像上失效,而且修补了一类图像的检测,往往会悄然导致另一类图像的检测效果倒退。
## 为什么 Pixel Art Fixer 是最先进的
在传统(非神经网络)图像处理领域,这是目前最强大的转换器:
- **多个独立检测器,然后达成共识。** 首先由三个低成本且相位不变的检测器(自相关、游程梳齿、位移自相似性)进行投票。当它们意见一致时,那就是最终答案。它们在不同的图像上才会失效,因此一致性是强有力的证据。
- **在意见不合时进行有原则的仲裁。** 一个融合的证据栈(频谱、区块瑞利商、单元格内方差以及“可提炼度”往返得分)按轴解决难题,并针对那些会使朴素工具失效的失败模式制定了明确的规则:八度/谐波陷阱、内容尺度与像素尺度之争、以及跨轴分歧。
- **处理固定网格无法应对的情况。** 非整数单元格尺寸、亚像素漂移、扭曲和不均匀的网格、强烈的抗锯齿以及 JPEG 区块伪影等都被视为首要处理的情况,而不是事后才考虑的补充。
- **两阶段重建:清晰的结构,准确的颜色。** 一旦确定了网格,降采样就会将*位置*与*颜色*解耦。一个小的自适应颜色量化**仅用于决定结构**——每个单元格在干净、平坦的量化标签中进行投票,因此区域边界和轮廓会变得清晰锐利,而不是模糊不清。然后,每个单元格的颜色是根据承载其获胜标签的**原始、未量化的像素**生成的,因此最终的颜色是准确的,并且任何真实的颜色(罕见的高光、1px 的点缀)都不会被强行抹去。这就是它如何在对齐工具的基础上获得干净线条,又不会丢失颜色的原因。
- **经过验证且速度极快。** 每个结果都会与经过评级的 ground truth 基准进行核对。其 Rust 核心在内存占用低 2.5-4 倍的情况下,速度比参考实现快 11-24 倍,转换典型图像仅需不到一秒钟的时间。

纯粹的图像处理能从严重损坏的图像中恢复的内容是有限的。对于最困难的输入,[神经网络版本](#the-neural-version) 会在此基础上继续处理。
## 准确率
使用 [pixel-bench](https://github.com/Retro-Diffusion/pixel-bench)(一个开源基准测试)进行测量,该基准测试通过 43 类现实世界中的损坏情况(分数和非整数放大、模糊、JPEG、噪声、网格漂移、AI 放大器模糊、绘画风格的伪像素纹理、破损的轮廓、坏点等)对原生像素画进行扭曲,并对每个工具恢复原始图像的效果进行评分。在 100 张源图像和 4,300 个扭曲输入中:

| 工具 | 精确原始尺寸 | 1 像素误差内 | 网格对齐 |
|---|---|---|---|
| **Pixel Art Fixer** | **77%** | **84%** | **94%** |
| PixelDetector | 4% | 7% | 80% |
| unfake.py | 3% | 8% | 67% |
| PixelSnapper | 4% | 19% | 63% |
| 朴素基准 | 2% | 4% | 50% |
Pixel Art Fixer 能在 77% 的图像上恢复精确的原始分辨率(没有其他工具能超过 5%),并且其检测到的网格线有 94% 的时间与真实网格重合。当它正确获取尺寸时,其颜色的平均 CIELAB 差异约为 1.6(几乎无法察觉)。它在所有 43 种失真类别中均处于领先地位,从干净的整数放大到严重的模糊、绘画风格的伪造、断裂的轮廓,甚至是故意将所有类型的破坏叠加在一起的极端“大杂烩”测试。对于损坏程度超过任何网格检测器恢复能力的输入,[神经网络版本](#the-neural-version) 将接手处理。
完整的方法论、分类别表格和复现说明位于 [pixel-bench](https://github.com/Retro-Diffusion/pixel-bench) repo 中。
## 目录
- [准确率](#accuracy)
- [用法](#usage)
- [Python](#python)
- [Rust](#rust)
- [选项与输出](#options-and-output)
- [神经网络版本](#the-neural-version)
- [工作原理](#how-it-works)
- [Pipeline 概述](#pipeline-overview)
- [网格检测:证据通道](#grid-detection-the-evidence-channels)
- [共识与仲裁](#consensus-and-arbitration)
- [重建](#reconstruction)
- [为什么这胜过朴素方法](#why-this-beats-naive-methods)
- [由 Retro Diffusion 制作](#made-by-retro-diffusion)
- [License](#license)
## 用法
本 repository 中存在两个实现版本。它们产生相同的结果;可根据具体环境进行选择。
- **[`python/`](python/)** 是参考实现:可读性最强,最容易修改和扩展。
- **[`rust/`](rust/)** 是原生核心:一个无依赖的二进制文件,速度快 11-24 倍,适用于服务器和批处理任务。
### Python
需要 Python 3.9+ 以及 `numpy`、`scipy`、`opencv-python` 和 `Pillow`。
```
cd python
pip install -r requirements.txt
```
在图像上运行 CLI:
```
python -m pixelfixer.cli input.png # print detection JSON
python -m pixelfixer.cli input.png --extract out.png # write the fixed pixel art
python -m pixelfixer.cli input.png --overlay grid.png # write a grid overlay
python -m pixelfixer.cli folder/ --json results.json # batch a folder
```
或者从 Python 中调用它:
```
import numpy as np
from PIL import Image
from pixelfixer import detect
from pixelfixer.reconstruct import reconstruct
rgba = np.array(Image.open("input.png").convert("RGBA"))
r = detect(rgba) # {step_x, step_y, cols, rows, consensus, ...}
out = reconstruct(rgba, r["step_x"], r["step_y"], r["cols"], r["rows"])
Image.fromarray(out).save("out.png") # true pixel art at r["cols"] x r["rows"]
```
单次调用的服务器入口点接收字节数据并返回 PNG 字节:
```
from pixelfixer.api import process
result = process(png_or_jpeg_bytes) # full quality
result = process(png_or_jpeg_bytes, mode="fast") # bounded latency
# result: cols, rows, step_x, step_y, consensus, confidence, png (bytes), timings
```
### Rust
需要稳定的 Rust 工具链。无需系统库,无需 OpenCV,除了 `cargo` 之外无需安装任何东西。
```
cd rust
cargo build --release # -> target/release/pixelfixer
```
```
# 检测 + 重构,写入修复后的图像
./target/release/pixelfixer process input.png output.png # full mode
./target/release/pixelfixer process input.png output.png fast # fast mode
# 仅检测(无输出文件),每张图像一行 JSON
./target/release/pixelfixer full input.png
./target/release/pixelfixer fast input.png
```
`process` 会打印出一行包含检测到的尺寸、单元格步长、决策路径和耗时的 JSON 数据:
```
{"file": "input.png", "cols": 104, "rows": 138, "step_x": 10.44,
"step_y": 10.49, "consensus": "fast:ac+rl(S)", "mode": "full",
"detect_s": 0.19, "recon_s": 0.11, "peak_rss_mb": 147.6}
```
### 选项与输出
- **模式。** `full`(默认)运行完整的仲裁以获得最佳准确率。`fast` 仅运行低成本的检测器以保证有限的延迟,并在它们意见不一致时标记为低置信度。
- **输出为 1x 像素画。** 它通常非常小(例如 64x64)。仅使用最近邻缩放显示它(CSS 中的 `image-rendering: pixelated`,canvas 上的 `imageSmoothingEnabled = false`)。JSON 中的 `cols` 和 `rows` 无需打开文件即可告知尺寸。
- **置信度。** `consensus` 字符串记录了决策路径:`fast:...`(低成本检测器达成一致,高置信度),一个由 `+` 连接的方法列表(绝对多数投票),或 `arbitrated`(由证据栈决定)。
- **输入限制。** 支持 PNG 和 JPEG,最小边长为 16 px,最大为 4 百万像素。透明度将根据每个单元格的多数像素予以保留。
## 神经网络版本
这个开源工具是使用经典图像处理能做到的最好结果,它能够处理绝大多数的真实输入。但是,有些图像的损坏程度超过了任何网格检测器能够恢复的极限:没有留下任何边界网格的极端抖动、小于约 3 px 的单元格,或者掩盖了真实步长的强烈抖动。
对于这些情况,Retro Diffusion 托管了一个**神经网络版 Pixel Art Fixer**,可免费使用:
### [在 retrodiffusion.ai 上体验 Pixel Art Fixer](https://retrodiffusion.ai/pixel-art-fixer)
神经引擎基于真实的像素画进行训练,而不是通过测量网格。它解决了更多的边缘情况,重建了该算法只能近似处理的细节和调色板,并在经典 pipeline 只能对现有内容进行池化的地方恢复了干净的 alpha 通道。它直接在浏览器中运行,无需注册,是 retrodiffusion.ai 独家提供的。这两者共享一个设计目标:输出真正的像素,随时可应用于游戏中。
## 工作原理
### Pipeline 概述
转换过程分为两个解耦的部分:
1. **网格检测**(`detect`)查找每个轴上的伪像素单元格尺寸(`step_x`、`step_y`、亚像素级别)、原始输出分辨率(`cols`、`rows`),以及记录其决策方式的 `consensus` 字符串。
2. **重建**(`reconstruct`)获取该网格,并将源图像缩减为原始的、真实像素的图像。
检测是难点所在,整个架构的存在就是为了击败四种特定的失败类别:八度/谐波歧义(2 倍或 1/2 的答案得分几乎与真实值一样高)、内容尺度伪装成像素尺度、网格漂移下的误判,以及堆叠一次性启发式规则带来的回归问题。
### 网格检测:证据通道
核心问题是当每个“像素”都是一个巨大的、模糊的、扭曲的或受压缩损坏的区块时,如何恢复其网格。以下每个通道都通过独立的物理信号来测量周期性,因此它们会在不同的图像上失效。

首先运行三个低成本、相位不变的检测器:
- **自相关(`autocorr.py`)。** 网格存在于*跨行共享*的边界位置,而不是在任何单一的扫描线上。它将边缘和曲率特征投射到行带中,进行带状自相关,并使用梳齿减去反梳齿的得分来评估候选步长(奖励步长倍数处的周期性,惩罚半倍数处的周期性)。这是精确度最高的方法,步长误差被优化到低于 1%。
- **游程(`runlengths.py`)。** 像素画即便模糊,也是由游程组成的。颜色变化边界之间的距离是单元格尺寸的整数倍;对这些距离进行软 GCD 梳齿计算(加上一致性平滑处理,使得在扫描线上持续存在的真实边界得到信任)就能找到它。这是速度最快的一类检测器,其梳齿峰值高度是经过校准的置信度。
- **自相似性`selfsim.py`)。** 当图像偏移一个完整的单元格时,它会与自身重新对齐,因此位移差异曲线会在步长的倍数处出现下降。梳齿 t 统计量能够击败奇次谐波混叠,而分散度自适应的区块投票可以处理在整个图像上漂移的网格。
当低成本检测器意见不一致时,将由一个更庞大的证据栈进行仲裁:
- **融合频谱和区块通道(`fusion.py`、`channels.py`)。** 经验上将真实步长排名最佳的通道的等权重总和:梯度图和曲率图上的区块局部瑞利相位相干性、Welch 频谱得分(无相位,在纯模糊图像上表现最强)以及全局瑞利相干性。
- **单元格内方差对比度(`varcontrast.py`)。** 当单元格内部均匀时,网格就是正确的。这个“方形打包器”通过总和面积表计算得出,评估最佳相位下的单元格相比于最差相位下的同质化程度高出多少。对于那些模糊到连边缘都无法存活的图像,它能承载关键的信号。
- **可提炼度(`reconsearch.py`)。** 八度仲裁器。它利用“盒式降采样后再放大的往返误差等于总单元格内方差”这一恒等式,测量在每个候选尺寸下进行降采样会破坏哪些内容。双因子得分(一个反相位项加上一个八度杀手)将真实的基础频率与其谐波分离开来,这是朴素检测器面临的最大失败类别。
### 共识与仲裁
检测优先达成共识,并分为多个层次:
1. **校准的提前退出。** 如果自相关和游程在尺寸上达成一致,且游程梳齿高度超过了在基准测试中始终正确的阈值,则立即返回结果(`consensus: "fast:ac+rl(S)"`)。
2. **绝对多数。** 在加入第四个融合 argmax 投票器后,如果有三种或更多的方法在宽高比合理的前提下对某个尺寸达成一致,则采用该结果。四票中的两票是故意*不够*的:这些方法共享一些内容和纹理锁定,因此微弱多数可能只是一种相关联的失败。
3. **按轴仲裁。** 如果没有绝对多数,则在一个候选池(每种方法的步长加上自相关的前几个峰值)中对每个轴进行评分。得分是融合证据、方差对比权重、一致性奖励和可提炼度项的总和,并对大于细节尺度的步长进行惩罚。在所有得分接近最佳的候选中,*最小*的合格步长获胜,这是三个低成本检测器独立收敛得出的谐波规则。
4. **跨轴协调。** 在遇到严重的轴向分歧时,它会倾向于在两个轴上选择更细的步长(过细的网格可以无损细分;过粗的网格会破坏细节),并且在接近相等的轴向会强制对齐为正方形。
`fast` 模式仅运行步骤 1 和低成本检测器,以保证有限的延迟。
### 重建——两阶段打包(`two_stage_pack`)
在已知网格(`cols` x `rows`)的情况下,重建过程会将源图像打包,使每个单元格对应一个真正的像素。其核心思想是**将结构与颜色解耦**,这也是同时获得清晰线条*和*准确颜色的关键:

1. **规则均匀的网格。** 在已知原始尺寸的情况下,真实的单元格边界就是一个均匀的网格(`x * cols / w`)。不进行逐次切割对齐:在细节丰富的艺术图像上,对齐到局部梯度会追逐*内容*边缘,并产生细长条/双倍宽度的单元格,因此这种做法被完全摒弃。
2. **自适应量化(仅用于结构)。** 图像被 k-means 量化为自适应数量的颜色 `K`(`adaptive_k`:图像的粗略颜色复杂度,限制在 `[16, 48]` 之间)。此调色板*仅*用于决定位置,绝不用于输出。
3. **阶段 1 - 位置。** 每个单元格在干净的量化**标签**上进行中心加权投票。因为投票是在平坦、明确无误的颜色之间进行的(而不是原始图像中模糊的渐变值),所以区域边界和轮廓显得清晰锐利,而不是模糊不清。这就是实现对齐工具般干净线条的机制。
4. **阶段 2 - 颜色。** 每个单元格的颜色是根据承载其获胜标签的**原始、未量化像素**的中心加权平均值生成的。因此,颜色是准确的,并从真实图像中进行了去噪处理,稀有颜色也能保留下来——边界单元格能干净地选取“轮廓”,然后获得*真实的*轮廓颜色,而不是混合色或经过调色板限制的近似色。
传统的网格切割重建器(`reconstruct`,包含相位求解 + 捕捉切割 + 扭曲细化 + 模式池化)作为可选方案保留(`two_stage=False` / `legacy`),但不再是默认选项。
### 为什么这胜过朴素方法
- 朴素的“最强周期”会锁定在内容上,而不是像素上。这里使用的是*最精细的一致*周期,并将步长限制在细节尺度内,因此 60 像素的单元格无法与 3 像素的细节共存。
- 固定的整数网格假设在相位 0 处存在一个全局单元格。此方法处理非整数单元格、亚像素漂移(按窗口计数)和扭曲的网格(按带切割)。
- 八度陷阱(即 2 倍和 1/2 的得分与真实值几乎一样高)在结构上被可提炼度仲裁器打破,而不是依赖脆弱的阈值。
- 平滑的重采样会抹除一阶差分边缘;信号转移到了二阶导数中,由曲率特征映射进行追踪。
- JPEG 的 8 像素区块网格会被检测到,并在通道处理之前予以剔除,因此压缩不会被误认为是艺术网格。
完整的技术文档(包括每个通道、规则及其背后的原理)位于 [`docs/HOW_IT_WORKS.md`](docs/HOW_IT_WORKS.md) 中。
## License
MIT。请参阅 [LICENSE](LICENSE)。
标签:SOC Prime, 像素艺术, 可视化界面, 图像处理, 图像转换, 开发工具, 逆向工具