Editor/Inference/SamKeypointFeedback.cs
// C# adaptation of SAM 3D Body's intermediate keypoint updates. See LICENSE-SAM and THIRD_PARTY_NOTICES.md.
// Copyright (c) Meta Platforms, Inc. and affiliates.
using System;
using System.Threading;
namespace HumanoidMocapX.Inference;
/// <summary>Updates 2D/3D keypoint positions and samples the conditioned image
/// context with zero padding and align_corners=false.</summary>
internal sealed class SamKeypointFeedback
{
readonly SamDecoderShape shape;
readonly int imageWidth, imageHeight, keypointStart;
readonly FlowLinear positionFirst, positionSecond, spatialFirst, spatialSecond, imageProjection;
readonly float[] hidden, embedded, features, projected, centered = new float[SamKeypoints.Count * 3];
readonly bool[] valid = new bool[SamKeypoints.Count];
internal SamKeypointFeedback(FlowWeights weights, SamDecoderShape shape, int imageWidth, int imageHeight, bool hand = false)
{
if (shape.Tokens < 145 || imageWidth < 1 || imageHeight < 1 || (long)imageWidth * imageHeight != shape.ImageTokens)
throw new ArgumentException("SAM feedback needs 70 2D/3D tokens and matching image patch dimensions.");
this.shape = shape; this.imageWidth = imageWidth; this.imageHeight = imageHeight;
keypointStart = shape.Tokens - SamKeypoints.Count * 2;
var suffix = hand ? "_hand" : "";
positionFirst = new(weights, "keypoint_posemb_linear" + suffix + ".layers.0.0", 2, shape.Width);
positionSecond = new(weights, "keypoint_posemb_linear" + suffix + ".layers.1", shape.Width, shape.Width);
spatialFirst = new(weights, "keypoint3d_posemb_linear" + suffix + ".layers.0.0", 3, shape.Width);
spatialSecond = new(weights, "keypoint3d_posemb_linear" + suffix + ".layers.1", shape.Width, shape.Width);
imageProjection = new(weights, "keypoint_feat_linear" + suffix, shape.ContextWidth, shape.Width);
hidden = new float[SamKeypoints.Count * shape.Width]; embedded = new float[hidden.Length]; projected = new float[hidden.Length];
features = new float[SamKeypoints.Count * shape.ContextWidth];
}
/// <summary>Consumes crop XY coordinates, camera depths and camera-space XYZ
/// keypoints. Changes only the final 140 token positions and the 70 2D tokens.
/// Rejects malformed or aliased buffers; reuses storage sequentially.</summary>
internal void Run(ReadOnlySpan<float> image, ReadOnlySpan<float> cropped, ReadOnlySpan<float> depths, ReadOnlySpan<float> points,
Span<float> tokens, Span<float> positions, CancellationToken cancellation = default)
{
cancellation.ThrowIfCancellationRequested();
if (image.Length != shape.ImageElements || cropped.Length != SamKeypoints.Count * 2 || depths.Length != SamKeypoints.Count
|| points.Length != centered.Length || tokens.Length != shape.TokenElements || positions.Length != tokens.Length
|| image.Overlaps(tokens) || image.Overlaps(positions) || cropped.Overlaps(tokens) || cropped.Overlaps(positions)
|| depths.Overlaps(tokens) || depths.Overlaps(positions) || points.Overlaps(tokens) || points.Overlaps(positions) || tokens.Overlaps(positions))
throw new ArgumentException("SAM keypoint feedback tensors have invalid dimensions or overlap.");
SamDecoder.Finite(image); SamDecoder.Finite(cropped); SamDecoder.Finite(depths); SamDecoder.Finite(points);
SamDecoder.Finite(tokens); SamDecoder.Finite(positions);
var position2d = positions.Slice(keypointStart * shape.Width, hidden.Length);
positionFirst.Run(cropped, SamKeypoints.Count, hidden, cancellation); NeuralOps.Relu(hidden);
positionSecond.RunParallel(hidden, SamKeypoints.Count, embedded, cancellation); embedded.CopyTo(position2d);
Sample(image, cropped, depths);
for (var point = 0; point < SamKeypoints.Count; point++) if (!valid[point]) position2d.Slice(point * shape.Width, shape.Width).Clear();
imageProjection.RunParallel(features, SamKeypoints.Count, projected, cancellation);
// Invalid samples are zeroed before projection, so its learned bias still applies.
NeuralOps.AddInPlace(tokens.Slice(keypointStart * shape.Width, hidden.Length), projected);
for (var point = 0; point < SamKeypoints.Count; point++)
for (var axis = 0; axis < 3; axis++) centered[point * 3 + axis] = points[point * 3 + axis] - (points[9 * 3 + axis] + points[10 * 3 + axis]) / 2;
spatialFirst.Run(centered, SamKeypoints.Count, hidden, cancellation); NeuralOps.Relu(hidden);
spatialSecond.RunParallel(hidden, SamKeypoints.Count, embedded, cancellation);
embedded.CopyTo(positions.Slice((keypointStart + SamKeypoints.Count) * shape.Width));
SamDecoder.Finite(tokens); SamDecoder.Finite(positions);
}
void Sample(ReadOnlySpan<float> image, ReadOnlySpan<float> cropped, ReadOnlySpan<float> depths)
{
features.AsSpan().Clear();
for (var point = 0; point < SamKeypoints.Count; point++)
{
var x = cropped[point * 2]; var y = cropped[point * 2 + 1];
valid[point] = x >= -.5f && x <= .5f && y >= -.5f && y <= .5f && depths[point] >= 1e-5f;
if (!valid[point]) continue;
x = (x + .5f) * imageWidth - .5f; y = (y + .5f) * imageHeight - .5f;
var left = (int)MathF.Floor(x); var top = (int)MathF.Floor(y); var dx = x - left; var dy = y - top;
var output = features.AsSpan(point * shape.ContextWidth, shape.ContextWidth);
Accumulate(image, left, top, (1 - dx) * (1 - dy), output);
Accumulate(image, left + 1, top, dx * (1 - dy), output);
Accumulate(image, left, top + 1, (1 - dx) * dy, output);
Accumulate(image, left + 1, top + 1, dx * dy, output);
}
}
void Accumulate(ReadOnlySpan<float> image, int x, int y, float weight, Span<float> output)
{
if (x < 0 || x >= imageWidth || y < 0 || y >= imageHeight) return;
var start = (y * imageWidth + x) * shape.ContextWidth;
for (var channel = 0; channel < output.Length; channel++) output[channel] += image[start + channel] * weight;
}
}