Skip to content

Releases: wahonet/WSC3D

v0.9.0

Choose a tag to compare

@wahonet wahonet released this 01 Jul 10:41

v0.9.0 — 数据可信度加固

v0.8.0 之前一直在加功能,到这一版功能链基本齐了。v0.9.0 不再扩功能,回头把"数据可信度"和"工程地基"做扎实:每条标注能不能进训练池、为什么不能、怎么一键修;AI 兜底产出的候选不再混在真神经网络置信度里;纯函数有了回归网,不会再改个小地方就出隐蔽 bug。

一句话:从"功能验证型"转向"数据质量型"。

完整发布说明:https://github.com/wahonet/WSC3D/blob/main/docs/RELEASE_NOTES_v0.9.0.md
逐步工作日志:https://github.com/wahonet/WSC3D/blob/main/docs/WORK_LOG_v0.9_reinforcement_2026-07-01.md

修复

  • import-md 不再静默失效:/api/iiml/:stoneId/import-md(从结构化档案导入标注)之前因为 catalog 不再解析 Markdown,导入 0 条却不报错;现在直接解析档案,找不到时明确抛 metadata_not_found。

改进

  • 训练就绪度面板:编辑任意标注,顶部实时显示"能否进训练池 / 卡在哪一项 / 一键修复",标注时就能修,不用等导出才发现大批失败。
  • 列表批量修复:多选标注后批量设类别 / 审核状态 / 质量 / 训练角色。SAM 一批产出 20 条 candidate,几下就升成可训练状态。
  • AI fallback 显式分级:SAM/YOLO 兜底的轮廓候选显式标 weak + fallback 徽章,不再用假置信度(0.62)混在真神经网络候选里,避免污染训练集。
  • SAM image embedding 缓存:同一块石头多次 prompt 只算一次 embedding,批量标注明显变快。
  • 对齐重投影误差反馈(保存 4 点对齐时状态条显示残差)。
  • catalog 自动失效:加新模型自动重建列表,不再需要手动 POST /api/scan/refresh。

工程地基

  • 单元测试底盘:之前零测试。这一版用 node:test + tsx(零新依赖)加了 63 个用例,覆盖训练池准入 11 项约束、4 点单应性矩阵 roundtrip、COCO 70/15/15 划分的防泄漏不变量、IIML frame 迁移、SAM3 概念词映射。
  • 依赖分层:requirements.txt 默认 CPU(MobileSAM 本就跑 CPU),GPU 用户换 requirements-cu128.txt 给 SAM3 提速;消除了 requirements / pyproject 长期的版本矛盾。
  • cloneDoc → 原生 structuredClone;App.tsx 抽出 SAM3 概念词映射纯函数;修了 main.py 端口注释笔误。

文档与许可

  • 采用 木兰宽松许可证第2版(MulanPSL-2.0),详见 LICENSE。
  • README 重写:口语化,每个模块(浏览 / 拼接 / 标注)讲清功能、作用和实现方式。
  • 新增 v0.9.0 发布说明与工作日志;归档了内部过程文档(ROADMAP / THINKING / 旧 worklog 等)。

验证

npm run typecheck 通过 · npm test 63/63 全绿 · Python py_compile 通过

WSC3D v0.8.0

Choose a tag to compare

@wahonet wahonet released this 04 May 15:55

WSC3D v0.8.0 — 图谱 UI 修缮 · 资源独立 tab · 三维生成正射图 · 多资源画布切换 · 跨资源坐标变换 · .hpsml 解包 · 正射图 1:1 对齐与跨资源 SAM/YOLO(J 补丁)

发布日期:2026-05-04
对应计划:v0.7.0 验收反馈修缮 + v0.8.0 M4 多资源架构落地
上一发布:v0.7.0 — 紧急修复 · 图谱完善 · 多解释 UI · AI 加深 · 多资源 · .hpsml 包

v0.7.0 浏览器端验收那轮的反馈集中在图谱 UI 挤、"资源"应该独立 tab、以及
没有原图 / 拓片时想用三维模型生成一张正射图当底图。把这波修掉后,顺势把
v0.8.0 规划的 M4 多资源架构三条线也落了地:多资源画布切换、跨资源
坐标变换(数据模型)
、.hpsml 研究包解包导入。

这一版的核心是:这块画像石除了三维模型和 pic/ 下的原图之外,现在也能用
自己生成的正射图、手工注册的拓片 / 法线图 / RTI / 点云作为底图来标注
,
还能把别人(别的研究者 / 别的机器)导出的 .hpsml 一键导进来。

工作日志:WORK_LOG_post_v0.7.0.md。


1. 图谱 UI 修缮(H1)

v0.7.0 的图谱 tab 被反馈:4 行 chip(布局 / 着色 / 中心性 / 类别)字太大挤换行;
PageRank 写英文没看懂;右侧 230px 排行榜侧栏把 canvas 挤窄。

这一版的调整:

  • 中心性算法中文化:权威度(PageRank)/ 邻居数(Degree)/ 桥梁度(Betweenness)
    / 接近度(Closeness)。PageRank 不再露英文;hint 补 "Google PageRank 同款算法"
  • chip 行 4 → 2:第一行 "布局 + 着色 + 中心";第二行 "中心性 + 类别 + 来源"。
    每段之间加 .knowledge-graph-filter-divider 细竖线视觉分组
  • 排行榜从侧栏挪到下方:.knowledge-graph-stage 改 flex-direction: column,
    canvas 占整行 min-height: 380px;排行榜改横向滚动卡片(每张 172px)
  • 群组规模 chip 并入排行榜 head:不再占独立区块;head 加 shortHintFor(kind)
    简短提示(如 "被高权重邻居指向 → 综合权威")
  • 整体字号统一缩小:chip 从 11.5 → 10.5px,padding 缩;.knowledge-graph-tab
    min-height 360 → 520px 让 canvas 更舒展

2. 资源独立 tab + 三维模型生成正射图(H2 + H3)

2.1 "资源" tab

AnnotationPanel.TabKey 加 "resources"(Layers 图标 + 中文"资源")。
原本嵌在 ListTab 顶部的 ResourcesEditor 移到这个新 tab 下,可以占满面板高度。

2.2 ResourcesEditor 重写:3 个 section

  1. 从三维模型生成正射图:4 个方向 chip(正面 / 背面 / 顶面 / 底面)+
    "生成正射图"按钮
  2. IIML 资源条目:列出 doc.resources[],每条支持预览图像(160px max-height
    object-fit: contain)/ 删除 / 新标签页打开
  3. 后端已落盘:列出 data/stone-resources/{stoneId}/ 下实际文件;未关联
    的一键"关联"到 IIML resources[]

2.3 正射图生成管线

前端 frontend/src/modules/annotation/orthophoto.ts(新建):

  • 独立 offscreen Three.js 渲染器:WebGLRenderer + document.createElement("canvas")
  • GLTFLoader 加载模型 → 算 AABB → OrthographicCamera frustum 正好裹住模型 + 5% 留白
  • 4 种视图方向(front / back / top / bottom)
  • 光照:AmbientLight 0.75 + DirectionalLight 1.0 斜上 45°(拓片摄影棚单灯效果)
  • 背景 3 档:light(近拓片纸色 #efe7d8,默认)/ dark / transparent
  • 输出 PNG blob + 像素尺寸 + 模型 AABB 尺寸 + frustumScale + view
  • 所有 Three.js 资源在 finally 里 dispose + forceContextLoss() 防 WebGL context 泄漏

后端 backend/src/server.ts:

  • GET /api/stones/:id/resources:列出 data/stone-resources/{stoneId}/ 下所有
    落盘图像
  • POST /api/stones/:id/resources:接收 PNG(Content-Type: image/png 原始二进制
    或 JSON { type, imageBase64 }),落盘为 {type}-{timestamp}.png
  • 静态托管 /assets/stone-resources/
  • body size 25MB(3072px 长边 PNG 大约 5-10MB)

生成后自动:generateOrthoImage → uploadStoneResource → onAddResource 加进
IIML → refreshServerResources 刷新后端列表。


3. 多资源画布切换(I1)

SourceImageView 新增 imageUrl?: string props:默认走 /ai/source-image/{stoneId}
(pic/ 原图),传了就用它(任意 doc.resources 里的 image 类资源 URI)。

AnnotationWorkspace 新增"资源切换" segmented UI,高清图模式下显示在
source-switch 与 layer-switch 之间:

  • 默认"原图"(pic/ 走 /ai/source-image/)
  • doc.resources[] 里 Orthophoto / Rubbing / NormalMap / LineDrawing /
    OriginalImage / RTI / Other 类型的资源都会自动列成 chip
  • chip 文案按类型 + 方向生成("正射·正" / "拓片" / "法线" / ...)
  • 切到非 pic/ 资源时强制禁用 Canny 线图叠加(后端 canny 管线只处理 pic/ 原图)

使用场景:生成正射图后切到"正射·正"底图,在上面继续标注;或手工注册
外部拓片 URI 后切到"拓片"底图做对照研究。


4. 跨资源坐标变换(I2)

数据模型层先行,为 v0.9.0 的画布跨资源投影做准备。

types.ts 新增 IimlResourceTransform 联合类型:

type IimlResourceTransform =
  | {
      kind: "orthographic-from-model";
      view: "front" | "back" | "top" | "bottom";
      modelAABB: { width: number; height: number; depth: number };
      pixelSize: { width: number; height: number };
      frustumScale: number;
      generatedAt?: string;
    }
  | {
      kind: "homography-4pt";
      controlPoints: Array<{ model: [number, number]; image: [number, number] }>;
      referenceResourceId?: string;
    }
  | {
      kind: "affine-matrix";
      matrix: number[];
      referenceResourceId?: string;
    };

IimlResourceEntry.transform 字段可选保存变换。

正射图生成时自动填入 transform: { kind: "orthographic-from-model", view, modelAABB, pixelSize, frustumScale }。这样 modelBox UV ↔ 正射图 UV 就有了
精确可算的对应关系。

ResourcesEditor 卡片上新增 .resources-item-transform 金绿色提示条,显示
"正射投影 · 正面 · AABB W×H · frustum 1.05× · 像素 W×H"。

画布投影实装留 v0.9.0:v0.8.0 只把跨资源元数据铺好,画布渲染时暂仍按
原 frame 显示(不做跨资源投影),避免引入画布层 bug 影响主流程稳定性。


5. .hpsml 解包导入(I3)

backend/src/services/hpsml.ts 新建 importHpsmlPackage(root, config, getCatalog, payload, options):

  • 校验:format === "hpsml" + formatVersion(不同版本告警继续尝试)
  • 解 stoneId 优先级:options.stoneId > context.stone.id >
    iiml.documentId 的前缀({stoneId}:iiml)
  • IIML 主体:直接走 saveIimlDoc(完整 ajv 校验,写入
    data/iiml/{stoneId}.iiml.json)
  • 拼接方案:写入 data/assembly-plans/;冲突时生成新 id +
    importedFromHpsml: true 标记
  • 冲突策略 options.conflictStrategy:
    • "overwrite"(默认):直接覆盖本机已有
    • "skip":若本机已存在则跳过 IIML 部分

后端端点:POST /api/hpsml/import?stoneId=...&conflict=overwrite|skip
(body = 完整 .hpsml JSON)

前端:

  • client.ts 加 importHpsmlPackage(payload, options) + HpsmlImportSummary 类型
  • AnnotationPanel ListTab 下载区加"导入 .hpsml"按钮
  • App.handleImportHpsml:用隐藏 <input type="file" accept=".json,.hpsml">
    触发文件选择,解析 JSON 后调 API;若导入的是当前 stoneId,自动重新拉 IIML
    让画布刷新

返回 summary:

{
  "stoneId": "asset-29",
  "imported": {
    "iiml": true,
    "annotations": 42,
    "relations": 18,
    "processingRuns": 6,
    "resources": 3,
    "assemblyPlans": 2
  },
  "skipped": { "iiml": false, "assemblyPlans": 0 },
  "warnings": []
}

6. commit 时间线

8cb7236 feat(annotation+backend): I1+I2+I3 多资源画布切换 + 跨资源坐标变换 + .hpsml 解包导入
8fb2583 feat(annotation+backend): H1+H2+H3 图谱 UI + 资源 tab 独立 + 三维模型生成正射图
ea995dc docs(v0.7.0): release notes + README + ROADMAP + 工作日志收尾

H 和 I 共 2 次 feat commit + 1 次 docs 收尾 commit(v0.7.0 → v0.8.0 共 3 次)。


7. 数据兼容

  • 历史 IIML 文档没 resources[*].transform 字段:按 undefined 处理,UI 容错显示
  • 历史 IIML 文档没 resources[*].type === "Orthophoto":跨资源切换 UI 只显示
    已存在的类型,不影响主流程
  • .hpsml v0.1.0 formatVersion:导入时校验;未来 formatVersion 变化时先告警
    再尝试兼容导入
  • data/stone-resources/{stoneId}/ 目录不入库(.gitignore 已有 data/ 但
    该子目录按需建立;多机协作时通过 .hpsml 包或单独 rsync)

8. 验收要点

进标注模式后依次试:

  1. 图谱 UI:图谱 tab → 布局 / 着色 / 中心 chip 一行完整显示不换行;
    中心性下方是 "权威度 / 邻居数 / 桥梁度 / 接近度";canvas 占整行变大;
    排行榜在 canvas 下方横向滚动
  2. 资源 tab:右侧 panel 应有 "资源" tab,点开看到 3 个 section
  3. 生成正射图:资源 tab → 选 "正面" → 点 "生成正射图" → 等 3-8 秒 →
    IIML 资源条目区应新增一条 Orthophoto,缩略图显示生成的正射图;卡片下方
    应有金绿色 "坐标变换 · 正射投影 · 正面 · AABB ... · frustum 1.05× · 像素 ..."
    提示条
  4. 多资源画布切换:标注模式 → 切到高清图 → canvas 右上角 source-switch
    下方应出现 "底图 原图 正射·正" 的资源切换条 → 点 "正射·正" → 画布显示
    正射图;+线图 按钮自动置灰
  5. .hpsml 导入:先从 v0.7.0 导出的 .hpsml 文件 → 列表 tab 下载区点 "导入
    .hpsml" → 选文件 → status 显示 "已导入 .hpsml(stoneId=xxx):IIML 写入、
    标注 N / 关系 N / 拼接方案 N" → 若是当前画像石,画布自动刷新
  6. 后端已落盘刷新:资源 tab 第 3 个 section 应列出生成过的正射图文件;
    点 "刷新" 应扫描 data/stone-resources/{stoneId}/ 重新列出

9. J 补丁:正射图 1:1 对齐 + 跨资源 SAM / YOLO

收到用户反馈"生成的正射还有白边、SAM / YOLO 只能跑 pic/、正射和 3D 模型标注
不同步"之后在当天补的 J 补丁。核心思路是让正射图从生成开始就严格对齐 3D
模型 AABB
,这样正射图 UV 数值上等于 modelBox UV,跨资源标注同步不需要再做
数学变换。

9.1 正射图 frustumScale 1.05 → 1.0

  • frontend/src/modules/annotation/orthophoto.ts:生成 frustum 从"AABB × 1.05
    留白"改为"严格贴 AABB"。生成的 PNG 紧贴模型边缘,没有白边
  • 返回值增加 equivalentToModel: boolean;view=front + frustumScale=1.0 满足
    时为 true,表示该正射图图像 UV 与 modelBox UV 完全 1:1 对应
  • IimlResourceTransform.orthographic-from-model 也加 equivalentToModel?: boolean
    字段跟随持久化;老数据(没有该字段)通过 view=front + |frustumScale-1|<1e-3
    的兜底判据也能识别为等价

9.2 SAM / YOLO 后端接 imageUri

  • ai-service/app/sam.py:新增 sam_segment_by_uri(uri, prompts_uv)。URI 解析
    支持 /assets/stone-resources/... → <repo>/data/stone-resources/... 本地
    路径反解;不走 HTTP,不依赖 backend 在线
  • ai-service/app/yolo.py:对应加 yolo_detect_by_uri(uri, ...)
  • ai-service/app/main.py:SamRequest / YoloRequest schema 加 imageUri
    字段;路由优先级 imageUri > stoneId > imageBase64
  • 这条新路径的坐标系是"图像 UV";当图像 UV 与 modelBox UV 等价时,前端直接
    当 model frame 坐标用,不需要额外变换

9.3 前端 AI 调用随资源走

  • frontend/src/api/client.ts:runSamSegmentationBySource / runYoloDetection
    参数加 imageUri?: string;SAM 路径要求 imageUri 或 stoneId 至少给一个
  • frontend/src/modules/annotation/sam.ts:refineBBoxWithSam 和
    requestSamCandidateWithSource 加 imageUri 参数;传了就走 imageUri 分支
  • frontend/src/modules/annotation/AnnotationCanvas.tsx:新增 activeImageUri
    prop;SAM 手动 prompt 提交时透传过去
  • frontend/src/modules/annotation/AnnotationWorkspace.tsx:新增
    onActiveImageResourceChange 回调,把当前底图资源(id / uri / type /
    equivalentToModel)告诉 App 层,让 YOLO 批量扫描 / SAM 精修都能拿到正确的
    imageUri
  • frontend/src/App.tsx:
    • handleSubmitYoloScan 读 activeImageResource.uri 作为 YOLO 输入;候选
      frame 按 equivalentToModel 决定(等价时记 model,否则跟随 sourceMode)
    • handleRefineWithSam 从 annotation.resourceId 反查资源 URI,在原资源上
      跑 SAM 精修,不错位到 pic/

9.4 跨资源标注自动同步(等价正射图)

  • AnnotationWorkspace 新增派生状态 activeResourceEquivalentToModel
    (transform.equivalentToModel === true 或 view=front + frustumScale≈1)
  • effectiveSourceMode = sourceMode === "image" && activeResourceEquivalentToModel ? "model" : sourceMode:在等价正射图上,画布按 model 坐标系处理
  • 传给 AnnotationCanvas 的 sourceMode 用 effectiveSourceMode → 在等价正射图
    上新建的标注 frame="model",3D 模型视图自动能看到;反过来 model frame 的
    历史标注也直接在等价正射图上显示
  • UI 额外提示:等价正射图顶部有一枚绿色徽章"此图与 3D 模型坐标系已对齐 ·
    标注自动双向同步"(.annotation-resource-aligned-hint 样式)
  • 非等价资源(top/bottom/back 方向、或 frustumScale 不是 1.0 的老数据)仍按
    image frame 处理,用户可走已有的 4 点单应性标定跨 frame 投影;这部分的
    自动反投影留 v0.9.0
    (画布层按 resource.transform 投影任意资源坐标)

9.5 验收

  • 生成正射图:图像紧贴模型 AABB,无白边
  • 在等价正射图底图上 SAM 框选 → 候选直接出现在 3D 模型视图上(切回 3D 模型
    模式可见)
  • ...
Read more

WSC3D v0.2.1

Choose a tag to compare

@wahonet wahonet released this 03 May 09:40

WSC3D v0.2.1 — 拼接模块多石拖动修复

发布日期:2026-05-03
Tag:v0.2.1

修复加入第二块画像石后,第一块 gizmo 错位、轴箭头无法响应拖动,仅中心
黄色 plane handle 表面上"还能用"的问题。

修复

  • gizmo 不再随每次加石头被重置:fitAssemblyCamera 现在只在首次
    加载石头时跑一次。之后加新石头会保留当前用户视角,避免相机突然平移
    到合并包围盒中心,造成"屏幕中央不再对齐 gizmo 中心"的错位陷阱。
  • dragging 中不再回灌 transform:新增 isDraggingRef,避免 React
    state 同步对正在被拖动的对象做 applyTransform,消除潜在抖动 / 位移
    反弹。
  • 新石头落点更友好:偏移改为基于"上一块的 X + 半宽估算",新加
    画像石紧邻已有石头序列右侧,避免落点离视野太远。

提示

  • 想一次性把全部石头框进视野,左侧工具栏有「重置视角」按钮(圆环箭头),
    手动 fit。
  • 若旧拼接方案是在错位状态下累计保存的,加载后可在面板里选中对应石块,
    重新使用 gizmo 或微调按钮校准。

详细发布记录见 git log v0.2.0..v0.2.1。

WSC3D v0.2.0

Choose a tag to compare

@wahonet wahonet released this 03 May 09:04

WSC3D v0.2.0 — 标注模块

发布日期:2026-05-03
Tag:v0.2.0

本次发布将标注模块从「图层 + 标注」两层模型简化为「一标注一图层」模型,
并完善了浏览 / 拼接 / 标注三大模块的能力。

标注模块

  • 标注坐标改为 modelBox 归一化空间 (u, v) ∈ [0, 1]²,StoneViewer 暴露 4 角屏幕投影。
    用户在 2D 模式下平移 / 缩放视图时,所有标注会随相机自动跟随,无需手动调整。
  • 工具集精简为 选择 / 矩形 / 圆 · 椭圆 / 点 / 钢笔 五件,
    矩形与椭圆需拖动出尺寸(≥ 4 像素)才会创建,避免误点产生空标注。
  • 创建后自动切回选择工具并选中新建标注,进入"草稿"状态:
    • 右侧详情面板显示「标签 / 备注 / 确定 / 取消 / 删除」。
    • 草稿外的标注同样支持随时重命名、隐藏、锁定、删除。
  • 不再有独立的 Layer 概念。每条标注自带 color / visible / locked:
    • 锁定后,整体拖动与四角 handle 都不可用,相当于把这一条标注冻结。
    • 隐藏后画布上不再渲染该条标注。
  • 标注列表与详情合并到单一面板,去掉了原有的 tab 切换。

浏览 / 拼接

  • 浏览模式不再渲染标注覆盖层,标注内容仅在标注工作区可见、可编辑。
  • 浏览/拼接其余功能保持原状(视角骰子、测量、拼接方案保存等)。

数据兼容

  • 进入旧 IIML 文档时自动迁移:补齐每条标注的 visible / locked / color,剥离过时的 layers 字段。
  • 颜色按调色板循环分配,老用户首次保存后会失去图层名称信息,但标注本体不丢。

工程

  • 移除了原本未启用的 SAM / YOLO / Canny 入口与"导入档案骨架 / 导出 IIML"按钮,专注手工标注。
  • AI 子服务(ai-service/)保留接口,留待 M3 重新接入。
  • 完善 README.md 与
    docs/ROADMAP.md,
    明确当前能力与近 / 中 / 远期工作计划。

已知问题

  • 浏览 / 拼接模式下没有标注气泡叠加,将在 M2 加上。
  • 钢笔工具尚未支持贝塞尔控制柄。
  • 主 chunk > 1MB,按模块做动态 import 的代码分割留待 M2。

完整下一步计划见 docs/ROADMAP.md。

V0.3.0: feat(annotation): AI 标注闭环 · 多源底图 · 4 点对齐校准

Choose a tag to compare

@wahonet wahonet released this 03 May 20:09

WSC3D v0.3.0 — AI 标注闭环 · 多源底图 · 4 点对齐校准

发布日期:2026-05-04
对应计划:M3 第一波(见 ROADMAP.md 第 2 节)
上一发布:v0.2.2 — 标注模块 ICON 化与工程小修

本次发布是标注模块自 v0.2.0 重构以来最大的一次能力扩展,三件大事:

  1. AI 标注闭环可用:SAM 候选从"能出"升级到"能用",修了致命的坐标系翻转,
    引入了高清图直读路径,候选审阅支持多选合并;
  2. 多源底图:标注画布可以在 3D 模型 与 画像石高清原图 之间任意切换,
    高清图模式下 SAM 候选与显示天然对齐,识别精度大幅提升;
  3. 4 点单应性对齐校准:用户在两个底图各点 4 对对应点,标注就能在两个坐标系
    之间双向投影 —— 在图上画的标注切回 3D 模型也能看到,反之亦然。

同时把鼠标交互在两种底图上拉齐:滚轮缩放 + 中键 / 右键拖动,再无差异。


1. 标注模块 · AI 闭环

1.1 SAM 高清图路径修复(关键 bug)

旧高清图路径下 SAM 返回的 polygon 在画布上 上下颠倒。根因是前后端 v 轴方向
约定不一致:前端 screenToUV / uvToScreen 用 v 向下(与图像/屏幕坐标一致),
后端 _uv_to_pixel_prompt 与 _flip_polygon_to_uv 却假设 "modelBox v 向上",
入口 / 出口各做一次 y 翻转 —— 结果是点击点送到原图错处分割,分割结果又被反向
画回画布。

修复:删除后端两处 y 翻转,统一约定 "前后端 UV 都 v 向下"。前端注释和 API 文档
同步更正。

1.2 高清图直读端点

新增 GET /ai/source-image/{stone_id}:

  • 在 ai-service 里读 pic/ 下匹配 stone_id 数字前缀的 tif / png / jpg
  • PIL 解码后按长边 4096 LANCZOS 缩放,落盘缓存到 ai-service/cache/source/{n}_max{m}.png
  • 第二次访问直接命中缓存(毫秒级)
  • 原图 mtime 比缓存新会自动重新转码

意义:浏览器原生不支持 tif,又不可能把 178 MB 原图塞进 base64;这条路径让前端
可以 <img src="/ai/source-image/asset-29"> 直接渲染高清原图。

1.3 候选合并(polygon union)

引入 polygon-clipping(35 KB,专做 2D 多边形布尔运算)。在候选 / 列表两个 tab
都新增 checkbox 多选:

  • 选中 ≥ 2 个候选 → 顶部出现"合并选中(N)"按钮
  • 几何上对所有源 polygon 做 union,只保留外环(丢孔洞),满足"只要最外面的边缘"
    的诉求
  • 合并后的 reviewStatus 用"最保守原则":任一源是候选 → 结果是候选;否则跟随
    第一个源的状态(避免已 approved 的标注合并后被打回未审)
  • 跨 frame(model + image)选中会被拒绝并提示,避免坐标系混淆

针对 SAM 经常把人物身体识别成两片的场景效果显著 —— 选两片合并即得完整轮廓。

1.4 候选审阅小改

  • 候选卡片左上加 checkbox + is-selected 高亮
  • 列表 tab 也复用同一套合并工具条,已 approved 标注合并不再走候选审定流程

2. 标注模块 · 多源底图

2.1 高清图视图(SourceImageView)

  • 用 <img> + 自维护的 ViewState { scale, offsetX, offsetY } 渲染 PNG
  • 滚轮:以光标为中心缩放(fit×0.5 ~ fit×30)
  • 中键 / 右键拖动:平移
  • 父级 fitToken 递增(工具栏"重置视角"按钮):复位到 contain-fit 状态
  • 窗口尺寸变化时不强制重置 viewState,避免用户调好的视角被 ResizeObserver 弄丢
  • 始终向 AnnotationCanvas 输出当前 transform 后的 4 角 → 标注 UV 坐标系就是
    这张图自身的归一化坐标

2.2 工作区切换 UI

AnnotationWorkspace 持有 sourceMode: "model" | "image" 状态,画布右上角浮动
segmented 切换条;切到高清图时 StoneViewer 卸载、SourceImageView 挂载(共享
同一个 ScreenProjection 协议,AnnotationCanvas 不感知底图来源)。

第一次切到高清图模式有 1~3 秒解码 + 缓存写盘的等待,之后秒开。


3. 标注模块 · 4 点对齐校准

3.1 数据模型

  • IimlAnnotation 加可选 frame: "image" | "model",缺省视为 "model",向后兼容
  • IimlDocument.culturalObject.alignment 持久化标定结果:controlPoints[]
    存 4 对 { modelUv, imageUv };version / calibratedAt / calibratedBy 记录元信息
  • 后端 IIML schema 已经是 additionalProperties: true,新字段无破坏性落盘

3.2 几何核心(homography.ts)

  • solveHomography(src, dst):4 点 DLT 构造 8×8 线性方程组 + 高斯消元(带主元)
    求 3×3 单应性矩阵;选择 8 元(h[8]=1)而非 SVD —— 我们标定的是大致正向矩形,
    浏览器里写稳定 SVD 不划算
  • applyHomography(H, point):齐次坐标投影 + 归一化
  • invertMat3:3×3 求逆(adjugate / det)
  • buildAlignmentMatrices(alignment):从 IIML alignment 一步算出双向矩阵

3.3 跨 frame 渲染

AnnotationCanvas 收到 sourceMode + alignment,每条标注按 frame === sourceMode
决定渲染策略:

annotation.frame sourceMode alignment 渲染
与 sourceMode 同 — — 实色实线,可拖动 / 改尺寸
与 sourceMode 异 — 已校准 稀疏虚线 + 半透明(投影态),仅可点选
与 sourceMode 异 — 未校准 跳过;画布顶部居中提示"有 N 个标注未对齐"

跨 frame 标注暂不支持就地拖拽 / 改尺寸 —— 避免反向解算坐标的复杂度,用户切回
原 frame 编辑即可。

3.4 标定流程

工具栏新增 Crosshair 按钮(已校准时右下角青色圆点提示),点击进入"乒乓式"
4 对点采集:

  1. 自动切到 3D 模型,提示"在 3D 模型上点第 1/4 个特征点"
  2. 收满 4 个后自动切到高清图,让用户点对应位置
  3. 8 个点齐了进入 review,画布同时显示当前 frame 的 4 个橙色编号点 + 用现场
    解算的 H 把对面 frame 的点投影过来的青色虚化点 —— 重合度即标定精度
  4. 底部浮窗按钮:保存对齐 / 重新采集 / 撤销上一点 / 切到对面底图 / 取消

保存即写入 IIML 并随 doc 自动持久化。再次进入标定按钮即可重新校准。


4. 视图交互一致化

历史问题:标注画布在最上层(z-index: 15),原本只在 3D 模型模式下转发滚轮和
中键 pointerdown 给 OrbitControls;右键 pan 没接,高清图模式更是完全没有 pan/zoom。

本版统一:

  • findStoneCanvas 拆成 findViewportTarget(找 .three-stage canvas 或
    .source-image-stage)和 findStoneCanvas(仅给 SAM 截图回退用)
  • 滚轮、中键 + 右键 pointerdown 都转发到 findViewportTarget 的结果
  • 3D 模型模式:右键 pan 由 OrbitControls 默认 RIGHT=PAN 接住;OrbitControls
    会自动 preventDefault contextmenu,不弹菜单
  • 高清图模式:SourceImageView 自己实现 wheel + pointer 监听,pointer state 用
    ref(不依赖 pointerId 严格匹配,兼容 AnnotationCanvas 转发的合成 PointerEvent)

最终两种底图下行为完全一致:左键标注、滚轮缩放、中键 / 右键平移、中键画
contextmenu 不弹。


5. 工程

  • 新增依赖:polygon-clipping@^0.15.7(用于候选合并)
  • 新增前端文件:SourceImageView.tsx、homography.ts、merge.ts、sam.ts
  • ai-service 新增端点 /ai/source-image/{stone_id} + 缓存目录 ai-service/cache/
  • pic/、ai-service/cache/ 加入 .gitignore,源 tif 与转码 PNG 都不进版本库
  • typecheck + lint + 生产 build 全绿

6. 数据兼容

  • 历史标注没有 frame 字段:渲染时按 "model" 处理,与 3D 模型模式行为一致,
    老数据无感
  • 历史 doc 没有 alignment:跨 frame 标注直接跳过显示并提示,行为退化为
    "只显示当前 frame 的标注"

7. 已知限制

  • 跨 frame 标注暂不支持就地编辑(设计取舍,详见 §3.3);用户切回原 frame 即可
  • 单应性变换假设 4 点对应大致正向矩形且不严格共线;极端共线 / 退化情况下
    solveHomography 返回 undefined,跨 frame 渲染整体跳过 + 提示重新校准
  • 候选合并目前只取每个多边形的外环;带孔(甜甜圈形状)的合并候选孔洞会被
    自动填掉。汉画像石浮雕场景几乎不会有真"环形主体",不阻塞使用
  • pic/ 目录下当前只有 1 张高清图(29东汉武氏祠左石室后壁小龛西侧画像石.tif);
    其它画像石需要补齐高清原图后才能用高清图模式
  • 主 chunk 体积仍然 800+ KB(gzip 245 KB),引入 polygon-clipping 之后未做
    额外的 chunk 拆分

8. 验收要点

  1. SAM 候选不再上下颠倒:进标注模块 → 切到高清图 → 点 SAM 工具 → 点击图上
    任意人物,候选 polygon 应严格贴合所点的图案
  2. 高清图模式对齐:同 1,候选轮廓应精确贴合,不再有"识别得对但位置错"的
    现象
  3. 多选合并:候选 / 列表 tab 任一,勾选 ≥ 2 条多边形 → 顶部"合并选中"按钮
    亮起 → 点击 → 原条目消失、出现合并标注(label 为"SAM 合并候选"或"合并标注")
  4. 对齐校准:工具栏 Crosshair 按钮 → 在 3D 模型上点 4 个角 → 自动切到高清图
    再点 4 个对应角 → review 阶段切回 3D 模型,看到橙色 + 青色编号点重合度
    → 保存对齐 → 工具栏按钮右下出现青色小圆点(已校准标记)
  5. 跨 frame 显示:在高清图上画一个矩形 → 切回 3D 模型,应看到该矩形以稀疏
    虚线 + 半透明形态投影到 3D 视图上的对应位置(前提是已完成 §4 的对齐)
  6. 视图交互一致:3D 模型 / 高清图两个模式下分别测:滚轮缩放 / 中键拖动 /
    右键拖动;都应该顺滑、不弹右键菜单

9. 下一步

完整规划见 ROADMAP.md。简要:

  • M3 剩余:YOLO 候选检测、AI 线图(Canny / Relic2Contour)、多解释并存、
    标注间关系(IIML relations)、知识图谱可视化
  • M4:多资源版本切换(原图 / RTI / 拓片 / 线图)、IIIF / COCO / .hpsml 导出

本次 未自动打 git tag,等待 QA 验收后由用户决定是否打 v0.3.0 tag。