File size: 4,942 Bytes
831819e | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 | import { esc, external, section, table, tier, thumbnail } from "./ui.js";
const methodTiers = {
scan: "S1",
marker: "S2",
rgbd: "S3",
mvkp: "S4",
device: "-",
synth: "SY",
manual2d: "-",
pseudo: "S5",
};
export function methodsView(context) {
return `<section class="view"><header class="page-heading"><h1>标注方法</h1></header><nav class="section-tabs" aria-label="标注方法">${context.data.meta.methods.map((m) => `<a href="#methods/${m.id}">${esc(m.short)}</a>`).join("")}</nav>
${context.data.meta.methods
.map((method) => {
const datasets = context.data.datasets.filter(
(d) => d.method === method.id,
);
return `<article class="method-section section" id="method-${method.id}"><header class="section-heading"><h2>${esc(method.name)}</h2>${tier(methodTiers[method.id], context.meta)}</header><ol class="flow">${method.steps.map((s) => `<li>${esc(s)}</li>`).join("")}</ol><dl class="facts"><div><dt>可信度</dt><dd>${esc(method.trust)}</dd></div><div><dt>常见问题</dt><dd>${esc(method.issues)}</dd></div><div><dt>SOMA路线</dt><dd><a href="#soma">${esc(method.route)}</a></dd></div></dl><div class="dataset-links">${datasets.map((d) => `<a href="#ds-${d.id}">${esc(d.name)}</a>`).join("")}</div></article>`;
})
.join("")}</section>`;
}
export function somaView(context) {
return `<section class="view"><header class="page-heading"><h1>SOMA转换</h1></header>
<p class="intro">原始标注、拓扑映射、SOMA原生拟合与训练监督分别记录。EgoRenderer的辅助拟合不参与渲染。</p>
<ol class="pipeline-steps"><li><b>原始标注</b><span>扫描、MANO、SMPL-X、MHR、关键点</span></li><li><b>拓扑与关节对应</b><span>SOMAHandLayer后端或显式对应表</span></li><li><b>原生参数拟合</b><span>Identity、pose与逐帧残差</span></li><li><b>训练监督</b><span>按真值来源区分shape、pose与弱监督</span></li></ol>
<div class="conversion-list">${context.data.meta.routes.map((route) => `<article id="route-${route.id}" class="conversion-row"><header><span class="mono route-id">${route.id}</span><h2>${esc(route.name)}</h2></header><p>${esc(route.how)}</p><div class="conversion-meta"><span>${route.shape ? "可监督shape" : "不监督shape"}</span><a href="#catalog?route=${route.id}">${context.data.datasets.filter((d) => d.route === route.id).length} 个数据集</a></div></article>`).join("")}</div>
${section("监督边界", `<ul class="body-list"><li>MANO 21点的指尖是网格顶点;与SOMA关节定义不完全相同,关键点监督须保留对应表。</li><li>只有明确的扫描、逐人标定、深度约束或合成来源用于shape监督。伪标签不能当成shape真值。</li><li>单目shape与尺度耦合,标准姿态顶点误差与骨长误差应分别记录。</li><li>映射到SOMA拓扑不等于已得到SOMA原生identity与pose;仍需原生拟合和残差记录。</li></ul>`)}
${section("参考", `<div class="link-list">${external("SOMA-X", "https://github.com/NVlabs/SOMA-X")}${external("SOMA论文", "https://arxiv.org/abs/2603.16858")}${external("SAM 3D Body", "https://arxiv.org/abs/2602.15989")}</div>`)}</section>`;
}
export function samplesView(context) {
const datasets = context.data.datasets
.slice()
.sort((a, b) => a.name.localeCompare(b.name));
const count = Object.values(context.previews).reduce(
(total, list) => total + list.length,
0,
);
const withPreview = datasets.filter((d) => context.previews[d.id]?.length);
return `<section class="view"><header class="page-heading"><h1>样例</h1><span class="muted">${count} 组 · ${withPreview.length} 个数据集</span></header>
<div class="sample-grid">${withPreview.map((dataset) => `<a class="sample-tile" href="#ds-${dataset.id}">${thumbnail(dataset, context)}<div><h2>${esc(dataset.name)}</h2><span>${context.previews[dataset.id].length} 组${context.videos[dataset.id]?.length ? ` · ${context.videos[dataset.id].length} 段视频` : ""}</span></div></a>`).join("")}</div>
<details class="reference-details"><summary>素材覆盖与抽样</summary><p>${esc(context.sampling.strategy)} ${esc(context.sampling.dimensions_note)} ${esc(context.sampling.scope)}</p><div class="link-list">${external("抽样记录", "data/sampling.json")}${external("素材来源", "data/preview_sources.json")}</div>
${table(
["数据集", "展示 / 素材池", "主分类", "视频", "官方图"],
datasets.map((d) => {
const sample = context.sampling.datasets?.[d.id];
return `<tr><td><a href="#ds-${d.id}">${esc(d.name)}</a></td><td class="mono">${sample ? `${sample.selected} / ${sample.pool}` : "未取得"}</td><td>${esc(sample?.primary_dimension || "—")}</td><td>${context.videos[d.id]?.length || 0}</td><td>${context.figures[d.id]?.figures?.length || 0}</td></tr>`;
}),
)}</details></section>`;
}
|