Commit 3663b358 by Stefan Schreistetter

Added Fake Tracker Class. re-implemented Gaze decimator.

parent 54d4ce37
using System;
using System.Threading.Tasks;
using TrackerBridge;
using System.Windows.Forms;
using System.Drawing;
using System.Timers;
using TrackerBridge.DSP;
namespace GazeWebSocketServer
......@@ -11,16 +8,18 @@ namespace GazeWebSocketServer
public class Program
{
private static GazeServer gazeServer;
private static GazeDecimatorFixedLength decimator = new GazeDecimatorFixedLength(1, 600);
public static void Main(string[] args)
{
ConfigurationData.InitializeUnexistingWithDefaults();
ConfigurationData config = ConfigurationData.ParseToObject();
IBridgeTracker tracker;
if (args.Length > 0 && args[0] == "-d")
{
Task.Run(() => SimulateGazeDataHz(600));
tracker = new FakeTracker(600);
tracker.GazeDataAvailable += OnGazeDataAvailable; //TODO: Extend interface usage
//tracker.GazeDataProcessor.OutputFrequency = config.OutputFrequency;
}
else
{
......@@ -36,25 +35,9 @@ namespace GazeWebSocketServer
Console.ReadLine();
}
private static void SimulateGazeDataHz(Int32 frequency)
{
System.Timers.Timer timer = new System.Timers.Timer(1000.0/frequency);
timer.Elapsed += (Object sender, ElapsedEventArgs e) =>
{
Point mousePosition = Control.MousePosition;
GazeData data = new GazeData(mousePosition.X, mousePosition.Y, mousePosition.X, mousePosition.Y, 0, 0);
if (gazeServer != null && gazeServer.isRunning)
{
decimator.Input(data);
if(decimator.Output.HasValue)
gazeServer.Publish(data);
}
};
timer.AutoReset = true;
timer.Start();
}
private static void OnGazeDataAvailable(TobiiEyeTracker sender, GazeData data)
private static void OnGazeDataAvailable(GazeData data, Object sender)
{
if (gazeServer != null && gazeServer.isRunning)
{
......@@ -62,12 +45,12 @@ namespace GazeWebSocketServer
}
}
private static void OnConnectionTimeout(TobiiEyeTracker sender)
private static void OnConnectionTimeout(IBridgeTracker sender)
{
Console.WriteLine("Timeout while searching for trackers.");
}
private static void OnConnectionEstablished(TobiiEyeTracker sender)
private static void OnConnectionEstablished(IBridgeTracker sender)
{
Console.WriteLine($"Tracker {sender.SerialNumber} connected.");
ConfigurationData config = ConfigurationData.ParseToObject();
......
......@@ -3,91 +3,94 @@ using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Timers;
namespace TrackerBridge.DSP
{
public class GazeDecimatorFixedLength : IGazeFilter
class GazeDecimator : IGazeFilter
{
private GazeData[] buffer;
private Int32 currentValueIndex;
public event GazeDataHandler OutputAvailable;
private Single inputFrequency;
private GazeData? output;
private GazeData output;
private Single outputFrequency;
private Object outputLock = new Object();
private Object inputLock = new Object();
private Object valueCountLock = new Object();
private Int64 valueCount;
public event EventHandler<GazeData> OutputAvailable;
public Single InputFrequency {
get { return inputFrequency; }
public Single InputFrequency { get => inputFrequency; set => inputFrequency = value; }
private Int64 ValueCount {
get {
lock (valueCountLock)
{
return valueCount;
}
}
set {
inputFrequency = value;
Reset();
lock (valueCountLock)
{
valueCount = value;
}
}
}
public GazeData? Output {
private GazeData Output {
get {
lock (outputLock)
{
GazeData? temp = null;
if (output.HasValue)
{
temp = output.Value;
output = null;
}
return temp;
return output;
}
}
}
public Single OutputFrequency {
get { return outputFrequency; }
set {
outputFrequency = value;
Reset();
lock (outputLock)
{
output = value;
}
}
}
public GazeDecimatorFixedLength(Single outputFrequency, Single inputFrequency)
public GazeDecimator(Single outputFrequency, Single inputFrequency)
{
this.outputFrequency = outputFrequency;
this.inputFrequency = inputFrequency;
Reset();
this.InputFrequency = inputFrequency;
Task.Run(() => TriggerOutput(outputFrequency));
}
public void Input(GazeData input)
public void Input(GazeData input, Object sender = null)
{
lock (inputLock)
if (ValueCount == 0)
{
currentValueIndex = (currentValueIndex + 1) % buffer.Length;
Output = input;
}
buffer[currentValueIndex] = input;
if (currentValueIndex == buffer.Length-1)
else
{
GazeData sum = buffer[0];
for (Int32 index = 1; index < buffer.Length; index++)
{
sum += buffer[index];
}
sum /= buffer.Length;
//Cumulative moving average (CMA) -> https://en.wikipedia.org/wiki/Moving_average#Cumulative_moving_average
lock (outputLock)
{
output = sum;
output += (input - output) / (ValueCount + 1);
}
}
}
ValueCount++;
}
public void Reset()
{
Int32 bufferLength = Convert.ToInt32(InputFrequency / OutputFrequency);
buffer = new GazeData[bufferLength];
currentValueIndex = -1;
output = null;
ValueCount = 0;
}
private void TriggerOutput(Single frequency)
{
Timer timer = new Timer(1000.0 / frequency); //TODO: Implement Dispose
timer.Elapsed += (Object sender, ElapsedEventArgs e) =>
{
if (ValueCount > 0)
{
OutputAvailable?.Invoke(Output, this);
Reset();
}
};
timer.AutoReset = true;
timer.Start();
}
}
}
......@@ -8,9 +8,8 @@ namespace TrackerBridge.DSP
{
interface IGazeFilter
{
event EventHandler<GazeData> OutputAvailable;
GazeData? Output { get; }
void Input(GazeData input);
event GazeDataHandler OutputAvailable;
void Input(GazeData input, Object sender = null);
void Reset();
}
}
using System;
using System.Drawing;
using System.Threading.Tasks;
using System.Timers;
using System.Windows.Forms;
namespace TrackerBridge
{
public class FakeTracker : IBridgeTracker
{
private event GazeDataHandler gazeDataAvailable;
public event GazeDataHandler GazeDataAvailable {
add {
gazeDataAvailable += value;
GazeDataProcessor.AddClient(value);
}
remove {
gazeDataAvailable -= value;
GazeDataProcessor.RemoveClient(value);
}
}
public event EventHandler<Single> TrackingFrequencyChanged;
private Single trackerFrequency;
public GazeDataHandler GazeDataAvailableMembers => gazeDataAvailable;
public String SerialNumber => throw new NotImplementedException();
public GazeDataProcessor GazeDataProcessor { get; }
public FakeTracker(Single frequency)
{
trackerFrequency = frequency;
GazeDataProcessor = new GazeDataProcessor(this);
//GazeDataProcessor.OutputFrequency = 1;
Task.Run(() => SimulateGazeDataHz(frequency));
}
private void SimulateGazeDataHz(Single frequency)
{
System.Timers.Timer timer = new System.Timers.Timer(1000.0 / frequency); //TODO: Implement Dispose
timer.Elapsed += (Object sender, ElapsedEventArgs e) =>
{
Point mousePosition = Control.MousePosition;
GazeData data = new GazeData(mousePosition.X, mousePosition.Y, mousePosition.X, mousePosition.Y, 0, 0);
GazeDataProcessor.Process(this, data);
};
timer.AutoReset = true;
timer.Start();
}
public Single GetTrackingFrequency()
{
return trackerFrequency;
}
public void SetTrackingFrequency(Single value)
{
throw new NotImplementedException();
}
}
}
......@@ -44,6 +44,18 @@ namespace TrackerBridge
return result;
}
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,
......
......@@ -11,8 +11,6 @@ namespace TrackerBridge
{
public class GazeDataProcessor
{
public event EventHandler<GazeData> ProcessedGazeDataAvailable;
private readonly IGazeFilter[] gazeFilters;
private readonly Single screenHeight;
private readonly Single screenWidth;
......@@ -26,15 +24,37 @@ namespace TrackerBridge
}
}
public GazeDataProcessor(IBridgeTracker tracker)
{
tracker.TrackingFrequencyChanged += OnTrackingFrequencyChanged;
screenHeight = Convert.ToSingle(SystemParameters.PrimaryScreenHeight);
screenWidth = Convert.ToSingle(SystemParameters.PrimaryScreenWidth);
gazeFilters = new IGazeFilter[1];
gazeFilters[0] = new GazeDecimatorFixedLength(outputFrequency, tracker.GetTrackingFrequency());
gazeFilters[0] = new GazeDecimator(60, tracker.GetTrackingFrequency()); //TODO: Refactor frequency passthrough
//Chain filters
for(Int32 index= 0; index < gazeFilters.Length; index++)
{
if(index == gazeFilters.Length - 1)
{
gazeFilters[index].OutputAvailable += tracker.GazeDataAvailableMembers;
}
else
{
gazeFilters[index].OutputAvailable += gazeFilters[index + 1].Input;
}
}
}
public void AddClient(GazeDataHandler gazeDataHandler)
{
gazeFilters[gazeFilters.Length - 1].OutputAvailable += gazeDataHandler;
}
public void RemoveClient(GazeDataHandler gazeDataHandler)
{
gazeFilters[gazeFilters.Length - 1].OutputAvailable -= gazeDataHandler;
}
public void Initialize()
{
foreach (IGazeFilter filter in gazeFilters)
......@@ -42,8 +62,8 @@ namespace TrackerBridge
filter.Reset();
}
}
public GazeData? Process(GazeDataEventArgs e)
public void Process(Object sender, GazeDataEventArgs e)
{
GazeData data = new GazeData(e.LeftEye.GazePoint.PositionOnDisplayArea.X * screenWidth,
e.LeftEye.GazePoint.PositionOnDisplayArea.Y * screenHeight,
......@@ -53,23 +73,18 @@ namespace TrackerBridge
e.SystemTimeStamp);
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;
}
public void Process(Object sender, GazeData input)
{
gazeFilters[0].Input(input);
}
private void OnTrackingFrequencyChanged(Object sender, Single frequency)
{
foreach(IGazeFilter filter in gazeFilters)
{
if(filter.GetType() == typeof(GazeDecimatorFixedLength))
if(filter.GetType() == typeof(GazeDecimator))
{
GazeDecimatorFixedLength decimator = (GazeDecimatorFixedLength)filter;
GazeDecimator decimator = (GazeDecimator)filter;
decimator.InputFrequency = frequency;
}
}
......
......@@ -6,10 +6,19 @@ using System.Threading.Tasks;
namespace TrackerBridge
{
public delegate void ConnectionEventHandler(IBridgeTracker sender);
public delegate void GazeDataHandler(GazeData data, Object sender);
public interface IBridgeTracker
{
event GazeDataHandler GazeDataAvailable;
event EventHandler<Single> TrackingFrequencyChanged;
void SetTrackingFrequency(Single value);
GazeDataHandler GazeDataAvailableMembers { get; }
GazeDataProcessor GazeDataProcessor { get;}
String SerialNumber { get; }
Single GetTrackingFrequency();
void SetTrackingFrequency(Single value);
}
}
......@@ -9,8 +9,8 @@ namespace TrackerBridge
{
public class TobiiEyeTracker : IBridgeTracker
{
public delegate void ConnectionEventHandler(TobiiEyeTracker sender);
public delegate void GazeDataHandler(TobiiEyeTracker sender, GazeData data);
//public delegate void ConnectionEventHandler(TobiiEyeTracker sender);
//public delegate void GazeDataHandler(TobiiEyeTracker sender, GazeData data);
public event ConnectionEventHandler ConnectionEvent;
public event ConnectionEventHandler ConnectionTimeout;
......@@ -19,10 +19,16 @@ namespace TrackerBridge
private IEyeTracker eyeTracker = null;
public GazeDataProcessor GazeDataProcessor { get; set; }
public GazeDataProcessor GazeDataProcessor { get; }
public Boolean IsConnected { get; private set; } = false;
public String SerialNumber { get; private set; } = null;
public GazeDataHandler GazeDataAvailableMembers {
get {
return GazeDataAvailable;
}
}
public TobiiEyeTracker()
{
GazeDataProcessor = new GazeDataProcessor(this);
......@@ -62,10 +68,6 @@ namespace TrackerBridge
eyeTracker.SetGazeOutputFrequency(value);
}
}
void IBridgeTracker.SetTrackingFrequency(Single value)
{
throw new NotImplementedException();
}
private void InitiateConnection()
{
......@@ -103,22 +105,13 @@ namespace TrackerBridge
ConnectionTimeout?.Invoke(this);
}
}
eyeTracker.GazeDataReceived += OnGazeDataReceived;
eyeTracker.GazeDataReceived += GazeDataProcessor.Process;
eyeTracker.GazeOutputFrequencyChanged += OnGazeOutputFrequencyChanged;
SerialNumber = eyeTracker.SerialNumber;
SetTrackingFrequency(600f);
ConnectionEvent?.Invoke(this);
}
private void OnGazeDataReceived(object sender, GazeDataEventArgs e)
{
GazeData? gazeData = GazeDataProcessor.Process(e);
if (gazeData.HasValue)
{
GazeDataAvailable?.Invoke(this, gazeData.Value);
}
}
private void OnGazeOutputFrequencyChanged(Object sender, GazeOutputFrequencyEventArgs e)
{
TrackingFrequencyChanged?.Invoke(this, e.GazeOutputFrequency);
......
......@@ -34,9 +34,12 @@
<WarningLevel>4</WarningLevel>
</PropertyGroup>
<ItemGroup>
<Reference Include="PresentationCore" />
<Reference Include="PresentationFramework" />
<Reference Include="System" />
<Reference Include="System.Core" />
<Reference Include="System.Drawing" />
<Reference Include="System.Windows.Forms" />
<Reference Include="System.Xml.Linq" />
<Reference Include="System.Data.DataSetExtensions" />
<Reference Include="Microsoft.CSharp" />
......@@ -48,7 +51,8 @@
</Reference>
</ItemGroup>
<ItemGroup>
<Compile Include="DSP\GazeDecimatorFixedLength.cs" />
<Compile Include="DSP\GazeDecimator.cs" />
<Compile Include="FakeTracker.cs" />
<Compile Include="GazeData.cs" />
<Compile Include="GazeDataProcessor.cs" />
<Compile Include="DSP\IGazeFilter.cs" />
......
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