Skip to content
Toggle navigation
P
Projects
G
Groups
S
Snippets
Help
Eye-Tracking Classroom
/
gaze-server.cs
This project
Loading...
Sign in
Toggle navigation
Go to a project
Project
Repository
Issues
1
Merge Requests
0
Pipelines
Wiki
Members
Activity
Graph
Charts
Create a new issue
Jobs
Commits
Issue Boards
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Charts
Commit
3663b358
authored
Oct 07, 2019
by
Stefan Schreistetter
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
Added Fake Tracker Class. re-implemented Gaze decimator.
parent
54d4ce37
Hide whitespace changes
Inline
Side-by-side
Showing
9 changed files
with
193 additions
and
114 deletions
+193
-114
GazeWebSocketServer/Program.cs
+8
-25
TrackerBridge/DSP/GazeDecimator.cs
+53
-50
TrackerBridge/DSP/IGazeFilter.cs
+2
-3
TrackerBridge/FakeTracker.cs
+61
-0
TrackerBridge/GazeData.cs
+12
-0
TrackerBridge/GazeDataProcessor.cs
+32
-17
TrackerBridge/IBridgeTracker.cs
+10
-1
TrackerBridge/TobiiEyeTracker.cs
+10
-17
TrackerBridge/TrackerBridge.csproj
+5
-1
No files found.
GazeWebSocketServer/Program.cs
View file @
3663b358
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
(
TobiiEy
eTracker
sender
)
private
static
void
OnConnectionTimeout
(
IBridg
eTracker
sender
)
{
Console
.
WriteLine
(
"Timeout while searching for trackers."
);
}
private
static
void
OnConnectionEstablished
(
TobiiEy
eTracker
sender
)
private
static
void
OnConnectionEstablished
(
IBridg
eTracker
sender
)
{
Console
.
WriteLine
(
$"Tracker
{
sender
.
SerialNumber
}
connected."
);
ConfigurationData
config
=
ConfigurationData
.
ParseToObject
();
...
...
TrackerBridge/DSP/GazeDecimator
FixedLength
.cs
→
TrackerBridge/DSP/GazeDecimator.cs
View file @
3663b358
...
...
@@ -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
{
p
rivate
GazeData
[]
buffer
;
private
Int32
currentValueIndex
;
p
ublic
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
GazeDecimator
FixedLength
(
Single
outputFrequency
,
Single
inputFrequency
)
public
GazeDecimator
(
Single
outputFrequency
,
Single
inputFrequency
)
{
this
.
outputFrequency
=
outputFrequency
;
this
.
i
nputFrequency
=
inputFrequency
;
Reset
(
);
this
.
I
nputFrequency
=
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
();
}
}
}
TrackerBridge/DSP/IGazeFilter.cs
View file @
3663b358
...
...
@@ -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
();
}
}
TrackerBridge/FakeTracker.cs
0 → 100644
View file @
3663b358
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
();
}
}
}
TrackerBridge/GazeData.cs
View file @
3663b358
...
...
@@ -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
,
...
...
TrackerBridge/GazeDataProcessor.cs
View file @
3663b358
...
...
@@ -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
(
GazeDecimator
FixedLength
))
if
(
filter
.
GetType
()
==
typeof
(
GazeDecimator
))
{
GazeDecimator
FixedLength
decimator
=
(
GazeDecimatorFixedLength
)
filter
;
GazeDecimator
decimator
=
(
GazeDecimator
)
filter
;
decimator
.
InputFrequency
=
frequency
;
}
}
...
...
TrackerBridge/IBridgeTracker.cs
View file @
3663b358
...
...
@@ -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
);
}
}
TrackerBridge/TobiiEyeTracker.cs
View file @
3663b358
...
...
@@ -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
);
...
...
TrackerBridge/TrackerBridge.csproj
View file @
3663b358
...
...
@@ -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" />
...
...
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment