Merge pull request #49 from ChristopherRemde/Azure_Kinect_Temp_Sync

Added Temporal Synchronisation
This commit is contained in:
Marek
2021-03-06 11:46:30 +00:00
committed by GitHub
17 changed files with 1268 additions and 271 deletions
-2
View File
@@ -46,8 +46,6 @@ namespace LiveScanPlayer
lineParts = ReadLine().Split(' ');
int frameTimestamp = Int32.Parse(lineParts[1]);
Console.WriteLine((frameTimestamp / 1000).ToString());
short[] tempVertices = new short[3 * nPoints];
byte[] tempColors = new byte[4 * nPoints];
+211
View File
@@ -22,6 +22,7 @@ using System.Threading;
using System.Net.Sockets;
using System.Net;
using System.ComponentModel;
using System.Windows.Forms;
namespace KinectServer
{
@@ -31,8 +32,15 @@ namespace KinectServer
Socket oServerSocket;
bool bServerRunning = false;
bool bWaitForSubToStart = false;
//This lock prevents the user from enabeling/disabling the Temp Sync State while the cameras are in transition to another state.
//When starting the server, all devices are already initialized, as the LiveScanClient can only connect with an initialized device
bool allDevicesInitialized = true;
KinectSettings oSettings;
SettingsForm fSettingsForm;
MainWindowForm fMainWindowForm;
object oClientSocketLock = new object();
object oFrameRequestLock = new object();
@@ -132,6 +140,21 @@ namespace KinectServer
this.oSettings = settings;
}
public void SetSettingsForm(SettingsForm settings)
{
fSettingsForm = settings;
}
public void SetMainWindowForm(MainWindowForm main)
{
fMainWindowForm = main;
}
public SettingsForm GetSettingsForm()
{
return fSettingsForm;
}
private void SocketListChanged()
{
if (eSocketListChanged != null)
@@ -225,6 +248,7 @@ namespace KinectServer
{
lock (oClientSocketLock)
{
for (int i = 0; i < lClientSockets.Count; i++)
{
lClientSockets[i].SendCalibrationData();
@@ -232,6 +256,170 @@ namespace KinectServer
}
}
/// <summary>
/// Request the device Sync state, so that we know which Device is Master and which are Subordinates before starting them
/// </summary>
public void RequestDeviceSyncState()
{
lock (oClientSocketLock)
{
for (int i = 0; i < lClientSockets.Count; i++)
{
lClientSockets[i].RequestTempSyncState();
}
}
}
/// <summary>
/// When a client has send its Device Sync State, we try to Set the Client Sync State
/// </summary>
public void SendTemporalSyncData()
{
lock (oClientSocketLock)
{
int masterCount = 0;
int subordinateCount = 0;
//First we check if we have recieved the Device Sync State of all Devices
//If not, we return and the next client who confirms their state starts this function again
for (int i = 0; i < lClientSockets.Count; i++)
{
if(lClientSockets[i].currentDeviceTempSyncState == KinectSocket.eTempSyncConfig.MASTER)
{
masterCount++;
}
if (lClientSockets[i].currentDeviceTempSyncState == KinectSocket.eTempSyncConfig.SUBORDINATE)
{
subordinateCount++;
}
if (lClientSockets[i].currentDeviceTempSyncState == KinectSocket.eTempSyncConfig.UNKNOWN)
{
return;
}
}
//On a second step we check if we have exactly one master and at least one subordinate
if(masterCount != 1 || subordinateCount < 1)
{
//If not, we show a error message and disable the temporal sync
fMainWindowForm?.SetStatusBarOnTimer("Temporal Sync cables not connected properly", 5000);
fSettingsForm?.ActivateTempSyncEnableButton();
return;
}
allDevicesInitialized = false;
byte syncOffSetCounter = 0;
for (int i = 0; i < lClientSockets.Count; i++)
{
if(lClientSockets[i].currentDeviceTempSyncState == KinectSocket.eTempSyncConfig.SUBORDINATE)
{
syncOffSetCounter++;
}
lClientSockets[i].SendTemporalSyncStatus(true, syncOffSetCounter);
}
bWaitForSubToStart = true;
}
}
/// <summary>
/// Sets all clients as standalone
/// </summary>
public void DisableTemporalSync()
{
allDevicesInitialized = false;
lock (oClientSocketLock)
{
for (int i = 0; i < lClientSockets.Count; i++)
{
lClientSockets[i].SendTemporalSyncStatus(false, 0);
}
}
}
public void ConfirmTemporalSyncDisabled()
{
if (bWaitForSubToStart)
return;
lock (oClientSocketLock)
{
for (int i = 0; i < lClientSockets.Count; i++)
{
if (lClientSockets[i].currentClientTempSyncState != KinectSocket.eTempSyncConfig.STANDALONE)
{
return;
}
}
}
allDevicesInitialized = true;
}
/// <summary>
/// Called when a sub client has started. This checks if all sub clients have already started. If yes, we initialize the master
/// </summary>
public void CheckForMasterStart()
{
if (!bWaitForSubToStart)
{
return;
}
bool allSubsStarted = true;
lock (oClientSocketLock)
{
for (int i = 0; i < lClientSockets.Count; i++)
{
if (!lClientSockets[i].bSubStarted && lClientSockets[i].currentClientTempSyncState == KinectSocket.eTempSyncConfig.SUBORDINATE)
{
allSubsStarted = false;
break;
}
}
bWaitForSubToStart = false;
if (allSubsStarted)
{
for (int i = 0; i < lClientSockets.Count; i++)
{
if(lClientSockets[i].currentDeviceTempSyncState == KinectSocket.eTempSyncConfig.MASTER)
{
lClientSockets[i].SendMasterInitialize();
return;
}
}
}
}
}
/// <summary>
/// Tells the server that it is now ok to start recieving user changes again
/// </summary>
public void MasterSuccessfullyRestarted()
{
allDevicesInitialized = true;
}
public bool GetAllDevicesInitialized()
{
return allDevicesInitialized;
}
public bool GetStoredFrame(List<List<byte>> lFramesRGB, List<List<Single>> lFramesVerts)
{
bool bNoMoreStoredFrames;
@@ -303,6 +491,7 @@ namespace KinectServer
//Wait till frames received
bool allGathered = false;
while (!allGathered)
{
allGathered = true;
@@ -318,6 +507,7 @@ namespace KinectServer
}
}
}
}
//Store received frames
@@ -330,6 +520,7 @@ namespace KinectServer
lFramesBody.Add(new List<Body>(lClientSockets[i].lBodies));
}
}
}
}
@@ -360,6 +551,11 @@ namespace KinectServer
lClientSockets.Add(new KinectSocket(newClient));
lClientSockets[lClientSockets.Count - 1].SendSettings(oSettings);
lClientSockets[lClientSockets.Count - 1].eChanged += new SocketChangedHandler(SocketListChanged);
lClientSockets[lClientSockets.Count - 1].eSubInitialized += new SubOrdinateInitialized(CheckForMasterStart);
lClientSockets[lClientSockets.Count - 1].eMasterRestart += new MasterRestarted(MasterSuccessfullyRestarted);
lClientSockets[lClientSockets.Count - 1].eSyncJackstate += new RecievedSyncJackState(SendTemporalSyncData);
lClientSockets[lClientSockets.Count - 1].eStandAloneInitialized += new StandAloneInitialized(ConfirmTemporalSyncDisabled);
if (eSocketListChanged != null)
{
eSocketListChanged(lClientSockets);
@@ -436,6 +632,21 @@ namespace KinectServer
lClientSockets[i].bLatestFrameReceived = true;
}
else if (buffer[0] == 4)
{
lClientSockets[i].ReceiveTemporalSyncStatus();
}
else if(buffer[0] == 5)
{
lClientSockets[i].RecieveMasterHasRestarted();
}
else if(buffer[0] == 6)
{
lClientSockets[i].RecieveDeviceSyncState();
}
buffer = lClientSockets[i].Receive(1);
}
}
+14
View File
@@ -42,6 +42,12 @@ namespace KinectServer
public bool bMergeScansForSave = true;
public bool bSaveAsBinaryPLY = true;
public bool bSyncEnabled = false;
public bool bAutoExposureEnabled = true;
public int nExposureStep = -8;
public KinectSettings()
{
aMinBounds[0] = -5f;
@@ -100,6 +106,14 @@ namespace KinectServer
bTemp = BitConverter.GetBytes(iCompressionLevel);
lData.AddRange(bTemp);
if (bAutoExposureEnabled)
lData.Add(1);
else
lData.Add(0);
bTemp = BitConverter.GetBytes(nExposureStep);
lData.AddRange(bTemp);
return lData;
}
}
+175 -7
View File
@@ -18,11 +18,15 @@ using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Net.Sockets;
using OpenTK.Graphics;
namespace KinectServer
{
public delegate void SocketChangedHandler();
public delegate void SubOrdinateInitialized();
public delegate void MasterRestarted();
public delegate void RecievedSyncJackState();
public delegate void StandAloneInitialized();
public class KinectSocket
{
@@ -33,8 +37,20 @@ namespace KinectServer
public bool bStoredFrameReceived = false;
public bool bNoMoreStoredFrames = true;
public bool bCalibrated = false;
public bool bSubStarted = false;
public bool bMasterStarted = false;
public enum eTempSyncConfig { MASTER, SUBORDINATE, STANDALONE, UNKNOWN }
//Shows how the *Device* is configured (Determined only by the Sync-Cables hooked up to the device)
public eTempSyncConfig currentDeviceTempSyncState = eTempSyncConfig.STANDALONE;
//Shows how the Client-Software is configured (This is set by the server)
public eTempSyncConfig currentClientTempSyncState = eTempSyncConfig.STANDALONE;
//The pose of the sensor in the scene (used by the OpenGLWindow to show the sensor)
public AffineTransform oCameraPose = new AffineTransform();
//The transform that maps the vertices in the sensor coordinate system to the world corrdinate system.
public AffineTransform oWorldTransform = new AffineTransform();
@@ -45,11 +61,17 @@ namespace KinectServer
public List<Body> lBodies = new List<Body>();
public event SocketChangedHandler eChanged;
public event SubOrdinateInitialized eSubInitialized;
public event MasterRestarted eMasterRestart;
public event RecievedSyncJackState eSyncJackstate;
public event StandAloneInitialized eStandAloneInitialized;
public KinectSocket(Socket clientSocket)
{
oSocket = clientSocket;
sSocketState = oSocket.RemoteEndPoint.ToString() + " Calibrated = false";
UpdateSocketState();
}
public void CaptureFrame()
@@ -121,6 +143,84 @@ namespace KinectServer
SendByte();
}
/// <summary>
/// Send the device the command to restart with Temporal Sync Enabled or Disabled
/// </summary>
/// <param name="tempSyncOn">Enable/Disable Temporal Sync</param>
/// <param name="syncOffSetMultiplier">Only set when this device should be a subordinate. Should be a unique number in ascending order for each sub</param>
public void SendTemporalSyncStatus(bool tempSyncOn, byte syncOffSetMultiplier)
{
bSubStarted = false;
currentClientTempSyncState = eTempSyncConfig.UNKNOWN;
if (tempSyncOn)
{
byte[] data = new byte[2];
data[0] = 7;
data[1] = syncOffSetMultiplier;
if (SocketConnected())
oSocket.Send(data);
}
else
{
byteToSend[0] = 8;
SendByte();
}
}
/// <summary>
/// Sends the master device the command to Start. Should only be called when all subs have started
/// </summary>
public void SendMasterInitialize()
{
byteToSend[0] = 9;
SendByte();
}
/// <summary>
/// Asks the client in which way the Sync-Cables are hooked up to the device
/// </summary>
public void RequestTempSyncState()
{
currentDeviceTempSyncState = eTempSyncConfig.UNKNOWN;
byteToSend[0] = 10;
SendByte();
}
public void RecieveDeviceSyncState()
{
byte tempSyncState;
byte[] buffer = new byte[1024];
while (oSocket.Available == 0)
{
if (!SocketConnected())
return;
}
oSocket.Receive(buffer, 3, SocketFlags.None);
tempSyncState = buffer[0];
if (tempSyncState == 0)
{
currentDeviceTempSyncState = eTempSyncConfig.SUBORDINATE;
}
else if (tempSyncState == 1)
{
currentDeviceTempSyncState = eTempSyncConfig.MASTER;
}
else if (tempSyncState == 2)
{
currentDeviceTempSyncState = eTempSyncConfig.STANDALONE;
}
eSyncJackstate.Invoke();
}
public void ReceiveCalibrationData()
{
bCalibrated = true;
@@ -148,6 +248,53 @@ namespace KinectServer
UpdateSocketState();
}
//Gets the TemporalSyncStatus from the device
public void ReceiveTemporalSyncStatus()
{
byte tempSyncState;
byte[] buffer = new byte[1024];
while (oSocket.Available == 0)
{
if (!SocketConnected())
return;
}
oSocket.Receive(buffer, 3, SocketFlags.None);
tempSyncState = buffer[0];
if (tempSyncState == 0)
{
currentClientTempSyncState = eTempSyncConfig.SUBORDINATE;
bSubStarted = true;
bMasterStarted = false;
eSubInitialized?.Invoke();
}
else if(tempSyncState == 1)
{
currentClientTempSyncState = eTempSyncConfig.MASTER;
bSubStarted = false;
}
else if (tempSyncState == 2)
{
currentClientTempSyncState = eTempSyncConfig.STANDALONE;
bSubStarted = false;
bMasterStarted = false;
eStandAloneInitialized?.Invoke();
}
UpdateSocketState();
}
public void RecieveMasterHasRestarted()
{
bMasterStarted = true;
eMasterRestart?.Invoke();
}
public void ReceiveFrame()
{
lFrameRGB.Clear();
@@ -165,6 +312,9 @@ namespace KinectServer
oSocket.Receive(buffer, 8, SocketFlags.None);
nToRead = BitConverter.ToInt32(buffer, 0);
int iCompressed = BitConverter.ToInt32(buffer, 4);
if (nToRead == -1)
@@ -173,6 +323,14 @@ namespace KinectServer
return;
}
//Sometimes we recieve negative values when the cameras are restarting, I don't know why yet.
//I'm just patching this up for now.s
if (nToRead <= 0)
{
return;
}
buffer = new byte[nToRead];
int nAlreadyRead = 0;
@@ -293,13 +451,23 @@ namespace KinectServer
public void UpdateSocketState()
{
if (bCalibrated)
sSocketState = oSocket.RemoteEndPoint.ToString() + " Calibrated = true";
else
sSocketState = oSocket.RemoteEndPoint.ToString() + " Calibrated = false";
string tempSyncMessage = "";
if (eChanged != null)
eChanged();
switch (currentClientTempSyncState)
{
case eTempSyncConfig.MASTER:
tempSyncMessage = "[MASTER]";
break;
case eTempSyncConfig.SUBORDINATE:
tempSyncMessage = "[SUBORDINATE]";
break;
default:
break;
}
sSocketState = oSocket.RemoteEndPoint.ToString() + " Calibrated = " + bCalibrated + " " + tempSyncMessage;
eChanged?.Invoke();
}
}
}
+14 -1
View File
@@ -124,11 +124,17 @@ namespace KinectServer
//Opens the settings form
private void btSettings_Click(object sender, EventArgs e)
{
if(oServer.GetSettingsForm() == null)
{
SettingsForm form = new SettingsForm();
form.oSettings = oSettings;
form.oServer = oServer;
form.Show();
oServer.SetSettingsForm(form);
oServer.SetMainWindowForm(this);
}
}
//Performs recording which is synchronized frame capture.
@@ -263,6 +269,12 @@ namespace KinectServer
while (!worker.CancellationPending)
{
Thread.Sleep(1);
if (!oServer.GetAllDevicesInitialized())
{
continue;
}
oServer.GetLatestFrame(lFramesRGB, lFramesVerts, lFramesBody);
//Update the vertex and color lists that are common between this class and the OpenGLWindow.
@@ -472,7 +484,7 @@ namespace KinectServer
OpenGLWorker.RunWorkerAsync();
}
private void SetStatusBarOnTimer(string message, int milliseconds)
public void SetStatusBarOnTimer(string message, int milliseconds)
{
statusLabel.Text = message;
@@ -496,6 +508,7 @@ namespace KinectServer
for (int i = 0; i < socketList.Count; i++)
listBoxItems.Add(socketList[i].sSocketState);
lClientListBox.DataSource = listBoxItems;
}
}
+286 -211
View File
@@ -33,6 +33,15 @@
this.lbICPIters = new System.Windows.Forms.Label();
this.txtICPIters = new System.Windows.Forms.TextBox();
this.grClient = new System.Windows.Forms.GroupBox();
this.grExposure = new System.Windows.Forms.GroupBox();
this.lbManualExposure = new System.Windows.Forms.Label();
this.chAutoExposureEnabled = new System.Windows.Forms.CheckBox();
this.trManualExposure = new System.Windows.Forms.TrackBar();
this.grTempSync = new System.Windows.Forms.GroupBox();
this.btSyncDisable = new System.Windows.Forms.Button();
this.btSyncEnable = new System.Windows.Forms.Button();
this.lbTempSync = new System.Windows.Forms.Label();
this.label1 = new System.Windows.Forms.Label();
this.grBody = new System.Windows.Forms.GroupBox();
this.chSkeletons = new System.Windows.Forms.CheckBox();
this.chBodyData = new System.Windows.Forms.CheckBox();
@@ -72,14 +81,17 @@
this.lbFilterDistance = new System.Windows.Forms.Label();
this.txtFilterDistance = new System.Windows.Forms.TextBox();
this.grServer = new System.Windows.Forms.GroupBox();
this.cbCompressionLevel = new System.Windows.Forms.ComboBox();
this.label2 = new System.Windows.Forms.Label();
this.rBinaryPly = new System.Windows.Forms.RadioButton();
this.lbFormat = new System.Windows.Forms.Label();
this.rAsciiPly = new System.Windows.Forms.RadioButton();
this.txtRefinIters = new System.Windows.Forms.TextBox();
this.lbOuterIters = new System.Windows.Forms.Label();
this.label2 = new System.Windows.Forms.Label();
this.cbCompressionLevel = new System.Windows.Forms.ComboBox();
this.grClient.SuspendLayout();
this.grExposure.SuspendLayout();
((System.ComponentModel.ISupportInitialize)(this.trManualExposure)).BeginInit();
this.grTempSync.SuspendLayout();
this.grBody.SuspendLayout();
this.grMarkers.SuspendLayout();
this.grBounding.SuspendLayout();
@@ -90,20 +102,18 @@
// lbMerge
//
this.lbMerge.AutoSize = true;
this.lbMerge.Location = new System.Drawing.Point(7, 69);
this.lbMerge.Margin = new System.Windows.Forms.Padding(4, 0, 4, 0);
this.lbMerge.Location = new System.Drawing.Point(5, 45);
this.lbMerge.Name = "lbMerge";
this.lbMerge.Size = new System.Drawing.Size(99, 20);
this.lbMerge.Size = new System.Drawing.Size(69, 13);
this.lbMerge.TabIndex = 22;
this.lbMerge.Text = "Scan saving:";
//
// chMerge
//
this.chMerge.AutoSize = true;
this.chMerge.Location = new System.Drawing.Point(156, 70);
this.chMerge.Margin = new System.Windows.Forms.Padding(4, 5, 4, 5);
this.chMerge.Location = new System.Drawing.Point(104, 45);
this.chMerge.Name = "chMerge";
this.chMerge.Size = new System.Drawing.Size(126, 24);
this.chMerge.Size = new System.Drawing.Size(86, 17);
this.chMerge.TabIndex = 23;
this.chMerge.Text = "merge scans";
this.chMerge.UseVisualStyleBackColor = true;
@@ -112,46 +122,143 @@
// lbICPIters
//
this.lbICPIters.AutoSize = true;
this.lbICPIters.Location = new System.Drawing.Point(7, 34);
this.lbICPIters.Margin = new System.Windows.Forms.Padding(4, 0, 4, 0);
this.lbICPIters.Location = new System.Drawing.Point(5, 22);
this.lbICPIters.Name = "lbICPIters";
this.lbICPIters.Size = new System.Drawing.Size(128, 20);
this.lbICPIters.Size = new System.Drawing.Size(86, 13);
this.lbICPIters.TabIndex = 24;
this.lbICPIters.Text = "Num of ICP iters:";
//
// txtICPIters
//
this.txtICPIters.Location = new System.Drawing.Point(156, 31);
this.txtICPIters.Margin = new System.Windows.Forms.Padding(4, 5, 4, 5);
this.txtICPIters.Location = new System.Drawing.Point(104, 20);
this.txtICPIters.Name = "txtICPIters";
this.txtICPIters.Size = new System.Drawing.Size(55, 26);
this.txtICPIters.Size = new System.Drawing.Size(38, 20);
this.txtICPIters.TabIndex = 25;
this.txtICPIters.TextChanged += new System.EventHandler(this.txtICPIters_TextChanged);
//
// grClient
//
this.grClient.Controls.Add(this.grExposure);
this.grClient.Controls.Add(this.grTempSync);
this.grClient.Controls.Add(this.grBody);
this.grClient.Controls.Add(this.grMarkers);
this.grClient.Controls.Add(this.grBounding);
this.grClient.Controls.Add(this.grFiltering);
this.grClient.Location = new System.Drawing.Point(18, 18);
this.grClient.Margin = new System.Windows.Forms.Padding(4, 5, 4, 5);
this.grClient.Location = new System.Drawing.Point(12, 12);
this.grClient.Name = "grClient";
this.grClient.Padding = new System.Windows.Forms.Padding(4, 5, 4, 5);
this.grClient.Size = new System.Drawing.Size(948, 447);
this.grClient.Size = new System.Drawing.Size(632, 408);
this.grClient.TabIndex = 43;
this.grClient.TabStop = false;
this.grClient.Text = "KinectClient settings";
//
// grExposure
//
this.grExposure.Controls.Add(this.lbManualExposure);
this.grExposure.Controls.Add(this.chAutoExposureEnabled);
this.grExposure.Controls.Add(this.trManualExposure);
this.grExposure.Location = new System.Drawing.Point(9, 283);
this.grExposure.Name = "grExposure";
this.grExposure.Size = new System.Drawing.Size(249, 115);
this.grExposure.TabIndex = 49;
this.grExposure.TabStop = false;
this.grExposure.Text = "Exposure Settings";
//
// lbManualExposure
//
this.lbManualExposure.AutoSize = true;
this.lbManualExposure.Location = new System.Drawing.Point(79, 52);
this.lbManualExposure.Name = "lbManualExposure";
this.lbManualExposure.Size = new System.Drawing.Size(91, 13);
this.lbManualExposure.TabIndex = 7;
this.lbManualExposure.Text = "Manual exposure:";
//
// chAutoExposureEnabled
//
this.chAutoExposureEnabled.AutoSize = true;
this.chAutoExposureEnabled.Checked = true;
this.chAutoExposureEnabled.CheckState = System.Windows.Forms.CheckState.Checked;
this.chAutoExposureEnabled.Location = new System.Drawing.Point(11, 20);
this.chAutoExposureEnabled.Name = "chAutoExposureEnabled";
this.chAutoExposureEnabled.Size = new System.Drawing.Size(135, 17);
this.chAutoExposureEnabled.TabIndex = 6;
this.chAutoExposureEnabled.Text = "Auto exposure enabled";
this.chAutoExposureEnabled.UseVisualStyleBackColor = true;
this.chAutoExposureEnabled.CheckedChanged += new System.EventHandler(this.chAutoExposureEnabled_CheckedChanged);
//
// trManualExposure
//
this.trManualExposure.Enabled = false;
this.trManualExposure.LargeChange = 1;
this.trManualExposure.Location = new System.Drawing.Point(6, 62);
this.trManualExposure.Maximum = -5;
this.trManualExposure.Minimum = -11;
this.trManualExposure.Name = "trManualExposure";
this.trManualExposure.Size = new System.Drawing.Size(237, 45);
this.trManualExposure.TabIndex = 5;
this.trManualExposure.Value = -8;
this.trManualExposure.Scroll += new System.EventHandler(this.trManualExposure_Scroll);
//
// grTempSync
//
this.grTempSync.Controls.Add(this.btSyncDisable);
this.grTempSync.Controls.Add(this.btSyncEnable);
this.grTempSync.Controls.Add(this.lbTempSync);
this.grTempSync.Controls.Add(this.label1);
this.grTempSync.Location = new System.Drawing.Point(271, 211);
this.grTempSync.Name = "grTempSync";
this.grTempSync.Size = new System.Drawing.Size(355, 97);
this.grTempSync.TabIndex = 48;
this.grTempSync.TabStop = false;
this.grTempSync.Text = "Temporal Sync";
//
// btSyncDisable
//
this.btSyncDisable.Location = new System.Drawing.Point(104, 19);
this.btSyncDisable.Name = "btSyncDisable";
this.btSyncDisable.Size = new System.Drawing.Size(92, 23);
this.btSyncDisable.TabIndex = 4;
this.btSyncDisable.Text = "Disable";
this.btSyncDisable.UseVisualStyleBackColor = true;
this.btSyncDisable.Click += new System.EventHandler(this.btSyncDisable_click);
//
// btSyncEnable
//
this.btSyncEnable.Location = new System.Drawing.Point(6, 19);
this.btSyncEnable.Name = "btSyncEnable";
this.btSyncEnable.Size = new System.Drawing.Size(92, 23);
this.btSyncEnable.TabIndex = 3;
this.btSyncEnable.Text = "Enable";
this.btSyncEnable.UseVisualStyleBackColor = true;
this.btSyncEnable.Click += new System.EventHandler(this.btSyncEnable_click);
//
// lbTempSync
//
this.lbTempSync.Location = new System.Drawing.Point(3, 45);
this.lbTempSync.Name = "lbTempSync";
this.lbTempSync.Size = new System.Drawing.Size(342, 47);
this.lbTempSync.TabIndex = 2;
this.lbTempSync.Text = "Before activating, make sure that all Kinects are connected to the server and pro" +
"perly connected via the sync cables. When Temporal Sync is activated, the exposu" +
"re needs to be set manually!";
//
// label1
//
this.label1.Location = new System.Drawing.Point(7, 41);
this.label1.MaximumSize = new System.Drawing.Size(0, 60);
this.label1.MinimumSize = new System.Drawing.Size(0, 30);
this.label1.Name = "label1";
this.label1.Size = new System.Drawing.Size(0, 30);
this.label1.TabIndex = 1;
this.label1.Text = "Notice: All devices need to be connected to the server and via sync cabel before" +
" enabeling! First Device in Server List will become the master";
//
// grBody
//
this.grBody.Controls.Add(this.chSkeletons);
this.grBody.Controls.Add(this.chBodyData);
this.grBody.Location = new System.Drawing.Point(14, 325);
this.grBody.Margin = new System.Windows.Forms.Padding(4, 5, 4, 5);
this.grBody.Location = new System.Drawing.Point(9, 211);
this.grBody.Name = "grBody";
this.grBody.Padding = new System.Windows.Forms.Padding(4, 5, 4, 5);
this.grBody.Size = new System.Drawing.Size(374, 101);
this.grBody.Size = new System.Drawing.Size(249, 66);
this.grBody.TabIndex = 47;
this.grBody.TabStop = false;
this.grBody.Text = "Body data";
@@ -159,10 +266,10 @@
// chSkeletons
//
this.chSkeletons.AutoSize = true;
this.chSkeletons.Location = new System.Drawing.Point(16, 63);
this.chSkeletons.Margin = new System.Windows.Forms.Padding(4, 5, 4, 5);
this.chSkeletons.Enabled = false;
this.chSkeletons.Location = new System.Drawing.Point(11, 41);
this.chSkeletons.Name = "chSkeletons";
this.chSkeletons.Size = new System.Drawing.Size(220, 24);
this.chSkeletons.Size = new System.Drawing.Size(154, 17);
this.chSkeletons.TabIndex = 21;
this.chSkeletons.Text = "show skeletons in live view";
this.chSkeletons.UseVisualStyleBackColor = true;
@@ -171,10 +278,10 @@
// chBodyData
//
this.chBodyData.AutoSize = true;
this.chBodyData.Location = new System.Drawing.Point(16, 29);
this.chBodyData.Margin = new System.Windows.Forms.Padding(4, 5, 4, 5);
this.chBodyData.Enabled = false;
this.chBodyData.Location = new System.Drawing.Point(11, 19);
this.chBodyData.Name = "chBodyData";
this.chBodyData.Size = new System.Drawing.Size(167, 24);
this.chBodyData.Size = new System.Drawing.Size(113, 17);
this.chBodyData.TabIndex = 19;
this.chBodyData.Text = "stream only bodies";
this.chBodyData.UseVisualStyleBackColor = true;
@@ -198,11 +305,9 @@
this.grMarkers.Controls.Add(this.txtTranslationX);
this.grMarkers.Controls.Add(this.lisMarkers);
this.grMarkers.Controls.Add(this.txtTranslationY);
this.grMarkers.Location = new System.Drawing.Point(406, 29);
this.grMarkers.Margin = new System.Windows.Forms.Padding(4, 5, 4, 5);
this.grMarkers.Location = new System.Drawing.Point(271, 19);
this.grMarkers.Name = "grMarkers";
this.grMarkers.Padding = new System.Windows.Forms.Padding(4, 5, 4, 5);
this.grMarkers.Size = new System.Drawing.Size(530, 285);
this.grMarkers.Size = new System.Drawing.Size(353, 185);
this.grMarkers.TabIndex = 45;
this.grMarkers.TabStop = false;
this.grMarkers.Text = "Calibration markers";
@@ -210,19 +315,17 @@
// lbX2
//
this.lbX2.AutoSize = true;
this.lbX2.Location = new System.Drawing.Point(345, 29);
this.lbX2.Margin = new System.Windows.Forms.Padding(4, 0, 4, 0);
this.lbX2.Location = new System.Drawing.Point(230, 19);
this.lbX2.Name = "lbX2";
this.lbX2.Size = new System.Drawing.Size(20, 20);
this.lbX2.Size = new System.Drawing.Size(14, 13);
this.lbX2.TabIndex = 49;
this.lbX2.Text = "X";
//
// btRemove
//
this.btRemove.Location = new System.Drawing.Point(350, 195);
this.btRemove.Margin = new System.Windows.Forms.Padding(4, 5, 4, 5);
this.btRemove.Location = new System.Drawing.Point(233, 127);
this.btRemove.Name = "btRemove";
this.btRemove.Size = new System.Drawing.Size(138, 35);
this.btRemove.Size = new System.Drawing.Size(92, 23);
this.btRemove.TabIndex = 59;
this.btRemove.Text = "Remove marker";
this.btRemove.UseVisualStyleBackColor = true;
@@ -230,76 +333,68 @@
//
// txtOrientationZ
//
this.txtOrientationZ.Location = new System.Drawing.Point(458, 58);
this.txtOrientationZ.Margin = new System.Windows.Forms.Padding(4, 5, 4, 5);
this.txtOrientationZ.Location = new System.Drawing.Point(305, 38);
this.txtOrientationZ.Name = "txtOrientationZ";
this.txtOrientationZ.Size = new System.Drawing.Size(55, 26);
this.txtOrientationZ.Size = new System.Drawing.Size(38, 20);
this.txtOrientationZ.TabIndex = 48;
this.txtOrientationZ.TextChanged += new System.EventHandler(this.txtOrientationZ_TextChanged);
//
// txtId
//
this.txtId.Location = new System.Drawing.Point(326, 143);
this.txtId.Margin = new System.Windows.Forms.Padding(4, 5, 4, 5);
this.txtId.Location = new System.Drawing.Point(217, 93);
this.txtId.Name = "txtId";
this.txtId.Size = new System.Drawing.Size(55, 26);
this.txtId.Size = new System.Drawing.Size(38, 20);
this.txtId.TabIndex = 58;
this.txtId.TextChanged += new System.EventHandler(this.txtId_TextChanged);
//
// lbY2
//
this.lbY2.AutoSize = true;
this.lbY2.Location = new System.Drawing.Point(411, 29);
this.lbY2.Margin = new System.Windows.Forms.Padding(4, 0, 4, 0);
this.lbY2.Location = new System.Drawing.Point(274, 19);
this.lbY2.Name = "lbY2";
this.lbY2.Size = new System.Drawing.Size(20, 20);
this.lbY2.Size = new System.Drawing.Size(14, 13);
this.lbY2.TabIndex = 50;
this.lbY2.Text = "Y";
//
// txtOrientationY
//
this.txtOrientationY.Location = new System.Drawing.Point(392, 58);
this.txtOrientationY.Margin = new System.Windows.Forms.Padding(4, 5, 4, 5);
this.txtOrientationY.Location = new System.Drawing.Point(261, 38);
this.txtOrientationY.Name = "txtOrientationY";
this.txtOrientationY.Size = new System.Drawing.Size(55, 26);
this.txtOrientationY.Size = new System.Drawing.Size(38, 20);
this.txtOrientationY.TabIndex = 47;
this.txtOrientationY.TextChanged += new System.EventHandler(this.txtOrientationY_TextChanged);
//
// lbId
//
this.lbId.AutoSize = true;
this.lbId.Location = new System.Drawing.Point(198, 148);
this.lbId.Margin = new System.Windows.Forms.Padding(4, 0, 4, 0);
this.lbId.Location = new System.Drawing.Point(132, 96);
this.lbId.Name = "lbId";
this.lbId.Size = new System.Drawing.Size(78, 20);
this.lbId.Size = new System.Drawing.Size(54, 13);
this.lbId.TabIndex = 57;
this.lbId.Text = "Marker id:";
//
// lbZ2
//
this.lbZ2.AutoSize = true;
this.lbZ2.Location = new System.Drawing.Point(476, 29);
this.lbZ2.Margin = new System.Windows.Forms.Padding(4, 0, 4, 0);
this.lbZ2.Location = new System.Drawing.Point(317, 19);
this.lbZ2.Name = "lbZ2";
this.lbZ2.Size = new System.Drawing.Size(19, 20);
this.lbZ2.Size = new System.Drawing.Size(14, 13);
this.lbZ2.TabIndex = 51;
this.lbZ2.Text = "Z";
//
// txtOrientationX
//
this.txtOrientationX.Location = new System.Drawing.Point(326, 58);
this.txtOrientationX.Margin = new System.Windows.Forms.Padding(4, 5, 4, 5);
this.txtOrientationX.Location = new System.Drawing.Point(217, 38);
this.txtOrientationX.Name = "txtOrientationX";
this.txtOrientationX.Size = new System.Drawing.Size(55, 26);
this.txtOrientationX.Size = new System.Drawing.Size(38, 20);
this.txtOrientationX.TabIndex = 46;
this.txtOrientationX.TextChanged += new System.EventHandler(this.txtOrientationX_TextChanged);
//
// btAdd
//
this.btAdd.Location = new System.Drawing.Point(202, 195);
this.btAdd.Margin = new System.Windows.Forms.Padding(4, 5, 4, 5);
this.btAdd.Location = new System.Drawing.Point(135, 127);
this.btAdd.Name = "btAdd";
this.btAdd.Size = new System.Drawing.Size(138, 35);
this.btAdd.Size = new System.Drawing.Size(92, 23);
this.btAdd.TabIndex = 56;
this.btAdd.Text = "Add marker";
this.btAdd.UseVisualStyleBackColor = true;
@@ -308,58 +403,51 @@
// lbTranslation
//
this.lbTranslation.AutoSize = true;
this.lbTranslation.Location = new System.Drawing.Point(198, 105);
this.lbTranslation.Margin = new System.Windows.Forms.Padding(4, 0, 4, 0);
this.lbTranslation.Location = new System.Drawing.Point(132, 68);
this.lbTranslation.Name = "lbTranslation";
this.lbTranslation.Size = new System.Drawing.Size(91, 20);
this.lbTranslation.Size = new System.Drawing.Size(62, 13);
this.lbTranslation.TabIndex = 52;
this.lbTranslation.Text = "Translation:";
//
// lbOrientation
//
this.lbOrientation.AutoSize = true;
this.lbOrientation.Location = new System.Drawing.Point(198, 63);
this.lbOrientation.Margin = new System.Windows.Forms.Padding(4, 0, 4, 0);
this.lbOrientation.Location = new System.Drawing.Point(132, 41);
this.lbOrientation.Name = "lbOrientation";
this.lbOrientation.Size = new System.Drawing.Size(91, 20);
this.lbOrientation.Size = new System.Drawing.Size(61, 13);
this.lbOrientation.TabIndex = 45;
this.lbOrientation.Text = "Orientation:";
//
// txtTranslationZ
//
this.txtTranslationZ.Location = new System.Drawing.Point(458, 100);
this.txtTranslationZ.Margin = new System.Windows.Forms.Padding(4, 5, 4, 5);
this.txtTranslationZ.Location = new System.Drawing.Point(305, 65);
this.txtTranslationZ.Name = "txtTranslationZ";
this.txtTranslationZ.Size = new System.Drawing.Size(55, 26);
this.txtTranslationZ.Size = new System.Drawing.Size(38, 20);
this.txtTranslationZ.TabIndex = 55;
this.txtTranslationZ.TextChanged += new System.EventHandler(this.txtTranslationZ_TextChanged);
//
// txtTranslationX
//
this.txtTranslationX.Location = new System.Drawing.Point(326, 100);
this.txtTranslationX.Margin = new System.Windows.Forms.Padding(4, 5, 4, 5);
this.txtTranslationX.Location = new System.Drawing.Point(217, 65);
this.txtTranslationX.Name = "txtTranslationX";
this.txtTranslationX.Size = new System.Drawing.Size(55, 26);
this.txtTranslationX.Size = new System.Drawing.Size(38, 20);
this.txtTranslationX.TabIndex = 53;
this.txtTranslationX.TextChanged += new System.EventHandler(this.txtTranslationX_TextChanged);
//
// lisMarkers
//
this.lisMarkers.FormattingEnabled = true;
this.lisMarkers.ItemHeight = 20;
this.lisMarkers.Location = new System.Drawing.Point(9, 63);
this.lisMarkers.Margin = new System.Windows.Forms.Padding(4, 5, 4, 5);
this.lisMarkers.Location = new System.Drawing.Point(6, 41);
this.lisMarkers.Name = "lisMarkers";
this.lisMarkers.Size = new System.Drawing.Size(178, 164);
this.lisMarkers.Size = new System.Drawing.Size(120, 108);
this.lisMarkers.TabIndex = 43;
this.lisMarkers.SelectedIndexChanged += new System.EventHandler(this.lisMarkers_SelectedIndexChanged);
//
// txtTranslationY
//
this.txtTranslationY.Location = new System.Drawing.Point(392, 100);
this.txtTranslationY.Margin = new System.Windows.Forms.Padding(4, 5, 4, 5);
this.txtTranslationY.Location = new System.Drawing.Point(261, 65);
this.txtTranslationY.Name = "txtTranslationY";
this.txtTranslationY.Size = new System.Drawing.Size(55, 26);
this.txtTranslationY.Size = new System.Drawing.Size(38, 20);
this.txtTranslationY.TabIndex = 54;
this.txtTranslationY.TextChanged += new System.EventHandler(this.txtTranslationY_TextChanged);
//
@@ -376,11 +464,9 @@
this.grBounding.Controls.Add(this.lbZ);
this.grBounding.Controls.Add(this.lbY);
this.grBounding.Controls.Add(this.lbX);
this.grBounding.Location = new System.Drawing.Point(14, 29);
this.grBounding.Margin = new System.Windows.Forms.Padding(4, 5, 4, 5);
this.grBounding.Location = new System.Drawing.Point(9, 19);
this.grBounding.Name = "grBounding";
this.grBounding.Padding = new System.Windows.Forms.Padding(4, 5, 4, 5);
this.grBounding.Size = new System.Drawing.Size(374, 140);
this.grBounding.Size = new System.Drawing.Size(249, 91);
this.grBounding.TabIndex = 46;
this.grBounding.TabStop = false;
this.grBounding.Text = "Bounding box";
@@ -388,104 +474,93 @@
// lbMin
//
this.lbMin.AutoSize = true;
this.lbMin.Location = new System.Drawing.Point(12, 58);
this.lbMin.Margin = new System.Windows.Forms.Padding(4, 0, 4, 0);
this.lbMin.Location = new System.Drawing.Point(8, 38);
this.lbMin.Name = "lbMin";
this.lbMin.Size = new System.Drawing.Size(95, 20);
this.lbMin.Size = new System.Drawing.Size(65, 13);
this.lbMin.TabIndex = 13;
this.lbMin.Text = "Min bounds:";
//
// txtMaxZ
//
this.txtMaxZ.Location = new System.Drawing.Point(272, 95);
this.txtMaxZ.Margin = new System.Windows.Forms.Padding(4, 5, 4, 5);
this.txtMaxZ.Location = new System.Drawing.Point(181, 62);
this.txtMaxZ.Name = "txtMaxZ";
this.txtMaxZ.Size = new System.Drawing.Size(55, 26);
this.txtMaxZ.Size = new System.Drawing.Size(38, 20);
this.txtMaxZ.TabIndex = 23;
this.txtMaxZ.TextChanged += new System.EventHandler(this.txtMaxZ_TextChanged);
//
// txtMaxY
//
this.txtMaxY.Location = new System.Drawing.Point(206, 95);
this.txtMaxY.Margin = new System.Windows.Forms.Padding(4, 5, 4, 5);
this.txtMaxY.Location = new System.Drawing.Point(137, 62);
this.txtMaxY.Name = "txtMaxY";
this.txtMaxY.Size = new System.Drawing.Size(55, 26);
this.txtMaxY.Size = new System.Drawing.Size(38, 20);
this.txtMaxY.TabIndex = 22;
this.txtMaxY.TextChanged += new System.EventHandler(this.txtMaxY_TextChanged);
//
// txtMinX
//
this.txtMinX.Location = new System.Drawing.Point(140, 54);
this.txtMinX.Margin = new System.Windows.Forms.Padding(4, 5, 4, 5);
this.txtMinX.Location = new System.Drawing.Point(93, 35);
this.txtMinX.Name = "txtMinX";
this.txtMinX.Size = new System.Drawing.Size(55, 26);
this.txtMinX.Size = new System.Drawing.Size(38, 20);
this.txtMinX.TabIndex = 14;
this.txtMinX.TextChanged += new System.EventHandler(this.txtMinX_TextChanged);
//
// txtMaxX
//
this.txtMaxX.Location = new System.Drawing.Point(140, 95);
this.txtMaxX.Margin = new System.Windows.Forms.Padding(4, 5, 4, 5);
this.txtMaxX.Location = new System.Drawing.Point(93, 62);
this.txtMaxX.Name = "txtMaxX";
this.txtMaxX.Size = new System.Drawing.Size(55, 26);
this.txtMaxX.Size = new System.Drawing.Size(38, 20);
this.txtMaxX.TabIndex = 21;
this.txtMaxX.TextChanged += new System.EventHandler(this.txtMaxX_TextChanged);
//
// txtMinY
//
this.txtMinY.Location = new System.Drawing.Point(206, 54);
this.txtMinY.Margin = new System.Windows.Forms.Padding(4, 5, 4, 5);
this.txtMinY.Location = new System.Drawing.Point(137, 35);
this.txtMinY.Name = "txtMinY";
this.txtMinY.Size = new System.Drawing.Size(55, 26);
this.txtMinY.Size = new System.Drawing.Size(38, 20);
this.txtMinY.TabIndex = 15;
this.txtMinY.TextChanged += new System.EventHandler(this.txtMinY_TextChanged);
//
// lbMax
//
this.lbMax.AutoSize = true;
this.lbMax.Location = new System.Drawing.Point(12, 100);
this.lbMax.Margin = new System.Windows.Forms.Padding(4, 0, 4, 0);
this.lbMax.Location = new System.Drawing.Point(8, 65);
this.lbMax.Name = "lbMax";
this.lbMax.Size = new System.Drawing.Size(99, 20);
this.lbMax.Size = new System.Drawing.Size(68, 13);
this.lbMax.TabIndex = 20;
this.lbMax.Text = "Max bounds:";
//
// txtMinZ
//
this.txtMinZ.Location = new System.Drawing.Point(272, 54);
this.txtMinZ.Margin = new System.Windows.Forms.Padding(4, 5, 4, 5);
this.txtMinZ.Location = new System.Drawing.Point(181, 35);
this.txtMinZ.Name = "txtMinZ";
this.txtMinZ.Size = new System.Drawing.Size(55, 26);
this.txtMinZ.Size = new System.Drawing.Size(38, 20);
this.txtMinZ.TabIndex = 16;
this.txtMinZ.TextChanged += new System.EventHandler(this.txtMinZ_TextChanged);
//
// lbZ
//
this.lbZ.AutoSize = true;
this.lbZ.Location = new System.Drawing.Point(290, 25);
this.lbZ.Margin = new System.Windows.Forms.Padding(4, 0, 4, 0);
this.lbZ.Location = new System.Drawing.Point(193, 16);
this.lbZ.Name = "lbZ";
this.lbZ.Size = new System.Drawing.Size(19, 20);
this.lbZ.Size = new System.Drawing.Size(14, 13);
this.lbZ.TabIndex = 19;
this.lbZ.Text = "Z";
//
// lbY
//
this.lbY.AutoSize = true;
this.lbY.Location = new System.Drawing.Point(225, 25);
this.lbY.Margin = new System.Windows.Forms.Padding(4, 0, 4, 0);
this.lbY.Location = new System.Drawing.Point(150, 16);
this.lbY.Name = "lbY";
this.lbY.Size = new System.Drawing.Size(20, 20);
this.lbY.Size = new System.Drawing.Size(14, 13);
this.lbY.TabIndex = 18;
this.lbY.Text = "Y";
//
// lbX
//
this.lbX.AutoSize = true;
this.lbX.Location = new System.Drawing.Point(159, 25);
this.lbX.Margin = new System.Windows.Forms.Padding(4, 0, 4, 0);
this.lbX.Location = new System.Drawing.Point(106, 16);
this.lbX.Name = "lbX";
this.lbX.Size = new System.Drawing.Size(20, 20);
this.lbX.Size = new System.Drawing.Size(14, 13);
this.lbX.TabIndex = 17;
this.lbX.Text = "X";
//
@@ -496,31 +571,27 @@
this.grFiltering.Controls.Add(this.lbFilterNeighbors);
this.grFiltering.Controls.Add(this.lbFilterDistance);
this.grFiltering.Controls.Add(this.txtFilterDistance);
this.grFiltering.Location = new System.Drawing.Point(14, 178);
this.grFiltering.Margin = new System.Windows.Forms.Padding(4, 5, 4, 5);
this.grFiltering.Location = new System.Drawing.Point(9, 116);
this.grFiltering.Name = "grFiltering";
this.grFiltering.Padding = new System.Windows.Forms.Padding(4, 5, 4, 5);
this.grFiltering.Size = new System.Drawing.Size(374, 135);
this.grFiltering.Size = new System.Drawing.Size(249, 88);
this.grFiltering.TabIndex = 45;
this.grFiltering.TabStop = false;
this.grFiltering.Text = "Filtering";
//
// txtFilterNeighbors
//
this.txtFilterNeighbors.Location = new System.Drawing.Point(140, 60);
this.txtFilterNeighbors.Margin = new System.Windows.Forms.Padding(4, 5, 4, 5);
this.txtFilterNeighbors.Location = new System.Drawing.Point(93, 39);
this.txtFilterNeighbors.Name = "txtFilterNeighbors";
this.txtFilterNeighbors.Size = new System.Drawing.Size(55, 26);
this.txtFilterNeighbors.Size = new System.Drawing.Size(38, 20);
this.txtFilterNeighbors.TabIndex = 20;
this.txtFilterNeighbors.TextChanged += new System.EventHandler(this.txtFilterNeighbors_TextChanged);
//
// chFilter
//
this.chFilter.AutoSize = true;
this.chFilter.Location = new System.Drawing.Point(140, 25);
this.chFilter.Margin = new System.Windows.Forms.Padding(4, 5, 4, 5);
this.chFilter.Location = new System.Drawing.Point(93, 16);
this.chFilter.Name = "chFilter";
this.chFilter.Size = new System.Drawing.Size(147, 24);
this.chFilter.Size = new System.Drawing.Size(100, 17);
this.chFilter.TabIndex = 18;
this.chFilter.Text = "filtering enabled";
this.chFilter.UseVisualStyleBackColor = true;
@@ -529,29 +600,26 @@
// lbFilterNeighbors
//
this.lbFilterNeighbors.AutoSize = true;
this.lbFilterNeighbors.Location = new System.Drawing.Point(12, 65);
this.lbFilterNeighbors.Margin = new System.Windows.Forms.Padding(4, 0, 4, 0);
this.lbFilterNeighbors.Location = new System.Drawing.Point(8, 42);
this.lbFilterNeighbors.Name = "lbFilterNeighbors";
this.lbFilterNeighbors.Size = new System.Drawing.Size(98, 20);
this.lbFilterNeighbors.Size = new System.Drawing.Size(67, 13);
this.lbFilterNeighbors.TabIndex = 19;
this.lbFilterNeighbors.Text = "N neighbors:";
//
// lbFilterDistance
//
this.lbFilterDistance.AutoSize = true;
this.lbFilterDistance.Location = new System.Drawing.Point(12, 105);
this.lbFilterDistance.Margin = new System.Windows.Forms.Padding(4, 0, 4, 0);
this.lbFilterDistance.Location = new System.Drawing.Point(8, 68);
this.lbFilterDistance.Name = "lbFilterDistance";
this.lbFilterDistance.Size = new System.Drawing.Size(106, 20);
this.lbFilterDistance.Size = new System.Drawing.Size(73, 13);
this.lbFilterDistance.TabIndex = 21;
this.lbFilterDistance.Text = "Max distance:";
//
// txtFilterDistance
//
this.txtFilterDistance.Location = new System.Drawing.Point(140, 100);
this.txtFilterDistance.Margin = new System.Windows.Forms.Padding(4, 5, 4, 5);
this.txtFilterDistance.Location = new System.Drawing.Point(93, 65);
this.txtFilterDistance.Name = "txtFilterDistance";
this.txtFilterDistance.Size = new System.Drawing.Size(55, 26);
this.txtFilterDistance.Size = new System.Drawing.Size(38, 20);
this.txtFilterDistance.TabIndex = 22;
this.txtFilterDistance.TextChanged += new System.EventHandler(this.txtFilterDistance_TextChanged);
//
@@ -568,79 +636,13 @@
this.grServer.Controls.Add(this.txtICPIters);
this.grServer.Controls.Add(this.chMerge);
this.grServer.Controls.Add(this.lbICPIters);
this.grServer.Location = new System.Drawing.Point(18, 478);
this.grServer.Margin = new System.Windows.Forms.Padding(4, 5, 4, 5);
this.grServer.Location = new System.Drawing.Point(12, 426);
this.grServer.Name = "grServer";
this.grServer.Padding = new System.Windows.Forms.Padding(4, 5, 4, 5);
this.grServer.Size = new System.Drawing.Size(948, 175);
this.grServer.Size = new System.Drawing.Size(632, 114);
this.grServer.TabIndex = 44;
this.grServer.TabStop = false;
this.grServer.Text = "KinectServer settings";
//
// rBinaryPly
//
this.rBinaryPly.AutoSize = true;
this.rBinaryPly.Location = new System.Drawing.Point(277, 105);
this.rBinaryPly.Margin = new System.Windows.Forms.Padding(4, 5, 4, 5);
this.rBinaryPly.Name = "rBinaryPly";
this.rBinaryPly.Size = new System.Drawing.Size(110, 24);
this.rBinaryPly.TabIndex = 30;
this.rBinaryPly.TabStop = true;
this.rBinaryPly.Text = "binary PLY";
this.rBinaryPly.UseVisualStyleBackColor = true;
this.rBinaryPly.CheckedChanged += new System.EventHandler(this.PlyFormat_CheckedChanged);
//
// lbFormat
//
this.lbFormat.AutoSize = true;
this.lbFormat.Location = new System.Drawing.Point(7, 106);
this.lbFormat.Margin = new System.Windows.Forms.Padding(4, 0, 4, 0);
this.lbFormat.Name = "lbFormat";
this.lbFormat.Size = new System.Drawing.Size(88, 20);
this.lbFormat.TabIndex = 29;
this.lbFormat.Text = "File format:";
//
// rAsciiPly
//
this.rAsciiPly.AutoSize = true;
this.rAsciiPly.Location = new System.Drawing.Point(156, 105);
this.rAsciiPly.Margin = new System.Windows.Forms.Padding(4, 5, 4, 5);
this.rAsciiPly.Name = "rAsciiPly";
this.rAsciiPly.Size = new System.Drawing.Size(111, 24);
this.rAsciiPly.TabIndex = 28;
this.rAsciiPly.TabStop = true;
this.rAsciiPly.Text = "ASCII PLY";
this.rAsciiPly.UseVisualStyleBackColor = true;
this.rAsciiPly.CheckedChanged += new System.EventHandler(this.PlyFormat_CheckedChanged);
//
// txtRefinIters
//
this.txtRefinIters.Location = new System.Drawing.Point(408, 31);
this.txtRefinIters.Margin = new System.Windows.Forms.Padding(4, 5, 4, 5);
this.txtRefinIters.Name = "txtRefinIters";
this.txtRefinIters.Size = new System.Drawing.Size(55, 26);
this.txtRefinIters.TabIndex = 27;
this.txtRefinIters.TextChanged += new System.EventHandler(this.txtRefinIters_TextChanged);
//
// lbOuterIters
//
this.lbOuterIters.AutoSize = true;
this.lbOuterIters.Location = new System.Drawing.Point(222, 36);
this.lbOuterIters.Margin = new System.Windows.Forms.Padding(4, 0, 4, 0);
this.lbOuterIters.Name = "lbOuterIters";
this.lbOuterIters.Size = new System.Drawing.Size(178, 20);
this.lbOuterIters.TabIndex = 26;
this.lbOuterIters.Text = "Num of refinement iters:";
//
// label2
//
this.label2.AutoSize = true;
this.label2.Location = new System.Drawing.Point(8, 139);
this.label2.Name = "label2";
this.label2.Size = new System.Drawing.Size(141, 20);
this.label2.TabIndex = 31;
this.label2.Text = "Compression level:";
//
// cbCompressionLevel
//
this.cbCompressionLevel.FormattingEnabled = true;
@@ -657,26 +659,91 @@
"15",
"17",
"19"});
this.cbCompressionLevel.Location = new System.Drawing.Point(154, 136);
this.cbCompressionLevel.Location = new System.Drawing.Point(103, 88);
this.cbCompressionLevel.Margin = new System.Windows.Forms.Padding(2);
this.cbCompressionLevel.Name = "cbCompressionLevel";
this.cbCompressionLevel.Size = new System.Drawing.Size(169, 28);
this.cbCompressionLevel.Size = new System.Drawing.Size(114, 21);
this.cbCompressionLevel.TabIndex = 32;
this.cbCompressionLevel.SelectedIndexChanged += new System.EventHandler(this.cbCompressionLevel_SelectedIndexChanged);
//
// label2
//
this.label2.AutoSize = true;
this.label2.Location = new System.Drawing.Point(5, 90);
this.label2.Margin = new System.Windows.Forms.Padding(2, 0, 2, 0);
this.label2.Name = "label2";
this.label2.Size = new System.Drawing.Size(95, 13);
this.label2.TabIndex = 31;
this.label2.Text = "Compression level:";
//
// rBinaryPly
//
this.rBinaryPly.AutoSize = true;
this.rBinaryPly.Location = new System.Drawing.Point(185, 68);
this.rBinaryPly.Name = "rBinaryPly";
this.rBinaryPly.Size = new System.Drawing.Size(76, 17);
this.rBinaryPly.TabIndex = 30;
this.rBinaryPly.TabStop = true;
this.rBinaryPly.Text = "binary PLY";
this.rBinaryPly.UseVisualStyleBackColor = true;
this.rBinaryPly.CheckedChanged += new System.EventHandler(this.PlyFormat_CheckedChanged);
//
// lbFormat
//
this.lbFormat.AutoSize = true;
this.lbFormat.Location = new System.Drawing.Point(5, 69);
this.lbFormat.Name = "lbFormat";
this.lbFormat.Size = new System.Drawing.Size(58, 13);
this.lbFormat.TabIndex = 29;
this.lbFormat.Text = "File format:";
//
// rAsciiPly
//
this.rAsciiPly.AutoSize = true;
this.rAsciiPly.Location = new System.Drawing.Point(104, 68);
this.rAsciiPly.Name = "rAsciiPly";
this.rAsciiPly.Size = new System.Drawing.Size(75, 17);
this.rAsciiPly.TabIndex = 28;
this.rAsciiPly.TabStop = true;
this.rAsciiPly.Text = "ASCII PLY";
this.rAsciiPly.UseVisualStyleBackColor = true;
this.rAsciiPly.CheckedChanged += new System.EventHandler(this.PlyFormat_CheckedChanged);
//
// txtRefinIters
//
this.txtRefinIters.Location = new System.Drawing.Point(272, 20);
this.txtRefinIters.Name = "txtRefinIters";
this.txtRefinIters.Size = new System.Drawing.Size(38, 20);
this.txtRefinIters.TabIndex = 27;
this.txtRefinIters.TextChanged += new System.EventHandler(this.txtRefinIters_TextChanged);
//
// lbOuterIters
//
this.lbOuterIters.AutoSize = true;
this.lbOuterIters.Location = new System.Drawing.Point(148, 23);
this.lbOuterIters.Name = "lbOuterIters";
this.lbOuterIters.Size = new System.Drawing.Size(118, 13);
this.lbOuterIters.TabIndex = 26;
this.lbOuterIters.Text = "Num of refinement iters:";
//
// SettingsForm
//
this.AutoScaleDimensions = new System.Drawing.SizeF(9F, 20F);
this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F);
this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font;
this.ClientSize = new System.Drawing.Size(984, 663);
this.ClientSize = new System.Drawing.Size(656, 554);
this.Controls.Add(this.grServer);
this.Controls.Add(this.grClient);
this.FormBorderStyle = System.Windows.Forms.FormBorderStyle.FixedSingle;
this.Margin = new System.Windows.Forms.Padding(4, 5, 4, 5);
this.MaximizeBox = false;
this.Name = "SettingsForm";
this.Text = "Settings";
this.FormClosed += new System.Windows.Forms.FormClosedEventHandler(this.SettingsForm_FormClosed);
this.Load += new System.EventHandler(this.SettingsForm_Load);
this.grClient.ResumeLayout(false);
this.grExposure.ResumeLayout(false);
this.grExposure.PerformLayout();
((System.ComponentModel.ISupportInitialize)(this.trManualExposure)).EndInit();
this.grTempSync.ResumeLayout(false);
this.grBody.ResumeLayout(false);
this.grBody.PerformLayout();
this.grMarkers.ResumeLayout(false);
@@ -744,6 +811,14 @@
private System.Windows.Forms.CheckBox chSkeletons;
private System.Windows.Forms.ComboBox cbCompressionLevel;
private System.Windows.Forms.Label label2;
private System.Windows.Forms.GroupBox grTempSync;
private System.Windows.Forms.Label label1;
private System.Windows.Forms.Label lbTempSync;
private System.Windows.Forms.Button btSyncDisable;
private System.Windows.Forms.Button btSyncEnable;
private System.Windows.Forms.TrackBar trManualExposure;
private System.Windows.Forms.GroupBox grExposure;
private System.Windows.Forms.Label lbManualExposure;
private System.Windows.Forms.CheckBox chAutoExposureEnabled;
}
}
+114
View File
@@ -30,6 +30,8 @@ namespace KinectServer
public KinectSettings oSettings;
public KinectServer oServer;
private Timer scrollTimer = null;
bool bFormLoaded = false;
public SettingsForm()
@@ -61,6 +63,14 @@ namespace KinectServer
chMerge.Checked = oSettings.bMergeScansForSave;
txtICPIters.Text = oSettings.nNumICPIterations.ToString();
txtRefinIters.Text = oSettings.nNumRefineIters.ToString();
btSyncEnable.Enabled = true;
btSyncDisable.Enabled = false;
chAutoExposureEnabled.Checked = oSettings.bAutoExposureEnabled;
trManualExposure.Value = oSettings.nExposureStep;
if (oSettings.bSaveAsBinaryPLY)
{
rBinaryPly.Checked = true;
@@ -78,9 +88,12 @@ namespace KinectServer
void UpdateClients()
{
if (bFormLoaded)
{
oServer.SendSettings();
}
}
void UpdateMarkerFields()
{
if (lisMarkers.SelectedIndex >= 0)
@@ -340,5 +353,106 @@ namespace KinectServer
}
UpdateClients();
}
private void btSyncEnable_click(object sender, EventArgs e)
{
if (oServer.GetAllDevicesInitialized() && oServer.nClientCount > 1)
{
oServer.RequestDeviceSyncState();
btSyncEnable.Enabled = false;
btSyncDisable.Enabled = true;
//Disable the Auto Exposure, as this could interfere with the temporal sync
chAutoExposureEnabled.Enabled = false;
trManualExposure.Enabled = true;
chAutoExposureEnabled.CheckState = CheckState.Unchecked;
}
}
private void btSyncDisable_click(object sender, EventArgs e)
{
if (oServer.GetAllDevicesInitialized())
{
oServer.DisableTemporalSync();
btSyncEnable.Enabled = true;
btSyncDisable.Enabled = false;
chAutoExposureEnabled.Enabled = true;
}
}
public void ActivateTempSyncEnableButton()
{
//As a Form code is run on a single UI thread, we need to communicate with that thread via Invoke
this.BeginInvoke(new MethodInvoker(delegate
{
btSyncEnable.Enabled = true;
btSyncDisable.Enabled = false;
chAutoExposureEnabled.Enabled = true;
}));
}
private void chAutoExposureEnabled_CheckedChanged(object sender, EventArgs e)
{
oSettings.bAutoExposureEnabled = chAutoExposureEnabled.Checked;
UpdateClients();
trManualExposure.Enabled = !oSettings.bAutoExposureEnabled;
}
/// <summary>
/// When the user scrolls on the trackbar, we wait a short amount of time to check if the user has scrolled again.
/// This prevents the Manual Exposure to be set too often, and only sets it when the user has stopped scrolling.
/// Code taken from: https://stackoverflow.com/a/15687418
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
private void trManualExposure_Scroll(object sender, EventArgs e)
{
if (scrollTimer == null)
{
// Will tick every 500ms
scrollTimer = new Timer()
{
Enabled = false,
Interval = 300,
Tag = (sender as TrackBar).Value
};
scrollTimer.Tick += (s, ea) =>
{
// check to see if the value has changed since we last ticked
if (trManualExposure.Value == (int)scrollTimer.Tag)
{
// scrolling has stopped so we are good to go ahead and do stuff
scrollTimer.Stop();
// Send the changed exposure to the devices
//Clamp Exposure Step between -11 and 1
int exposureStep = trManualExposure.Value;
int exposureStepClamped = exposureStep < -11 ? -11 : exposureStep > 1 ? 1 : exposureStep;
oSettings.nExposureStep = exposureStepClamped;
UpdateClients();
scrollTimer.Dispose();
scrollTimer = null;
}
else
{
// record the last value seen
scrollTimer.Tag = trManualExposure.Value;
}
};
scrollTimer.Start();
}
}
private void SettingsForm_FormClosed(object sender, FormClosedEventArgs e)
{
oServer.SetSettingsForm(null);
}
}
}
+9
View File
@@ -19,6 +19,15 @@ To start working with our software you will need a Windows machine with the Kine
Both the binary and source distributions contain a manual (in the docs directory) which contains the steps necessary to start working with our software (it won't take more than a couple of minutes to set up).
#### Temporal Synchronziaton (Azure Kinect only) ####
LiveScan3D supports the synchronization feature of the Azure Kinect, which will temporally sync multiple devices to allow for a cleaner capture.
To enable it, connect all devices via cable in a Daisy-chain configuration [(more information here)](https://docs.microsoft.com/en-us/azure/kinect-dk/multi-camera-sync/). Open the settings in the LiveScan server and click the "Enable"-Button found under "Temporal Sync". The devices will now perform a restart and after a few seconds you should be able to see the role of the devices (Master, Subordinate, Slave) in the Client-List of the Server. A error message will appear if the devices are not connected properly, or experience other difficulties.
*Note: While the Sync feature is activated, the camera exposure has to be controlled manually.*
#### Exposure Control (Azure Kinect only) ####
Livescan supports exposure control for all clients. LiveScan uses auto exposure as a default setting. To enable or disable manual exposure, open the settings on the LiveScan server and tick the "Auto exposure enabled" box. If auto exposure is disabled, you can manually set the exposure with the slider provided below the box.
## Where to get help ##
If you have any problems feel free to contact us: Marek Kowalski <m.kowalski@ire.pw.edu.pl>, Jacek Naruniec <j.naruniec@ire.pw.edu.pl>. We usually answer emails quickly (our timezone is CET).
Binary file not shown.
+19 -4
View File
@@ -14,17 +14,21 @@ public:
AzureKinectCapture();
~AzureKinectCapture();
bool Initialize();
bool Initialize(SYNC_STATE state, int syncOffset);
bool AcquireFrame();
bool Close();
void MapDepthFrameToCameraSpace(Point3f *pCameraSpacePoints);
void MapColorFrameToCameraSpace(Point3f *pCameraSpacePoints);
void MapDepthFrameToColorSpace(UINT16 *pDepthInColorSpace);
void MapColorFrameToDepthSpace(RGB *pColorInDepthSpace);
int GetSyncJackState();
uint64_t GetTimeStamp();
int GetDeviceIndex();
void SetExposureState(bool enableAutoExposure, int exposureStep);
private:
k4a_device_t kinectSensor = NULL;
int32_t captureTimeoutMs = 1000;
k4a_image_t colorImage = NULL;
k4a_image_t depthImage = NULL;
k4a_image_t pointCloudImage = NULL;
@@ -32,10 +36,21 @@ private:
k4a_image_t colorImageInDepth = NULL;
k4a_image_t depthImageInColor = NULL;
k4a_image_t colorImageDownscaled = NULL;
k4a_transformation_t transformationColorDownscaled = NULL;
k4a_transformation_t transformation = NULL;
int colorImageDownscaledWidth;
int colorImageDownscaledHeight;
k4a_transformation_t transformation = NULL;
k4a_transformation_t transformationColorDownscaled = NULL;
bool syncInConnected = false;
bool syncOutConnected = false;
uint64_t currentTimeStamp = 0;
SYNC_STATE syncState = Standalone;
int deviceIDForRestart = -1;
int restartAttempts = 0;
bool autoExposureEnabled = true;
int exposureTimeStep = 0;
void UpdateDepthPointCloud();
void UpdateDepthPointCloudForColorFrame();
};
@@ -10,13 +10,13 @@ class FrameFileWriterReader
{
public:
FrameFileWriterReader();
void openNewFileForWriting();
void openNewFileForWriting(int deviceID);
void openCurrentFileForReading();
// leave filename blank if you want the filename to be generated from the date
void setCurrentFilename(std::string filename = "");
void writeFrame(std::vector<Point3s> points, std::vector<RGB> colors);
void writeFrame(std::vector<Point3s> points, std::vector<RGB> colors, uint64_t timestamp, int deviceID);
bool readFrame(std::vector<Point3s> &outPoints, std::vector<RGB> &outColors);
bool openedForWriting() { return m_bFileOpenedForWriting; }
+9 -1
View File
@@ -40,12 +40,18 @@ public:
ICapture();
~ICapture();
virtual bool Initialize() = 0;
virtual bool Initialize(SYNC_STATE state, int syncOffset) = 0;
virtual bool AcquireFrame() = 0;
virtual bool Close() = 0;
virtual void MapDepthFrameToCameraSpace(Point3f *pCameraSpacePoints) = 0;
virtual void MapColorFrameToCameraSpace(Point3f *pCameraSpacePoints) = 0;
virtual void MapDepthFrameToColorSpace(UINT16 *pColorSpacePoints) = 0;
virtual void MapColorFrameToDepthSpace(RGB *pDepthSpacePoints) = 0;
virtual int GetSyncJackState() = 0;
virtual uint64_t GetTimeStamp() = 0;
virtual int GetDeviceIndex() = 0;
virtual void SetExposureState(bool enableAutoExposure, int exposureStep) = 0;
bool bInitialized;
@@ -57,5 +63,7 @@ public:
RGB *pColorRGBX;
std::vector<Body> vBodies;
std::string serialNumber;
};
+14 -1
View File
@@ -18,7 +18,7 @@
#include "ImageRenderer.h"
#include "SocketCS.h"
#include "calibration.h"
#include "utils.h"
//#include "utils.h"
#include "azureKinectCapture.h"
#include "frameFileWriterReader.h"
#include <thread>
@@ -43,6 +43,10 @@ private:
bool m_bFilter;
bool m_bStreamOnlyBodies;
bool m_bIsMaster;
bool m_bIsSubOrdinate;
bool m_bRestartingCamera;
ICapture *pCapture;
int m_nFilterNeighbors;
@@ -51,10 +55,18 @@ private:
bool m_bCaptureFrame;
bool m_bConnected;
bool m_bConfirmCaptured;
bool m_bConfirmTempSyncState;
bool m_bConfirmSubOrdinateStarted;
bool m_bConfirmRestartAsMaster;
bool m_bConfirmCalibrated;
bool m_bShowDepth;
bool m_bFrameCompression;
int m_iCompressionLevel;
bool m_bAutoExposureEnabled;
int m_nExposureStep;
enum tempSyncConfig { MASTER, SUBORDINATE, STANDALONE };
tempSyncConfig currentTempSyncState;
FrameFileWriterReader m_framesFileWriterReader;
@@ -71,6 +83,7 @@ private:
double m_fFreq;
INT64 m_nNextStatusTime;
DWORD m_nFramesSinceUpdate;
int frameRecordCounter;
Point3f* m_pCameraSpaceCoordinates;
RGB* m_pColorInColorSpace;
+16 -2
View File
@@ -27,7 +27,11 @@ enum INCOMING_MESSAGE_TYPE
MSG_REQUEST_STORED_FRAME,
MSG_REQUEST_LAST_FRAME,
MSG_RECEIVE_CALIBRATION,
MSG_CLEAR_STORED_FRAMES
MSG_CLEAR_STORED_FRAMES,
MSG_SET_TEMPSYNC_ON,
MSG_SET_TEMPSYNC_OFF,
MSG_START_MASTER,
MSG_REQUEST_SYNC_JACK_STATE,
};
enum OUTGOING_MESSAGE_TYPE
@@ -35,7 +39,17 @@ enum OUTGOING_MESSAGE_TYPE
MSG_CONFIRM_CAPTURED,
MSG_CONFIRM_CALIBRATED,
MSG_STORED_FRAME,
MSG_LAST_FRAME
MSG_LAST_FRAME,
MSG_CONFIRM_TEMP_SYNC_STATUS,
MSG_CONFIRM_MASTER_RESTART,
MSG_SYNC_JACK_STATE
};
enum SYNC_STATE
{
Subordinate,
Master,
Standalone
};
typedef struct Point3f
+174 -1
View File
@@ -22,13 +22,31 @@ AzureKinectCapture::~AzureKinectCapture()
k4a_device_close(kinectSensor);
}
bool AzureKinectCapture::Initialize()
/// <summary>
/// Initialize the device. If you want to initialize it as Standalone, set "asMaster" and "asSubordinate" to false
/// </summary>
/// <param name="asMaster">Initializes this device as master</param>
/// <param name="asSubordinate">Initalizes this devices as subordinate</param>
/// <param name="syncOffsetMultiplier">Should only be set when initializing as Subordinate. Each subordinate should have a unique, ascending value</param>
/// <returns></returns>
bool AzureKinectCapture::Initialize(SYNC_STATE state, int syncOffsetMultiplier)
{
uint32_t count = k4a_device_get_installed_count();
int deviceIdx = 0;
//We save the deviceId of this Client.
//When the cameras are reinitialized during runtime, we can then gurantee
//that each LiveScan instance uses the same device as before (In case two or more Kinects are connected to the same PC)
//A device ID of -1 means that no Kinects has been successfully initalized yet (only happens when the Client starts)
if (deviceIDForRestart != -1) {
deviceIdx = deviceIDForRestart;
}
kinectSensor = NULL;
while (K4A_FAILED(k4a_device_open(deviceIdx, &kinectSensor)))
{
if (deviceIDForRestart == -1)
{
deviceIdx++;
if (deviceIdx >= count)
@@ -38,6 +56,26 @@ bool AzureKinectCapture::Initialize()
}
}
else {
//Sometimes the cameras fail to reinitialize, so we try to initialize them three times with a slight delay before failing
if (restartAttempts > 2)
{
bInitialized = false;
return bInitialized;
}
else {
restartAttempts++;
Sleep(200);
}
}
}
k4a_device_configuration_t config = K4A_DEVICE_CONFIG_INIT_DISABLE_ALL;
config.camera_fps = K4A_FRAMES_PER_SECOND_30;
config.color_format = K4A_IMAGE_FORMAT_COLOR_BGRA32;
@@ -45,6 +83,24 @@ bool AzureKinectCapture::Initialize()
config.depth_mode = K4A_DEPTH_MODE_NFOV_UNBINNED;
config.synchronized_images_only = true;
if (state == Master)
{
config.wired_sync_mode = K4A_WIRED_SYNC_MODE_MASTER;
}
else if (state == Subordinate)
{
config.wired_sync_mode = K4A_WIRED_SYNC_MODE_SUBORDINATE;
//Sets the offset on subordinate devices. Should be a multiple of 160, each subordinate having a different multiplier in ascending order.
//This is very important, as it avoids firing the Kinects lasers at the same time.
config.subordinate_delay_off_master_usec = 160 * syncOffsetMultiplier;
}
else
{
config.wired_sync_mode = K4A_WIRED_SYNC_MODE_STANDALONE;
}
// Start the camera with the given configuration
bInitialized = K4A_SUCCEEDED(k4a_device_start_cameras(kinectSensor, &config));
@@ -54,6 +110,21 @@ bool AzureKinectCapture::Initialize()
bInitialized = false;
return bInitialized;
}
//Workaround for a bug. When the camera starts in manual Exposure mode, the brightness of the RBG image
//is much lower than in auto exposure mode. To prevent this, we first set the camera to auto exposure mode and
//then switch to manual mode again if it has been enabled before
if (autoExposureEnabled == false) {
k4a_device_set_color_control(kinectSensor, K4A_COLOR_CONTROL_EXPOSURE_TIME_ABSOLUTE, K4A_COLOR_CONTROL_MODE_AUTO, 0);
//Give it a second to adjust
Sleep(1000);
SetExposureState(false, exposureTimeStep);
}
transformation = k4a_transformation_create(&calibration);
@@ -104,6 +175,9 @@ bool AzureKinectCapture::Initialize()
calibrationColorDownscaled.color_camera_calibration.intrinsics.parameters.param.fy /= rescaleRatio;
transformationColorDownscaled = k4a_transformation_create(&calibrationColorDownscaled);
//If this device is a subordinate, it is expected to start capturing at a later time (When the master has started), so we skip this check
if (state != Subordinate)
{
std::chrono::time_point<std::chrono::system_clock> start = std::chrono::system_clock::now();
bool bTemp;
do
@@ -117,16 +191,35 @@ bool AzureKinectCapture::Initialize()
break;
}
} while (!bTemp);
}
size_t serialNoSize;
k4a_device_get_serialnum(kinectSensor, NULL, &serialNoSize);
serialNumber = std::string(serialNoSize, '\0');
k4a_device_get_serialnum(kinectSensor, (char*)serialNumber.c_str(), &serialNoSize);
deviceIDForRestart = deviceIdx;
restartAttempts = 0;
return bInitialized;
}
bool AzureKinectCapture::Close()
{
if (!bInitialized)
{
return false;
}
k4a_device_stop_cameras(kinectSensor);
k4a_device_close(kinectSensor);
bInitialized = false;
return true;
}
bool AzureKinectCapture::AcquireFrame()
{
if (!bInitialized)
@@ -149,6 +242,9 @@ bool AzureKinectCapture::AcquireFrame()
colorImage = k4a_capture_get_color_image(capture);
depthImage = k4a_capture_get_depth_image(capture);
currentTimeStamp = k4a_image_get_device_timestamp_usec(colorImage);
if (colorImage == NULL || depthImage == NULL)
{
k4a_capture_release(capture);
@@ -187,11 +283,13 @@ bool AzureKinectCapture::AcquireFrame()
memcpy(pColorRGBX, k4a_image_get_buffer(colorImageDownscaled), nColorFrameWidth * nColorFrameHeight * sizeof(RGB));
memcpy(pDepth, k4a_image_get_buffer(depthImage), nDepthFrameHeight * nDepthFrameWidth * sizeof(UINT16));
k4a_capture_release(capture);
return true;
}
void AzureKinectCapture::UpdateDepthPointCloudForColorFrame()
{
if (transformedDepthImage == NULL)
@@ -283,4 +381,79 @@ void AzureKinectCapture::MapColorFrameToDepthSpace(RGB* pColorInDepthSpace)
memcpy(pColorInDepthSpace, k4a_image_get_buffer(colorImageInDepth), nDepthFrameHeight * nDepthFrameWidth * 4 * (int)sizeof(uint8_t));
}
/// <summary>
/// Enables/Disables Auto Exposure and/or sets the exposure to a step value between -11 and -5
/// The kinect supports exposure values up to 1, but these are only available in lower FPS modes (5 or 15 FPS)
/// For further information on how this value translates to ms-Values, please take a look
/// at this table: https://github.com/microsoft/Azure-Kinect-Sensor-SDK/blob/develop/src/color/color_priv.h
/// </summary>
/// <param name="exposureStep">The Exposure Step between -11 and 1</param>
void AzureKinectCapture::SetExposureState(bool enableAutoExposure, int exposureStep)
{
if (bInitialized)
{
if (enableAutoExposure)
{
k4a_device_set_color_control(kinectSensor, K4A_COLOR_CONTROL_EXPOSURE_TIME_ABSOLUTE, K4A_COLOR_CONTROL_MODE_AUTO, 0);
autoExposureEnabled = true;
}
else
{
//Formula copied from here: https://github.com/microsoft/Azure-Kinect-Sensor-SDK/blob/7cd8683a1a71b8baebef4a3537e6edd8639d1e95/examples/k4arecorder/main.cpp#L333
float absExposure = (exp2f((float)exposureStep) * 1000000.0f);
//We add 0.5 because C++ always truncates when converting to an integer.
//This ensures that values will always be rounded correctly
float absExposureRoundingMargin = absExposure + 0.5;
int32_t absoluteExposureInt = (int32_t)absExposureRoundingMargin;
k4a_device_set_color_control(kinectSensor, K4A_COLOR_CONTROL_EXPOSURE_TIME_ABSOLUTE, K4A_COLOR_CONTROL_MODE_MANUAL, absoluteExposureInt);
autoExposureEnabled = false;
exposureTimeStep = exposureStep;
}
}
}
/// <summary>
/// Determines if this camera is configured as a Master, Subordinate or Standalone.
/// This is achieved by looking at how the sync out and sync in ports of the device are connected
/// </summary>
/// <returns>Returns int -1 for Subordinate, int 0 for Master and int 1 for Standalone</returns>
int AzureKinectCapture::GetSyncJackState()
{
if (K4A_RESULT_SUCCEEDED == k4a_device_get_sync_jack(kinectSensor, &syncInConnected, &syncOutConnected))
{
if (syncInConnected)
{
return -1; //Device is Subordinate, as it recieves a signal via its "Sync In" Port
}
else if (!syncInConnected && syncOutConnected)
{
return 0; //Device is Master, as it doens't recieve a signal from its "Sync In" Port, but sends one through its "Sync Out" Port
}
else
{
return 1; //Device is Standalone, as it doesn't have a valid cabel configuration on its Sync Ports
}
}
else
{
return 1; //Probably failed because there are no cabels connected, this means the device should be set as standalone
}
}
uint64_t AzureKinectCapture::GetTimeStamp()
{
return currentTimeStamp;
}
int AzureKinectCapture::GetDeviceIndex()
{
return deviceIDForRestart;
}
+7 -5
View File
@@ -39,14 +39,14 @@ void FrameFileWriterReader::openCurrentFileForReading()
m_bFileOpenedForWriting = false;
}
void FrameFileWriterReader::openNewFileForWriting()
void FrameFileWriterReader::openNewFileForWriting(int deviceID)
{
closeFileIfOpened();
char filename[1024];
time_t t = time(0);
struct tm * now = localtime(&t);
sprintf(filename, "recording_%04d_%02d_%02d_%02d_%02d.bin", now->tm_year + 1900, now->tm_mon + 1, now->tm_mday, now->tm_hour, now->tm_min, now->tm_sec);
sprintf(filename, "recording_%01d_%04d_%02d_%02d_%02d_%02d.bin", deviceID, now->tm_year + 1900, now->tm_mon + 1, now->tm_mday, now->tm_hour, now->tm_min, now->tm_sec);
m_sFilename = filename;
m_pFileHandle = fopen(filename, "wb");
@@ -86,15 +86,17 @@ bool FrameFileWriterReader::readFrame(std::vector<Point3s> &outPoints, std::vect
}
void FrameFileWriterReader::writeFrame(std::vector<Point3s> points, std::vector<RGB> colors)
void FrameFileWriterReader::writeFrame(std::vector<Point3s> points, std::vector<RGB> colors, uint64_t timestamp, int deviceID)
{
if (!m_bFileOpenedForWriting)
openNewFileForWriting();
openNewFileForWriting(deviceID);
FILE *f = m_pFileHandle;
int nPoints = static_cast<int>(points.size());
fprintf(f, "n_points= %d\nframe_timestamp= %d\n", nPoints, getRecordingTimeMilliseconds());
//The Timestamp is generated by the Kinect instead of the system. If temporal Sync is enabled, Master and Subordinate have a synced timestamp
fprintf(f, "n_points= %d\nframe_timestamp= %d\n", nPoints, timestamp);
if (nPoints > 0)
{
fwrite((void*)points.data(), sizeof(points[0]), nPoints, f);
+175 -5
View File
@@ -56,13 +56,17 @@ LiveScanClient::LiveScanClient() :
m_bConnected(false),
m_bConfirmCaptured(false),
m_bConfirmCalibrated(false),
m_bConfirmRestartAsMaster(false),
m_bShowDepth(false),
m_bSocketThread(true),
m_bFrameCompression(true),
m_iCompressionLevel(2),
m_pClientSocket(NULL),
m_nFilterNeighbors(10),
m_fFilterThreshold(0.01f)
m_fFilterThreshold(0.01f),
m_bRestartingCamera(false),
m_bAutoExposureEnabled(true), // Which state the Auto Exposure should be set to
m_nExposureStep(-5)
{
pCapture = new AzureKinectCapture();
@@ -206,7 +210,8 @@ void LiveScanClient::UpdateFrame()
if (m_bCaptureFrame)
{
m_framesFileWriterReader.writeFrame(m_vLastFrameVertices, m_vLastFrameRGB);
uint64_t timeStamp = pCapture->GetTimeStamp();
m_framesFileWriterReader.writeFrame(m_vLastFrameVertices, m_vLastFrameRGB, timeStamp, pCapture->GetDeviceIndex());
m_bConfirmCaptured = true;
m_bCaptureFrame = false;
}
@@ -275,16 +280,16 @@ LRESULT CALLBACK LiveScanClient::DlgProc(HWND hWnd, UINT message, WPARAM wParam,
// Init Direct2D
D2D1CreateFactory(D2D1_FACTORY_TYPE_SINGLE_THREADED, &m_pD2DFactory);
// Get and initialize the default Kinect sensor
bool res = pCapture->Initialize();
// Get and initialize the default Kinect sensor as standalone
bool res = pCapture->Initialize(Standalone, 0);
if (res)
{
calibration.LoadCalibration(pCapture->serialNumber);
m_pDepthRGBX = new RGB[pCapture->nColorFrameWidth * pCapture->nColorFrameHeight];
m_pDepthInColorSpace = new UINT16[pCapture->nColorFrameWidth * pCapture->nColorFrameHeight];
m_pCameraSpaceCoordinates = new Point3f[pCapture->nColorFrameWidth * pCapture->nColorFrameHeight];
m_pColorInColorSpace = new RGB[pCapture->nColorFrameWidth * pCapture->nColorFrameHeight];
pCapture->SetExposureState(true, 0);
}
else
{
@@ -444,6 +449,124 @@ void LiveScanClient::HandleSocket()
//calibrate
else if (received[i] == MSG_CALIBRATE)
m_bCalibrate = true;
//Enables Temporal sync on this client
else if (received[i] == MSG_SET_TEMPSYNC_ON) {
i++; //Get next byte (the sync Offset)
int syncOffset = received[i];
//Determine if this device is a subordinate, master, or standalone
int jackState = pCapture->GetSyncJackState();
bool res = false;
switch (jackState)
{
case -1:
currentTempSyncState = SUBORDINATE;
//Restart this device as Subordinate, with a unique syncOffset (send by the server)
m_bRestartingCamera = true;
res = pCapture->Close();
if (!res) {
SetStatusMessage(L"Subordinate device failed to close! Restart Application!", 10000, true);
return;
}
res = pCapture->Initialize(Subordinate, syncOffset);
if (!res) {
SetStatusMessage(L"Subordinate device failed to reinitialize! Restart Application!", 10000, true);
return;
}
//Confirm to the server, that we set this device as subordinate
m_bConfirmTempSyncState = true;
m_bRestartingCamera = false;
break;
case 0:
currentTempSyncState = MASTER;
//Only Close this device, as it needs to wait for all subordinates to start, before starting itself
m_bRestartingCamera = true;
res = pCapture->Close();
if (!res) {
SetStatusMessage(L"Master device failed to close! Restart Application!", 10000, true);
return;
}
m_bConfirmTempSyncState = true;
break;
case 1://Device is Standalone
currentTempSyncState = STANDALONE;
//Restart this device as Standalone
m_bRestartingCamera = true;
res = pCapture->Close();
if (!res) {
SetStatusMessage(L"Capture device failed to close! Restart Application!", 10000, true);
return;
}
res = pCapture->Initialize(Standalone, 0);
if (!res) {
SetStatusMessage(L"Capture device failed to reinitialize! Restart Application!", 10000, true);
return;
}
m_bConfirmTempSyncState = true;
m_bRestartingCamera = false;
break;
default:
break;
}
}
//Sets this device as Standalone
else if (received[i] == MSG_SET_TEMPSYNC_OFF) {
currentTempSyncState = STANDALONE;
m_bRestartingCamera = true;
bool res;
res = pCapture->Close();
if (!res) {
SetStatusMessage(L"Capture device failed to close! Restart Application!", 10000, true);
return;
}
res = pCapture->Initialize(Standalone, 0);
if (!res) {
SetStatusMessage(L"Capture device failed to reinitialize! Restart Application!", 10000, true);
return;
}
m_bConfirmTempSyncState = true;
m_bRestartingCamera = false;
}
//Got confirmation from the server that all subs have started, and we can now start the master
else if (received[i] == MSG_START_MASTER) {
if (currentTempSyncState == MASTER)
{
bool res = pCapture->Initialize(Master, 0);
if (!res) {
SetStatusMessage(L"Master device failed to reinitialize! Restart Application!", 10000, true);
return;
}
m_bConfirmRestartAsMaster = true;
m_bRestartingCamera = false;
}
}
//receive settings
//TODO: what if packet is split?
else if (received[i] == MSG_RECEIVE_SETTINGS)
@@ -506,6 +629,14 @@ void LiveScanClient::HandleSocket()
else
m_bFrameCompression = false;
m_bAutoExposureEnabled = (received[i] != 0);
i++;
m_nExposureStep = *(int*)(received.c_str() + i);
i += sizeof(int);
pCapture->SetExposureState(m_bAutoExposureEnabled, m_nExposureStep);
//so that we do not lose the next character in the stream
i--;
}
@@ -558,6 +689,18 @@ void LiveScanClient::HandleSocket()
{
m_framesFileWriterReader.closeFileIfOpened();
}
else if (received[i] == MSG_REQUEST_SYNC_JACK_STATE)
{
int size = 3;
char* buffer = new char[size];
buffer[0] = MSG_SYNC_JACK_STATE;
buffer[1] = pCapture->GetSyncJackState() + 1; //Gets the current Sync Jack State and adds + 1, as we can't send a negative value
m_pClientSocket->SendBytes(buffer, size);
m_bConfirmTempSyncState = false;
}
}
if (m_bConfirmCaptured)
@@ -567,6 +710,33 @@ void LiveScanClient::HandleSocket()
m_bConfirmCaptured = false;
}
//Send validation to the server that this device has been set to a specific Sync State
if (m_bConfirmTempSyncState)
{
int size = 3; //Somehow it doesn't work when sending only two bytes?? (So we send an extra one)
char* buffer = new char[size];
buffer[0] = MSG_CONFIRM_TEMP_SYNC_STATUS;
switch (currentTempSyncState)
{
case SUBORDINATE: buffer[1] = 0; break;
case MASTER: buffer[1] = 1; break;
case STANDALONE: buffer[1] = 2; break;
}
m_pClientSocket->SendBytes(buffer, size);
m_bConfirmTempSyncState = false;
}
//Send validation to the server that the Master camera has started recording again
if (m_bConfirmRestartAsMaster)
{
byteToSend = MSG_CONFIRM_MASTER_RESTART;
m_pClientSocket->SendBytes(&byteToSend, 1);
m_bConfirmRestartAsMaster = false;
}
if (m_bConfirmCalibrated)
{
int size = (9 + 3) * sizeof(float) + sizeof(int) + 1;