Skip to content

feat(pixel-grid): add independent native grid reconstructor - #495

Merged
xyh202131 merged 12 commits into
1024XEngineer:mainfrom
huyanxius:feat/491-pixel-grid-reconstructor
Aug 25, 2026
Merged

xyh202131 merged 12 commits into
1024XEngineer:mainfrom
huyanxius:feat/491-pixel-grid-reconstructor

Conversation

@huyanxius

@huyanxius huyanxius commented Aug 20, 2026 •

Copy link
Copy Markdown
Collaborator

新增与检测器和业务应用解耦的显式网格重建库:调用方给定网格后,Rust 模块返回每格单色的原生 1x PNG;源码位于仓库根目录,不属于 Python 后端。

Why

网格识别与像素重建是两种不同职责。把重建逻辑绑定在检测器、Python 后端或生成管线中,会导致后续替换检测算法时同时改动颜色恢复,并扩大本地算法的业务耦合。

Changes

  • 新增独立 Rust library,只接收 PNG/JPEG、cols、rows、colors 并返回 PNG。
  • 使用两阶段结构标签投票与原色恢复,使 colors 只控制结构聚类,不硬性截断最终全局色板。
  • 钳制密集网格的负三角权重,避免颜色外插产生荧光坏点。
  • 在解码和算法分配前限制 32MiB 输入、4MP 像素和 128MiB 保守工作集。
  • 将模块放置在 native/pixel-perfect/crates/reconstructor/,删除生产 stdin/stdout CLI。
  • 更新独立 path-filter CI、MIT 许可证和固定上游版本说明。

Implementation

  • reconstruct_bytes 是唯一算法入口;网格参数是唯一空间契约,模块不推断像素密度。
  • 重建器使用 crate-local manifest 与 lockfile,可在检测器尚未合入时独立构建。
  • Python 原生扩展与工具 API 由 feat(pixel-perfect): expose an independent tool API #492 单独交付。

Verification

  • cargo fmt --check:通过。
  • cargo test --release --locked:8 项测试通过,0 项失败。
  • git diff --check upstream/main...HEAD:通过。
  • GitHub Actions:等待当前 head 完成。

Scope

Related Issues

Closes #491

Refs #489

Detected grids need a separate local stage that can rebuild one color per cell.

Add deterministic two-stage reconstruction with bounded memory and explicit grid arguments.

Images can now be rebuilt without invoking detection, application services, or generation flows.
The native reconstructor needs a reproducible package boundary and dependency graph.

Add the Rust manifest, locked dependencies, and local target exclusion.

The reconstruction module can now build independently with deterministic inputs.
Explicit reconstruction must preserve source colors without creating dense-grid artifacts.

Cover exact cells, uncapped final palettes, bad points, input limits, and working-set rejection.

Color and resource regressions now fail before this module reaches the application layer.
The extracted reconstruction algorithm must remain traceable and license compliant.

Document its explicit-grid contract, two-stage color behavior, fixed upstream revision, and MIT terms.

Maintainers can review the reuse boundary without consulting the generation codebase.
The standalone reconstructor needs a narrow gate independent of backend CI.

Run format and locked release tests only for reconstructor paths and its workflow.

Reconstruction changes now receive isolated validation without touching generation jobs.
@vercel

vercel Bot commented Aug 20, 2026

Copy link
Copy Markdown

Deployment failed for project windup with the following error:

Resource is limited - try again in 24 hours (more than 100, code: "api-deployments-free-per-day").

Learn More: https://vercel.com/huyan-s-projects1?upgradeToPro=build-rate-limit

@codecov

codecov Bot commented Aug 20, 2026

Copy link
Copy Markdown

Codecov Report

✅ All modified and coverable lines are covered by tests.

📢 Thoughts on this report? Let us know!

@fennoai fennoai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

审查了独立重建器的输入边界、两阶段标签/颜色恢复、透明度多数票、CLI 参数契约、工作集估算以及 path-filter CI。发现透明 PNG 的可见颜色恢复仍会受到透明像素 RGB 元数据影响,建议在合并前修正。固定 SHA 范围的 git diff --check 通过;本环境未安装 cargo,因此无法复跑 Rust 测试。

Comment thread native/pixel-perfect/crates/reconstructor/src/reconstruct.rs
Transparent pixel metadata could tint a cell that reconstructs as opaque.

Exclude non-visible pixels from selected and fallback visible color averages.

Opaque cell colors now reflect only pixels that contribute visible color.
The visible-color regression needs a fixture with conflicting hidden RGB data.

Add a majority-opaque red cell whose transparent pixels store blue channels.

The test prevents hidden PNG metadata from tinting reconstructed output.
The reconstructor is a native algorithm library rather than Python backend code.

Move the independent crate to the root native area and remove the retired CLI.

The later PyO3 binding can consume it without coupling this module to Python.
The reconstructor workflow still watched the retired backend-native path.

Point path filters and the working directory at the independent native crate.

Reconstruction checks now run for the relocated module.
@vercel

vercel Bot commented Aug 21, 2026 •

Copy link
Copy Markdown

The latest updates on your projects. Learn more about Vercel for GitHub.

1 Skipped Deployment
Project Deployment Actions Updated (UTC)
windup Ignored Ignored Preview Aug 21, 2026 4:16am

@huyanxius huyanxius changed the title feat(pixel-grid): add explicit grid reconstructor feat(pixel-grid): add independent native grid reconstructor Aug 21, 2026
The provenance note still claimed an algorithm change that has been withdrawn.

Remove the transparent-color fix statement from the native module documentation.

The pull request now describes only relocation and the existing algorithm.

@xiaocheny214 xiaocheny214 left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

这个没啥问题

xyh202131
xyh202131 previously approved these changes Aug 21, 2026

@xyh202131 xyh202131 left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

按请求批量审批当前提交。

@xyh202131
xyh202131 dismissed their stale review August 21, 2026 09:16

按请求撤销此前审批。

@huyanxius
huyanxius requested review from minorcell and nighca August 24, 2026 05:55
@nighca

nighca commented Aug 24, 2026 •

Copy link
Copy Markdown
Contributor

@fennoai 介绍下这里的“像素重建”具体算法是什么样的,评估下是否有必要单独使用 rust 实现,使用 python 实现成本是否高

@fennoai

fennoai Bot commented Aug 24, 2026 •

Copy link
Copy Markdown
Contributor

分析结论

这部分“像素重建”不是检测网格,而是在调用方已经给出 cols × rows 的前提下,把任意输入图像压缩成每个网格单元一个颜色的原生 1x PNG。入口是 reconstruct_bytes(source, cols, rows, structure_colors)。

算法流程

  1. 输入与资源限制

    • 只接受 PNG/JPEG;解码前检查输入字节数、图片像素数、最小边长、网格边界和估算工作集。
    • 目前上限是 32 MiB 编码输入、4 MP 像素、128 MiB 保守工作集,避免压缩炸弹或超大网格直接触发大量分配。
  2. 结构颜色量化:确定“这个格子属于哪类”

    • 从不透明像素中最多均匀采样 60,000 个 RGB 点。
    • 使用固定种子的 k-means++ 初始化 + Lloyd 迭代,得到 structure_colors 个结构中心;再把每个源像素并行分配到最近中心,生成每像素 label。
    • 这里的颜色聚类只服务于结构标签,不是最终调色板,所以 colors=2 不会把最终输出强行压成 2 色。
  3. 空间映射与结构投票

    • 对每个源像素按显式规则映射到一个输出 cell:cell_x = floor(x * cols / width)、cell_y = floor(y * rows / height)。
    • 同时计算 X/Y 方向的三角权重,中心附近权重大,边界附近权重小;实现中将负权重钳制为 0,避免密集网格下加权平均发生颜色外插,产生超出输入范围的“荧光色”。
    • 每个 cell 对内部像素的 label 做加权投票,票数最高的 label 成为该 cell 的结构归属。
  4. 原色恢复:只在胜出结构内取颜色

    • 再遍历源像素,只收集 label 等于该 cell 胜出 label 的像素,使用同样的空间权重对原始 RGB 做加权平均。
    • 如果某格没有足够的胜出样本,则退化为该格全部像素的普通平均。
    • alpha 使用格内多数票决定透明/不透明;RGB 最后四舍五入并钳制到 [0,255],输出尺寸严格为 cols × rows。

对应实现主要在 native/pixel-perfect/crates/reconstructor/src/kmeans.rs、native/pixel-perfect/crates/reconstructor/src/reconstruct.rs 和 native/pixel-perfect/crates/reconstructor/src/lib.rs;测试覆盖了规则网格恢复、结构色数不限制最终色板、密集网格不越界,以及输入/工作集边界。

是否有必要单独用 Rust

从算法本身看,不是必须。 Python 完全可以实现:Pillow 负责 PNG/JPEG 解码编码,NumPy 负责数组化的网格映射、投票和加权聚合,k-means 可以自己写或使用 scikit-learn。若只在 Python 后端内部调用、图片规模不大、部署环境已有 NumPy/Pillow,那么 Python 版本的实现成本并不高,核心算法大约是中等复杂度,而不是 Rust 才能完成的算法。

从工程边界看,Rust 有合理价值,但理由主要是交付形态和约束,而非“Python 性能一定不够”:

  • 这是一个明确的、与检测器/后端解耦的 library;Rust crate 可以独立构建、独立测试,不把 Python 运行时和业务依赖带进核心模块。
  • 输入上限、checked arithmetic、解码限制和工作集预估集中在一个原生边界内,更容易把“不可信图片输入”的内存行为控制住。
  • k-means 的标签分配已经用 Rayon 并行;Rust 可以提供稳定的确定性实现和较低的运行时/分发依赖。
  • 后续 feat(pixel-perfect): expose an independent tool API #492 需要 PyO3 时,Python 只做薄封装,算法核心不需要再迁移一次;未来也可被其他 Rust/CLI/服务调用方复用。

成本判断与建议

  • 短期 Python 成本:低到中。 若接受 NumPy/Pillow/scikit-learn 依赖,开发和调试更快;纯 Python 不建议,逐像素双重循环和 k-means 分配在 4 MP 输入上会明显变慢。
  • Rust 当前成本:中等。 本 PR 已把依赖、锁文件、测试和边界限制独立好;真正额外的成本主要是 Rust 工具链、PyO3 集成、跨平台 wheel/构建发布和后续维护。
  • 性能收益不能仅凭代码断言。 当前实现有 Rayon,但是否值得 Rust,应该补一组代表性输入的 benchmark:不同源图尺寸、网格密度、structure_colors,对比 NumPy 版本的端到端耗时、峰值内存和输出一致性。

我的判断是:如果目标只是当前 Python 管线里的功能,Python + NumPy 足够,没必要为了算法重写 Rust;如果目标是长期维护的独立原生库、明确的内存边界、可复用 API,以及 #492 的薄 PyO3 集成,那么保留 Rust 是合理的架构选择。 这更像“边界/复用/部署”的投资,而不是当前算法对 Python 的硬性性能要求。

验证

  • 已按要求锁定并检查固定提交范围 0b1e5acd6fa62988dff453161cb09773ecdc0731...e2045059983c5f07012343564c347bb3a10c9a27。
  • git diff --check 通过。
  • 当前执行环境未安装 cargo(命令返回 cargo: command not found),因此本轮无法重新运行 cargo test --release --locked;源码中的测试覆盖范围已检查。

View job run

@nighca

nighca commented Aug 24, 2026

Copy link
Copy Markdown
Contributor

@huyanxius 看上去没有什么有很强的理由走 rust?考虑到额外引入一种语言增加的开发、维护成本,我建议走服务端原来的 python 实现

@xyh202131

Copy link
Copy Markdown
Contributor

@huyanxius 看上去没有什么有很强的理由走 rust?考虑到额外引入一种语言增加的开发、维护成本,我建议走服务端原来的 python 实现

有开源代码可以复用

@nighca

nighca commented Aug 24, 2026

Copy link
Copy Markdown
Contributor

有开源代码可以复用

@xyh202131 是指当前的采样算法本身,还是指依赖的库(image、rayon)?

@xyh202131

Copy link
Copy Markdown
Contributor

有开源代码可以复用

@xyh202131 是指当前的采样算法本身,还是指依赖的库(image、rayon)?

好像都有,不需要做什么调整即可复用

@xiaocheny214

Copy link
Copy Markdown
Contributor

@huyanxius 看上去没有什么有很强的理由走 rust?考虑到额外引入一种语言增加的开发、维护成本,我建议走服务端原来的 python 实现

这个是直接拿图片像素画效果最好的一个库复用的。但因为这个库是rust写的,如果想要使用python实现,迁移这个rust库的成本巨高,估算在五六千行代码。
所以采用了一个折中的办法,干脆直接导入这个rust库,然后在上面做了一层封装,让python直接能调用这个功能就行。

@huyanxius

Copy link
Copy Markdown
Collaborator Author

@huyanxius 看上去没有什么有很强的理由走 rust?考虑到额外引入一种语言增加的开发、维护成本,我建议走服务端原来的 python 实现

这个是直接拿图片像素画效果最好的一个库复用的。但因为这个库是rust写的,如果想要使用python实现,迁移这个rust库的成本巨高,估算在五六千行代码。 所以采用了一个折中的办法,干脆直接导入这个rust库,然后在上面做了一层封装,让python直接能调用这个功能就行。

@xiaocheny214 现在来看很低了,之前高是因为detector占了 5000 多行,现在我们把那一套detector弃用了,这里的核心 Rust 源码大概只有 500 多行,我觉得可以按照导师的意思,用 Python 来实现

@nighca

nighca commented Aug 24, 2026

Copy link
Copy Markdown
Contributor

这个是直接拿图片像素画效果最好的一个库复用的

@xiaocheny214 我没在依赖中看到这个库,还是说现在提交的 src 的内容就是这个库?如果是的话,那核心算法应该也有 4、5 百行代码,迁移为 python 需要五六千行很奇怪啊

依赖的库(image、rayon)

现在依赖的这俩看上去都是跟这个算法无关的基础能力,python 社区理应有对应的替代,总感觉是哪里我们理解上有偏差

@huyanxius

Copy link
Copy Markdown
Collaborator Author

有开源代码可以复用

@xyh202131 是指当前的采样算法本身,还是指依赖的库(image、rayon)?

指的是采样算法本身。当前两阶段重建和 deterministic k-means 来自 Retro-Diffusion/pixel-art-fixer,image、rayon 只是解码和并行依赖。

@huyanxius

Copy link
Copy Markdown
Collaborator Author

这个是直接拿图片像素画效果最好的一个库复用的

@xiaocheny214 我没在依赖中看到这个库,还是说现在提交的 src 的内容就是这个库?如果是的话,那核心算法应该也有 4、5 百行代码,迁移为 python 需要五六千行很奇怪啊

依赖的库(image、rayon)

现在依赖的这俩看上去都是跟这个算法无关的基础能力,python 社区理应有对应的替代,总感觉是哪里我们理解上有偏差

@nighca 他应该是把之前的代码算进来了🤣目前来看就是 500 行左右

@huyanxius

Copy link
Copy Markdown
Collaborator Author

@nighca 那我先来按 Python 迁移一个版本,然后对比原来的 rust 测试一下质量和速度?这样如何?

@nighca

nighca commented Aug 24, 2026

Copy link
Copy Markdown
Contributor

@nighca 那我先来按 Python 迁移一个版本,然后对比原来的 rust 测试一下质量和速度?这样如何?

@huyanxius 可以的,其实质量不应该有差异,因为质量是算法决定的,而跨语言迁移理论上不影响算法。

@xyh202131 xyh202131 left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

独立算法库边界明确,CI 与资源限制覆盖完整;可以合并。

@xyh202131
xyh202131 merged commit bede3cf into 1024XEngineer:main Aug 25, 2026
12 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

feat(pixel-grid): add an explicit grid reconstructor

4 participants