如何从一张图片中提取真正"像被人挑过"的配色
文章摘要
设计师 / 工程师 Amanda Hinton 用一篇长博客记录了她为自己的工具 Spectrimage 从零打磨”图片→五色配色”算法的全过程。这是一篇典型的”工程师写设计、设计师写工程”的复盘文:每一次迭代都同时回答了”为什么算法的输出看起来不对”和”应该如何修正”。最终目标是得到一个 同一张图片每次产出相同 5 种颜色,并且像人类挑选过 的配色。
色彩空间的选择:作者最初使用 RGB / HSL,很快发现这两个空间在感知上严重非线性——HSL 中等饱和度的红和等饱和度的蓝在人眼看来差距巨大;用 saturation 做阈值会得到”看起来很灰但被算法当成有色”的样本。她转而使用 Oklab/OKLCH——一个 2020 年由 Björn Ottosson 提出的近似感知均匀的色彩空间。OKLCH 中 C(chroma)真正等于”距离无彩色轴的距离”,可以可靠地区分”灰”和”色”,这是后续所有改进的基础。
第一版(弃用):基于 RGB 的 median-cut 量化(GIF 编码经典算法),叠加大量硬编码规则(”如果某色太接近灰则丢弃”“如果两色太近则合并”)。代码越写越复杂,维护性崩溃。
第二版:引入 K-means++ 聚类,K = 14(多次基准测试得出的最佳值),从最多 9 万个采样像素中初始化。聚类初始种子使用图像规范化哈希,保证同一张图永远输出相同结果(这一点对设计工具至关重要——你不能让用户每次刷新得到不同的”品牌色”)。聚类之后用 0.07 的合并阈值,把感知上几乎相同的两个簇合二为一。
第三版:解决”两种红色被算成两种颜色”的问题——在 Oklab 距离里把色相/彩度平面(chromatic plane)的权重设为亮度轴的 2 倍。这样亮度差不再被等同于色相差,使算法更接近人类”两种颜色”的判断。
第四版(最终):三项关键结构改进:
- Phantom Guard(鬼影屏蔽):丢弃权重小于 2.5% 且彩度极低的簇,避免把 JPEG 压缩噪点中近灰的像素带入最终配色。
- Mass Allocation(质量分配):根据图像中”无彩色像素占比”决定最终五色中允许多少个灰阶位,避免浅色摄影作品被强行塞入饱和色。
- Centroid-Aware Selection(质心感知挑选):彩色簇取簇内 chroma 最高的像素作为代表(这样观感更”纯”),无彩色簇则取最接近质心的像素(避免噪声)。
输出 5 个色块按色相排序、灰色置后,并允许用户在 Spectrimage 应用中手动微调——作者承认任何算法都无法替代人类最后的拣选。
文章的可贵之处在于,它把”调色板提取”这个看似简单的任务,变成了一节关于色彩科学、聚类算法、感知均匀性、再现性工程与人机协作的综合课程,对所有自己写过设计辅助工具的开发者都有直接启发。
HN 评论精华
-
cududa:盛赞”我见过最好的图片配色生成器”,并强调这件事的难度——市面上多数工具会给出”看起来颜色都对,但拼起来很丑”的五连色块。它需要的不是更快的聚类,而是对人类色彩感知的深入理解。
-
rezmason:分享了 David Aerne 的一系列在线配色工具(okpalette.color.pizza 等),都基于类似的 Oklab/OKLCH 思路。这些工具大多对 sRGB 像素先做去伽马,再进入 Oklab 计算,使得阴影区不会被错误识别为饱和色。
-
indigo945:提出一个工程改进方向——除了像素值聚类,还应考虑像素的 空间邻近性。一个真正”重要”的颜色往往出现在大块连续区域,而阴影伪色斑块虽然像素数多,却散布在边界。引入图像分割(如 SLIC superpixels)可以避免被压缩噪声欺骗。
-
firebot:联想到 allrgb.com(一个用 24 位 RGB 全部 16,777,216 个三元色各一次构图的艺术挑战),引出关于”颜色覆盖率”的趣味话题。
-
comradesmith:表示要照着博客自己实现一遍——”看一遍懂、写一遍熟、debug 一遍才真懂”。这种博客对学习者特别友好,因为每次迭代都附带反例图与原因解释。
-
sarreph:分享一个对照实验——直接让 Gemini 多模态模型从图中”挑五种主要颜色”,效果竟然不错。引发讨论:在 LLM/VLM 时代,专门做配色提取的算法是否还值得精雕?多数评论认为”算法的可解释性、再现性、零成本运行”仍是 LLM 暂时无法替代的。
-
aardvarkdriver:链接到作者另一篇关于”为单张图片生成色谱(spectrum)”的博客,进一步说明 Spectrimage 是一个系列项目;从单像素采样到聚类再到色谱生成,作者建立了完整的工具链。
-
anentropic:实用主义提问——”博客里有没有可以试用的链接?”反映出大多数读者的真实诉求:先看一眼自己的照片能跑出什么。这条提问本身也提醒作者,技术博客在技术细节之外不要忘了贴 demo 入口。