Skip to content

Repository files navigation

Xiangliu Grid / 相柳网格

Version: 0.6.0

本工具是 大云壁画工具箱的一员(相柳网格 · 精卫 · 白泽评审 · 重明 DiffEye)。图像算法保持不变,本版为系列化交付(安全修复 + 统一外壳)。详见 CHANGELOG.md。

Xiangliu Grid logo


English

Xiangliu Grid is a local web tool for splitting large master images into strict, numbered square tiles, then stitching selected or complete tiles back into their original grid positions — with seam-balanced color correction so that dozens of independently AI-restored tiles merge into one seamless image.

Origin

This small tool was created for the mural recreation and restoration workflow of Dayun Chanyuan. The project uses very high-resolution scanned mural images, but current AI image models work more reliably on controlled 2048 x 2048 image blocks. Xiangliu Grid helps split a large scan into numbered, overlapping, workable tiles so different people can restore sections in parallel and stitch them back into place later.

Why "Xiangliu"

Xiangliu, or 相柳, is a many-headed mythic being from the Classic of Mountains and Seas. The name fits this tool because a single large image is divided into many coordinated parts, each with its own identity, while still belonging to one whole body.

Features

  • Strict square tiling: every tile is exactly 2048 x 2048 by default.
  • Fixed overlap: adjacent tiles overlap by 20px by default.
  • No resampling: the tool only crops the prepared master image. It does not scale, enlarge, or shrink pixels.
  • Top-left alignment: the source image is pinned to the top-left corner; blank padding appears only on the right and bottom edges.
  • Visual grid preview: the browser preview shows the full working canvas, including right/bottom blank padding.
  • Numbered outputs: tiles use stable IDs such as R01_C01, R04_C12.
  • Manifest files: JSON and CSV manifests record tile IDs, coordinates, status fields, and filenames.
  • Locator map: tile_locator_map.jpg shows each tile number on the full working canvas.
  • Seam Balance color correction: measure adjacent tile edge color differences, solve per-tile RGB offsets globally, apply small biases, then stitch with wide feather blending.
  • Low-frequency color field correction: estimate a smooth color drift field from a thumbnail, upsample it, and apply it per-tile at full resolution to remove large-area brightness/color shifts without losing detail.
  • Padding trim: when stitching, optionally trim the right/bottom padding added during splitting, so output matches the original source dimensions.
  • Stitching modes:
    • Local preview: stitch only returned tiles into the smallest local region.
    • Full canvas fill: place returned tiles back into the full canvas with blanks elsewhere.
    • Complete stitch: require all tiles and fail if any are missing.

Color & Stitch Pipeline

The Problem

When a large mural scan is split into 48 tiles and each tile is independently AI-restored, every tile comes back with its own low-frequency color drift: some blocks are slightly brighter, some slightly warmer, some slightly desaturated. Simple edge feathering softens the seam but cannot fix the per-block color mismatch — the result looks like a patchwork of slightly different shades.

Solution: Two-Layer Processing

Layer 1 — Seam Balance (per-tile RGB bias)

Instead of trying to color-match each tile to a reference image (which amplifies differences), this method builds a constraint network between neighboring tiles and solves for a small overall offset per tile.

Algorithm:

  1. Read all tiles and find row/column adjacency relationships.
  2. For each pair of adjacent tiles, sample a 20px strip at the shared edge (with 80px inset to avoid corners/padding). Compute the median RGB of each strip.
  3. The difference between adjacent strips becomes a constraint: bias_left - bias_right ≈ right_edge_mean - left_edge_mean.
  4. All constraints form a linear system. Solve with least squares + regularization (bias toward zero, so tiles only shift as much as necessary).
  5. Clamp each tile's bias to ±max_bias (default ±18 color levels) to prevent over-correction.
  6. Apply the bias to each tile: tile = tile + bias.

Why this works:

  • It's a global solution, not a local patch — the entire grid is balanced at once.
  • Each tile gets a single small RGB offset applied uniformly, so the same pixel value maps to the same output anywhere → edges are naturally continuous.
  • Regularization keeps changes conservative: regularize = 0.35 means "only adjust as much as the edges actually need."
  • The max-bias clamp prevents any tile from being pushed to an unnatural color.

Layer 2 — Low-Frequency Color Field Correction

Seam balance fixes edge mismatches between adjacent tiles. But if the entire upper-left is slightly dark and the lower-right is slightly bright (a slow drift across many tiles), seam balance alone cannot fix that. This is a low-frequency problem.

Algorithm:

  1. Build a small thumbnail (600px wide) of the stitched image.
  2. Convert to LAB color space.
  3. Apply a large-radius Gaussian blur (radius ≈ 1/4 of thumbnail width) to extract the low-frequency drift field. In auto mode, L uses the selected strength while A/B use 35% of it; lightness mode leaves A/B untouched.
  4. Compute the global mean of the blurred field.
  5. The correction field = blurred_field - global_mean.
  6. Upsample the correction field to full resolution (it's smooth, so upsampling loses no information).
  7. For each full-resolution tile, extract the corresponding region of the correction field and subtract it in LAB space.
  8. Convert back to RGB.

Why this preserves detail:

  • The correction field is smooth and low-frequency — it only contains slow brightness/color drifts, not image content.
  • Upsampling a smooth field to full resolution is lossless (there's no high-frequency detail to lose).
  • The correction is applied to the full-resolution original tiles, not to an upscaled image. All mural details, brushstrokes, and textures are preserved at original resolution.
  • The UI keeps this simple: Auto / Lightness only / Off. Auto is the default and avoids over-flattening local color temperature.
  • Reduce yellow substrate restores low-chroma warm plaster/paper toward its pre-calibration global cast. A soft OKLab mask protects stronger red, green, and blue pigments.

Stitching

After color correction, tiles are stitched with weighted feather blending:

  • Each tile generates a feather mask: center weight is high, edges gradually decrease.
  • Adjacent tiles' edges blend via weighted average: result = sum(tile * mask) / sum(mask).
  • Default feather is 80px for seam-balance mode (wider than the 20px overlap), producing smooth transitions.

This is more robust than simple paste-overwrite, which creates hard seams.

Measured Results

On a 48-tile mural (4 rows × 12 columns, 24162 × 7051 px):

Metric Before After Seam Balance Reduction
Mean seam difference 6.47 2.54 -61%
P90 seam difference 15.03 5.37 -64%
Max seam difference 36.00 11.67 -68%

Image sharpness (Laplacian variance) is preserved within 2% of the uncorrected baseline — no detail loss.

Advantages

  1. No reference image needed — the method works from the tiles' own edge relationships. No need to manually pick a "standard" tile or color card.
  2. Deterministic, not AI — reproducible results, no random variation, no model dependency.
  3. Conservative by design — regularization + max-bias clamp means it only changes what needs changing. A tile that already matches its neighbors gets near-zero bias.
  4. Scales to huge images — the low-frequency correction uses a 600px thumbnail for estimation but applies at full resolution, so memory is bounded regardless of output size.
  5. No detail loss — correction is a smooth low-frequency field applied per-tile at full resolution. Brushstrokes, textures, and fine details are untouched.

Workflow

  1. Prepare and scale the large source image externally with your preferred imaging software.
  2. Open Xiangliu Grid locally.
  3. Select the prepared master image.
  4. Preview the grid and padding.
  5. Split tiles.
  6. Restore or edit tiles in parallel (each person/AI works on their own tiles independently).
  7. Stitch with Seam Balance (default) + optional Low-Frequency Correction + Trim Padding for final output.

Cropping Rules

Default values:

Tile size: 2048 x 2048
Overlap:   20px
Stride:    2048 - 20 = 2028px

Adjacent horizontal tiles:

Tile 1: x = 0..2047
Tile 2: x = 2028..4075
Overlap: x = 2028..2047, exactly 20px

Vertical tiles follow the same rule.

Run Locally

Double-click:

xiangliu-grid\run_xiangliu_grid.bat

Or run in PowerShell:

.\xiangliu-grid\run_xiangliu_grid.ps1

Then open:

http://127.0.0.1:8765

Outputs

After splitting, the tool creates:

outputs/<job_name>/tiles/
outputs/<job_name>/tiles_manifest.csv
outputs/<job_name>/tiles_manifest.json
outputs/<job_name>/tile_locator_map.jpg

Tile filename example:

R01_C01_x0_y0_v001.png

Notes

  • Use the file picker for large images. Drag-and-drop copies the file into the tool folder.
  • The tool does not scale pixels. Scaling should happen before import.
  • Right and bottom padding is expected when the master size is not an exact multiple of the stride.
  • Keep Rxx_Cxx in restored filenames so the stitcher can place each tile correctly.
  • For best seam-balance results, use Trim Padding so color statistics exclude the padding area.

Changelog

v0.5.1

  • Simplified low-frequency controls: the UI now offers Auto / Lightness only / Off. Auto applies full low-frequency lightness correction and only 35% color-temperature correction.
  • Selective yellow-substrate reduction: a 0–100% control restores low-chroma warm background toward the input tiles' global substrate cast while protecting stronger pigments.
  • Fix yellow cast: standard-palette recolor no longer shifts reds to yellow-brown.
    • apply_palette_profile: hue now pulls at most ±10° with confidence weighting (was: hard pull to family hue), chroma scale capped at 1.35, near-neutral pixels barely move.
    • recolor_tile: 18-color grid correction (per your design: source hue picks the family + source lightness picks the level → the original color is corrected to the matching light/base/deep swatch, e.g. light red → 浅陶红, mid red → 基准赭红, deep red → 深栗红). Lightness comes from the grayscale normalization; hue/chroma are corrected toward the palette level. With preserve_local_hue checked (default) hue correction is bounded and mid-tones between families (cyan/purple) are preserved via distance attenuation (no hard compression); unchecked pulls all hues to palette levels (strong seam unification). saturation_gain default 1.0, removed the min_chroma floor, dark-area chroma boost reduced from +10% to +3%.
  • Palette white balance: build_palette_profile now estimates the reference's global warm cast from its least-saturated pixels and subtracts it, so a yellowed standard image no longer produces a yellowed palette. Recorded as cast in the profile; toggleable.
  • Three lightness levels: each family now keeps 浅/基准/深 (light/base/deep) levels; recoloring interpolates target chroma by pixel lightness instead of a single median.
  • Multi-format palette loading: load_palette_profile accepts (1) native profiles, (2) structured color cards {cave, period, colors:[{family, level, name, hex}]}, (3) simple swatch lists {swatches:[{name, rgb|hex}]}. White/black/neutral swatches are excluded from chromatic families automatically.
  • One-click calibration (two-stage pipeline): "一键校准并拼合" now runs the full two-stage pipeline on all tiles without selecting any: stage 1 = decolor → joint grayscale/ink normalization (kills lightness seams) → 18-color grid correction (light/base/deep swatches from the palette); stage 2 = palette-residual seam balance + optional low-frequency correction → feather stitch → trim padding. palette_family mode is this two-stage pipeline (the old single-stage per-tile apply and the standalone "experiment mode" checkbox are removed). Defaults: palette strength 0.9, ink lightness 0.55, ink expand 1px. Falls back to the manifest source image when no palette is given. Palette preview now renders all swatches including white/black neutrals; the color-comparison reference shows the palette board.
  • Frontend panel reorganized into numbered sections: ① palette source, ② one-click calibration, ③ advanced parameters, ④ experiment mode, ⑤ other settings.
  • Fix palette preview crash: palette preview now loads a CJK font (fallback to default) instead of failing on Chinese swatch names.

v0.4.1

  • Fixed low-frequency correction to apply per-tile at full resolution (no blur from upscaling).
  • Low-frequency correction now runs before stitching, not after.

v0.4.0

  • Added Seam Balance color mode: per-tile RGB bias solved from adjacent edge differences.
  • Added Low-Frequency Color Field Correction: removes large-area brightness/color drift.
  • Added Trim Padding: output matches original source dimensions.
  • Three strength presets: light (max_bias=10), standard (18), strong (24).

v0.3.x

  • Four-edge feather mask with numpy (true 0→255 gradient, endpoint-accurate).
  • Weighted blending instead of sequential paste.
  • Trim padding for original-dimension output.

License and Branding

The source code is released under the MIT License.

The names Xiangliu Grid and 相柳网格, as well as the project logo and visual identity, are reserved by the project author and are not granted as branding or trademark rights under the MIT License.


中文

相柳网格是一个本地网页工具,用于把已经处理好的大图母版严格切分为带编号的方形图块,并在修复后按原始网格位置进行局部或完整拼合。v0.4 起内置接缝平衡与低频颜色场校正,让几十块独立修复的图块拼回后看不出色块边界。

缘起

这个小工具的制作缘起,是因为我们正在推进大云禅院壁画修复与重现工作。项目中有高清扫描版的大图,但受当前 AI 图像模型能力限制,工作图块更适合控制在 2048 x 2048。相柳网格用于把一张巨大的扫描图切分成带编号、带重叠区、便于分工处理的工作界面,后续再按原始位置局部或完整拼合回来。

名称含义

"相柳"出自《山海经》,具有多首、多分支的意象。这个工具把一张大图拆成多个编号明确的图块,每一块都可以单独处理,但最终仍能回到同一个整体之中,因此命名为"相柳网格"。

功能

  • 严格方形切块:默认每块 2048 x 2048。
  • 固定重叠区:默认相邻块重叠 20px。
  • 不重采样:工具只裁切已准备好的母版,不做缩放、放大或缩小。
  • 左上贴齐:母版左边和上边严格贴住画布,空白只出现在最右边和最底边。
  • 可视化编号预览:预览区域显示完整工作画布,包括右/下白边。
  • 稳定编号:输出图块使用 R01_C01、R04_C12 等编号。
  • 清单记录:生成 JSON 和 CSV manifest,记录编号、坐标、状态和文件名。
  • 定位总览:生成 tile_locator_map.jpg,在完整画布上显示所有编号。
  • 接缝平衡调色:测量相邻图块边缘的颜色差异,全局求解每块 RGB 偏移量,施加小幅校正后宽羽化拼合。
  • 低频颜色场校正:用缩略图估算平滑的颜色漂移场,放大后逐块在全分辨率上应用,消除大面积明暗/色温不均,不损失细节。
  • 补色边裁切:拼合时可选裁掉切分时添加的右/下补色边,输出尺寸还原为母版原图尺寸。
  • 拼合模式:
    • 局部试拼:只拼回指定或已回传图块的最小局部区域。
    • 回填整图:把已有图块放回完整画布,其他区域留空。
    • 完整拼合:要求所有图块存在,缺块时报错。

调色与拼合技术路线

问题

大图切成 48 块后,每块独立用 AI 修复,回来时每块都有自己的低频色彩漂移:有的偏亮、有的偏暖、有的偏灰。只做边缘羽化能软化接缝,但解决不了整块的色偏——拼出来还是一块深一块浅。

解决方案:两层处理

第一层:接缝平衡(块级 RGB 偏移)

不再试图让每块图各自调到完美,而是在拼合阶段建立"块与块之间的颜色约束网络",求出每个图块应当做多少小幅整体偏移。

算法步骤:

  1. 读取所有图块,按行列找到相邻关系。
  2. 对每一对相邻块,取共享边缘的 20px 条带(上下各留 80px 避开角落和补色边),算每条边缘的 RGB 中位数。
  3. 相邻边缘的色差变成一个约束:bias_左 - bias_右 ≈ 右边缘均值 - 左边缘均值。
  4. 所有约束组成一个线性方程组,用最小二乘法 + 正则化求解(正则化把 bias 往 0 拉,只调必要的量)。
  5. 把每块的偏移限制在 ±max_bias(默认 ±18 色阶)以内,防止过度校正。
  6. 对每块施加偏移:图块 = 图块 + 偏移。

为什么有效:

  • 这是全局求解,不是局部修补——整张网格一次性平衡。
  • 每块只加一个统一的小偏移,相同像素值无论在哪块都映射到同一输出 → 边界天然连续。
  • 正则化保证保守:regularize = 0.35 意思是"只调边缘实际需要的量"。
  • 最大偏移限制防止任何块被推到不自然的颜色。

第二层:低频颜色场校正

接缝平衡解决了相邻块边缘的跳变。但如果整张图左上偏暗、右下偏亮(跨多块的缓变),接缝平衡解决不了——这是低频问题。

算法步骤:

  1. 用缩略图(600px 宽)快速拼一个小图。
  2. 转 LAB 色彩空间。
  3. 做大半径高斯模糊(半径约为缩略图宽度的 1/4),提取低频漂移场。自动模式对 L 通道使用完整强度,对 A/B 色温通道只使用 35% 强度;仅明度模式不改 A/B。
  4. 算模糊场的全局均值。
  5. 校正场 = 模糊场 - 全局均值。
  6. 把校正场放大到全尺寸(校正场是平滑的,放大不丢信息)。
  7. 对每块全分辨率原图,取对应区域的校正场,在 LAB 空间减掉。
  8. 转回 RGB。

为什么不损失细节:

  • 校正场是平滑的低频场——只包含缓慢的明暗/色温漂移,不包含图像内容。
  • 把平滑场放大到全尺寸是无损的(没有高频细节会丢失)。
  • 校正施加在全分辨率原图块上,不是施加在放大后的图上。壁画的笔触、纹理、细节全部保留在原始分辨率。
  • 界面只保留「自动 / 仅明度 / 关闭」3 种模式。默认使用自动模式,避免把局部色温过度抹平。
  • 「减少黄底」会把低彩度墙底、纸底拉回校色前的全局底色;OKLab 软蒙版会保护彩度较高的红、绿、青等颜料。

拼合

颜色校正后,图块用加权羽化混合拼合:

  • 每块生成羽化权重图:中心权重高,边缘逐渐降低。
  • 相邻块的边缘通过加权平均混合:结果 = sum(图块 × 权重) / sum(权重)。
  • 接缝平衡模式默认羽化 80px(比 20px 的实际重叠区更宽),过渡更平滑。

这比简单的覆盖粘贴更稳,后者会产生硬接缝。

量化效果

在一个 48 块的壁画上(4 行 × 12 列,24162 × 7051 像素):

指标 校正前 接缝平衡后 降幅
平均接缝色差 6.47 2.54 -61%
P90 接缝色差 15.03 5.37 -64%
最大接缝色差 36.00 11.67 -68%

图像清晰度(拉普拉斯方差)与未校正基准差异 <2%,无细节损失。

优势

  1. 不需要参考图 — 算法直接从图块间的边缘关系推导,无需手动指定"标准块"或色卡。
  2. 确定性算法,非 AI — 结果可复现,无随机性,不依赖模型。
  3. 设计上保守 — 正则化 + 最大偏移限制,只改必要的部分。已经和邻居匹配的块几乎不动。
  4. 支持超大图 — 低频校正用 600px 缩略图估算,全分辨率应用,内存开销可控。
  5. 不损失细节 — 校正量是平滑的低频场,在全分辨率图块上应用,笔触、纹理、细节完全保留。

推荐流程

  1. 先用外部图像软件处理/缩放大图母版。
  2. 本地启动相柳网格。
  3. 选择已处理好的母版图。
  4. 预览编号、网格和右/下白边。
  5. 开始切分。
  6. 团队按编号并行修复图块(每人/AI 独立处理各自的块)。
  7. 拼合时选接缝平衡(默认)+ 可选低频颜色场校正 + 裁掉补色边,输出最终整图。

裁切规则

默认规则:

切块尺寸:2048 x 2048
重叠区域:20px
步长:2048 - 20 = 2028px

横向相邻块:

第 1 块:x = 0..2047
第 2 块:x = 2028..4075
重叠区:x = 2028..2047,正好 20px

纵向同理。

本地运行

双击:

xiangliu-grid\run_xiangliu_grid.bat

或在 PowerShell 中运行:

.\xiangliu-grid\run_xiangliu_grid.ps1

然后打开:

http://127.0.0.1:8765

输出文件

切分后,工具会创建:

outputs/<任务名>/tiles/
outputs/<任务名>/tiles_manifest.csv
outputs/<任务名>/tiles_manifest.json
outputs/<任务名>/tile_locator_map.jpg

图块文件名示例:

R01_C01_x0_y0_v001.png

注意事项

  • 大图建议使用"选择原图",拖拽会复制文件到工具目录。
  • 工具不缩放像素,缩放请在导入前完成。
  • 当母版尺寸不是步长整数倍时,右侧和底部出现补空是正常现象。
  • 修复后的文件名请保留 Rxx_Cxx 编号,方便准确回拼。
  • 接缝平衡建议配合"裁掉补色边"使用,避免补色区干扰颜色统计。

更新日志

v0.5.1

  • 简化低频控制:界面改为「自动 / 仅明度 / 关闭」。自动模式完整校正低频明度,只使用 35% 强度校正色温。
  • 选择性减少黄底:新增 0~100% 滑杆,把低彩度暖色背景拉回输入图块的全局底色,同时保护彩度较高的颜料色。
  • 修复发黄:标准色谱上色不再把红变成土黄。
    • apply_palette_profile:色相最多 ±10° 有界微调(原为硬拉到族色相),彩度缩放上限降到 1.35,近中性像素几乎不动。
    • recolor_tile: 18 色网格矫正(按你的设计意图:源色相分族 + 明度分档 → 把原图颜色矫正到色卡浅/基准/深对应档位,如浅红→浅陶红、中红→基准赭红、深红→深栗红)。明度来自灰阶归一化,色相/彩度向色卡档位矫正;勾选 preserve_local_hue 时色相有界矫正且中间色(青/紫等)按距离衰减保留(不硬压缩),取消勾选则强拉到色卡档位(强统一色相接缝)。saturation_gain 默认 1.0,去掉 min_chroma 垫底,暗部彩度加成从 +10% 降到 +3%。
  • 色卡白平衡:build_palette_profile 从参考图彩度最低的像素估计全局色偏并扣除,标准图本身偏黄也不会导出偏黄的色卡;记入 profile 的 cast,可开关。
  • 三档明度:每个色族保留 浅/基准/深 levels,上色时按像素明度插值目标彩度,不再用单一中位数。
  • 色卡多格式读取:load_palette_profile 支持(1)工具生成格式、(2)结构化色卡 {cave, period, colors:[{family, level, name, hex}]}、(3)简单 swatches 列表 {swatches:[{name, rgb|hex}]};白/黑/灰自动不进有彩色色族。
  • 一键校准(两阶段流水线):palette_family 模式即两阶段——第一阶段对全部图块 去色 → 联合灰阶/墨线归一化(消除块间明度差)→ 18 色网格矫正(按色卡浅/基准/深档位矫正);第二阶段 palette_residual 接缝平衡 + 可选低频颜色场校正 → 羽化拼合 → 裁补色边。无需选择图块;旧的单阶段逐块 apply 与独立"实验模式"复选框已移除。默认参数:迁移强度 0.9、墨线明度 0.55、墨线外扩 1px;未给色卡时自动用 manifest 源图。色卡预览图现在包含白/黑中性色共 18 色,颜色对比图的 reference 直接显示色板。
  • 前端面板重排:按编号分区(① 色卡来源 / ② 一键校准 / ③ 高级参数 / ④ 其他设置)。
  • 修复色卡预览崩溃:预览图改用中文字体(失败回退默认),不再因中文色名报 latin-1 错误。

v0.4.1

  • 修复低频校正:改为逐块在全分辨率上应用,不再因放大导致模糊。
  • 低频校正改为在拼合前执行,而非拼合后。

v0.4.0

  • 新增接缝平衡调色模式:从相邻边缘色差全局求解每块 RGB 偏移。
  • 新增低频颜色场校正:消除大面积明暗/色温漂移。
  • 新增补色边裁切:输出尺寸还原为母版原图尺寸。
  • 三档强度预设:轻度(max_bias=10)、标准(18)、强力(24)。

v0.3.x

  • 四边羽化遮罩(numpy 实现,端点精确 0→255 渐变)。
  • 加权混合替代顺序粘贴。
  • 补色边裁切,输出原图尺寸。

开源协议与品牌

源代码使用 MIT License 发布。

Xiangliu Grid / 相柳网格 的名称、项目 logo 和视觉识别保留为项目作者的品牌资产,不随 MIT 协议授予商标或品牌使用权。

About

把两万像素宽的壁画扫描图切成带编号的方图块,修完拼回去,接缝处做颜色校正。

Topics

Resources

Stars

0 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages