产出真实小分辨率、颜色数受控、边缘硬朗的 sprite,而非马赛克滤镜。 纯 numpy/PIL 自研实现,无额外依赖、无需模型权重。 三种模式:按目标宽度 / 按像素块大小 / 自动检测网格。第三种专治 AI 生成的伪像素图(看着像素风,实际网格歪斜、边缘抗锯齿、上千颜色)。 选型说明:Pixel Snapper(MIT)解决的是「伪像素图 → 完美像素图」, 而「普通图 → 像素画」是另一个问题,核心在降采样与调色板量化, 故两条路都做进同一节点。 网格检测处理了两类经典误判: - 谐波(八度)错误:取得最高分后回查真约数(octave killer) - 内容周期冒充像素周期:把最佳/最差相位的分差并入评分(anti-phase) 评分用单元内方差而非相邻差分——差分对模糊极敏感,实测会把 4 像素 网格判成 24~28;组内方差则天然压制过大的 s。 实测:干净放大图 k=2~16 共 27/27 全对零八度错误;非方形网格与相位 偏移全对;普通插画正确判为未检出;端到端把 32×32 放大 10 倍加模糊 噪点的图还原回 32×32,与真值 MAE 0.0049;整数倍放大为纯复制无插值。 调色板在 CIELAB 空间聚类(RGB 距离与人眼感受相差很远,会丢暗部层次), 降采样默认主导色(均值会造出新颜色并糊边),内置 PICO-8/Game Boy 等 可确认取值的复古调色板。 Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
46 lines
1.1 KiB
Python
46 lines
1.1 KiB
Python
# -*- coding: utf-8 -*-
|
||
"""
|
||
内置复古调色板
|
||
==============
|
||
只收录能确认取值的经典调色板,宁缺毋滥 —— 调色板值错了,
|
||
产出的美术资产就和目标机器/风格对不上,属于很难事后发现的错误。
|
||
灰阶类由代码等距生成,不存在记错的问题。
|
||
"""
|
||
import numpy as np
|
||
|
||
|
||
def _hex(*codes):
|
||
return np.array([[int(c[i:i + 2], 16) for i in (0, 2, 4)] for c in codes],
|
||
dtype=np.float32)
|
||
|
||
|
||
# PICO-8 官方 16 色
|
||
PICO8 = _hex(
|
||
"000000", "1D2B53", "7E2553", "008751", "AB5236", "5F574F", "C2C3C7",
|
||
"FFF1E8", "FF004D", "FFA300", "FFEC27", "00E436", "29ADFF", "83769C",
|
||
"FF77A8", "FFCCAA",
|
||
)
|
||
|
||
# 初代 Game Boy(DMG)四级绿
|
||
GAMEBOY = _hex("0F380F", "306230", "8BAC0F", "9BBC0F")
|
||
|
||
# 1-bit 黑白
|
||
ONEBIT = _hex("000000", "FFFFFF")
|
||
|
||
|
||
def _gray(n):
|
||
v = np.linspace(0, 255, n, dtype=np.float32)
|
||
return np.stack([v, v, v], axis=1)
|
||
|
||
|
||
PALETTES = {
|
||
"PICO-8 (16色)": PICO8,
|
||
"Game Boy (4色绿)": GAMEBOY,
|
||
"黑白 1-bit (2色)": ONEBIT,
|
||
"灰阶 4 级": _gray(4),
|
||
"灰阶 8 级": _gray(8),
|
||
"灰阶 16 级": _gray(16),
|
||
}
|
||
|
||
PALETTE_NAMES = list(PALETTES.keys())
|