0

我正在尝试创建一个 UWP 应用程序来衡量一个人注视多个对象的时间。大约有 300 个对象,它们都需要测量时间并将其显示在文本文件中。我已经成功地为一个对象编写了这个代码,但我不知道我如何能够用多个对象来做到这一点。我看到了这篇文章如何更有效地在 C# 中创建 300 个秒表?这个问题的答案对我帮助很大,但是我的代码不能很好地实现代码。所以我喜欢创建一个对象列表的想法,然后当人注视对象 [o] 时,相应的秒表将在眼睛进入对象时启动,并在眼睛离开对象时停止。问题正如我已经提到的,该解决方案不适用于我正在使用的代码。这是我使用的仅适用于一个元素的代码。

public sealed partial class BlankPage1 : Page
{
    private GazeElement gazeButtonControl;
    private GazePointer gazePointer;

    public BlankPage1()
    {
        this.InitializeComponent();
        Stopwatch Timer = new Stopwatch();
        gazePointer = GazeInput.GetGazePointer(null);
        gazeButtonControl = GazeInput.GetGazeElement(GazeBlock);
        gazeButtonControl = new GazeElement();
        GazeInput.SetGazeElement(GazeBlock, gazeButtonControl);
        gazeButtonControl.StateChanged += GazeButtonControl_StateChanged;

        void GazeButtonControl_StateChanged(object sender, StateChangedEventArgs ea)
        {
            if (ea.PointerState == PointerState.Enter)
            {
                Timer.Start();
            }

            if (ea.PointerState == PointerState.Exit)
            {
                Timer.Stop();
                CreateStatistics();
            }
        }

        void CreateStatistics()
        {
            File.WriteAllText(@"C:\Users\Vincent Korpelshoek\AppData\Local\Packages\app.a264e06e2-5084-4424-80a9-bee5f5fbb6b6_8wekyb3d8bbwe\LocalState\Resultaten.txt", Timer.Elapsed.ToString(););
        }
    }
}

“GazeBlock”是在 XAML 文件中创建的第一个对象的名称。长话短说,我想实现这个解决方案:

static Dictionary<object, Stopwatch> stopwatchesByObject;

static void Main(string[] args)
{
    List<object> objects = new List<object>();

    // now you have to fill the objects list...

    stopwatchesByObject = new Dictionary<object, Stopwatch>();
    foreach (var o in objects)
    {
        stopwatchesByObject.Add(o, new Stopwatch());
    }
}

// Call this method when the user starts gazing at object o
static void StartGazingAt(object o)
{
    stopwatchesByObject[o].Start();
}

// Call this method when the user stops gazing at object o
static void StopGazingAt(object o)
{
    stopwatchesByObject[o].Stop();
}

static void CreateStatistics()
{
    StringBuilder sb = new StringBuilder();
    foreach (var entry in stopwatchesByObject)
    {
        sb.AppendLine($"Gazed at {entry.Key.ToString()} for {entry.Value.Elapsed.TotalSeconds} seconds.");
    }
    File.WriteAllText("c:\\temp\\statictics.txt", sb.ToString());
}

但我不知道如何将这两个“合并”在一起,因此该解决方案不仅适用于一个对象,而且适用于大约 300 个对象。如果有人知道如何帮助我完成这项工作,谢谢!

文森特

4

2 回答 2

0

似乎对于您创建的每个对象,您需要将它添加到字典中(连同一个 new Stopwatch),然后将GazeButtonControl_StateChanged事件处理程序添加到它(您可以将相同的事件处理程序添加到所有控件),然后在该事件中处理程序,您将使用以下sender参数引用正确的秒表:stopwatchesByObject[sender].Start();

这可能不完全正确,但我认为您需要执行以下操作来合并这两段代码:

public sealed partial class BlankPage1 : Page
{
    private GazeElement gazeButtonControl;
    private GazePointer gazePointer;
    static Dictionary<object, Stopwatch> stopwatchesByObject;

    public BlankPage1()
    {
        this.InitializeComponent();
        gazePointer = GazeInput.GetGazePointer(null);
        gazeButtonControl = GazeInput.GetGazeElement(GazeBlock);
        gazeButtonControl = new GazeElement();
        GazeInput.SetGazeElement(GazeBlock, gazeButtonControl);
        gazeButtonControl.StateChanged += GazeButtonControl_StateChanged;

        // Add the object to our dictionary along with a new stopwatch
        stopwatchesByObject.Add(gazeButtonControl, new Stopwatch());

        private void GazeButtonControl_StateChanged(object sender, StateChangedEventArgs ea)
        {
            // Use the sender argument to choose the correct timer
            if (ea.PointerState == PointerState.Enter)
            {
                if (stopwatchesByObject.ContainsKey(sender))
                {
                    stopwatchesByObject[sender].Start();
                }
            }
            else if (ea.PointerState == PointerState.Exit)
            {
                if (stopwatchesByObject.ContainsKey(sender))
                {
                    stopwatchesByObject[sender].Stop();
                    CreateStatistics();
                }
            }
        }

        private void CreateStatistics()
        {
            StringBuilder sb = new StringBuilder();

            foreach (var entry in stopwatchesByObject)
            {
                sb.AppendLine($"Gazed at {entry.Key} for {entry.Value.Elapsed.TotalSeconds} seconds.");
            }

            File.WriteAllText("c:\\temp\\statictics.txt", sb.ToString());
        }
    }
}
于 2019-01-30T21:55:09.257 回答
0

@Vincent 也许值得以不同的方式看待这个问题。

通过眼动追踪,用户在任何时间点都只能查看屏幕上的一个位置,因此除非您的对象在 2D 空间中彼此重叠或在 3D 空间中的视线中可能对齐,否则您可能只感兴趣在计时用户注视点停留在当前最顶层对象的时间长度。一个秒表可能足以跟踪活动对象从 OnEnter 到 OnExit 的时间。

如果在 OnExit 上将特定凝视交互的持续时间添加到 lastGazedObject 的累积时间计数中,您可能不需要(或不想)管理 300 个秒表,并且可能只需在每次用户注视进入时重复使用相同的秒表对象然后离开对象。当它离开一个物体时,下一个凝视点要么落在另一个物体上,要么落在没有物体的空白空间上。

你看过这个样本吗?它具有许多用于确定凝视在单个对象中保留多长时间的部分,以及一些额外的逻辑来跟踪 lastGazedObject 您可能能够完成您所追求的目标,而无需管理一大堆秒表或计时器。

但是,即使您尝试解决的场景确实解决了问题,例如一次可能与多个对象相交的光线投射(由于空间中的重叠或对齐),它仍然应该很容易拥有一个 long运行秒表并只跟踪 UserIsGazingAt 的每个对象的标志属性以及 GazeAtStarted 的时间,然后在注视离开对象后立即计算持续时间并将持续时间添加到对象的总持续时间中。

高温高压

于 2019-04-08T21:35:18.303 回答