Commit 7f1eeecc by Stefan Schreistetter

Finished prototype of gaze decimator.

parent 6906eca1
<?xml version="1.0" encoding="utf-8"?>
<configuration>
<configSections>
<sectionGroup name="userSettings" type="System.Configuration.UserSettingsGroup, System, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089" >
<section name="SteveCadwallader.CodeMaid.Properties.Settings" type="System.Configuration.ClientSettingsSection, System, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089" />
</sectionGroup>
</configSections>
<userSettings>
<SteveCadwallader.CodeMaid.Properties.Settings>
<setting name="Reorganizing_MemberTypeConstructors" serializeAs="String">
<value>Constructors||6||Constructors</value>
</setting>
<setting name="Reorganizing_MemberTypeProperties" serializeAs="String">
<value>Properties||5||Properties</value>
</setting>
<setting name="Reorganizing_MemberTypeEnums" serializeAs="String">
<value>Enums||1||Enums</value>
</setting>
<setting name="Reorganizing_MemberTypeDestructors" serializeAs="String">
<value>Destructors||7||Destructors</value>
</setting>
<setting name="Reorganizing_MemberTypeDelegates" serializeAs="String">
<value>Delegates||2||Delegates</value>
</setting>
<setting name="Reorganizing_MemberTypeFields" serializeAs="String">
<value>Fields||4||Fields</value>
</setting>
<setting name="Reorganizing_MemberTypeInterfaces" serializeAs="String">
<value>Interfaces||8||Interfaces</value>
</setting>
<setting name="Reorganizing_MemberTypeEvents" serializeAs="String">
<value>Events||3||Events</value>
</setting>
</SteveCadwallader.CodeMaid.Properties.Settings>
</userSettings>
</configuration>
\ No newline at end of file
...@@ -3,6 +3,7 @@ ...@@ -3,6 +3,7 @@
<appSettings> <appSettings>
<add key="TrackerSerialNumber" value="TPSP1-010108442544" /> <add key="TrackerSerialNumber" value="TPSP1-010108442544" />
<add key="TrackerFrequency_Hz" value="120" /> <add key="TrackerFrequency_Hz" value="120" />
<add key="OutputFrequency_Hz" value="60" />
<add key="WebSocketPort" value="8001" /> <add key="WebSocketPort" value="8001" />
<add key="WebSocketEndpoint" value="/gaze" /> <add key="WebSocketEndpoint" value="/gaze" />
<add key="DebugFlag" value="false" /> <add key="DebugFlag" value="false" />
......
...@@ -11,6 +11,7 @@ namespace GazeWebSocketServer ...@@ -11,6 +11,7 @@ namespace GazeWebSocketServer
{ {
public string TrackerSerialNumber { get; private set; } public string TrackerSerialNumber { get; private set; }
public float TrackerFrequency { get; private set; } public float TrackerFrequency { get; private set; }
public float OutputFrequency { get; private set; }
public int WebSocketPort { get; private set; } public int WebSocketPort { get; private set; }
public string WebSocketEndpoint { get; private set; } public string WebSocketEndpoint { get; private set; }
public bool DebugFlag { get; private set; } public bool DebugFlag { get; private set; }
...@@ -21,6 +22,7 @@ namespace GazeWebSocketServer ...@@ -21,6 +22,7 @@ namespace GazeWebSocketServer
{ {
TrackerSerialNumber = ConfigurationManager.AppSettings["TrackerSerialNumber"], TrackerSerialNumber = ConfigurationManager.AppSettings["TrackerSerialNumber"],
TrackerFrequency = float.Parse(ConfigurationManager.AppSettings["TrackerFrequency_Hz"]), TrackerFrequency = float.Parse(ConfigurationManager.AppSettings["TrackerFrequency_Hz"]),
OutputFrequency = float.Parse(ConfigurationManager.AppSettings["OutputFrequency_Hz"]),
WebSocketPort = int.Parse(ConfigurationManager.AppSettings["WebSocketPort"]), WebSocketPort = int.Parse(ConfigurationManager.AppSettings["WebSocketPort"]),
WebSocketEndpoint = ConfigurationManager.AppSettings["WebSocketEndpoint"], WebSocketEndpoint = ConfigurationManager.AppSettings["WebSocketEndpoint"],
DebugFlag = bool.Parse(ConfigurationManager.AppSettings["DebugFlag"]) DebugFlag = bool.Parse(ConfigurationManager.AppSettings["DebugFlag"])
...@@ -32,6 +34,7 @@ namespace GazeWebSocketServer ...@@ -32,6 +34,7 @@ namespace GazeWebSocketServer
{ {
InitializeSetting("TrackerSerialNumber", "TPSP1-"); InitializeSetting("TrackerSerialNumber", "TPSP1-");
InitializeSetting("TrackerFrequency_Hz", "600"); InitializeSetting("TrackerFrequency_Hz", "600");
InitializeSetting("OutputFrequency_Hz", "60");
InitializeSetting("WebSocketPort", "8001"); InitializeSetting("WebSocketPort", "8001");
InitializeSetting("WebSocketEndpoint", "/gaze"); InitializeSetting("WebSocketEndpoint", "/gaze");
InitializeSetting("DebugFlag", "false"); InitializeSetting("DebugFlag", "false");
......
...@@ -4,12 +4,15 @@ using TrackerBridge; ...@@ -4,12 +4,15 @@ using TrackerBridge;
using System.Windows.Forms; using System.Windows.Forms;
using System.Drawing; using System.Drawing;
using System.Timers; using System.Timers;
using TrackerBridge.DSP;
namespace GazeWebSocketServer namespace GazeWebSocketServer
{ {
public class Program public class Program
{ {
private static GazeServer gazeServer; private static GazeServer gazeServer;
private static GazeDecimator decimator = new GazeDecimator(1, 600);
public static void Main(string[] args) public static void Main(string[] args)
{ {
ConfigurationData.InitializeUnexistingWithDefaults(); ConfigurationData.InitializeUnexistingWithDefaults();
...@@ -17,7 +20,7 @@ namespace GazeWebSocketServer ...@@ -17,7 +20,7 @@ namespace GazeWebSocketServer
if (args.Length > 0 && args[0] == "-d") if (args.Length > 0 && args[0] == "-d")
{ {
Task.Run(() => SimulateGazeDataHz(120)); Task.Run(() => SimulateGazeDataHz(10));
} }
else else
{ {
...@@ -35,13 +38,15 @@ namespace GazeWebSocketServer ...@@ -35,13 +38,15 @@ namespace GazeWebSocketServer
private static void SimulateGazeDataHz(Int32 frequency) private static void SimulateGazeDataHz(Int32 frequency)
{ {
System.Timers.Timer timer = new System.Timers.Timer(1.0/frequency); System.Timers.Timer timer = new System.Timers.Timer(1000.0/frequency);
timer.Elapsed += (Object sender, ElapsedEventArgs e) => timer.Elapsed += (Object sender, ElapsedEventArgs e) =>
{ {
Point mousePosition = Control.MousePosition; Point mousePosition = Control.MousePosition;
GazeData data = new GazeData(mousePosition.X, mousePosition.Y, mousePosition.X, mousePosition.Y, 0, 0); GazeData data = new GazeData(mousePosition.X, mousePosition.Y, mousePosition.X, mousePosition.Y, 0, 0);
if (gazeServer != null && gazeServer.isRunning) if (gazeServer != null && gazeServer.isRunning)
{ {
decimator.Input(data);
if(decimator.Output.HasValue)
gazeServer.Publish(data); gazeServer.Publish(data);
} }
}; };
......
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace TrackerBridge.DSP
{
public class GazeDecimator : IGazeFilter
{
private GazeData[] buffer;
private Int32 currentValueIndex;
private Single inputFrequency;
private GazeData? output;
private Single outputFrequency;
private Object outputLock = new Object();
private Object inputLock = new Object();
public Single InputFrequency {
get { return inputFrequency; }
set {
inputFrequency = value;
Reset();
}
}
public GazeData? Output {
get {
lock (outputLock)
{
GazeData? temp = null;
if (output.HasValue)
{
temp = output.Value;
output = null;
}
return temp;
}
}
}
public Single OutputFrequency {
get { return outputFrequency; }
set {
outputFrequency = value;
Reset();
}
}
public GazeDecimator(Single outputFrequency, Single inputFrequency)
{
this.outputFrequency = outputFrequency;
this.inputFrequency = inputFrequency;
Reset();
}
public void Input(GazeData input)
{
lock (inputLock)
{
buffer[currentValueIndex] = input;
currentValueIndex = (currentValueIndex + 1) % buffer.Length;
if (currentValueIndex == 0)
{
GazeData sum = buffer[0];
for (Int32 index = 1; index < buffer.Length; index++)
{
sum += buffer[index];
}
lock (outputLock)
{
output = sum / buffer.Length;
}
}
}
}
public void Reset()
{
Int32 bufferLength = Convert.ToInt32(InputFrequency / OutputFrequency);
buffer = new GazeData[bufferLength];
currentValueIndex = 0;
output = null;
}
}
}
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace TrackerBridge.DSP
{
interface IGazeFilter
{
GazeData? Output { get; }
void Input(GazeData input);
void Reset();
}
}
...@@ -31,5 +31,29 @@ namespace TrackerBridge ...@@ -31,5 +31,29 @@ namespace TrackerBridge
FormattableString message = $"{leftX};{leftY};{rightX};{rightY};{trackerTimeStamp};{systemTimeStamp}"; FormattableString message = $"{leftX};{leftY};{rightX};{rightY};{trackerTimeStamp};{systemTimeStamp}";
return FormattableString.Invariant(message); return FormattableString.Invariant(message);
} }
public static GazeData operator +(GazeData a, GazeData b)
{
GazeData result = new GazeData(a.leftX + b.leftX,
a.leftY + b.leftY,
a.rightX + b.rightX,
a.rightY + b.rightY,
Math.Abs(a.trackerTimeStamp - b.trackerTimeStamp),
Math.Abs(a.systemTimeStamp - b.systemTimeStamp));
return result;
}
public static GazeData operator /(GazeData a, Single b)
{
GazeData result = new GazeData(a.leftX / b,
a.leftY / b,
a.rightX / b,
a.rightY / b,
a.trackerTimeStamp / Convert.ToInt64(b),
a.systemTimeStamp / Convert.ToInt64(b));
return result;
}
} }
} }
...@@ -5,21 +5,44 @@ using System.Linq; ...@@ -5,21 +5,44 @@ using System.Linq;
using System.Text; using System.Text;
using System.Threading.Tasks; using System.Threading.Tasks;
using Tobii.Research; using Tobii.Research;
using TrackerBridge.DSP;
namespace TrackerBridge namespace TrackerBridge
{ {
public class GazeDataProcessor public class GazeDataProcessor
{ {
readonly float screenHeight; public event EventHandler<GazeData> ProcessedGazeDataAvailable;
readonly float screenWidth;
public GazeDataProcessor() private readonly IGazeFilter[] gazeFilters;
private readonly Single screenHeight;
private readonly Single screenWidth;
private Single outputFrequency;
public Single OutputFrequency {
get { return outputFrequency; }
set {
outputFrequency = value;
Initialize();
}
}
public GazeDataProcessor(IBridgeTracker tracker)
{ {
tracker.TrackingFrequencyChanged += OnTrackingFrequencyChanged;
screenHeight = Convert.ToSingle(SystemParameters.PrimaryScreenHeight); screenHeight = Convert.ToSingle(SystemParameters.PrimaryScreenHeight);
screenWidth = Convert.ToSingle(SystemParameters.PrimaryScreenWidth); screenWidth = Convert.ToSingle(SystemParameters.PrimaryScreenWidth);
gazeFilters = new IGazeFilter[1];
gazeFilters[0] = new GazeDecimator(outputFrequency, tracker.GetTrackingFrequency());
}
public void Initialize()
{
foreach (IGazeFilter filter in gazeFilters)
{
filter.Reset();
}
} }
public GazeData Extract(GazeDataEventArgs e) public GazeData? Process(GazeDataEventArgs e)
{ {
GazeData data = new GazeData(e.LeftEye.GazePoint.PositionOnDisplayArea.X * screenWidth, GazeData data = new GazeData(e.LeftEye.GazePoint.PositionOnDisplayArea.X * screenWidth,
e.LeftEye.GazePoint.PositionOnDisplayArea.Y * screenHeight, e.LeftEye.GazePoint.PositionOnDisplayArea.Y * screenHeight,
...@@ -27,7 +50,28 @@ namespace TrackerBridge ...@@ -27,7 +50,28 @@ namespace TrackerBridge
e.RightEye.GazePoint.PositionOnDisplayArea.Y * screenHeight, e.RightEye.GazePoint.PositionOnDisplayArea.Y * screenHeight,
e.DeviceTimeStamp, e.DeviceTimeStamp,
e.SystemTimeStamp); e.SystemTimeStamp);
return data;
gazeFilters[0].Input(data);
for (Int32 index = 1; index < gazeFilters.Length; index++)
{
if (gazeFilters[index - 1].Output.HasValue)
{
gazeFilters[index].Input(gazeFilters[index - 1].Output.Value);
}
}
//TODO: If output, invoke event
return gazeFilters[gazeFilters.Length - 1].Output;
}
private void OnTrackingFrequencyChanged(Object sender, Single frequency)
{
foreach(IGazeFilter filter in gazeFilters)
{
if(filter.GetType() == typeof(GazeDecimator))
{
GazeDecimator decimator = (GazeDecimator)filter;
decimator.InputFrequency = frequency;
}
}
} }
} }
} }
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace TrackerBridge
{
public interface IBridgeTracker
{
event EventHandler<Single> TrackingFrequencyChanged;
void SetTrackingFrequency(Single value);
Single GetTrackingFrequency();
}
}
...@@ -7,32 +7,38 @@ using Tobii.Research; ...@@ -7,32 +7,38 @@ using Tobii.Research;
namespace TrackerBridge namespace TrackerBridge
{ {
public class TobiiEyeTracker public class TobiiEyeTracker : IBridgeTracker
{ {
public delegate void ConnectionEventHandler(TobiiEyeTracker sender); public delegate void ConnectionEventHandler(TobiiEyeTracker sender);
public delegate void GazeDataHandler(TobiiEyeTracker sender, GazeData data); public delegate void GazeDataHandler(TobiiEyeTracker sender, GazeData data);
public event ConnectionEventHandler ConnectionEvent; public event ConnectionEventHandler ConnectionEvent;
public event ConnectionEventHandler ConnectionTimeout; public event ConnectionEventHandler ConnectionTimeout;
public event GazeDataHandler GazeDataAvailable; public event GazeDataHandler GazeDataAvailable;
public event EventHandler<Single> TrackingFrequencyChanged;
public Boolean IsConnected { get; private set; }
public String SerialNumber { get => serialNumber; }
private IEyeTracker eyeTracker = null; private IEyeTracker eyeTracker = null;
private String serialNumber = null;
private GazeDataProcessor gazeDataProcessor; public GazeDataProcessor GazeDataProcessor { get; set; }
public Boolean IsConnected { get; private set; } = false;
public String SerialNumber { get; private set; } = null;
public TobiiEyeTracker() public TobiiEyeTracker()
{ {
gazeDataProcessor = new GazeDataProcessor(); GazeDataProcessor = new GazeDataProcessor(this);
} }
public TobiiEyeTracker(String serialNumber) : this() public TobiiEyeTracker(String serialNumber) : this()
{ {
this.serialNumber = serialNumber; SerialNumber = serialNumber;
}
public void Connect()
{
Task task = new Task(() => InitiateConnection());
task.Start();
} }
public float GetTrackingFrequency() public Single GetTrackingFrequency()
{ {
if (eyeTracker != null) if (eyeTracker != null)
{ {
...@@ -43,18 +49,22 @@ namespace TrackerBridge ...@@ -43,18 +49,22 @@ namespace TrackerBridge
throw new NullReferenceException(); throw new NullReferenceException();
} }
} }
Single IBridgeTracker.GetTrackingFrequency()
{
throw new NotImplementedException();
}
public void SetTrackingFrequency(float value) public void SetTrackingFrequency(float value)
{ {
if (eyeTracker != null) if (eyeTracker != null && eyeTracker.GetAllGazeOutputFrequencies().Contains(value))
{ {
eyeTracker.SetGazeOutputFrequency(value); eyeTracker.SetGazeOutputFrequency(value);
} }
} }
void IBridgeTracker.SetTrackingFrequency(Single value)
public void Connect()
{ {
Task task = new Task(() => InitiateConnection()); throw new NotImplementedException();
task.Start();
} }
private void InitiateConnection() private void InitiateConnection()
...@@ -65,7 +75,7 @@ namespace TrackerBridge ...@@ -65,7 +75,7 @@ namespace TrackerBridge
EyeTrackerCollection eyeTrackers = EyeTrackingOperations.FindAllEyeTrackers(); EyeTrackerCollection eyeTrackers = EyeTrackingOperations.FindAllEyeTrackers();
if (eyeTrackers.Count > 0) if (eyeTrackers.Count > 0)
{ {
if (serialNumber == null) if (SerialNumber == null)
{ {
eyeTracker = eyeTrackers[0]; eyeTracker = eyeTrackers[0];
break; break;
...@@ -74,7 +84,7 @@ namespace TrackerBridge ...@@ -74,7 +84,7 @@ namespace TrackerBridge
{ {
foreach (IEyeTracker t in eyeTrackers) foreach (IEyeTracker t in eyeTrackers)
{ {
if (serialNumber == t.SerialNumber) if (SerialNumber == t.SerialNumber)
{ {
eyeTracker = t; eyeTracker = t;
break; break;
...@@ -94,15 +104,24 @@ namespace TrackerBridge ...@@ -94,15 +104,24 @@ namespace TrackerBridge
} }
} }
eyeTracker.GazeDataReceived += OnGazeDataReceived; eyeTracker.GazeDataReceived += OnGazeDataReceived;
serialNumber = eyeTracker.SerialNumber; eyeTracker.GazeOutputFrequencyChanged += OnGazeOutputFrequencyChanged;
SerialNumber = eyeTracker.SerialNumber;
SetTrackingFrequency(600f); SetTrackingFrequency(600f);
ConnectionEvent?.Invoke(this); ConnectionEvent?.Invoke(this);
} }
private void OnGazeDataReceived(object sender, GazeDataEventArgs e) private void OnGazeDataReceived(object sender, GazeDataEventArgs e)
{ {
GazeData gazeData = gazeDataProcessor.Extract(e); GazeData? gazeData = GazeDataProcessor.Process(e);
GazeDataAvailable?.Invoke(this, gazeData); if (gazeData.HasValue)
{
GazeDataAvailable?.Invoke(this, gazeData.Value);
}
}
private void OnGazeOutputFrequencyChanged(Object sender, GazeOutputFrequencyEventArgs e)
{
TrackingFrequencyChanged?.Invoke(this, e.GazeOutputFrequency);
} }
} }
} }
\ No newline at end of file
...@@ -48,8 +48,11 @@ ...@@ -48,8 +48,11 @@
</Reference> </Reference>
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>
<Compile Include="DSP\GazeDecimator.cs" />
<Compile Include="GazeData.cs" /> <Compile Include="GazeData.cs" />
<Compile Include="GazeDataProcessor.cs" /> <Compile Include="GazeDataProcessor.cs" />
<Compile Include="DSP\IGazeFilter.cs" />
<Compile Include="IBridgeTracker.cs" />
<Compile Include="TobiiEyeTracker.cs" /> <Compile Include="TobiiEyeTracker.cs" />
<Compile Include="Properties\AssemblyInfo.cs" /> <Compile Include="Properties\AssemblyInfo.cs" />
</ItemGroup> </ItemGroup>
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or sign in to comment