Editor/Inference/YoloImage.cs
// C# adaptation of YOLOX's non-legacy validation transform. See THIRD_PARTY_NOTICES.md.
using System;
using System.Threading;
namespace HumanoidMocapX.Inference;
internal static class YoloImage
{
/// <summary>Resizes RGBA8 into the upper-left of a 640×640 BGR HWC float image,
/// padding with 114. Bilinear samples are rounded to bytes; alpha is ignored.
/// Rejects malformed/overlapping buffers and unrepresentable aspect ratios.</summary>
internal static void Prepare(ReadOnlySpan<byte> rgba, int width, int height, Span<float> output,
CancellationToken cancellation = default)
{
if (width < 1 || height < 1 || (long)width * height > int.MaxValue / 4 || rgba.Length != (long)width * height * 4
|| output.Length != YoloNetwork.ImageSize * YoloNetwork.ImageSize * 3
|| rgba.Overlaps(System.Runtime.InteropServices.MemoryMarshal.AsBytes(output)))
throw new ArgumentException("YOLOX preprocessing needs RGBA8 pixels and a separate [640,640,3] output.");
cancellation.ThrowIfCancellationRequested();
var ratio = Math.Min(YoloNetwork.ImageSize / (double)width, YoloNetwork.ImageSize / (double)height);
var resizedWidth = (int)(width * ratio); var resizedHeight = (int)(height * ratio);
if (resizedWidth < 1 || resizedHeight < 1) throw new ArgumentException("Image aspect ratio leaves no pixels after resizing.");
output.Fill(114);
for (var y = 0; y < resizedHeight; y++)
{
cancellation.ThrowIfCancellationRequested();
var sourceY = Math.Clamp((y + .5) * height / resizedHeight - .5, 0, height - 1);
var top = (int)sourceY; var bottom = Math.Min(top + 1, height - 1); var vertical = sourceY - top;
for (var x = 0; x < resizedWidth; x++)
{
var sourceX = Math.Clamp((x + .5) * width / resizedWidth - .5, 0, width - 1);
var left = (int)sourceX; var right = Math.Min(left + 1, width - 1); var horizontal = sourceX - left;
for (var channel = 0; channel < 3; channel++)
{
var a = rgba[(top * width + left) * 4 + 2 - channel]; var b = rgba[(top * width + right) * 4 + 2 - channel];
var c = rgba[(bottom * width + left) * 4 + 2 - channel]; var d = rgba[(bottom * width + right) * 4 + 2 - channel];
var upper = a + (b - a) * horizontal; var lower = c + (d - c) * horizontal;
output[(y * YoloNetwork.ImageSize + x) * 3 + channel] = (float)Math.Floor(upper + (lower - upper) * vertical + .5);
}
}
}
}
}