测量一个人凝视多个物体的时间

时间:2019-01-30 21:32:59

标签: c# object uwp stopwatch eye-tracking

我正在尝试创建一个UWP应用,该应用可以测量一个人凝视多个对象的时间。大约有300个对象,它们都需要测量时间并将其显示在文本文件中。我已经成功地对一个对象进行了编码,但是我不知道如何对多个对象进行编码。我看到了这篇How to create 300 stopwatches in C# more efficiently?帖子,它的答案对我很有帮助,但是代码不能很好地实现我的代码。因此,我喜欢创建对象列表的想法,然后当该人凝视对象[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个对象。如果有人知道如何帮助我完成这项工作,谢谢!

Vincent

2 个答案:

答案 0 :(得分:0)

对于您创建的每个对象,似乎都需要将其添加到字典中(以及新的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());
        }
    }
}

答案 1 :(得分:0)

@Vincent也许值得以另一种方式看待这个问题。

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

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

您看过this sample吗? 它具有许多用于确定注视在单个对象中保留多长时间的部分,并带有一些附加逻辑来跟踪lastGazedObject,您可能可以在不管理大量秒表或计时器的情况下完成所要执行的操作。

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

HTH