2026-05-24-23-24-34 支持自动匹配采样切片调节
This commit is contained in:
@@ -1044,6 +1044,7 @@ interface AutoMatchContext {
|
||||
volume: DicomHuVolume;
|
||||
metrics: ExportSceneMetrics;
|
||||
samples: Point3DRecord[];
|
||||
sampleSlices: number[];
|
||||
basePose: ModelPoseValue;
|
||||
weights: AutoMatchWeights;
|
||||
}
|
||||
@@ -1117,6 +1118,19 @@ function chooseAutoMatchSampleSlices(input: unknown, depth: number) {
|
||||
.sort((a, b) => a - b);
|
||||
}
|
||||
|
||||
function nearestAutoMatchSampleSlice(slice: number, sampleSlices: number[], tolerance = 1) {
|
||||
let nearest: number | null = null;
|
||||
let nearestDistance = Infinity;
|
||||
sampleSlices.forEach((candidate) => {
|
||||
const distance = Math.abs(candidate - slice);
|
||||
if (distance < nearestDistance) {
|
||||
nearest = candidate;
|
||||
nearestDistance = distance;
|
||||
}
|
||||
});
|
||||
return nearestDistance <= tolerance ? nearest : null;
|
||||
}
|
||||
|
||||
function collectAutoMatchPreviews(project: ProjectRecord) {
|
||||
return (project.stlFiles ?? []).reduce<Record<string, ModelPreviewRecord>>((accumulator, fileName) => {
|
||||
const filePath = getProjectModelFilePath(project, fileName);
|
||||
@@ -1207,14 +1221,18 @@ function evaluateAutoMatchPose(
|
||||
context.samples.forEach((sample) => {
|
||||
const transformed = transformPointForExportPose(sample.x, sample.y, sample.z, context.metrics, pose);
|
||||
const mapped = mapAutoMatchPointToVolume(transformed, context.metrics, context.volume);
|
||||
const sampleSlice = nearestAutoMatchSampleSlice(mapped.slice, context.sampleSlices);
|
||||
if (sampleSlice === null) {
|
||||
return;
|
||||
}
|
||||
contributors += 1;
|
||||
|
||||
if (mapped.slice < 0 || mapped.slice >= context.volume.depth) {
|
||||
if (sampleSlice < 0 || sampleSlice >= context.volume.depth) {
|
||||
missPenalty += 0.8;
|
||||
return;
|
||||
}
|
||||
|
||||
const bone = sampleAutoMatchBoneWindow(context.volume, mapped.slice, mapped.x, mapped.y);
|
||||
const bone = sampleAutoMatchBoneWindow(context.volume, sampleSlice, mapped.x, mapped.y);
|
||||
if (bone.value > 0) {
|
||||
hitReward += bone.value;
|
||||
} else {
|
||||
@@ -1323,6 +1341,7 @@ function createAutoMatchContext(project: ProjectRecord, body: Record<string, unk
|
||||
}
|
||||
|
||||
const boneFiles = resolveAutoMatchBoneFiles(project, body.boneFiles);
|
||||
const sampleSlices = chooseAutoMatchSampleSlices(body.sampleSlices, volume.depth);
|
||||
const samples = collectAutoMatchSamples(project, boneFiles);
|
||||
if (!samples.length) {
|
||||
throw new Error('未能从骨骼 STL 中采样到可匹配点');
|
||||
@@ -1334,11 +1353,12 @@ function createAutoMatchContext(project: ProjectRecord, body: Record<string, unk
|
||||
volume,
|
||||
metrics,
|
||||
samples,
|
||||
sampleSlices,
|
||||
basePose: normalizeModelPoseValue(body.pose as Partial<ModelPoseValue> | undefined),
|
||||
weights: normalizeAutoMatchWeights(body.weights),
|
||||
} satisfies AutoMatchContext,
|
||||
boneFiles,
|
||||
sampleSlices: chooseAutoMatchSampleSlices(body.sampleSlices, volume.depth),
|
||||
sampleSlices,
|
||||
adjustable: normalizeAutoMatchAdjustable(body.adjustable),
|
||||
iterations: normalizeAutoMatchIterations(body.iterations),
|
||||
candidatesPerRound: normalizeAutoMatchCandidatesPerRound(body.candidatesPerRound),
|
||||
@@ -1375,6 +1395,8 @@ function runProjectAutoMatch(project: ProjectRecord, body: Record<string, unknow
|
||||
basePose: context.basePose,
|
||||
bestPose: best.pose,
|
||||
bestScore: best.score,
|
||||
bestMode: best.mode,
|
||||
bestChanged: best.changed,
|
||||
iterations,
|
||||
evaluated,
|
||||
boneFiles,
|
||||
|
||||
Reference in New Issue
Block a user