You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Kinect V2存储关节点位置时出现大量重复值问题求助

解决关节数据存储重复的问题

我来帮你拆解下这个问题的核心原因,然后给出几个针对性的解决办法:

为什么会出现重复值?

你提到数据存储是在DrawBody方法里执行的,而这个方法通常是和渲染帧同步的(比如每秒调用60次),但你的姿态识别模块(比如Kinect、MediaPipe这类)生成新关节数据的频率往往更低(比如每秒30次)。这就导致同一个关节数据会被渲染线程重复读取、存储多次,直到新的姿态数据到来——这就是你看到连续20次左右重复值的原因。

而单值存储时你觉得“数值变化更连续”,可能是因为单值场景下你无意中避开了这个同步问题,或者单值的波动阈值更明显,让你误以为没有重复。

可行的解决方案

方案1:添加数据变化检测(精准过滤重复)

在存储数据前,先和上一次存储的数值做对比,只有当数据变化超过一个极小的精度阈值时,才执行存储操作。这样就能过滤掉渲染线程重复读取的旧数据。

示例代码(C#):

// 定义类级别的变量,保存上一次存储的关键数据
private Vector3 _lastElbowLeftPos = Vector3.Zero;
private float _lastSpineBaseShoulderRHO = 0f;
// 设定精度阈值,避免浮点数微小波动误判
private const float _changeThreshold = 1e-6f;

// 在DrawBody方法内执行存储逻辑
public void DrawBody(IReadOnlyList<Joint> joints)
{
    // 获取当前帧的关节数据和计算值
    var currentElbowPos = joints[JointType.ElbowLeft].Position;
    var currentSpineMidPos = joints[JointType.SpineMid].Position;
    var currentRHO = spineBaseShoulderRHO;

    // 检查数据是否有足够幅度的变化
    if (Vector3.Distance(currentElbowPos, _lastElbowLeftPos) > _changeThreshold ||
        Math.Abs(currentRHO - _lastSpineBaseShoulderRHO) > _changeThreshold)
    {
        // 只有数据变化时才存储
        gesture.L.E.AddFrameDescriptor(
            currentElbowPos.X, currentElbowPos.Y, currentElbowPos.Z,
            currentSpineMidPos.X, currentSpineMidPos.Y, currentSpineMidPos.Z,
            currentRHO
        );
        
        // 更新上一次存储的数值
        _lastElbowLeftPos = currentElbowPos;
        _lastSpineBaseShoulderRHO = currentRHO;
    }

    // 其他绘制逻辑...
}

方案2:将存储逻辑移到数据更新回调中(最优架构)

大部分姿态识别库都会提供数据更新回调(比如Kinect的FrameArrived事件、MediaPipe的OnResults回调),这些回调只会在新的关节数据生成时触发。把存储逻辑放在这里,就能从根源上避免重复存储的问题——因为每次回调都是新数据。

伪代码示例:

// 假设这是姿态识别库提供的数据更新回调
private void OnPoseDataReceived(IReadOnlyList<Joint> joints)
{
    // 在这里计算spineBaseShoulderRHO
    float spineBaseShoulderRHO = CalculateSpineBaseShoulderRHO(joints);

    // 直接存储,因为这里每一次都是新的姿态数据
    gesture.L.E.AddFrameDescriptor(
        joints[JointType.ElbowLeft].Position.X,
        joints[JointType.ElbowLeft].Position.Y,
        joints[JointType.ElbowLeft].Position.Z,
        joints[JointType.SpineMid].Position.X,
        joints[JointType.SpineMid].Position.Y,
        joints[JointType.SpineMid].Position.Z,
        spineBaseShoulderRHO
    );

    // 触发绘制逻辑(如果需要的话)
    DrawBody(joints);
}

这个方案把数据处理和渲染绘制做了分离,是更健壮、更符合工程规范的做法。

方案3:控制存储频率(简单粗暴的过滤)

如果暂时无法调整代码架构,可以设置一个固定的时间间隔,每隔一段时间才存储一次数据,过滤掉过于密集的重复帧。

示例代码:

private DateTime _lastStoreTime = DateTime.MinValue;
// 设置存储间隔,比如33ms对应每秒30次存储,和常见的姿态数据更新频率匹配
private const int _storeIntervalMs = 33;

public void DrawBody(IReadOnlyList<Joint> joints)
{
    if (DateTime.Now - _lastStoreTime > TimeSpan.FromMilliseconds(_storeIntervalMs))
    {
        gesture.L.E.AddFrameDescriptor(
            joints[JointType.ElbowLeft].Position.X,
            joints[JointType.ElbowLeft].Position.Y,
            joints[JointType.ElbowLeft].Position.Z,
            joints[JointType.SpineMid].Position.X,
            joints[JointType.SpineMid].Position.Y,
            joints[JointType.SpineMid].Position.Z,
            spineBaseShoulderRHO
        );
        _lastStoreTime = DateTime.Now;
    }

    // 其他绘制逻辑...
}

这个方法的缺点是可能会错过一些快速变化的细节,但适合对数据密度要求不高的场景。

总结

优先推荐方案2,从架构层面解决同步问题;如果暂时没法调整代码结构,方案1的变化检测是更精准的选择,能保留所有有效数据的同时过滤重复。

内容的提问来源于stack exchange,提问作者SoupCode0169

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.28 03:28:20