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

Posted

技术标签:

【中文标题】测量一个人注视多个物体的时间【英文标题】:Measure the time a person has gazed at multiple objects 【发布时间】:2019-06-24 06:45:09 【问题描述】:

我正在尝试创建一个 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 个对象。如果有人知道如何帮助我完成这项工作,谢谢!

文森特

【问题讨论】:

【参考方案1】:

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

【讨论】:

非常感谢鲁弗斯!这是朝着正确方向迈出的一步,但在“GazeInput.GetGazeElement(GazeBlock)”中,括号之间的元素必须是在 XAML 页面中声明的元素。如果查看的唯一元素只是第一个对象,代码如何知道它需要在某个对象处启动秒表?如何创建某种包含所有对象的列表,并将其实现到 GetGazeElement 中?我希望你知道我的意思,因为这很难解释。 我不知道,我以前从未使用过这个框架。我知道您正在谈论的行在您当前的代码中不是必需的,因为您将该值丢弃在下一行并将其设置为 new GazeElement()(但可能需要删除该行)。跨度> 【参考方案2】:

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

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

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

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

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

HTH

【讨论】:

以上是关于测量一个人注视多个物体的时间的主要内容,如果未能解决你的问题,请参考以下文章

一次按多个键

百度地图如何测量两个地点的距离

如何单从照片里判断一个人的身高

有关测量个人在团队中绩效

屏幕空间的阴影映射技术个人理解

在 SQLite 数据库中实现诸如引用计数之类的东西