deleted a bunch of stuff I'm not making use of

This commit is contained in:
Cowwan 2024-02-05 16:43:28 -05:00
parent ccbcae05c0
commit 1e622bbc92
65 changed files with 0 additions and 14534 deletions

File diff suppressed because it is too large Load diff

View file

@ -1,8 +0,0 @@
fileFormatVersion: 2
guid: 697b139e69dcb414498dcd93210620ff
NativeFormatImporter:
externalObjects: {}
mainObjectFileID: 0
userData:
assetBundleName:
assetBundleVariant:

File diff suppressed because it is too large Load diff

View file

@ -1,11 +0,0 @@
fileFormatVersion: 2
guid: 735f1f2cba9bb364892bc2c7e7a30c19
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View file

@ -1,78 +0,0 @@
using System.Collections.Generic;
using UnityEngine;
using VRM;
namespace OpenSee {
public class OpenSeeVRMExpression : MonoBehaviour
{
public OpenSee openSee;
public OpenSeeExpression openSeeExpression;
public VRMBlendShapeProxy vrmBlendShapeProxy;
public string expressionNeutral = "neutral";
public string expressionFun = "smile";
public string expressionSorrow = "sad";
public string expressionAngry = "angry";
public string expressionJoy = "shocked";
private BlendShapeKey lastKey;
void Start()
{
}
void Update()
{
if (openSeeExpression == null || vrmBlendShapeProxy == null) {
return;
}
float rightEyeOpen = 1f;
float leftEyeOpen = 1f;
if (openSee != null) {
var openSeeData = openSee.trackingData;
if (openSeeData == null || openSeeData.Length < 1)
return;
int idx = -1;
int i = 0;
foreach (var item in openSeeData) {
if (item.id == openSeeExpression.faceId)
idx = i;
i++;
}
if (idx > -1) {
rightEyeOpen = openSeeData[idx].rightEyeOpen;
leftEyeOpen = openSeeData[idx].leftEyeOpen;
}
}
vrmBlendShapeProxy.ImmediatelySetValue(BlendShapeKey.CreateFromPreset(BlendShapePreset.Neutral), 0f);
vrmBlendShapeProxy.ImmediatelySetValue(BlendShapeKey.CreateFromPreset(BlendShapePreset.Fun), 0f);
vrmBlendShapeProxy.ImmediatelySetValue(BlendShapeKey.CreateFromPreset(BlendShapePreset.Sorrow), 0f);
vrmBlendShapeProxy.ImmediatelySetValue(BlendShapeKey.CreateFromPreset(BlendShapePreset.Angry), 0f);
vrmBlendShapeProxy.ImmediatelySetValue(BlendShapeKey.CreateFromPreset(BlendShapePreset.Joy), 0f);
vrmBlendShapeProxy.ImmediatelySetValue(BlendShapeKey.CreateFromPreset(BlendShapePreset.Blink_R), 0f);
vrmBlendShapeProxy.ImmediatelySetValue(BlendShapeKey.CreateFromPreset(BlendShapePreset.Blink_L), 0f);
if (openSeeExpression.expression == expressionFun) {
vrmBlendShapeProxy.ImmediatelySetValue(BlendShapeKey.CreateFromPreset(BlendShapePreset.Fun), 1f);
return;
} else if (openSeeExpression.expression == expressionSorrow) {
vrmBlendShapeProxy.ImmediatelySetValue(BlendShapeKey.CreateFromPreset(BlendShapePreset.Sorrow), 1f);
return;
} else if (openSeeExpression.expression == expressionAngry) {
vrmBlendShapeProxy.ImmediatelySetValue(BlendShapeKey.CreateFromPreset(BlendShapePreset.Angry), 1f);
return;
} else if (openSeeExpression.expression == expressionJoy) {
vrmBlendShapeProxy.ImmediatelySetValue(BlendShapeKey.CreateFromPreset(BlendShapePreset.Joy), 1f);
return;
} else {
/*if (rightEyeOpen < 0.05) {
vrmBlendShapeProxy.ImmediatelySetValue(new BlendShapeKey(BlendShapePreset.Blink_R), 1f);
}
if (leftEyeOpen < 0.05) {
vrmBlendShapeProxy.ImmediatelySetValue(new BlendShapeKey(BlendShapePreset.Blink_L), 1f);
}*/
}
vrmBlendShapeProxy.ImmediatelySetValue(BlendShapeKey.CreateFromPreset(BlendShapePreset.Neutral), 1f);
}
}
}

View file

@ -1,11 +0,0 @@
fileFormatVersion: 2
guid: 3c7910e1fb62bf449920cea2fdf07326
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View file

@ -1,270 +0,0 @@
using System;
using System.Diagnostics;
using System.IO;
using System.Net;
using System.Runtime.InteropServices;
using System.Text;
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
namespace OpenSee {
[Serializable]
public enum OpenSeeWebcamType { Unknown = -1, DirectShow, Blackmagic };
[Serializable]
public enum OpenSeeWebcamFormat { Any = 0, Unknown = 1, ARGB = 100, XRGB, I420 = 200, NV12, YV12, Y800, YVYU = 300, YUY2, UYVY, HDYC, MJPEG = 400, H264 };
[Serializable]
public struct OpenSeeWebcamCapability {
public int id;
// DirectShow
public int minCX;
public int minCY;
public int maxCX;
public int maxCY;
public int granularityCX;
public int granularityCY;
public int minInterval;
public int maxInterval;
public int rating;
public OpenSeeWebcamFormat format;
// Blackmagic
public int bmTimescale;
public int bmFrameduration;
public int bmModecode;
}
[Serializable]
public class OpenSeeWebcam {
public OpenSeeWebcamType type = OpenSeeWebcamType.Unknown;
public int id;
public string name;
// DirectShow
public string path;
// Blackmagic
public long bmId;
public int bmFlags;
// General
public OpenSeeWebcamCapability[] caps;
public List<string> prettyCaps = null;
private List<Tuple<OpenSeeWebcamCapability, int>> splitCaps = null;
bool ge(bool a, bool b) {
return a || (!a && !b);
}
private int CompareCaps(OpenSeeWebcamCapability a, OpenSeeWebcamCapability b) {
int aRes = a.minCX * a.minCY;
int bRes = b.minCX * b.minCY;
bool aGoodFps = a.minInterval <= 670000;
bool bGoodFps = a.minInterval <= 670000;
bool aGoodRes = aRes >= 850000 && aRes <= 2200000;
bool bGoodRes = bRes >= 850000 && bRes <= 2200000;
if (a.rating < b.rating && ge(aGoodFps, bGoodFps) && ge(aGoodRes, bGoodRes))
return -1;
if (a.rating > b.rating && ge(bGoodFps, aGoodFps) && ge(bGoodRes, aGoodRes))
return 1;
if (aRes > bRes && ge(aGoodFps, bGoodFps) && ge(aGoodRes, bGoodRes))
return -1;
if (aRes < bRes && ge(bGoodFps, aGoodFps) && ge(bGoodRes, aGoodRes))
return 1;
if (a.minInterval < b.minInterval)
return -1;
if (a.minInterval > b.minInterval)
return 1;
return 0;
}
private string GetPrettyCapability(OpenSeeWebcamCapability cap) {
float fps = 10000000f / (float)cap.minInterval;
string prettyCap = cap.minCX + "x" + cap.minCY + ", " + fps.ToString("0.##") + "fps (" + cap.format.ToString() + ")";
return prettyCap;
}
public List<string> GetPrettyCapabilities() {
if (splitCaps != null && prettyCaps != null)
return prettyCaps;
splitCaps = new List<Tuple<OpenSeeWebcamCapability, int>>();
for (int i = 0; i < caps.Length; i++) {
if (caps[i].minCX == caps[i].maxCX && caps[i].minCY == caps[i].maxCY)
splitCaps.Add(new Tuple<OpenSeeWebcamCapability, int>(caps[i], i));
else {
OpenSeeWebcamCapability min = caps[i];
OpenSeeWebcamCapability max = caps[i];
min.maxCX = min.minCX;
min.maxCY = min.minCY;
max.minCX = max.maxCX;
max.minCY = max.maxCY;
splitCaps.Add(new Tuple<OpenSeeWebcamCapability, int>(min, i));
splitCaps.Add(new Tuple<OpenSeeWebcamCapability, int>(max, i));
}
}
splitCaps.Sort((a, b) => CompareCaps(a.Item1, b.Item1));
prettyCaps = new List<string>();
if (type == OpenSeeWebcamType.DirectShow)
prettyCaps.Add("Default settings");
foreach (var cap in splitCaps) {
prettyCaps.Add(GetPrettyCapability(cap.Item1));
}
return prettyCaps;
}
public OpenSeeWebcamCapability GetCapabilityByPrettyIndex(int index) {
int dshowOffset = 0;
if (type == OpenSeeWebcamType.DirectShow) {
if (index == 0) {
OpenSeeWebcamCapability cap = new OpenSeeWebcamCapability();
cap.id = -1;
cap.format = OpenSeeWebcamFormat.Any;
cap.minInterval = 10000000 / 60;
return cap;
}
dshowOffset = 1;
}
if (splitCaps == null || index >= splitCaps.Count + dshowOffset || index < 0)
throw new InvalidOperationException("Invalid capability index.");
return caps[splitCaps[index - dshowOffset].Item2];
}
}
[DefaultExecutionOrder(-50)]
public class OpenSeeWebcamInfo : MonoBehaviour {
#region DllImport
// DirectShow
[DllImport("dshowcapture_x64", CallingConvention = CallingConvention.Cdecl, EntryPoint = "create_capture")]
private static extern System.IntPtr create_capture_x64();
[DllImport("dshowcapture_x64", CallingConvention = CallingConvention.Cdecl, EntryPoint = "get_json_length")]
private static extern int get_json_length_x64(System.IntPtr cap);
[DllImport("dshowcapture_x64", CallingConvention = CallingConvention.Cdecl, EntryPoint = "get_json")]
private static extern void get_json_x64(System.IntPtr cap, [Out] StringBuilder namebuffer, int bufferlength);
[DllImport("dshowcapture_x64", CallingConvention = CallingConvention.Cdecl, EntryPoint = "destroy_capture")]
private static extern void destroy_capture_x64(System.IntPtr cap);
[DllImport("dshowcapture_x86", CallingConvention = CallingConvention.Cdecl, EntryPoint = "create_capture")]
private static extern System.IntPtr create_capture_x86();
[DllImport("dshowcapture_x86", CallingConvention = CallingConvention.Cdecl, EntryPoint = "get_json_length")]
private static extern int get_json_length_x86(System.IntPtr cap);
[DllImport("dshowcapture_x86", CallingConvention = CallingConvention.Cdecl, EntryPoint = "get_json")]
private static extern void get_json_x86(System.IntPtr cap, [Out] StringBuilder namebuffer, int bufferlength);
[DllImport("dshowcapture_x86", CallingConvention = CallingConvention.Cdecl, EntryPoint = "destroy_capture")]
private static extern void destroy_capture_x86(System.IntPtr cap);
// Blackmagic
[DllImport("libminibmcapture64", CallingConvention = CallingConvention.Cdecl, EntryPoint = "get_json_length")]
private static extern int bm_get_json_length_x64();
[DllImport("libminibmcapture64", CallingConvention = CallingConvention.Cdecl, EntryPoint = "get_json")]
private static extern void bm_get_json_x64([Out] StringBuilder namebuffer, int bufferlength);
[DllImport("libminibmcapture32", CallingConvention = CallingConvention.Cdecl, EntryPoint = "get_json_length")]
private static extern int bm_get_json_length_x86();
[DllImport("libminibmcapture32", CallingConvention = CallingConvention.Cdecl, EntryPoint = "get_json")]
private static extern void bm_get_json_x86([Out] StringBuilder namebuffer, int bufferlength);
#endregion
[Serializable]
public class OpenSeeWebcamList {
public List<OpenSeeWebcam> list;
}
public List<OpenSeeWebcam> cameras;
public bool dumpJson = false;
private static bool dumpJsonStatic = false;
static private string ListCameraDetails_x64() {
System.IntPtr cap = create_capture_x64();
int length = get_json_length_x64(cap);
StringBuilder buffer = new StringBuilder(length);
get_json_x64(cap, buffer, length);
destroy_capture_x64(cap);
return buffer.ToString();
}
static private string ListCameraDetails_x86() {
System.IntPtr cap = create_capture_x86();
int length = get_json_length_x86(cap);
StringBuilder buffer = new StringBuilder(length);
get_json_x86(cap, buffer, length);
destroy_capture_x86(cap);
return buffer.ToString();
}
static private string ListBlackMagicDetails_x64() {
int length = bm_get_json_length_x64();
StringBuilder buffer = new StringBuilder(length);
bm_get_json_x64(buffer, length);
return buffer.ToString();
}
static private string ListBlackMagicDetails_x86() {
int length = bm_get_json_length_x86();
StringBuilder buffer = new StringBuilder(length);
bm_get_json_x86(buffer, length);
return buffer.ToString();
}
static public List<OpenSeeWebcam> ListCameraDetails(bool includeBlackMagic) {
string jsonData = null;
string bmJsonData = null;
if (Environment.Is64BitProcess) {
jsonData = ListCameraDetails_x64();
if (includeBlackMagic)
bmJsonData = ListBlackMagicDetails_x64();
} else {
jsonData = ListCameraDetails_x86();
if (includeBlackMagic)
bmJsonData = ListBlackMagicDetails_x86();
}
if (dumpJsonStatic) {
UnityEngine.Debug.Log("Camera JSON: " + jsonData);
if (includeBlackMagic)
UnityEngine.Debug.Log("Blackmagic JSON: " + bmJsonData);
}
List<OpenSeeWebcam> details = JsonUtility.FromJson<OpenSeeWebcamList>("{\"list\":" + jsonData + "}").list;
foreach (var cam in details)
cam.type = OpenSeeWebcamType.DirectShow;
if (includeBlackMagic) {
List<OpenSeeWebcam> bmDetails = JsonUtility.FromJson<OpenSeeWebcamList>("{\"list\":" + bmJsonData + "}").list;
foreach (var cam in bmDetails)
cam.type = OpenSeeWebcamType.Blackmagic;
details.AddRange(bmDetails);
}
return details;
}
void Start() {
Initialize(false);
}
public void Initialize(bool includeBlackMagic) {
dumpJsonStatic = dumpJson;
cameras = ListCameraDetails(includeBlackMagic);
foreach (var camera in cameras)
camera.GetPrettyCapabilities();
}
}
}

View file

@ -1,11 +0,0 @@
fileFormatVersion: 2
guid: 2e9598f1218283b418c7e72604be0335
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: -50
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

Binary file not shown.

Before

Width:  |  Height:  |  Size: 149 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.2 MiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 371 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.4 MiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 17 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.6 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 70 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 57 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 113 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 48 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 202 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 175 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 338 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 150 KiB

View file

@ -1,279 +0,0 @@
using System;
using System.Collections;
using System.Collections.Generic;
using System.Net;
using System.Net.Sockets;
using System.Threading;
using UnityEngine;
namespace OpenSee {
public class OpenSee : MonoBehaviour {
[Header("UDP server settings")]
[Tooltip("To listen for remote connections, change this to 0.0.0.0 or your actual IP on the desired interface")]
public string listenAddress = "127.0.0.1";
[Tooltip("This is the port the server will listen for tracking packets on")]
public int listenPort = 11573;
private const int nPoints = 68;
private const int packetFrameSize = 8 + 4 + 2 * 4 + 2 * 4 + 1 + 4 + 3 * 4 + 3 * 4 + 4 * 4 + 4 * 68 + 4 * 2 * 68 + 4 * 3 * 70 + 4 * 14;
[Header("Tracking data")]
[Tooltip("This is an informational property that tells you how many packets have been received")]
public int receivedPackets = 0;
[Tooltip("This contains the actual tracking data")]
public OpenSeeData[] trackingData = null;
public bool listening { get; private set; } = false;
[HideInInspector]
public float maxFit3DError = 100f;
[System.Serializable]
public class OpenSeeData {
[Tooltip("The time this tracking data was captured at.")]
public double time;
[Tooltip("This is the id of the tracked face. When tracking multiple faces, they might get reordered due to faces coming and going, but as long as tracking is not lost on a face, its id should stay the same. Face ids depend only on the order of first detection and locations of the faces.")]
public int id;
[Tooltip("This field gives the resolution of the camera or video being tracked.")]
public Vector2 cameraResolution;
[Tooltip("This field tells you how likely it is that the right eye is open.")]
public float rightEyeOpen;
[Tooltip("This field tells you how likely it is that the left eye is open.")]
public float leftEyeOpen;
[Tooltip("This field contains the rotation of the right eyeball.")]
public Quaternion rightGaze;
[Tooltip("This field contains the rotation of the left eyeball.")]
public Quaternion leftGaze;
[Tooltip("This field tells you if 3D points have been successfully estimated from the 2D points. If this is false, do not rely on pose or 3D data.")]
public bool got3DPoints;
[Tooltip("This field contains the error for fitting the original 3D points. It shouldn't matter much, but it it is very high, something is probably wrong")]
public float fit3DError;
[Tooltip("This is the rotation vector for the 3D points to turn into the estimated face pose.")]
public Vector3 rotation;
[Tooltip("This is the translation vector for the 3D points to turn into the estimated face pose.")]
public Vector3 translation;
[Tooltip("This is the raw rotation quaternion calculated from the OpenCV rotation matrix. It does not match Unity's coordinate system, but it still might be useful.")]
public Quaternion rawQuaternion;
[Tooltip("This is the raw rotation euler angles calculated by OpenCV from the rotation matrix. It does not match Unity's coordinate system, but it still might be useful.")]
public Vector3 rawEuler;
[Tooltip("This field tells you how certain the tracker is.")]
public float[] confidence;
[Tooltip("These are the detected face landmarks in image coordinates. There are 68 points. The last too points are pupil points from the gaze tracker.")]
public Vector2[] points;
[Tooltip("These are 3D points estimated from the 2D points. The should be rotation and translation compensated. There are 70 points with guesses for the eyeball center positions being added at the end of the 68 2D points.")]
public Vector3[] points3D;
[Tooltip("This field contains a number of action unit like features.")]
public OpenSeeFeatures features;
[System.Serializable]
public class OpenSeeFeatures {
[Tooltip("This field indicates whether the left eye is opened(0) or closed (-1). A value of 1 means open wider than normal.")]
public float EyeLeft;
[Tooltip("This field indicates whether the right eye is opened(0) or closed (-1). A value of 1 means open wider than normal.")]
public float EyeRight;
[Tooltip("This field indicates how steep the left eyebrow is, compared to the median steepness.")]
public float EyebrowSteepnessLeft;
[Tooltip("This field indicates how far up or down the left eyebrow is, compared to its median position.")]
public float EyebrowUpDownLeft;
[Tooltip("This field indicates how quirked the left eyebrow is, compared to its median quirk.")]
public float EyebrowQuirkLeft;
[Tooltip("This field indicates how steep the right eyebrow is, compared to the average steepness.")]
public float EyebrowSteepnessRight;
[Tooltip("This field indicates how far up or down the right eyebrow is, compared to its median position.")]
public float EyebrowUpDownRight;
[Tooltip("This field indicates how quirked the right eyebrow is, compared to its median quirk.")]
public float EyebrowQuirkRight;
[Tooltip("This field indicates how far up or down the left mouth corner is, compared to its median position.")]
public float MouthCornerUpDownLeft;
[Tooltip("This field indicates how far in or out the left mouth corner is, compared to its median position.")]
public float MouthCornerInOutLeft;
[Tooltip("This field indicates how far up or down the right mouth corner is, compared to its median position.")]
public float MouthCornerUpDownRight;
[Tooltip("This field indicates how far in or out the right mouth corner is, compared to its median position.")]
public float MouthCornerInOutRight;
[Tooltip("This field indicates how open or closed the mouth is, compared to its median pose.")]
public float MouthOpen;
[Tooltip("This field indicates how wide the mouth is, compared to its median pose.")]
public float MouthWide;
}
public OpenSeeData() {
confidence = new float[nPoints];
points = new Vector2[nPoints];
points3D = new Vector3[nPoints + 2];
}
private Vector3 swapX(Vector3 v) {
v.x = -v.x;
return v;
}
private float readFloat(byte[] b, ref int o) {
float v = System.BitConverter.ToSingle(b, o);
o += 4;
return v;
}
private Quaternion readQuaternion(byte[] b, ref int o) {
float x = readFloat(b, ref o);
float y = readFloat(b, ref o);
float z = readFloat(b, ref o);
float w = readFloat(b, ref o);
Quaternion q = new Quaternion(x, y, z, w);
return q;
}
private Vector3 readVector3(byte[] b, ref int o) {
Vector3 v = new Vector3(readFloat(b, ref o), -readFloat(b, ref o), readFloat(b, ref o));
return v;
}
private Vector2 readVector2(byte[] b, ref int o) {
Vector2 v = new Vector2(readFloat(b, ref o), readFloat(b, ref o));
return v;
}
public void readFromPacket(byte[] b, int o) {
time = System.BitConverter.ToDouble(b, o);
o += 8;
id = System.BitConverter.ToInt32(b, o);
o += 4;
cameraResolution = readVector2(b, ref o);
rightEyeOpen = readFloat(b, ref o);
leftEyeOpen = readFloat(b, ref o);
byte got3D = b[o];
o++;
got3DPoints = false;
if (got3D != 0)
got3DPoints = true;
fit3DError = readFloat(b, ref o);
rawQuaternion = readQuaternion(b, ref o);
Quaternion convertedQuaternion = new Quaternion(-rawQuaternion.x, rawQuaternion.y, -rawQuaternion.z, rawQuaternion.w);
rawEuler = readVector3(b, ref o);
rotation = rawEuler;
rotation.z = (rotation.z - 90) % 360;
rotation.x = -(rotation.x + 180) % 360;
float x = readFloat(b, ref o);
float y = readFloat(b, ref o);
float z = readFloat(b, ref o);
translation = new Vector3(-y, x, -z);
for (int i = 0; i < nPoints; i++) {
confidence[i] = readFloat(b, ref o);
}
for (int i = 0; i < nPoints; i++) {
points[i] = readVector2(b, ref o);
}
for (int i = 0; i < nPoints + 2; i++) {
points3D[i] = readVector3(b, ref o);
}
rightGaze = Quaternion.LookRotation(swapX(points3D[66]) - swapX(points3D[68])) * Quaternion.AngleAxis(180, Vector3.right) * Quaternion.AngleAxis(180, Vector3.forward);
leftGaze = Quaternion.LookRotation(swapX(points3D[67]) - swapX(points3D[69])) * Quaternion.AngleAxis(180, Vector3.right) * Quaternion.AngleAxis(180, Vector3.forward);
features = new OpenSeeFeatures();
features.EyeLeft = readFloat(b, ref o);
features.EyeRight = readFloat(b, ref o);
features.EyebrowSteepnessLeft = readFloat(b, ref o);
features.EyebrowUpDownLeft = readFloat(b, ref o);
features.EyebrowQuirkLeft = readFloat(b, ref o);
features.EyebrowSteepnessRight = readFloat(b, ref o);
features.EyebrowUpDownRight = readFloat(b, ref o);
features.EyebrowQuirkRight = readFloat(b, ref o);
features.MouthCornerUpDownLeft = readFloat(b, ref o);
features.MouthCornerInOutLeft = readFloat(b, ref o);
features.MouthCornerUpDownRight = readFloat(b, ref o);
features.MouthCornerInOutRight = readFloat(b, ref o);
features.MouthOpen = readFloat(b, ref o);
features.MouthWide = readFloat(b, ref o);
}
}
private Dictionary<int, OpenSeeData> openSeeDataMap;
private Socket socket;
private byte[] buffer;
private Thread receiveThread = null;
private volatile bool stopReception = false;
public OpenSeeData GetOpenSeeData(int faceId) {
if (openSeeDataMap == null)
return null;
if (!openSeeDataMap.ContainsKey(faceId))
return null;
return openSeeDataMap[faceId];
}
void performReception() {
EndPoint senderRemote = new IPEndPoint(IPAddress.Any, 0);
listening = true;
while (!stopReception) {
try {
int receivedBytes = socket.ReceiveFrom(buffer, SocketFlags.None, ref senderRemote);
if (receivedBytes < 1 || receivedBytes % packetFrameSize != 0) {
continue;
}
receivedPackets++;
int i = 0;
for (int offset = 0; offset < receivedBytes; offset += packetFrameSize) {
OpenSeeData newData = new OpenSeeData();
newData.readFromPacket(buffer, offset);
openSeeDataMap[newData.id] = newData;
i++;
}
trackingData = new OpenSeeData[openSeeDataMap.Count];
openSeeDataMap.Values.CopyTo(trackingData, 0);
} catch { }
}
}
void Start () {
if (openSeeDataMap == null)
openSeeDataMap = new Dictionary<int, OpenSeeData>();
buffer = new byte[65535];
if (socket == null) {
socket = new Socket(AddressFamily.InterNetwork, SocketType.Dgram, ProtocolType.Udp);
IPAddress ip;
IPAddress.TryParse(listenAddress, out ip);
socket.Bind(new IPEndPoint(ip, listenPort));
socket.ReceiveTimeout = 15;
}
receiveThread = new Thread(() => performReception());
receiveThread.Start();
}
void Update () {
if (receiveThread != null && !receiveThread.IsAlive) {
Start();
}
}
void EndReceiver() {
if (receiveThread != null) {
stopReception = true;
receiveThread.Join();
stopReception = false;
}
if (socket != null)
socket.Close();
}
void OnApplicationQuit() {
EndReceiver();
}
void OnDestroy() {
EndReceiver();
}
}
}

View file

@ -1,11 +0,0 @@
fileFormatVersion: 2
guid: 7b5af009eeb86f9469d2be8970e5a0f4
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View file

@ -1,725 +0,0 @@
using System;
using System.Collections.Generic;
using System.IO;
using System.IO.Compression;
using System.Runtime.Serialization;
using System.Runtime.Serialization.Formatters.Binary;
using UnityEngine;
namespace OpenSee {
public class OpenSeeExpression : MonoBehaviour
{
[Header("Settings")]
[Tooltip("This is the source of face tracking data. If it is not set, any OpenSee component on the current object is used.")]
public OpenSee openSee;
[Tooltip("When enabled ThunderSVM is used instead of LibSVM, which is usually faster, but may cause issues on some systems.")]
public bool useThunderSVM = false;
[Header("Simple mode")]
[Tooltip("When enabled, some simple heuristics will be used to detect expressions, rather than an SVM model. Outputs one of: neutral, fun, angry, surprise")]
public bool simpleMode = false;
[Tooltip("This smoothing factor is applied to the features used for simple expression detection.")]
[Range(0f, 1f)]
public float simpleSmoothing = 0.6f;
[Tooltip("This smoothing factor is applied to the features used for simple expression detection.")]
[Range(0f, 5f)]
public float simpleSensitivity = 1f;
[Header("Calibration")]
[Tooltip("This specifies which expression calibration data should be collected for.")]
public string calibrationExpression = "neutral";
[Tooltip("This specifies the id of the face for which data should be collected and predictions should be made. Face ids depend only on the order of first detection and locations of the faces.")]
public int faceId = 0;
[Tooltip("This keeps low numbers of misdetections from changing the expression, but introduces a bit of lag to expression changes. For example, a value of 1 means that a new expression has to be detected twice in a row, before the predicted expression changes.")]
public int expressionStabilizer = 1;
[Tooltip("Setting this to a value above 1 will record only every recordingSkip-th frame when capture calibration data. This can be useful with cameras that have a high framerate leading to only a short time for capturing varied expression information. Usually at least 20-30 seconds are required to capture a good variety of angles and expression variation, so this should be set accordingly when using the recording flag. At 1, no frames are skipped.")]
public int recordingSkip = 2;
[Tooltip("If allowOverRecording is enabled and expression data is recorded beyond 100%, this is used instead of recordingSkip to avoid quickly replacing the existing data.")]
public int overRecordingSkip = 5;
[Tooltip("This is the filename used for loading and saving expression data using the load and save flags.")]
public string filename = "";
[Tooltip("When enabled, training will be done in such a way that the model can output probabilities. This is a lot slower!")]
public bool enableProbabilityTraining = false;
[Tooltip("This is the SVM training C value.")]
public float C = 2f;
[Tooltip("This map allows you to set weights for different classes.")]
public Dictionary<string, float> weightMap = null;
[Header("Toggles")]
[Tooltip("When enabled, calibration data will be collected from the given OpenSee component.")]
public bool recording = false;
[Tooltip("When enabled, you can keep recording past 100%. When doing so, random frames in the already collected data will be overwritten with new data. To prevent quickly replacing all the collected data, overRecordingSkip is used instead of recordingSkip, which should be set to a higher value.")]
public bool allowOverRecording = false;
[Tooltip("When enabled, the calibration data collected for the current expression is cleared and this flag is set back to false.")]
public bool clear = false;
[Tooltip("When enabled, a new prediction model is trained and this flag is set back to false. Only expressions for which percentRecorded is 100% will be included in training.")]
public bool train = false;
[Tooltip("When enabled and a model is loaded, the current expression will be predicted every frame.")]
public bool predict = false;
[Tooltip("When enabled, the expression data from the specified filename will be loaded and this flag is set back to false.")]
public bool load = false;
[Tooltip("When enabled, the expression data will be saved to the specified filename and this flag is set back to false.")]
public bool save = false;
[Header("Point selection")]
[Tooltip("These settings can be used to train an expression detection model on a subset of points.")]
public PointSelection pointSelection;
[Header("Information")]
[Tooltip("This is the number of expressions for which calibration data was collected. The maximum number is 10.")]
public int expressionNumber = 0;
[Tooltip("This is the percentage of necessary training data collected for the current expression.")]
public float percentRecorded = 0.0f;
[Tooltip("This shows whether a model is ready to predict expressions with.")]
public bool modelReady = false;
[Tooltip("This is the time the current expression was detected.")]
public float expressionTime = 0f;
[Tooltip("This is currently detected expression.")]
public string expression = "";
[Tooltip("These are the probabilities of all expressions. The labels in order can be retrieved through the GetClassLabels methods.")]
public double[] probabilities;
[Header("Training statistics")]
[Tooltip("This shows the accuracy result of the last training run.")]
public float accuracy = 0.0f;
[Tooltip("This is the confusion matrix for the last training run's validation set.")]
public int[,] confusionMatrix = null;
[Tooltip("This is a pretty printed string representation of the confusion matrix.")]
public string confusionMatrixString = "";
[Tooltip("This shows any accuracy warnings that resulted from the last training run.")]
public string[] warnings = null;
private float lastMouthCorner = 0f;
private float lastEyebrows = 0f;
private bool hadFun = false;
private bool hadAngry = false;
private bool hadSurprised = false;
float AdjustThreshold(bool active) {
if (active)
return 0.8f;
else
return 1f;
}
void ThresholdDetection() {
lastMouthCorner = lastMouthCorner * simpleSmoothing + (openSeeData.features.MouthCornerUpDownLeft + openSeeData.features.MouthCornerUpDownRight) * 0.5f * (1f - simpleSmoothing);
lastEyebrows = lastEyebrows * simpleSmoothing + (openSeeData.features.EyebrowUpDownLeft + openSeeData.features.EyebrowUpDownRight) * 0.5f * (1f - simpleSmoothing);
if (lastMouthCorner * simpleSensitivity < -0.2f * AdjustThreshold(hadFun)) {
expression = "fun";
hadFun = true;
hadSurprised = false;
hadAngry = false;
} else if (lastEyebrows * simpleSensitivity > 0.2f * AdjustThreshold(hadSurprised)) {
expression = "surprise";
hadFun = false;
hadSurprised = true;
hadAngry = false;
} else if (lastEyebrows * simpleSensitivity < -0.25f * AdjustThreshold(hadAngry) && lastMouthCorner * simpleSensitivity > -0.3f * (2f - AdjustThreshold(hadAngry))) {
expression = "angry";
hadFun = false;
hadSurprised = false;
hadAngry = true;
} else {
expression = "neutral";
hadFun = false;
hadSurprised = false;
hadAngry = false;
}
expressionTime = Time.time;
}
[Serializable]
public class PointSelection {
[Tooltip("When enabled, the points of the face contour will be used to determine the expression.")]
public bool pointsFaceContour = true;
[Tooltip("When enabled, the points of the right brow will be used to determine the expression.")]
public bool pointsBrowRight = true;
[Tooltip("When enabled, the points of the left brow will be used to determine the expression.")]
public bool pointsBrowLeft = true;
[Tooltip("When enabled, the points of the right eye will be used to determine the expression.")]
public bool pointsEyeRight = true;
[Tooltip("When enabled, the points of the left eye will be used to determine the expression.")]
public bool pointsEyeLeft = true;
[Tooltip("When enabled, the points of the nose will be used to determine the expression.")]
public bool pointsNose = true;
[Tooltip("When enabled, the points of the corners of the mouth will be used to determine the expression.")]
public bool pointsMouthCorner = true;
[Tooltip("When enabled, the points of the upper lip will be used to determine the expression.")]
public bool pointsLipUpper = true;
[Tooltip("When enabled, the points of the lower lip will be used to determine the expression.")]
public bool pointsLipLower = true;
[Tooltip("When enabled, certain manually designed features will be used to determine the expression.")]
public bool features = true;
[Tooltip("When enabled, the depth value of points is also used for training.")]
public bool includeDepth = false;
}
[Serializable]
private class OpenSeeExpressionRepresentation {
private Dictionary<string, List<float[]>> expressions;
private byte[] modelBytes = null;
private string[] classLabels = null;
private int[] indices = null;
private PointSelection pointSelection;
private bool thunderSVM = false;
//private bool newModel = false;
static public void LoadSerialized(byte[] modelBytes, out Dictionary<string, List<float[]>> expressions, out SVMModel model, out string[] classLabels, out int[] indices, ref PointSelection pointSelection) {
IFormatter formatter = new BinaryFormatter();
MemoryStream memoryStream = new MemoryStream(modelBytes);
memoryStream.Position = 0;
OpenSeeExpressionRepresentation oser;
using (GZipStream gzipStream = new GZipStream(memoryStream, CompressionMode.Decompress)) {
oser = formatter.Deserialize(gzipStream) as OpenSeeExpressionRepresentation;
}
expressions = oser.expressions;
/*if (oser.thunderSVM)
model = new ThunderSVMModel(oser.modelBytes);
else*/
model = new SVMModel(oser.modelBytes);
classLabels = oser.classLabels;
indices = oser.indices;
//pointSelection = oser.pointSelection;
if (indices == null) {
indices = new int[1 + 1 + 3 + 4 + 3 + 3 * 66];
for (int i = 0; i < 1 + 1 + 3 + 4 + 3 + 3 * 66; i++)
indices[i] = i;
}
/*if (pointSelection == null)
pointSelection = new PointSelection();
if (!oser.newModel)
pointSelection.features = true;*/
}
static public byte[] ToSerialized(Dictionary<string, List<float[]>> expressions, SVMModel model, string[] classLabels, int[] indices, PointSelection pointSelection) {
OpenSeeExpressionRepresentation oser = new OpenSeeExpressionRepresentation();
oser.expressions = expressions;
oser.modelBytes = model.SaveModel();
oser.classLabels = classLabels;
oser.indices = indices;
oser.pointSelection = pointSelection;
oser.thunderSVM = model is ThunderSVMModel;
//oser.newModel = true;
IFormatter formatter = new BinaryFormatter();
MemoryStream memoryStream = new MemoryStream();
using (GZipStream gzipStream = new GZipStream(memoryStream, CompressionMode.Compress)) {
formatter.Serialize(gzipStream, oser);
gzipStream.Flush();
}
return memoryStream.ToArray();
}
}
private OpenSee.OpenSeeData openSeeData = null;
private Dictionary<string, List<float[]>> expressions;
private SVMModel model = null;
private string[] classLabels = null;
private int maxSamples = 1666;
// rightEyeOpen, leftEyeOpen, translation, rawQuaternion, rawEuler, confidence, points/(width, height), points3D, features
private int colsFull = 1 + 1 + 3 + 4 + 3 + /*66 + 2 * 66 +*/ 3 * 66 + 14;
private int colsBase = 1 + 1 + 3 + 4 + 3;
private int cols;
private double lastCapture = 0.0;
private float warningThreshold = 5;
private int currentPrediction = -1;
private int lastPrediction = -1;
private int lastPredictionCount = 0;
private int frameCount = 0;
private System.Random rnd;
private int[] indices;
private int[] indicesFaceContour = new int[] {0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16};
private int[] indicesBrowRight = new int[] {17, 18, 19, 20, 21};
private int[] indicesBrowLeft = new int[] {22, 23, 24, 25, 26};
private int[] indicesEyeRight = new int[] {36, 37, 38, 39, 40, 41};
private int[] indicesEyeLeft = new int[] {42, 43, 44, 45, 46, 47};
private int[] indicesNose = new int[] {27, 28, 29, /*30, */31, 32, 33, 34, 35};
private int[] indicesMouthCorner = new int[] {58, 62};
private int[] indicesLipUpper = new int[] {48, 49, 50, 51, 52, 59, 60, 61};
private int[] indicesLipLower = new int[] {53, 54, 55, 56, 57, 63, 64, 65};
private void SelectPoints() {
List<int> indexList = new List<int>();
for (int i = 0; i < colsBase; i++)
if (i > 4) // Translation and (sometimes unavailable) eye open fields should not be used for training!
indexList.Add(i);
cols = indexList.Count;
if (pointSelection.pointsFaceContour)
foreach (int i in indicesFaceContour) {
indexList.Add(colsBase + i * 3);
indexList.Add(colsBase + i * 3 + 1);
cols += 2;
if (pointSelection.includeDepth) {
indexList.Add(colsBase + i * 3 + 2);
cols++;
}
}
if (pointSelection.pointsBrowRight)
foreach (int i in indicesBrowRight) {
indexList.Add(colsBase + i * 3);
indexList.Add(colsBase + i * 3 + 1);
cols += 2;
if (pointSelection.includeDepth) {
indexList.Add(colsBase + i * 3 + 2);
cols++;
}
}
if (pointSelection.pointsBrowLeft)
foreach (int i in indicesBrowLeft) {
indexList.Add(colsBase + i * 3);
indexList.Add(colsBase + i * 3 + 1);
cols += 2;
if (pointSelection.includeDepth) {
indexList.Add(colsBase + i * 3 + 2);
cols++;
}
}
if (pointSelection.pointsEyeRight)
foreach (int i in indicesEyeRight) {
indexList.Add(colsBase + i * 3);
indexList.Add(colsBase + i * 3 + 1);
cols += 2;
if (pointSelection.includeDepth) {
indexList.Add(colsBase + i * 3 + 2);
cols++;
}
}
if (pointSelection.pointsEyeLeft)
foreach (int i in indicesEyeLeft) {
indexList.Add(colsBase + i * 3);
indexList.Add(colsBase + i * 3 + 1);
cols += 2;
if (pointSelection.includeDepth) {
indexList.Add(colsBase + i * 3 + 2);
cols++;
}
}
if (pointSelection.pointsNose)
foreach (int i in indicesNose) {
indexList.Add(colsBase + i * 3);
indexList.Add(colsBase + i * 3 + 1);
cols += 2;
if (pointSelection.includeDepth) {
indexList.Add(colsBase + i * 3 + 2);
cols++;
}
}
if (pointSelection.pointsNose)
foreach (int i in indicesMouthCorner) {
indexList.Add(colsBase + i * 3);
indexList.Add(colsBase + i * 3 + 1);
cols += 2;
if (pointSelection.includeDepth) {
indexList.Add(colsBase + i * 3 + 2);
cols++;
}
}
if (pointSelection.pointsLipUpper)
foreach (int i in indicesLipUpper) {
indexList.Add(colsBase + i * 3);
indexList.Add(colsBase + i * 3 + 1);
cols += 2;
if (pointSelection.includeDepth) {
indexList.Add(colsBase + i * 3 + 2);
cols++;
}
}
if (pointSelection.pointsLipLower)
foreach (int i in indicesLipLower) {
indexList.Add(colsBase + i * 3);
indexList.Add(colsBase + i * 3 + 1);
cols += 2;
if (pointSelection.includeDepth) {
indexList.Add(colsBase + i * 3 + 2);
cols++;
}
}
if (pointSelection.features)
for (int i = 0; i < 14; i++) {
indexList.Add(colsBase + 66 * 3 + i);
cols++;
}
indices = indexList.ToArray();
}
private void ResetInfo() {
recording = false;
clear = false;
train = false;
modelReady = false;
accuracy = 0.0f;
confusionMatrix = null;
warnings = null;
percentRecorded = 0.0f;
expression = "";
confusionMatrixString = "";
lastPrediction = -1;
currentPrediction = -1;
lastPredictionCount = 0;
expressionTime = 0f;
}
void Start()
{
if (openSee == null)
openSee = GetComponent<OpenSee>();
if (openSee == null) {
ResetInfo();
return;
}
ResetInfo();
expressions = new Dictionary<string, List<float[]>>();
if (useThunderSVM)
model = new ThunderSVMModel();
else
model = new SVMModel();
rnd = new System.Random();
}
private float[] GetData(OpenSee.OpenSeeData t) {
float[] data = new float[colsFull];
data[0] = t.rightEyeOpen;
data[1] = t.leftEyeOpen;
data[2] = t.translation.x;
data[3] = t.translation.y;
data[4] = t.translation.z;
data[5] = t.rawQuaternion.x;
data[6] = t.rawQuaternion.y;
data[7] = t.rawQuaternion.z;
data[8] = t.rawQuaternion.w;
data[9] = t.rawEuler.x;
data[10] = t.rawEuler.y;
data[11] = t.rawEuler.z;
/*for (int i = 0; i < 66; i++)
data[12 + i] = t.confidence[i];
for (int i = 0; i < 66; i++) {
data[12 + 66 + 2 * i] = t.points[i].x / t.cameraResolution.x;
data[12 + 66 + 2 * i + 1] = t.points[i].y / t.cameraResolution.y;
}*/
for (int i = 0; i < 66; i++) {
data[12 + /*66 + 2 * 66 +*/ 3 * i] = t.points3D[i].x;
data[12 + /*66 + 2 * 66 +*/ 3 * i + 1] = t.points3D[i].y;
data[12 + /*66 + 2 * 66 +*/ 3 * i + 2] = t.points3D[i].z;
}
data[12 + 66 * 3 + 0] = t.features.EyeLeft;
data[12 + 66 * 3 + 1] = t.features.EyeRight;
data[12 + 66 * 3 + 2] = t.features.EyebrowSteepnessLeft;
data[12 + 66 * 3 + 3] = t.features.EyebrowUpDownLeft;
data[12 + 66 * 3 + 4] = t.features.EyebrowQuirkLeft;
data[12 + 66 * 3 + 5] = t.features.EyebrowSteepnessRight;
data[12 + 66 * 3 + 6] = t.features.EyebrowUpDownRight;
data[12 + 66 * 3 + 7] = t.features.EyebrowQuirkRight;
data[12 + 66 * 3 + 8] = t.features.MouthCornerUpDownLeft;
data[12 + 66 * 3 + 9] = t.features.MouthCornerInOutLeft;
data[12 + 66 * 3 + 10] = t.features.MouthCornerUpDownRight;
data[12 + 66 * 3 + 11] = t.features.MouthCornerInOutRight;
data[12 + 66 * 3 + 12] = t.features.MouthOpen;
data[12 + 66 * 3 + 13] = t.features.MouthWide;
return data;
}
public bool TrainModel() {
Debug.Log("---------------------");
train = false;
if (openSee == null) {
ResetInfo();
return false;
}
modelReady = false;
if (model is SVMModel && useThunderSVM)
model = new ThunderSVMModel();
else if (model is ThunderSVMModel && !useThunderSVM)
model = new SVMModel();
SelectPoints();
List<string> keys = new List<string>();
List<string> accuracyWarnings = new List<string>();
int samples = 0;
foreach (string key in expressions.Keys) {
List<float[]> list = new List<float[]>(expressions[key]);
list.RemoveAll(x => x.Length != colsFull);
if (list != null && list.Count == maxSamples) {
Debug.Log("[Training info] Adding expression " + key + " to training data.");
keys.Add(key);
samples += list.Count;
} else {
if (list != null && list.Count > 20) {
Debug.Log("[Training warning] Expression " + key + " has little data and might be inaccurate. (" + list.Count + ")");
accuracyWarnings.Add("Expression " + key + " has little data and might be inaccurate. (" + list.Count + ")");
samples += list.Count;
keys.Add(key);
} else {
Debug.Log("[Training warning] Skipping expression " + key + " due to lack of collected data. (" + list.Count + ")");
accuracyWarnings.Add("Skipping expression " + key + " due to lack of collected data. (" + list.Count + ")");
continue;
}
}
}
int classes = keys.Count;
if (classes < 2 || classes > 10) {
Debug.Log("[Training error] The number of expressions that can be used for training is " + classes + ", which is either below 2 or higher than 10.");
accuracyWarnings.Add("[Training error] The number of expressions that can be used for training is " + classes + ", which is either below 2 or higher than 10.");
return false;
}
keys.Sort();
classLabels = keys.ToArray();
float[] weights = null;
if (weightMap != null) {
weights = new float[classLabels.Length];
for (int i = 0; i < classLabels.Length; i++) {
if (weightMap.ContainsKey(classLabels[i]))
weights[i] = weightMap[classLabels[i]];
else
weights[i] = 1f;
Debug.Log("[Training info] Adding weight " + weights[i] + " for " + classLabels[i] + ".");
}
}
Debug.Log("[Training info] Preparing trainig data.");
int train_split = maxSamples * 3 / 4;
int test_split = maxSamples - train_split;
int rows_train = classes * train_split;
int rows_test = classes * test_split;
float[] X_train = new float[rows_train * cols];
float[] X_test = new float[rows_test * cols];
float[] y_train = new float[rows_train];
float[] y_test = new float[rows_test];
int i_train = 0;
int i_test = 0;
System.Random rnd = new System.Random();
for (int i = 0; i < classes; i++) {
List<float[]> list = new List<float[]>(expressions[keys[i]]);
list.RemoveAll(x => x.Length != colsFull);
int local_train_split = list.Count * 3 / 4;
test_split = list.Count - local_train_split;
for (int j = list.Count; j > 1;) {
j--;
int k = rnd.Next(j + 1);
float[] tmp = list[k];
list[k] = list[j];
list[j]= tmp;
}
int train_split_current = train_split;
if (classLabels[i] == "neutral")
train_split_current *= 1;
for (int j = 0; j < train_split_current; j++) {
float factor = 1f;
float adder = 0f;
/*if (j > train_split || j > list.Count) {
factor = UnityEngine.Random.Range(0.98f, 1.02f);
adder = UnityEngine.Random.Range(-0.02f, 0.02f);
}*/
for (int k = 0; k < cols; k++) {
float v = list[j % local_train_split][indices[k]] * factor + adder;
X_train[i_train * cols + k] = v;
}
y_train[i_train] = i;
i_train++;
}
for (int j = local_train_split; j < local_train_split + test_split; j++) {
for (int k = 0; k < cols; k++) {
float v = list[j][indices[k]];
X_test[i_test * cols + k] = v;
}
y_test[i_test] = i;
i_test++;
}
}
Debug.Log("[Training info] Preparation complete.");
int probability = 0;
if (enableProbabilityTraining)
probability = 1;
model.TrainModel(X_train, y_train, weights, i_train, cols, probability, C);
confusionMatrix = model.ConfusionMatrix(X_test, y_test, i_test, out accuracy);
confusionMatrixString = SVMModel.FormatMatrix(confusionMatrix, classLabels);
for (int label = 0; label < classes; label++) {
int total = 0;
for (int p = 0; p < classes; p++) {
total += confusionMatrix[label, p];
}
float error = 100f * (1f - ((float)confusionMatrix[label, label] / (float)total));
if (error > warningThreshold) {
accuracyWarnings.Add("[Training warning] The expression \"" + classLabels[label] + "\" is misclassified with a chance of " + error.ToString("0.00") + "%.");
Debug.Log("[Training warning] The expression \"" + classLabels[label] + "\" is misclassified with a chance of " + error.ToString("0.00") + "%.");
}
}
warnings = accuracyWarnings.ToArray();
modelReady = true;
Debug.Log("[Training info] Trained model.");
return true;
}
public bool PredictExpression() {
if (openSee == null)
return false;
if (!simpleMode && !(modelReady && model.Ready())) {
ResetInfo();
return false;
}
openSeeData = openSee.GetOpenSeeData(faceId);
if (openSeeData == null || openSeeData.time <= lastCapture)
return false;
if (simpleMode) {
ThresholdDetection();
return true;
}
float[] faceData = GetData(openSeeData);
float[] predictionData = new float[cols];
for (int i = 0; i < cols; i++)
predictionData[i] = faceData[indices[i]];
float[] prediction = model.Predict(predictionData, out probabilities, 1);
int predictedExpression = (int)Mathf.Round(prediction[0]);
if (predictedExpression == lastPrediction)
lastPredictionCount++;
else {
lastPrediction = predictedExpression;
lastPredictionCount = 1;
}
if (lastPredictionCount > expressionStabilizer) {
currentPrediction = lastPrediction;
expressionTime = Time.time;
}
if (currentPrediction >= 0 && currentPrediction <= classLabels.Length)
expression = classLabels[currentPrediction];
else
expression = "";
return true;
}
public bool CaptureCalibrationData() {
if (openSee == null) {
ResetInfo();
return false;
}
if (recordingSkip < 1)
recordingSkip = 1;
if (calibrationExpression == "")
return false;
if (expressions.ContainsKey(calibrationExpression) || expressions.Keys.Count < 10) {
openSeeData = openSee.GetOpenSeeData(faceId);
if (openSeeData == null || openSeeData.time <= lastCapture)
return false;
if (!expressions.ContainsKey(calibrationExpression)) {
expressions.Add(calibrationExpression, new List<float[]>());
}
List<float[]> list = expressions[calibrationExpression];
if (list.Count >= maxSamples) {
percentRecorded = 100f;
recording = allowOverRecording;
if (!recording)
return false;
}
int skip = recordingSkip;
if (percentRecorded >= 100f)
skip = overRecordingSkip;
if (frameCount % skip != 0)
return true;
if (percentRecorded >= 100f) {
list[rnd.Next(maxSamples)] = GetData(openSeeData);
} else
list.Add(GetData(openSeeData));
percentRecorded = 100f * (float)list.Count/(float)maxSamples;
return true;
} else {
recording = false;
calibrationExpression = "";
return false;
}
}
public string[] GetClassLabels() {
List<string> labels = new List<string>();
foreach (string l in classLabels)
labels.Add(String.Copy(l));
return labels.ToArray();
}
public string[] GetExpressions() {
List<string> keys = new List<string>();
foreach (string key in expressions.Keys)
keys.Add(key);
keys.Sort();
return keys.ToArray();
}
public void ClearExpression() {
if (expressions.ContainsKey(calibrationExpression))
expressions.Remove(calibrationExpression);
clear = false;
}
public void LoadFromBytes(byte[] data) {
load = false;
if (openSee == null) {
ResetInfo();
return;
}
OpenSeeExpressionRepresentation.LoadSerialized(data, out expressions, out model, out classLabels, out indices, ref pointSelection);
cols = indices.Length;
if (model.Ready())
modelReady = true;
}
public byte[] SaveToBytes() {
save = false;
if (openSee == null) {
ResetInfo();
return null;
}
return OpenSeeExpressionRepresentation.ToSerialized(expressions, model, classLabels, indices, pointSelection);
}
public void LoadFromFile() {
load = false;
if (openSee == null) {
ResetInfo();
return;
}
byte[] data = File.ReadAllBytes(filename);
LoadFromBytes(data);
}
public void SaveToFile() {
save = false;
if (openSee == null) {
ResetInfo();
return;
}
byte[] data = SaveToBytes();
File.WriteAllBytes(filename, data);
}
void Update()
{
frameCount++;
if (openSee == null || expressions == null) {
ResetInfo();
return;
}
if (clear)
ClearExpression();
if (recording && calibrationExpression != "") {
CaptureCalibrationData();
}
if (train)
TrainModel();
expressionNumber = expressions.Keys.Count;
if (load)
LoadFromFile();
if (save)
SaveToFile();
if (!predict)
expression = "";
else if (simpleMode || modelReady)
PredictExpression();
else
predict = false;
if (expressions.ContainsKey(calibrationExpression))
percentRecorded = 100f * (float)expressions[calibrationExpression].Count/(float)maxSamples;
else
percentRecorded = 0f;
if (openSeeData == null)
return;
lastCapture = openSeeData.time;
}
}
}

View file

@ -1,11 +0,0 @@
fileFormatVersion: 2
guid: 9066de4c7793c1e40b212724f72fc064
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View file

@ -1,331 +0,0 @@
using UnityEngine;
namespace OpenSee {
[DefaultExecutionOrder(-1)]
public class OpenSeeIKTarget : MonoBehaviour
{
[Header("Settings")]
[Tooltip("This is the source of face tracking data.")]
public OpenSee openSee;
[Tooltip("When this is set to another game object, its kinematic interpolation component will get updated from values of this.")]
public OpenSeeKinematicInterpolation kinematicInterpolation;
[Tooltip("When set, the this object will follow the specified transform instead and automatically recalibrate based on it.")]
public Transform externalTarget = null;
[Tooltip("This can be used to skip the first few tracking frames.")]
public int skipFirst = 5;
[Tooltip("When set to true, the next rotation and translation values will be set as zero rotation and zero translation.")]
public bool calibrate = true;
[Tooltip("This sets which face id to look for in the OpenSee data.")]
public int faceId = 0;
[Tooltip("When enabled, the IK target will not move up and down.")]
public bool preventVerticalMotion = false;
[Tooltip("When this is enabled, rotations and movement are mirrored.")]
public bool mirrorMotion = false;
[Tooltip("Often, the translation vector's scale is too high. Setting this somewhere between 0.05 to 0.3 seems stabilize things, but it also reduces the range of motion.")]
public float translationScale = 0.3f;
[Tooltip("This smoothed out the detected motion. Values can be between 0 (no smoothing) and 1 (no motion). The appropriate value probably depends on the camera's frame rate.")]
[Range(0, 1)]
public float smooth = 0.2f;
[Tooltip("When enabled, tracking will lag by one video capture frame, but the captured motion information is interpolated between frames, making things look smoother and less jittery and jumpy.")]
public bool interpolate = true;
[Tooltip("When set to true, the transform will be updated in FixedUpdate, otherwise it will be updated in Update.")]
public bool fixedUpdate = false;
[Tooltip("When set to true, the IK target's position and location will slowly drift back to its neutral pose.")]
public bool driftBack = false;
[Tooltip("This sets the strength of the drifting effect. At 0 there is now drifting, while the IK target will be static at 1.")]
public float driftFactor = 0.005f;
[Tooltip("This sets the minimum angle difference between two poses after which the pose will be considered an outlier.")]
[Range(0, 360)]
public float outlierThresholdAngle = 35f;
[Tooltip("This sets the number of seconds for which angle outliers are ignored before being accepted. Setting this to zero will disable outlier skipping.")]
public float outlierSkipPeriod = 0.4f;
[Tooltip("This sets the minimum distance difference between two poses after which the pose will be considered an outlier.")]
public float outlierThresholdDistance = 2f;
[Tooltip("This sets the number of seconds for which distance outliers are ignored before being accepted. Once this period elapses, automatic recalibration is triggered. Setting this to zero will disable outlier skipping.")]
public float outlierSkipPeriodDistance = 0.4f;
[Tooltip("If set to true, persistent positional outliers will cause automatic recalibration.")]
public bool outlierRecalibrate = false;
[Tooltip("If set to true, recalibration caused by positional outliers will keep the current position and rotation of the head.")]
public bool outlierKeepOffset = false;
[Header("Information")]
[Tooltip("This is the number of received tracking frames.")]
public int trackingFrames = 0;
[Tooltip("This is the current rotation calibration value as euler angles.")]
public Vector3 rotationOffset = new Vector3(0f, 0f, -90f);
[Tooltip("This is the current translation calibration.")]
public Vector3 translationOffset = new Vector3(0f, 0f, 0f);
[Tooltip("This is the average number of interpolated frames per received tracking data.")]
public float averageInterpolations = 0f;
[Tooltip("This is the number of outlier skipped tracking data frames so far.")]
public int outlierSkips = 0;
[Tooltip("This is the number of distance outlier skipped tracking data frames so far.")]
public int outlierSkipsDistance = 0;
[Tooltip("This is the number of times a recalibration was triggered due to positional outliers.")]
public int outlierCalibrations = 0;
private double updated = 0.0f;
private Quaternion dR = Quaternion.Euler(0f, 0f, -90f);
private Vector3 dT = new Vector3(0f, 0f, 0f);
private int interpolationCount = 1;
private int interpolateState = 0;
private float avgInterps = 1f;
private Quaternion lastR;
private Vector3 lastT;
private Quaternion currentR;
private Vector3 currentT;
private bool lastMirror = false;
private bool gotAccepted = false;
private Quaternion lastAccepted;
private bool skipped = false;
private float skipStartTime = -1f;
private bool gotAcceptedPosition = false;
private Vector3 lastAcceptedPosition;
private bool skippedPosition = false;
private float skipStartTimePosition = -1f;
private Transform lastExternalTarget = null;
public void Calibrate() {
calibrate = true;
}
public static Vector3 PrettyEuler(Vector3 last, Vector3 current) {
// Ew, but how would you do componentwise filtering/interpolation with quaternions?
if (Mathf.Abs(current.x - last.x) > Mathf.Abs((current.x - 360f) - last.x))
current.x -= 360f;
else if (Mathf.Abs(current.x - last.x) > Mathf.Abs((current.x + 360f) - last.x))
current.x += 360f;
if (Mathf.Abs(current.y - last.y) > Mathf.Abs((current.y - 360f) - last.y))
current.y -= 360f;
else if (Mathf.Abs(current.y - last.y) > Mathf.Abs((current.y + 360f) - last.y))
current.x += 360f;
if (Mathf.Abs(current.z - last.z) > Mathf.Abs((current.z - 360f) - last.z))
current.z -= 360f;
else if (Mathf.Abs(current.z - last.z) > Mathf.Abs((current.z + 360f) - last.z))
current.z += 360f;
return current;
}
Vector3 FilterPos(Vector3 a, Vector3 b) {
return Vector3.Lerp(a, b, 1f - smooth);
}
Quaternion FilterRot(Quaternion a, Quaternion b) {
return Quaternion.Lerp(a, b, 1f - smooth);
}
void Interpolate() {
if (!interpolate || interpolateState < 2)
return;
float t = Mathf.Clamp((float)interpolationCount / avgInterps, 0f, 1.5f);
transform.localPosition = Vector3.SlerpUnclamped(lastT, currentT, t);
transform.localRotation = Quaternion.SlerpUnclamped(lastR, currentR, t);
interpolationCount++;
//transform.localPosition = new Vector3(0.3f * ((Time.time/3f) % 3f) - 0.5f, 0.3f * Mathf.Sin(Mathf.Rad2Deg * ((Time.time/5f) % 3f)), 0f);
//transform.localRotation = Quaternion.identity * Quaternion.AngleAxis(20f * Mathf.Sin(Mathf.Rad2Deg * ((Time.time/5f) % 3f)) - 10f, Vector3.up);
}
Quaternion MirrorQuaternion(Quaternion q) {
return new Quaternion(-q.x, q.y, q.z, -q.w);
}
Vector3 MirrorTranslation(Vector3 v) {
return new Vector3(-v.x, v.y, v.z);
}
void RunUpdate() {
var openSeeData = openSee.GetOpenSeeData(faceId);
Quaternion convertedQuaternion;
Vector3 t;
Vector3 convertedTranslation;
if (externalTarget == null) {
if (openSeeData == null || openSeeData.fit3DError > openSee.maxFit3DError)
return;
if (openSeeData.time > updated) {
updated = openSeeData.time;
trackingFrames++;
if (trackingFrames < skipFirst)
return;
} else {
Interpolate();
return;
}
convertedQuaternion = new Quaternion(-openSeeData.rawQuaternion.y, -openSeeData.rawQuaternion.x, openSeeData.rawQuaternion.z, openSeeData.rawQuaternion.w);
t = openSeeData.translation;
t.x = -t.x;
t.z = -t.z;
convertedTranslation = new Vector3(t.x, t.y, t.z);
} else {
convertedQuaternion = externalTarget.localRotation;
convertedTranslation = externalTarget.localPosition;
t = convertedTranslation;
}
// Check for angular outliers
if (gotAccepted) {
float angularDifference = Quaternion.Angle(lastAccepted, convertedQuaternion);
if (angularDifference >= outlierThresholdAngle) {
if (!skipped) {
if (outlierSkipPeriod >= 0.0000001f) {
skipStartTime = Time.time;
skipped = true;
}
} else {
if (Time.time > skipStartTime + outlierSkipPeriod) {
lastAccepted = convertedQuaternion;
skipped = false;
}
}
} else {
skipped = false;
lastAccepted = convertedQuaternion;
}
} else {
lastAccepted = convertedQuaternion;
skipped = false;
}
gotAccepted = true;
if (skipped) {
outlierSkips += 1;
return;
}
// Check for positional outliers
bool keepOffset = false;
if (gotAcceptedPosition) {
float distance = Vector3.Distance(t, lastAcceptedPosition);
if (distance > outlierThresholdDistance) {
if (!skippedPosition) {
if (outlierSkipPeriodDistance >= 0.0000001f) {
skipStartTimePosition = Time.time;
skippedPosition = true;
}
} else {
if (Time.time > skipStartTimePosition + outlierSkipPeriodDistance) {
lastAcceptedPosition = t;
skippedPosition = false;
if (outlierRecalibrate) {
calibrate = true;
keepOffset = outlierKeepOffset;
outlierCalibrations += 1;
}
}
}
} else {
skippedPosition = false;
lastAcceptedPosition = t;
}
} else {
skippedPosition = false;
lastAcceptedPosition = t;
}
gotAcceptedPosition = true;
if (skippedPosition) {
outlierSkipsDistance += 1;
return;
}
calibrate = calibrate || (externalTarget != lastExternalTarget);
lastExternalTarget = externalTarget;
if (calibrate) {
dR = convertedQuaternion;
dR = Quaternion.Inverse(dR);
dT = t;
rotationOffset = new Vector3(dR.eulerAngles.x, dR.eulerAngles.y, dR.eulerAngles.z);
translationOffset = new Vector3(dT.x, dT.y, dT.z);
lastAcceptedPosition = translationOffset;
skippedPosition = false;
}
if (mirrorMotion != lastMirror || (mirrorMotion && calibrate)) {
dR = Quaternion.Inverse(MirrorQuaternion(Quaternion.Inverse(dR)));
dT = MirrorTranslation(dT);
lastMirror = mirrorMotion;
}
if (calibrate && keepOffset) {
dR = Quaternion.Inverse(Quaternion.Inverse(transform.localRotation) * Quaternion.Inverse(dR));
dT -= transform.localPosition;
}
calibrate = false;
if (mirrorMotion) {
convertedQuaternion = MirrorQuaternion(convertedQuaternion);
t = MirrorTranslation(t);
}
if (interpolateState > 1)
avgInterps = Mathf.Lerp(avgInterps, (float)interpolationCount, 0.15f);
interpolationCount = 0;
averageInterpolations = avgInterps;
lastT = transform.localPosition;
lastR = transform.localRotation;
if (interpolateState > 0) {
currentT = FilterPos(transform.localPosition, (t - dT) * translationScale);
currentR = FilterRot(transform.localRotation, convertedQuaternion * dR);
} else {
currentT = (t - dT) * translationScale;
currentR = convertedQuaternion * dR;
}
if (interpolateState < 2)
interpolateState++;
if (interpolate) {
Interpolate();
} else {
transform.localPosition = FilterPos(transform.localPosition, (t - dT) * translationScale);
transform.localRotation = FilterRot(transform.localRotation, convertedQuaternion * dR);
}
if (preventVerticalMotion) {
currentT.y = 0f;
Vector3 pos = transform.localPosition;
pos.y = 0f;
transform.localPosition = pos;
}
if (kinematicInterpolation != null && kinematicInterpolation.gameObject != gameObject) {
if (interpolate)
kinematicInterpolation.UpdateKI(updated, currentT, currentR);
else
kinematicInterpolation.UpdateKI(updated, transform.localPosition, transform.localRotation);
}
if (driftBack) {
if (mirrorMotion) {
dT = Vector3.Lerp(dT, MirrorTranslation(convertedTranslation), driftFactor);
dR = Quaternion.Lerp(dR, Quaternion.Inverse(convertedQuaternion), driftFactor);
} else {
dT = Vector3.Lerp(dT, convertedTranslation, driftFactor);
dR = Quaternion.Lerp(dR, Quaternion.Inverse(convertedQuaternion), driftFactor);
}
rotationOffset = new Vector3(dR.eulerAngles.x, dR.eulerAngles.y, dR.eulerAngles.z);
translationOffset = new Vector3(dT.x, dT.y, dT.z);
}
}
public void SetPreventVerticalMotion(bool v) {
preventVerticalMotion = v;
}
void FixedUpdate()
{
if (fixedUpdate)
RunUpdate();
}
void Update()
{
if (!fixedUpdate)
RunUpdate();
}
}
}

View file

@ -1,11 +0,0 @@
fileFormatVersion: 2
guid: 16cac0ed1df366e4cbb82f6c6a93ef1a
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: -5
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View file

@ -1,232 +0,0 @@
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
namespace OpenSee {
public class InterpolatedMap<T, V, U> where V : InterpolatedValue<U>, new() {
private Dictionary<T, V> map = new Dictionary<T, V>();
private float clamp = 1f;
private float smoothing = 0f;
private bool gotDefault = false;
private U defaultValue;
public void Clear() {
map.Clear();
}
public void SetSmoothing(float smoothing) {
this.smoothing = smoothing;
foreach (var entry in map) {
if (entry.Value != null)
entry.Value.SetSmoothing(smoothing);
}
}
public void SetClamp(float clamp) {
this.clamp = clamp;
foreach (var entry in map) {
if (entry.Value != null)
entry.Value.SetClamp(clamp);
}
}
void Prepare(T key) {
if (!map.ContainsKey(key)) {
map.Add(key, new V());
map[key].SetSmoothing(smoothing);
map[key].SetClamp(clamp);
}
}
public void SetValue(T key, U v) {
Prepare(key);
map[key].SetValue(v);
}
public void Store(T key, U v) {
Prepare(key);
map[key].UpdateValue(v);
}
public void Store(T key, U v, double nowT) {
if (!map.ContainsKey(key)) {
map.Add(key, new V());
map[key].SetSmoothing(smoothing);
map[key].SetClamp(clamp);
}
map[key].UpdateValue(v, nowT);
}
public U GetDefault() {
if (gotDefault)
return defaultValue;
V tmp = new V();
defaultValue = tmp.GetDefault();
return defaultValue;
}
public bool Check(T key) {
return map.ContainsKey(key);
}
public U Get(T key) {
if (!map.ContainsKey(key))
return GetDefault();
return map[key].Interpolate();
}
}
abstract public class InterpolatedValue<V> {
private float interpolateT = 0f;
private float updateT = 0f;
private double lastT = 0f;
private double currentT = 0f;
private float clamp = 1f;
private float smoothing = 0f;
private int gotData = 0;
private bool haveDefault = false;
private V defaultValue;
private bool valueSet = false;
private V dataValue;
private V dataValueLast;
abstract public V ValueLerpUnclamped(V a, V b, float t);
abstract public V GetBuiltinDefault();
public void SetDefault(V defaultValue) {
this.defaultValue = defaultValue;
haveDefault = true;
}
public void ResetDefault() {
haveDefault = false;
}
public V GetDefault() {
if (haveDefault)
return defaultValue;
return GetBuiltinDefault();
}
public void SetSmoothing(float smoothing) {
this.smoothing = smoothing;
}
public void SetClamp(float clamp) {
this.clamp = clamp;
}
public void SetValue(V v) {
dataValueLast = v;
dataValue = v;
valueSet = true;
}
public InterpolatedValue(float smoothing = 0f, float clamp = 1f) {
this.smoothing = smoothing;
this.clamp = clamp;
}
public void UpdateValue(V v) {
UpdateValue(v, Time.realtimeSinceStartup);
}
public void UpdateValue(V v, double nowT) {
if (nowT < 0f)
return;
lock (this) {
if (nowT < currentT || gotData == 0) {
// Reinitialize
gotData = 1;
updateT = Time.time;
lastT = 0f;
currentT = nowT;
dataValueLast = GetDefault();
dataValue = ValueLerpUnclamped(v, dataValueLast, smoothing);
} else if (nowT == currentT) {
// Change value
dataValue = ValueLerpUnclamped(v, dataValueLast, smoothing);
} else {
// Regular operation
updateT = Time.time;
lastT = currentT;
currentT = nowT;
if (gotData < 2)
gotData++;
dataValueLast = dataValue;
dataValue = ValueLerpUnclamped(v, dataValueLast, smoothing);
}
}
}
public V Interpolate() {
lock (this) {
interpolateT = Time.time;
if (gotData < 2) {
if (valueSet)
return dataValue;
else
return GetDefault();
}
float t = Mathf.Min((interpolateT - updateT) / (float)(currentT - lastT), clamp);
return ValueLerpUnclamped(dataValueLast, dataValue, t);
}
}
}
public class InterpolatedColor : InterpolatedValue<Color> {
public override Color ValueLerpUnclamped(Color a, Color b, float t) {
return Color.LerpUnclamped(a, b, t);
}
public override Color GetBuiltinDefault() {
return Color.clear;
}
}
public class InterpolatedQuaternion : InterpolatedValue<Quaternion> {
public override Quaternion ValueLerpUnclamped(Quaternion a, Quaternion b, float t) {
return Quaternion.SlerpUnclamped(a, b, t);
}
public override Quaternion GetBuiltinDefault() {
return Quaternion.identity;
}
}
public class InterpolatedVector2 : InterpolatedValue<Vector2> {
public override Vector2 ValueLerpUnclamped(Vector2 a, Vector2 b, float t) {
return Vector2.LerpUnclamped(a, b, t);
}
public override Vector2 GetBuiltinDefault() {
return Vector2.zero;
}
}
public class InterpolatedVector3 : InterpolatedValue<Vector3> {
public override Vector3 ValueLerpUnclamped(Vector3 a, Vector3 b, float t) {
return Vector3.LerpUnclamped(a, b, t);
}
public override Vector3 GetBuiltinDefault() {
return Vector3.zero;
}
}
public class InterpolatedVector4 : InterpolatedValue<Vector4> {
public override Vector4 ValueLerpUnclamped(Vector4 a, Vector4 b, float t) {
return Vector4.LerpUnclamped(a, b, t);
}
public override Vector4 GetBuiltinDefault() {
return Vector4.zero;
}
}
public class InterpolatedFloat : InterpolatedValue<float> {
public override float ValueLerpUnclamped(float a, float b, float t) {
return Mathf.LerpUnclamped(a, b, t);
}
public override float GetBuiltinDefault() {
return 0f;
}
}
}

View file

@ -1,11 +0,0 @@
fileFormatVersion: 2
guid: d61e11f1b6900a7419383be1377f191b
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View file

@ -1,149 +0,0 @@
using System;
using System.Diagnostics;
using System.Runtime.InteropServices;
// From: https://stackoverflow.com/a/9164742
// Is this better? https://stackoverflow.com/a/36648201
namespace OpenSee
{
public class Win32 {
[DllImport("kernel32.dll", SetLastError = true)] [return: MarshalAs(UnmanagedType.Bool)]
static extern bool CloseHandle(IntPtr hObject);
}
public class Job : IDisposable
{
[DllImport("kernel32.dll", CharSet = CharSet.Unicode)]
static extern IntPtr CreateJobObject(IntPtr a, string lpName);
[DllImport("kernel32.dll")]
static extern bool SetInformationJobObject(IntPtr hJob, JobObjectInfoType infoType, IntPtr lpJobObjectInfo, UInt32 cbJobObjectInfoLength);
[DllImport("kernel32.dll", SetLastError = true)]
static extern bool AssignProcessToJobObject(IntPtr job, IntPtr process);
[DllImport("kernel32.dll", SetLastError = true)]
[return: MarshalAs(UnmanagedType.Bool)]
static extern bool CloseHandle(IntPtr hObject);
private IntPtr handle;
private bool disposed;
public Job()
{
handle = CreateJobObject(IntPtr.Zero, null);
var info = new JOBOBJECT_BASIC_LIMIT_INFORMATION
{
LimitFlags = 0x2000
};
var extendedInfo = new JOBOBJECT_EXTENDED_LIMIT_INFORMATION
{
BasicLimitInformation = info
};
int length = Marshal.SizeOf(typeof(JOBOBJECT_EXTENDED_LIMIT_INFORMATION));
IntPtr extendedInfoPtr = Marshal.AllocHGlobal(length);
Marshal.StructureToPtr(extendedInfo, extendedInfoPtr, false);
if (!SetInformationJobObject(handle, JobObjectInfoType.ExtendedLimitInformation, extendedInfoPtr, (uint)length))
throw new Exception(string.Format("Unable to set information. Error: {0}", Marshal.GetLastWin32Error()));
Marshal.FreeHGlobal(extendedInfoPtr);
}
public void Dispose()
{
Dispose(true);
GC.SuppressFinalize(this);
}
private void Dispose(bool disposing)
{
if (disposed)
return;
if (disposing) { }
Close();
disposed = true;
}
public void Close()
{
CloseHandle(handle);
handle = IntPtr.Zero;
}
public bool AddProcess(IntPtr processHandle)
{
return AssignProcessToJobObject(handle, processHandle);
}
public bool AddProcess(int processId)
{
return AddProcess(Process.GetProcessById(processId).Handle);
}
}
#region Helper classes
[StructLayout(LayoutKind.Sequential)]
struct IO_COUNTERS
{
public UInt64 ReadOperationCount;
public UInt64 WriteOperationCount;
public UInt64 OtherOperationCount;
public UInt64 ReadTransferCount;
public UInt64 WriteTransferCount;
public UInt64 OtherTransferCount;
}
[StructLayout(LayoutKind.Sequential)]
struct JOBOBJECT_BASIC_LIMIT_INFORMATION
{
public Int64 PerProcessUserTimeLimit;
public Int64 PerJobUserTimeLimit;
public UInt32 LimitFlags;
public UIntPtr MinimumWorkingSetSize;
public UIntPtr MaximumWorkingSetSize;
public UInt32 ActiveProcessLimit;
public UIntPtr Affinity;
public UInt32 PriorityClass;
public UInt32 SchedulingClass;
}
[StructLayout(LayoutKind.Sequential)]
public struct SECURITY_ATTRIBUTES
{
public UInt32 nLength;
public IntPtr lpSecurityDescriptor;
public Int32 bInheritHandle;
}
[StructLayout(LayoutKind.Sequential)]
struct JOBOBJECT_EXTENDED_LIMIT_INFORMATION
{
public JOBOBJECT_BASIC_LIMIT_INFORMATION BasicLimitInformation;
public IO_COUNTERS IoInfo;
public UIntPtr ProcessMemoryLimit;
public UIntPtr JobMemoryLimit;
public UIntPtr PeakProcessMemoryUsed;
public UIntPtr PeakJobMemoryUsed;
}
public enum JobObjectInfoType
{
AssociateCompletionPortInformation = 7,
BasicLimitInformation = 2,
BasicUIRestrictions = 4,
EndOfJobTimeInformation = 6,
ExtendedLimitInformation = 9,
SecurityLimitInformation = 5,
GroupInformation = 11
}
#endregion
}

View file

@ -1,11 +0,0 @@
fileFormatVersion: 2
guid: 3251308a085a78545a82e7f34ebc2d34
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View file

@ -1,108 +0,0 @@
using System;
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
namespace OpenSee {
public class OpenSeeKinematicInterpolation : MonoBehaviour
{
public float interpolateClamp = 1f;
private Vector3 lastPos;
private Vector3 lastPosV;
private double lastT;
private Vector3 currentPos;
private Vector3 currentPosV;
private double currentT = 0f;
private Vector3 lastRot = Vector3.zero;
private Vector3 lastRotV;
private Vector3 currentRot;
private Vector3 currentRotV;
private float dT;
private Vector3 coeffPosA;
private Vector3 coeffPosB;
private Vector3 coeffRotA;
private Vector3 coeffRotB;
private double updateT;
private double interpolateT;
private int ready = 0;
public void UpdateKI(double newT, Vector3 newPos, Quaternion newRot) {
Interpolate();
if (newT - currentT > 3f)
ready = 0;
currentPos = transform.localPosition;
currentRot = OpenSeeIKTarget.PrettyEuler(currentRot, transform.localRotation.eulerAngles);
float dTNow = (float)(interpolateT - updateT);
if (interpolateT - updateT > 0 || ready < 1) {
currentPosV = (currentPos - lastPos) / dT;
currentRotV = (currentRot - lastRot) / dT;
} else {
currentPosV = Vector3.zero;
currentRotV = Vector3.zero;
}
lastPos = currentPos;
lastPosV = currentPosV;
lastRot = currentRot;
lastRotV = currentRotV;
lastT = currentT;
currentPos = newPos;
currentRot = OpenSeeIKTarget.PrettyEuler(lastRot, newRot.eulerAngles);
currentT = newT;
dT = (float)(currentT - lastT);
currentPosV = (currentPos - lastPos) / dT;
currentRotV = (currentRot - lastRot) / dT;
float dTPow2 = Mathf.Pow(dT, 2);
float dTPow3 = Mathf.Pow(dT, 3);
coeffPosA = (- (2f*(currentPosV * dT + 2f * dT * lastPosV - 3f * currentPos + 3f * lastPos)) / dTPow2) / 2f;
coeffPosB = ((6f*(currentPosV * dT + dT * lastPosV - 2f * currentPos + 2f * lastPos)) / dTPow3)/6f;
coeffRotA = (- (2f*(currentRotV * dT + 2f * dT * lastRotV - 3f * currentRot + 3f * lastRot)) / dTPow2) / 2f;
coeffRotB = ((6f*(currentRotV * dT + dT * lastRotV - 2f * currentRot + 2f * lastRot)) / dTPow3)/6f;
updateT = Time.time;
if (ready <= 2)
ready++;
}
float InterpolateValue(float dTNow, float dTNowPow2, float dTNowPow3, float a, float b, float x1, float x2, float v1, float v2) {
return x1 + v1 * dTNow + dTNowPow2 * a + dTNowPow3 * b;
}
void Interpolate() {
interpolateT = Time.time;
if (interpolateT == updateT || ready <= 2)
return;
float dTNow = (float)(interpolateT - updateT);
if (dTNow >= dT) {
transform.localPosition = Vector3.LerpUnclamped(lastPos, currentPos, Mathf.Min((float)(dTNow / dT), interpolateClamp));
transform.localEulerAngles = Vector3.LerpUnclamped(lastRot, currentRot, Mathf.Min((float)(dTNow / dT), interpolateClamp));
} else {
float dTNowPow2 = Mathf.Pow(dTNow, 2);
float dTNowPow3 = Mathf.Pow(dTNow, 3);
float x = InterpolateValue(dTNow, dTNowPow2, dTNowPow3, coeffPosA.x, coeffPosB.x, lastPos.x, currentPos.x, lastPosV.x, currentPosV.x);
float y = InterpolateValue(dTNow, dTNowPow2, dTNowPow3, coeffPosA.y, coeffPosB.y, lastPos.y, currentPos.y, lastPosV.y, currentPosV.y);
float z = InterpolateValue(dTNow, dTNowPow2, dTNowPow3, coeffPosA.z, coeffPosB.z, lastPos.z, currentPos.z, lastPosV.z, currentPosV.z);
transform.localPosition = new Vector3(x, y, z);
x = InterpolateValue(dTNow, dTNowPow2, dTNowPow3, coeffRotA.x, coeffRotB.x, lastRot.x, currentRot.x, lastRotV.x, currentRotV.x);
y = InterpolateValue(dTNow, dTNowPow2, dTNowPow3, coeffRotA.y, coeffRotB.y, lastRot.y, currentRot.y, lastRotV.y, currentRotV.y);
z = InterpolateValue(dTNow, dTNowPow2, dTNowPow3, coeffRotA.z, coeffRotB.z, lastRot.z, currentRot.z, lastRotV.z, currentRotV.z);
transform.localEulerAngles = new Vector3(x, y, z);
}
}
public void Update() {
Interpolate();
}
}
}

View file

@ -1,11 +0,0 @@
fileFormatVersion: 2
guid: a4112b4be90fc9e4baee9eade65378c3
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: -1
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View file

@ -1,474 +0,0 @@
using System;
using System.Diagnostics;
using System.IO;
using System.Net;
using System.Runtime.InteropServices;
using System.Text;
using System.Collections;
using System.Collections.Generic;
using System.Text.RegularExpressions;
using UnityEngine;
namespace OpenSee {
public class OpenSeeLauncher : MonoBehaviour {
#region DllImport
[DllImport("dshowcapture_x64", CallingConvention = CallingConvention.Cdecl, EntryPoint = "create_capture")]
private static extern System.IntPtr create_capture_x64();
[DllImport("dshowcapture_x64", CallingConvention = CallingConvention.Cdecl, EntryPoint = "get_devices")]
private static extern int get_devices_x64(System.IntPtr cap);
[DllImport("dshowcapture_x64", CallingConvention = CallingConvention.Cdecl, EntryPoint = "get_device")]
private static extern void get_device_x64(System.IntPtr cap, int deviceno, [Out] StringBuilder namebuffer, int bufferlength);
[DllImport("dshowcapture_x64", CallingConvention = CallingConvention.Cdecl, EntryPoint = "destroy_capture")]
private static extern void destroy_capture_x64(System.IntPtr cap);
[DllImport("dshowcapture_x86", CallingConvention = CallingConvention.Cdecl, EntryPoint = "create_capture")]
private static extern System.IntPtr create_capture_x86();
[DllImport("dshowcapture_x86", CallingConvention = CallingConvention.Cdecl, EntryPoint = "get_devices")]
private static extern int get_devices_x86(System.IntPtr cap);
[DllImport("dshowcapture_x86", CallingConvention = CallingConvention.Cdecl, EntryPoint = "get_device")]
private static extern void get_device_x86(System.IntPtr cap, int deviceno, [Out] StringBuilder namebuffer, int bufferlength);
[DllImport("dshowcapture_x86", CallingConvention = CallingConvention.Cdecl, EntryPoint = "destroy_capture")]
private static extern void destroy_capture_x86(System.IntPtr cap);
#endregion
[Header("Settings")]
[Tooltip("If this is left empty, it will default to the OpenSee component on the same game object.")]
public OpenSee openSeeTarget;
[Tooltip("The numeric index of the camera as in the list returned by the ListCameras function.")]
public int cameraIndex = -1;
[Tooltip("The path to a video file that should be used as input for the tracker instead of a camera")]
public string videoPath = "";
[Tooltip("Should facetracker.exe be started automatically with the scene?")]
public bool autoStart = false;
[Tooltip("If this is enabled, available cameras are automatically printed to the debug console.")]
public bool autoListCameras = false;
[Tooltip("If this is enabled, no output from the tracker will be printed to the debug console. This cannot be changed while the tracker is running.")]
public bool dontPrint = true;
[Tooltip("If enabled, the next available port within 500 starting after the one given on the OpenSee component will be used.")]
public bool dynamicPort = false;
[Tooltip("The path to \"facetracker.exe\".")]
public string exePath = "facetracker.exe";
[Tooltip("The path, where the .onnx model files can be found")]
public string modelPath = "models\\";
[Tooltip("Additional options that should be passed to the face tracker.")]
public List<string> commandlineOptions = new List<string>(new string[] { "--silent", "1", "--max-threads", "1" });
[Tooltip("This string will be appended at the end of the tracker options without quoting.")]
public string extraOptions = "";
[Tooltip("If enabled, the tracker commandline option string will be logged with Debug.Log.")]
public bool logCommandline = false;
[Tooltip("IL2CPP doesn't support Proocess.Start. When this is enabled, OpenSeeLauncher will create the tracking process by calling the necessary API functions directly through the DLLs. In this case, reading the standard output from the process will not be supported and it will instead be send to the logfiles set in pinvokeStdOut and pinvokeStdErr in the persistent data directory. It will also retrieve the camera list directly through the libdshowcapture DLLs, so make sure it is part of your Unity project.")]
public bool usePinvoke = false;
[Tooltip("When this is enabled, even if usePinvoke is disabled, the camera list will be retrieved through libdshowcapture DLLs directly, which can be faster. Make sure the DLLs are in your Unity project.")]
public bool usePinvokeListCameras = false;
[Tooltip("This is the standard output log file's name in the persistent data directory.")]
public string pinvokeStdOut = "output.txt";
[Tooltip("This is the standard error log file's name in the persistent data directory.")]
public string pinvokeStdErr = "error.txt";
[Header("Runtime information")]
[Tooltip("This field shows if the tracker is currently alive.")]
public bool trackerAlive = false;
private string ip;
private Process trackerProcess = null;
private StringBuilder trackerSB = null;
private bool dontPrintNow = false;
private System.IntPtr processHandle = System.IntPtr.Zero;
private System.IntPtr processStdOut = System.IntPtr.Zero;
private System.IntPtr processStdErr = System.IntPtr.Zero;
private Job job = null;
public void UnsetOption(string name, bool hasArgument) {
int count = 1;
if (hasArgument)
count++;
int found = -1;
int i = 0;
foreach (string arg in commandlineOptions) {
if (arg == name) {
found = i;
break;
}
i++;
}
if (found > -1)
commandlineOptions.RemoveRange(found, count);
}
public void SetOption(string name, string argument) {
UnsetOption(name, argument != null);
commandlineOptions.Add(name);
if (argument != null)
commandlineOptions.Add(argument);
}
private bool CheckSetup(bool requireTarget) {
if (openSeeTarget == null)
openSeeTarget = GetComponent<OpenSee>();
if (openSeeTarget == null) {
UnityEngine.Debug.LogError("No openSeeTarget is set.");
return false;
}
IPAddress address;
if (!File.Exists(exePath)) {
UnityEngine.Debug.LogError("Facetracker executable cannot be found.");
return false;
}
/*if (!Directory.Exists(modelPath)) {
UnityEngine.Debug.LogError("Model directory cannot be found.");
return false;
}*/
if (requireTarget) {
ip = openSeeTarget.listenAddress;
if (!IPAddress.TryParse(ip, out address)) {
UnityEngine.Debug.LogError("No valid IP address was given in the OpenSee component.");
return false;
}
if (openSeeTarget.listenPort < 1 || openSeeTarget.listenPort > 65535) {
UnityEngine.Debug.LogError("No valid port was given in the OpenSee component.");
return false;
}
if (cameraIndex >= 0 && videoPath != "") {
UnityEngine.Debug.LogError("Entering both a camera index and a video filename is not valid.");
return false;
}
if (cameraIndex < 0 && !File.Exists(videoPath)) {
if (videoPath != "") {
UnityEngine.Debug.LogError("The given video file does not exist.");
} else {
UnityEngine.Debug.LogError("No camera or video file was given.");
}
return false;
}
}
if (job == null) {
job = new Job();
}
return true;
}
private string[] ListCameras_x64() {
List<string> cameras = new List<string>();
System.IntPtr cap = create_capture_x64();
int count = get_devices_x64(cap);
for (int i = 0; i < count; i++) {
StringBuilder namebuffer = new StringBuilder(2048);
get_device_x64(cap, i, namebuffer, 2048);
cameras.Add(namebuffer.ToString());
}
destroy_capture_x64(cap);
return cameras.ToArray();
}
private string[] ListCameras_x86() {
List<string> cameras = new List<string>();
System.IntPtr cap = create_capture_x86();
int count = get_devices_x86(cap);
for (int i = 0; i < count; i++) {
StringBuilder namebuffer = new StringBuilder(2048);
get_device_x86(cap, i, namebuffer, 2048);
cameras.Add(namebuffer.ToString());
}
destroy_capture_x86(cap);
return cameras.ToArray();
}
public string[] ListCameras() {
if (usePinvoke || usePinvokeListCameras) {
if (Environment.Is64BitProcess)
return ListCameras_x64();
else
return ListCameras_x86();
}
if (!CheckSetup(false))
return null;
StringBuilder stringBuilder;
ProcessStartInfo processStartInfo;
Process process;
stringBuilder = new StringBuilder();
processStartInfo = new ProcessStartInfo();
processStartInfo.CreateNoWindow = true;
processStartInfo.RedirectStandardOutput = true;
processStartInfo.RedirectStandardInput = true;
processStartInfo.RedirectStandardError = true;
processStartInfo.UseShellExecute = false;
processStartInfo.FileName = exePath;
processStartInfo.Arguments = "--list-cameras 2";
process = new Process();
process.StartInfo = processStartInfo;
process.EnableRaisingEvents = true;
process.OutputDataReceived += new DataReceivedEventHandler(delegate(object sender, DataReceivedEventArgs e) {
stringBuilder.Append(e.Data);
stringBuilder.Append("\n");
});
process.Start();
job.AddProcess(process.Handle);
process.BeginOutputReadLine();
process.WaitForExit();
process.CancelOutputRead();
string cameraInfo = stringBuilder.ToString();
string[] cameras = cameraInfo.Split(new[] { "\r\n", "\r", "\n" }, StringSplitOptions.RemoveEmptyEntries);
return cameras;
}
public float[] Benchmark(int threads) {
if (!CheckSetup(false))
return null;
StringBuilder stringBuilder;
ProcessStartInfo processStartInfo;
Process process;
stringBuilder = new StringBuilder();
processStartInfo = new ProcessStartInfo();
processStartInfo.CreateNoWindow = true;
processStartInfo.RedirectStandardOutput = true;
processStartInfo.RedirectStandardInput = true;
processStartInfo.RedirectStandardError = true;
processStartInfo.UseShellExecute = false;
processStartInfo.FileName = exePath;
processStartInfo.Arguments = "--benchmark 1 --priority 4 --max-threads " + threads.ToString();
process = new Process();
process.StartInfo = processStartInfo;
process.EnableRaisingEvents = true;
process.OutputDataReceived += new DataReceivedEventHandler(delegate(object sender, DataReceivedEventArgs e) {
stringBuilder.Append(e.Data);
stringBuilder.Append("\n");
});
process.Start();
job.AddProcess(process.Handle);
process.BeginOutputReadLine();
process.WaitForExit();
process.CancelOutputRead();
string[] lines = stringBuilder.ToString().Split(new[] { "\r\n", "\r", "\n" }, StringSplitOptions.RemoveEmptyEntries);
float[] results = new float[lines.Length];
for (int i = 0; i < lines.Length; i++) {
results[i] = Single.Parse(lines[i]);
}
return results;
}
// From: http://csharptest.net/529/how-to-correctly-escape-command-line-arguments-in-c/index.html
private static string EscapeArguments(params string[] args)
{
StringBuilder arguments = new StringBuilder();
Regex invalidChar = new Regex("[\x00\x0a\x0d]");// these can not be escaped
Regex needsQuotes = new Regex(@"\s|""");// contains whitespace or two quote characters
Regex escapeQuote = new Regex(@"(\\*)(""|$)");// one or more '\' followed with a quote or end of string
for (int carg = 0; args != null && carg < args.Length; carg++)
{
if (args[carg] == null) { throw new ArgumentNullException("args[" + carg + "]"); }
if (invalidChar.IsMatch(args[carg])) { throw new ArgumentOutOfRangeException("args[" + carg + "]"); }
if (args[carg] == String.Empty) { arguments.Append("\"\""); }
else if (!needsQuotes.IsMatch(args[carg])) { arguments.Append(args[carg]); }
else
{
arguments.Append('"');
arguments.Append(escapeQuote.Replace(args[carg], m => m.Groups[1].Value + m.Groups[1].Value + (m.Groups[2].Value == "\"" ? "\\\"" : "")));
arguments.Append('"');
}
if (carg + 1 < args.Length)
arguments.Append(' ');
}
return arguments.ToString();
}
public bool StartTracker() {
if (!CheckSetup(true))
return false;
List<string> arguments = new List<string>();
arguments.Add("--ip");
arguments.Add(ip);
if (dynamicPort && !openSeeTarget.listening) {
System.Net.IPEndPoint[] inUse = System.Net.NetworkInformation.IPGlobalProperties.GetIPGlobalProperties().GetActiveUdpListeners();
Array.Sort(inUse, delegate(System.Net.IPEndPoint a, System.Net.IPEndPoint b) { return a.Port.CompareTo(b.Port); });
int port = openSeeTarget.listenPort + 1;
for (int i = 0; i < inUse.Length; i++) {
if (inUse[i].Port < port)
continue;
if (inUse[i].Port == port) {
if (port <= openSeeTarget.listenPort + 500 && port <= IPEndPoint.MaxPort) {
port++;
continue;
} else {
return false;
}
}
break;
}
openSeeTarget.listenPort = port;
}
arguments.Add("--port");
arguments.Add(openSeeTarget.listenPort.ToString());
arguments.Add("--model-dir");
arguments.Add(modelPath);
arguments.Add("--capture");
if (videoPath != "" && File.Exists(videoPath))
arguments.Add(videoPath);
else
arguments.Add(cameraIndex.ToString());
foreach (string argument in commandlineOptions) {
arguments.Add(argument);
}
string argumentString = EscapeArguments(arguments.ToArray());
if (extraOptions != "")
argumentString = argumentString + " " + extraOptions;
if (logCommandline)
UnityEngine.Debug.Log("Starting tracker: " + argumentString);
StopTracker();
if (!usePinvoke) {
ProcessStartInfo processStartInfo;
processStartInfo = new ProcessStartInfo();
processStartInfo.CreateNoWindow = true;
processStartInfo.RedirectStandardOutput = true;
processStartInfo.RedirectStandardInput = true;
processStartInfo.RedirectStandardError = true;
processStartInfo.UseShellExecute = false;
processStartInfo.FileName = exePath;
processStartInfo.Arguments = argumentString;
trackerSB = new StringBuilder();
trackerProcess = new Process();
trackerProcess.StartInfo = processStartInfo;
dontPrintNow = dontPrint;
if (!dontPrintNow) {
trackerProcess.EnableRaisingEvents = true;
trackerProcess.OutputDataReceived += new DataReceivedEventHandler(delegate(object sender, DataReceivedEventArgs e) {
trackerSB.Append(e.Data);
trackerSB.Append("\n");
});
trackerProcess.ErrorDataReceived += new DataReceivedEventHandler(delegate(object sender, DataReceivedEventArgs e) {
trackerSB.Append(e.Data);
trackerSB.Append("\n");
});
}
trackerProcess.Start();
job.AddProcess(trackerProcess.Handle);
if (!dontPrintNow) {
trackerProcess.BeginOutputReadLine();
trackerProcess.BeginErrorReadLine();
}
return !trackerProcess.HasExited;
} else {
string dir = Path.GetDirectoryName(exePath);
string outputLog = Application.persistentDataPath + "/" + pinvokeStdOut;
string errorLog = Application.persistentDataPath + "/" + pinvokeStdErr;
OpenSeeProcessInterface.Start(exePath, "facetracker " + argumentString, dir, true, outputLog, errorLog, out processHandle, out processStdOut, out processStdErr);
if (processHandle != System.IntPtr.Zero) {
job.AddProcess(processHandle);
return OpenSeeProcessInterface.Alive(processHandle);
} else
return false;
}
}
public void StopTracker() {
if (processHandle != System.IntPtr.Zero) {
if (OpenSeeProcessInterface.Alive(processHandle))
OpenSeeProcessInterface.TerminateProcess(processHandle, 0);
OpenSeeProcessInterface.CloseHandle(processHandle);
processHandle = System.IntPtr.Zero;
}
if (processStdOut != System.IntPtr.Zero) {
OpenSeeProcessInterface.CloseHandle(processStdOut);
processStdOut = System.IntPtr.Zero;
}
if (processStdErr != System.IntPtr.Zero) {
OpenSeeProcessInterface.CloseHandle(processStdErr);
processStdErr = System.IntPtr.Zero;
}
if (trackerProcess != null && !trackerProcess.HasExited) {
trackerProcess.CloseMainWindow();
trackerProcess.Close();
if (!dontPrintNow) {
try {
trackerProcess.CancelOutputRead();
trackerProcess.CancelErrorRead();
} catch {}
}
}
trackerProcess = null;
}
public void Start() {
if (autoStart)
StartTracker();
if (autoListCameras) {
string[] cameras = ListCameras();
if (cameras == null || cameras.Length < 1) {
UnityEngine.Debug.Log("No cameras found.");
return;
}
UnityEngine.Debug.Log("Cameras:");
for (int i = 0; i < cameras.Length; i++) {
UnityEngine.Debug.Log(i + " = " + cameras[i]);
}
}
}
public void Update() {
if (processHandle != System.IntPtr.Zero) {
trackerAlive = OpenSeeProcessInterface.Alive(processHandle);
return;
} else {
if (trackerProcess != null)
trackerAlive = !trackerProcess.HasExited;
else {
trackerAlive = false;
return;
}
}
if (dontPrintNow || trackerSB == null)
return;
int len = trackerSB.Length;
if (len > 0) {
string output = trackerSB.ToString();
UnityEngine.Debug.Log("Tracker: " + output);
trackerSB.Clear();
}
}
private void CleanJob() {
if (job != null) {
job.Dispose();
job = null;
}
}
public void OnDestroy() {
StopTracker();
CleanJob();
}
public void OnApplicationQuit() {
StopTracker();
CleanJob();
}
}
}

View file

@ -1,11 +0,0 @@
fileFormatVersion: 2
guid: beae834477f91834691fb7248fddacf6
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View file

@ -1,364 +0,0 @@
using System;
using System.ComponentModel;
using System.Diagnostics;
using System.Runtime.InteropServices;
namespace OpenSee {
// Based on https://github.com/josh4364/IL2cppStartProcess/blob/master/StartExternalProcess.cs
public class OpenSeeProcessInterface {
#region DllImport
[DllImport("kernel32.dll", SetLastError=true, CharSet=CharSet.Auto)]
private static extern IntPtr CreateFile(
string lpFileName,
EFileAccess dwDesiredAccess,
EFileShare dwShareMode,
SECURITY_ATTRIBUTES lpSecurityAttributes,
ECreationDisposition dwCreationDisposition,
EFileAttributes dwFlagsAndAttributes,
IntPtr hTemplateFile
);
[StructLayout(LayoutKind.Sequential)]
private struct SECURITY_ATTRIBUTES
{
public int nLength;
public IntPtr lpSecurityDescriptor;
public int bInheritHandle;
}
[Flags]
enum EFileAccess : uint {
//
// Standart Section
//
AccessSystemSecurity = 0x1000000, // AccessSystemAcl access type
MaximumAllowed = 0x2000000, // MaximumAllowed access type
Delete = 0x10000,
ReadControl = 0x20000,
WriteDAC = 0x40000,
WriteOwner = 0x80000,
Synchronize = 0x100000,
StandardRightsRequired = 0xF0000,
StandardRightsRead = ReadControl,
StandardRightsWrite = ReadControl,
StandardRightsExecute = ReadControl,
StandardRightsAll = 0x1F0000,
SpecificRightsAll = 0xFFFF,
FILE_READ_DATA = 0x0001, // file & pipe
FILE_LIST_DIRECTORY = 0x0001, // directory
FILE_WRITE_DATA = 0x0002, // file & pipe
FILE_ADD_FILE = 0x0002, // directory
FILE_APPEND_DATA = 0x0004, // file
FILE_ADD_SUBDIRECTORY = 0x0004, // directory
FILE_CREATE_PIPE_INSTANCE = 0x0004, // named pipe
FILE_READ_EA = 0x0008, // file & directory
FILE_WRITE_EA = 0x0010, // file & directory
FILE_EXECUTE = 0x0020, // file
FILE_TRAVERSE = 0x0020, // directory
FILE_DELETE_CHILD = 0x0040, // directory
FILE_READ_ATTRIBUTES = 0x0080, // all
FILE_WRITE_ATTRIBUTES = 0x0100, // all
//
// Generic Section
//
GenericRead = 0x80000000,
GenericWrite = 0x40000000,
GenericExecute = 0x20000000,
GenericAll = 0x10000000,
SPECIFIC_RIGHTS_ALL = 0x00FFFF,
FILE_ALL_ACCESS =
StandardRightsRequired |
Synchronize |
0x1FF,
FILE_GENERIC_READ =
StandardRightsRead |
FILE_READ_DATA |
FILE_READ_ATTRIBUTES |
FILE_READ_EA |
Synchronize,
FILE_GENERIC_WRITE =
StandardRightsWrite |
FILE_WRITE_DATA |
FILE_WRITE_ATTRIBUTES |
FILE_WRITE_EA |
FILE_APPEND_DATA |
Synchronize,
FILE_GENERIC_EXECUTE =
StandardRightsExecute |
FILE_READ_ATTRIBUTES |
FILE_EXECUTE |
Synchronize
}
[Flags]
public enum EFileShare : uint
{
/// <summary>
///
/// </summary>
None = 0x00000000,
/// <summary>
/// Enables subsequent open operations on an object to request read access.
/// Otherwise, other processes cannot open the object if they request read access.
/// If this flag is not specified, but the object has been opened for read access, the function fails.
/// </summary>
Read = 0x00000001,
/// <summary>
/// Enables subsequent open operations on an object to request write access.
/// Otherwise, other processes cannot open the object if they request write access.
/// If this flag is not specified, but the object has been opened for write access, the function fails.
/// </summary>
Write = 0x00000002,
/// <summary>
/// Enables subsequent open operations on an object to request delete access.
/// Otherwise, other processes cannot open the object if they request delete access.
/// If this flag is not specified, but the object has been opened for delete access, the function fails.
/// </summary>
Delete = 0x00000004
}
public enum ECreationDisposition : uint
{
/// <summary>
/// Creates a new file. The function fails if a specified file exists.
/// </summary>
New = 1,
/// <summary>
/// Creates a new file, always.
/// If a file exists, the function overwrites the file, clears the existing attributes, combines the specified file attributes,
/// and flags with FILE_ATTRIBUTE_ARCHIVE, but does not set the security descriptor that the SECURITY_ATTRIBUTES structure specifies.
/// </summary>
CreateAlways = 2,
/// <summary>
/// Opens a file. The function fails if the file does not exist.
/// </summary>
OpenExisting = 3,
/// <summary>
/// Opens a file, always.
/// If a file does not exist, the function creates a file as if dwCreationDisposition is CREATE_NEW.
/// </summary>
OpenAlways = 4,
/// <summary>
/// Opens a file and truncates it so that its size is 0 (zero) bytes. The function fails if the file does not exist.
/// The calling process must open the file with the GENERIC_WRITE access right.
/// </summary>
TruncateExisting = 5
}
[Flags]
public enum EFileAttributes : uint
{
Readonly = 0x00000001,
Hidden = 0x00000002,
System = 0x00000004,
Directory = 0x00000010,
Archive = 0x00000020,
Device = 0x00000040,
Normal = 0x00000080,
Temporary = 0x00000100,
SparseFile = 0x00000200,
ReparsePoint = 0x00000400,
Compressed = 0x00000800,
Offline = 0x00001000,
NotContentIndexed= 0x00002000,
Encrypted = 0x00004000,
Write_Through = 0x80000000,
Overlapped = 0x40000000,
NoBuffering = 0x20000000,
RandomAccess = 0x10000000,
SequentialScan = 0x08000000,
DeleteOnClose = 0x04000000,
BackupSemantics = 0x02000000,
PosixSemantics = 0x01000000,
OpenReparsePoint = 0x00200000,
OpenNoRecall = 0x00100000,
FirstPipeInstance= 0x00080000
}
[DllImport("kernel32.dll", SetLastError=true)]
private static extern UInt32 WaitForSingleObject(IntPtr hHandle, UInt32 dwMilliseconds);
const UInt32 INFINITE = 0xFFFFFFFF;
const UInt32 WAIT_ABANDONED = 0x00000080;
const UInt32 WAIT_OBJECT_0 = 0x00000000;
const UInt32 WAIT_TIMEOUT = 0x00000102;
[DllImport("kernel32.dll", CharSet = CharSet.Unicode, SetLastError = true)]
[return: MarshalAs(UnmanagedType.Bool)]
private static extern bool CreateProcessW(
string lpApplicationName,
[In] string lpCommandLine,
IntPtr procSecAttrs,
IntPtr threadSecAttrs,
bool bInheritHandles,
ProcessCreationFlags dwCreationFlags,
IntPtr lpEnvironment,
string lpCurrentDirectory,
ref STARTUPINFO lpStartupInfo,
ref PROCESS_INFORMATION lpProcessInformation
);
[DllImport("kernel32.dll", SetLastError = true)]
[return: MarshalAs(UnmanagedType.Bool)]
public static extern bool CloseHandle(IntPtr hObject);
[DllImport("kernel32.dll", SetLastError = true)]
[return: MarshalAs(UnmanagedType.Bool)]
public static extern bool TerminateProcess(IntPtr processHandle, uint exitCode);
[DllImport("kernel32.dll", SetLastError = true)]
private static extern IntPtr OpenProcess(ProcessAccessRights access, bool inherit, uint processId);
[Flags]
private enum ProcessAccessRights : uint
{
PROCESS_CREATE_PROCESS = 0x0080, // Required to create a process.
PROCESS_CREATE_THREAD = 0x0002, // Required to create a thread.
PROCESS_DUP_HANDLE = 0x0040, // Required to duplicate a handle using DuplicateHandle.
PROCESS_QUERY_INFORMATION = 0x0400, // Required to retrieve certain information about a process, such as its token, exit code, and priority class (see OpenProcessToken, GetExitCodeProcess, GetPriorityClass, and IsProcessInJob).
PROCESS_QUERY_LIMITED_INFORMATION = 0x1000, // Required to retrieve certain information about a process (see QueryFullProcessImageName). A handle that has the PROCESS_QUERY_INFORMATION access right is automatically granted PROCESS_QUERY_LIMITED_INFORMATION. Windows Server 2003 and Windows XP/2000: This access right is not supported.
PROCESS_SET_INFORMATION = 0x0200, // Required to set certain information about a process, such as its priority class (see SetPriorityClass).
PROCESS_SET_QUOTA = 0x0100, // Required to set memory limits using SetProcessWorkingSetSize.
PROCESS_SUSPEND_RESUME = 0x0800, // Required to suspend or resume a process.
PROCESS_TERMINATE = 0x0001, // Required to terminate a process using TerminateProcess.
PROCESS_VM_OPERATION = 0x0008, // Required to perform an operation on the address space of a process (see VirtualProtectEx and WriteProcessMemory).
PROCESS_VM_READ = 0x0010, // Required to read memory in a process using ReadProcessMemory.
PROCESS_VM_WRITE = 0x0020, // Required to write to memory in a process using WriteProcessMemory.
DELETE = 0x00010000, // Required to delete the object.
READ_CONTROL = 0x00020000, // Required to read information in the security descriptor for the object, not including the information in the SACL. To read or write the SACL, you must request the ACCESS_SYSTEM_SECURITY access right. For more information, see SACL Access Right.
SYNCHRONIZE = 0x00100000, // The right to use the object for synchronization. This enables a thread to wait until the object is in the signaled state.
WRITE_DAC = 0x00040000, // Required to modify the DACL in the security descriptor for the object.
WRITE_OWNER = 0x00080000, // Required to change the owner in the security descriptor for the object.
STANDARD_RIGHTS_REQUIRED = 0x000f0000,
PROCESS_ALL_ACCESS = STANDARD_RIGHTS_REQUIRED | SYNCHRONIZE | 0xFFF // All possible access rights for a process object.
}
[StructLayout(LayoutKind.Sequential)]
private struct PROCESS_INFORMATION
{
internal IntPtr hProcess;
internal IntPtr hThread;
internal uint dwProcessId;
internal uint dwThreadId;
}
[StructLayout(LayoutKind.Sequential)]
private struct STARTUPINFO
{
internal uint cb;
internal IntPtr lpReserved;
internal IntPtr lpDesktop;
internal IntPtr lpTitle;
internal uint dwX;
internal uint dwY;
internal uint dwXSize;
internal uint dwYSize;
internal uint dwXCountChars;
internal uint dwYCountChars;
internal uint dwFillAttribute;
internal uint dwFlags;
internal ushort wShowWindow;
internal ushort cbReserved2;
internal IntPtr lpReserved2;
internal IntPtr hStdInput;
internal IntPtr hStdOutput;
internal IntPtr hStdError;
}
[Flags]
private enum ProcessCreationFlags : uint
{
NONE = 0,
CREATE_BREAKAWAY_FROM_JOB = 0x01000000,
CREATE_DEFAULT_ERROR_MODE = 0x04000000,
CREATE_NEW_CONSOLE = 0x00000010,
CREATE_NEW_PROCESS_GROUP = 0x00000200,
CREATE_NO_WINDOW = 0x08000000,
CREATE_PROTECTED_PROCESS = 0x00040000,
CREATE_PRESERVE_CODE_AUTHZ_LEVEL = 0x02000000,
CREATE_SECURE_PROCESS = 0x00400000,
CREATE_SEPARATE_WOW_VDM = 0x00000800,
CREATE_SHARED_WOW_VDM = 0x00001000,
CREATE_SUSPENDED = 0x00000004,
CREATE_UNICODE_ENVIRONMENT = 0x00000400,
DEBUG_ONLY_THIS_PROCESS = 0x00000002,
DEBUG_PROCESS = 0x00000001,
DETACHED_PROCESS = 0x00000008,
EXTENDED_STARTUPINFO_PRESENT = 0x00080000,
INHERIT_PARENT_AFFINITY = 0x00010000
}
#endregion
public static uint Start(string exePath, string commandline, string dir, bool hidden, string outputLog, string errorLog, out IntPtr handle, out IntPtr handleStdOut, out IntPtr handleStdErr)
{
SECURITY_ATTRIBUTES sa = new SECURITY_ATTRIBUTES();
sa.nLength = Marshal.SizeOf<SECURITY_ATTRIBUTES>();
sa.lpSecurityDescriptor = IntPtr.Zero;
sa.bInheritHandle = 1;
handle = IntPtr.Zero;
handleStdOut = IntPtr.Zero;
handleStdErr = IntPtr.Zero;
if (outputLog != null)
handleStdOut = CreateFile(outputLog, EFileAccess.FILE_WRITE_DATA, EFileShare.Read | EFileShare.Write, sa, ECreationDisposition.CreateAlways, EFileAttributes.Normal, IntPtr.Zero);
if (errorLog != null)
handleStdErr = CreateFile(errorLog, EFileAccess.FILE_WRITE_DATA, EFileShare.Read | EFileShare.Write, sa, ECreationDisposition.CreateAlways, EFileAttributes.Normal, IntPtr.Zero);
ProcessCreationFlags flags = hidden ? ProcessCreationFlags.CREATE_NO_WINDOW : ProcessCreationFlags.NONE;
STARTUPINFO startupinfo = new STARTUPINFO
{
cb = (uint)Marshal.SizeOf<STARTUPINFO>(),
dwFlags = 0x00000100,
hStdInput = IntPtr.Zero,
hStdOutput = handleStdOut,
hStdError = handleStdErr
};
PROCESS_INFORMATION processinfo = new PROCESS_INFORMATION();
if (!CreateProcessW(exePath, commandline, IntPtr.Zero, IntPtr.Zero, true, flags, IntPtr.Zero, dir, ref startupinfo, ref processinfo))
{
throw new Win32Exception();
}
handle = OpenProcess(ProcessAccessRights.PROCESS_ALL_ACCESS, false, processinfo.dwProcessId);
return processinfo.dwProcessId;
}
public static bool Alive(IntPtr handle) {
uint ret = WaitForSingleObject(handle, 0);
return ret == WAIT_TIMEOUT;
}
public static int KillProcess(uint pid)
{
IntPtr handle = OpenProcess(ProcessAccessRights.PROCESS_ALL_ACCESS, false, pid);
if (handle == IntPtr.Zero)
{
return -1;
}
if (!TerminateProcess(handle, 0))
{
throw new Win32Exception();
}
if (!CloseHandle(handle))
{
throw new Win32Exception();
}
return 0;
}
}
}

View file

@ -1,11 +0,0 @@
fileFormatVersion: 2
guid: 8130804d2fedd6d47a6cf0a447058d08
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View file

@ -1,225 +0,0 @@
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
namespace OpenSee {
public class OpenSeeShowPoints : MonoBehaviour {
public OpenSee openSee = null;
public int faceId = 0;
public bool only30Points = false;
public bool show3DPoints = true;
public bool applyTranslation = false;
public bool applyRotation = false;
[Range(0, 1)]
public float minConfidence = 0.20f;
public bool showGaze = true;
public Material material;
public bool showLines = false;
public float lineWidth = 0.01f;
public Material lineMaterial;
public bool receiveShadows = false;
private OpenSee.OpenSeeData openSeeData;
private GameObject[] gameObjects;
private LineRenderer[] lineRenderers;
private GameObject centerBall;
private double updated = 0.0;
private int total = 70;
private int[] lines = new int[]{/* Contour */ 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, -1, /* Eyebrows */ 18, 19, 20, 21, -1, 23, 24, 25, 26, -1, /* Nose */ 28, 29, 30, 33, 32, 33, 34, 35, -1, /* Eye */ 37, 38, 39, 40, 41, 36, /* Eye */ 43, 44, 45, 46, 47, 42, /* Mouth */ 49, 50, 51, 52, 62, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 64, 65, 58, 58, 62};
private HashSet<int> pt30Set = new HashSet<int> { 0, 2, 5, 8, 11, 14, 16, 17, 19, 21, 22, 24, 26, 27, 30, 33, 36, 37, 39, 40, 42, 43, 45, 46, 50, 55, 58, 60, 62, 64 };
private int[] linesPt30Set = new int[]{/* Contour */ 2, -1, 5, -1, -1, 8, -1, -1, 11, -1, -1, 14, -1, -1, 16, -1, -1, /* Eyebrows */ 19, -1, 21, -1, -1, 24, -1, 26, -1, -1, /* Nose */ 30, -1, -1, 33, -1, -1, -1, -1, -1, /* Eye */ 37, 39, -1, 40, 36, -1, /* Eye */ 43, 45, -1, 46, 42, -1, /* Mouth */ -1, -1, 62, -1, -1, -1, -1, 58, -1, -1, 60, -1, 62, -1, 64, -1, 58, -1, 58, 62};
void Start () {
if (openSee == null) {
openSee = GetComponent<OpenSee>();
}
gameObjects = new GameObject[70];
lineRenderers = new LineRenderer[68];
if (lineMaterial == null)
showLines = false;
if (!showGaze)
total = 66;
for (int i = 0; i < total; i++) {
gameObjects[i] = GameObject.CreatePrimitive(PrimitiveType.Sphere);
gameObjects[i].name = "Point " + (i + 1);
if (material != null)
gameObjects[i].GetComponent<Renderer>().material = material;
gameObjects[i].GetComponent<Renderer>().receiveShadows = receiveShadows;
gameObjects[i].layer = gameObject.layer;
gameObjects[i].transform.SetParent(transform);
gameObjects[i].transform.localScale = new Vector3(0.025f, 0.025f, 0.025f);
if (i >= 68) {
GameObject cylinder = GameObject.CreatePrimitive(PrimitiveType.Cylinder);
if (material != null)
cylinder.GetComponent<Renderer>().material = material;
cylinder.GetComponent<Renderer>().receiveShadows = receiveShadows;
cylinder.layer = gameObject.layer;
cylinder.transform.SetParent(gameObjects[i].transform);
cylinder.transform.localEulerAngles = new Vector3(90f, 0f, 0f);
cylinder.transform.localPosition = new Vector3(0f, 0f, -4f);
cylinder.transform.localScale = new Vector3(1f, 4f, 1f);
}
if (only30Points && i < 66 && !pt30Set.Contains(i))
gameObjects[i].SetActive(false);
}
for (int i = 0; i < 68; i++) {
if (i == 66) {
GameObject lineGameObject = new GameObject("LineGameObject");
if (only30Points)
lineGameObject.transform.SetParent(gameObjects[50].transform);
else
lineGameObject.transform.SetParent(gameObjects[48].transform);
lineGameObject.layer = gameObject.layer;
lineRenderers[i] = lineGameObject.AddComponent(typeof(LineRenderer)) as LineRenderer;
} else if (i == 67) {
GameObject lineGameObject = new GameObject("LineGameObject");
if (only30Points)
lineGameObject.transform.SetParent(gameObjects[55].transform);
else
lineGameObject.transform.SetParent(gameObjects[53].transform);
lineGameObject.layer = gameObject.layer;
lineRenderers[i] = lineGameObject.AddComponent(typeof(LineRenderer)) as LineRenderer;
}
else
lineRenderers[i] = gameObjects[i].AddComponent(typeof(LineRenderer)) as LineRenderer;
lineRenderers[i].useWorldSpace = true;
lineRenderers[i].generateLightingData = true;
lineRenderers[i].material = lineMaterial;
lineRenderers[i].receiveShadows = receiveShadows;
lineRenderers[i].widthMultiplier = lineWidth;
lineRenderers[i].positionCount = 2;
}
centerBall = GameObject.CreatePrimitive(PrimitiveType.Sphere);
centerBall.name = "Center";
centerBall.transform.SetParent(transform);
centerBall.transform.localScale = new Vector3(0.1f, 0.1f, 0.1f);
}
void Update () {
if (!openSee)
return;
/*openSeeData = openSee.trackingData;
if (openSeeData == null || openSeeData.Length < 1)
return;*/
openSeeData = openSee.GetOpenSeeData(faceId);
if (openSeeData == null || (show3DPoints && openSeeData.fit3DError > openSee.maxFit3DError))
return;
if (openSeeData.time > updated) {
updated = openSeeData.time;
} else {
return;
}
if (show3DPoints) {
centerBall.gameObject.SetActive(false);
for (int i = 0; i < total; i++) {
if (openSeeData.got3DPoints && (i >= 68 || openSeeData.confidence[i] > minConfidence)) {
Renderer renderer = gameObjects[i].GetComponent<Renderer>();
Vector3 pt = openSeeData.points3D[i];
pt.x = -pt.x;
gameObjects[i].transform.localPosition = pt;
if (i < 68)
renderer.material.SetColor("_Color", Color.Lerp(Color.red, Color.green, openSeeData.confidence[i]));
else {
if (i == 68)
gameObjects[i].transform.localRotation = openSeeData.rightGaze;
else
gameObjects[i].transform.localRotation = openSeeData.leftGaze;
}
} else {
Renderer renderer = gameObjects[i].GetComponent<Renderer>();
renderer.material.SetColor("_Color", Color.cyan);
}
}
if (applyTranslation) {
Vector3 v = openSeeData.translation;
v.x = -v.x;
v.z = -v.z;
transform.localPosition = v;
}
if (applyRotation) {
Quaternion offset = Quaternion.Euler(0f, 0f, -90f);
Quaternion convertedQuaternion = new Quaternion(-openSeeData.rawQuaternion.y, -openSeeData.rawQuaternion.x, openSeeData.rawQuaternion.z, openSeeData.rawQuaternion.w) * offset;
transform.localRotation = convertedQuaternion;
}
} else {
centerBall.gameObject.SetActive(false);
Vector3 center = new Vector3(0.0f, 0.0f, 0.0f);
float minX = 10000.0f;
float minY = 10000.0f;
float maxX = -1.0f;
float maxY = -1.0f;
for (int i = 0; i < 66; i++) {
float x = openSeeData.points[i].x;
float y = -openSeeData.points[i].y;
if (minX > x) {
minX = x;
}
if (minY > y) {
minY = y;
}
if (maxX < x) {
maxX = x;
}
if (maxY < y) {
maxY = y;
}
center += new Vector3(x, y, 0.0f);
}
center = center / 66;
center = center - new Vector3(minX, minY, 0.0f);
center.x = center.x / (maxX - minX);
center.y = center.y / (maxX - minX);
center.z = 0.5f;
centerBall.transform.localPosition = center;
for (int i = 0; i < 66; i++) {
Renderer renderer = gameObjects[i].GetComponent<Renderer>();
renderer.receiveShadows = receiveShadows;
renderer.material.SetColor("_Color", Color.Lerp(Color.red, Color.green, openSeeData.confidence[i]));
float x = openSeeData.points[i].x;
float y = -openSeeData.points[i].y;
Vector3 position = new Vector3(x, y, 0.0f);
position = position - new Vector3(minX, minY, 0.0f);
position.x = position.x / (maxX - minX);
position.y = position.y / (maxX - minX);
gameObjects[i].transform.localPosition = position;
}
}
for (int i = 0; i < 68; i++) {
if ((!only30Points && lines[i] == -1) || (only30Points && linesPt30Set[i] == -1))
continue;
if (!showLines || lineMaterial == null) {
lineRenderers[i].enabled = false;
} else {
int a = i;
int b = lines[i];
if (only30Points) {
b = linesPt30Set[i];
if (i == 66)
a = 50;
if (i == 67)
a = 55;
} else {
if (i == 66)
a = 48;
if (i == 67)
a = 53;
}
Color color = Color.Lerp(Color.red, Color.green, Mathf.Lerp(0.5f, openSeeData.confidence[a], openSeeData.confidence[b]));
lineRenderers[i].enabled = true;
lineRenderers[i].widthMultiplier = lineWidth;
lineRenderers[i].receiveShadows = receiveShadows;
lineRenderers[i].material.SetColor("_Color", color);
lineRenderers[i].startColor = color;
lineRenderers[i].endColor = color;
lineRenderers[i].SetPosition(0, gameObjects[a].transform.position);
lineRenderers[i].SetPosition(1, gameObjects[b].transform.position);
}
}
}
}
}

View file

@ -1,11 +0,0 @@
fileFormatVersion: 2
guid: 9c0b8bb971ed0e14288631f4274a3807
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View file

@ -1,8 +0,0 @@
fileFormatVersion: 2
guid: f1dfc5f1c2e6f294e8191828595882b1
folderAsset: yes
DefaultImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:

View file

@ -1,285 +0,0 @@
using System;
using System.Collections.Generic;
using System.IO;
using System.IO.Compression;
using System.Runtime.InteropServices;
using System.Runtime.Serialization;
using System.Runtime.Serialization.Formatters.Binary;
using System.Text;
using UnityEngine;
namespace OpenSee {
public class SVMModel {
#region DllImport
[DllImport("SVMModel", CallingConvention = CallingConvention.Cdecl, EntryPoint = "trainModel")]
private static extern System.IntPtr trainModelDll(float[] features, float[] labels, float[] weights, int rows, int cols, int classes, int probability, float C);
protected virtual System.IntPtr trainModel(float[] features, float[] labels, float[] weights, int rows, int cols, int classes, int probability, float C) {
Debug.Log("Training LibSVM");
return trainModelDll(features, labels, weights, rows, cols, classes, probability, C);
}
[DllImport("SVMModel", CallingConvention = CallingConvention.Cdecl, EntryPoint = "predict")]
private static extern void predictDll(System.IntPtr model, float[] features, [Out] float[] predictions, [Out] double[] probabilities, int rows);
protected virtual void predict(System.IntPtr model, float[] features, [Out] float[] predictions, [Out] double[] probabilities, int rows) {
predictDll(model, features, predictions, probabilities, rows);
}
[DllImport("SVMModel", CallingConvention = CallingConvention.Cdecl, CharSet = CharSet.Ansi, EntryPoint = "loadModel")]
private static extern System.IntPtr loadModelDll([MarshalAs(UnmanagedType.LPStr)]string filename, int cols, int classes, double[] means, double[] sdevs);
protected virtual System.IntPtr loadModel([MarshalAs(UnmanagedType.LPStr)]string filename, int cols, int classes, double[] means, double[] sdevs) {
return loadModelDll(filename, cols, classes, means, sdevs);
}
[DllImport("SVMModel", CallingConvention = CallingConvention.Cdecl, CharSet = CharSet.Ansi, EntryPoint = "loadModelString")]
private static extern System.IntPtr loadModelStringDll([MarshalAs(UnmanagedType.LPStr)]string modelString, int cols, int classes, double[] means, double[] sdevs);
protected virtual System.IntPtr loadModelString([MarshalAs(UnmanagedType.LPStr)]string modelString, int cols, int classes, double[] means, double[] sdevs) {
Debug.Log("Loading LibSVM");
return loadModelStringDll(modelString, cols, classes, means, sdevs);
}
[DllImport("SVMModel", CallingConvention = CallingConvention.Cdecl, EntryPoint = "getScales")]
private static extern void getScalesDll(System.IntPtr model, [Out] double[] means, [Out] double[] sdevs);
protected virtual void getScales(System.IntPtr model, [Out] double[] means, [Out] double[] sdevs) {
getScalesDll(model, means, sdevs);
}
[DllImport("SVMModel", CallingConvention = CallingConvention.Cdecl, CharSet = CharSet.Ansi, EntryPoint = "saveModel")]
private static extern int saveModelDll(System.IntPtr model, [MarshalAs(UnmanagedType.LPStr)]string filename);
protected virtual int saveModel(System.IntPtr model, [MarshalAs(UnmanagedType.LPStr)]string filename) {
return saveModelDll(model, filename);
}
[DllImport("SVMModel", CallingConvention = CallingConvention.Cdecl, CharSet = CharSet.Ansi, EntryPoint = "saveModelString")]
private static extern string saveModelStringDll(System.IntPtr model);
protected virtual string saveModelString(System.IntPtr model) {
return saveModelStringDll(model);
}
[DllImport("SVMModel", CallingConvention = CallingConvention.Cdecl, EntryPoint = "destroyModel")]
private static extern void destroyModelDll(System.IntPtr model);
protected virtual void destroyModel(System.IntPtr model) {
destroyModelDll(model);
}
#endregion
private bool haveModel = false;
private System.IntPtr model;
private int cols;
private int maxClasses;
[Serializable]
private class SVMModelRepresentation {
public string modelString;
public int cols;
public int maxClasses;
public double[] means;
public double[] sdevs;
}
public System.IntPtr LoadSerialized(byte[] modelBytes, out int cols, out int maxClasses, bool compress) {
IFormatter formatter = new BinaryFormatter();
MemoryStream memoryStream = new MemoryStream(modelBytes);
memoryStream.Position = 0;
SVMModelRepresentation smr;
if (compress) {
using (GZipStream gzipStream = new GZipStream(memoryStream, CompressionMode.Decompress)) {
smr = formatter.Deserialize(gzipStream) as SVMModelRepresentation;
}
} else {
smr = formatter.Deserialize(memoryStream) as SVMModelRepresentation;
}
cols = smr.cols;
maxClasses = smr.maxClasses;
System.IntPtr model = loadModelString(smr.modelString, smr.cols, smr.maxClasses, smr.means, smr.sdevs);
return model;
}
public byte[] ToSerialized(System.IntPtr model, int cols, int maxClasses, bool compress) {
SVMModelRepresentation smr = new SVMModelRepresentation();
smr.cols = cols;
smr.maxClasses = maxClasses;
smr.means = new double[cols];
smr.sdevs = new double[cols];
getScales(model, smr.means, smr.sdevs);
smr.modelString = saveModelString(model);
IFormatter formatter = new BinaryFormatter();
MemoryStream memoryStream = new MemoryStream();
if (compress) {
using (GZipStream gzipStream = new GZipStream(memoryStream, CompressionMode.Compress)) {
formatter.Serialize(gzipStream, smr);
gzipStream.Flush();
}
} else {
formatter.Serialize(memoryStream, smr);
}
return memoryStream.ToArray();
}
public void DestroyModel() {
if (haveModel) {
destroyModel(model);
haveModel = false;
}
}
private void LoadModel(byte[] modelBytes, bool compress) {
DestroyModel();
model = LoadSerialized(modelBytes, out cols, out maxClasses, compress);
haveModel = true;
}
public void LoadModel(byte[] modelBytes) {
LoadModel(modelBytes, true);
}
private byte[] SaveModel(bool compress) {
if (!haveModel)
return null;
return ToSerialized(model, cols, maxClasses, compress);
}
public byte[] SaveModel() {
return SaveModel(true);
}
// features is a rows*cols long float array with rows written one after another. labels is a rows long float array with the corresponding classes as integral numbers from 0 to num_classes-1, where all classes have to exist. Training on more than 10000 rows is disabled.
public bool TrainModel(float[] features, float[] labels, float[] weights, int rows, int cols, int probability, float C) {
DestroyModel();
//if (rows > 10000)
// return false;
if (cols < 1 || rows < 1 || features.Length < rows * cols || labels.Length < rows)
return false;
int max = -1;
HashSet<int> knownClasses = new HashSet<int>();
for (int i = 0; i < rows; i++) {
labels[i] = (float)Math.Round(labels[i]);
int l = (int)labels[i];
if (l > max)
max = l;
if (l < 0)
return false;
knownClasses.Add(l);
}
for (int i = 0; i <= max; i++) {
if (!knownClasses.Contains(i))
return false;
}
maxClasses = max + 1;
this.cols = cols;
float start = Time.realtimeSinceStartup;
model = trainModel(features, labels, weights, rows, cols, maxClasses, probability, C);
Debug.Log("Training took: " + (Time.realtimeSinceStartup - start).ToString());
haveModel = true;
return true;
}
// This function takes the same arguments as train, except for cols, which is not necessary. The diagonal are correctly classified entries. The first index is labels, the second index is classifications.
public int[,] ConfusionMatrix(float[] features, float[] labels, int rows, out float accuracy) {
accuracy = 0f;
if (!haveModel)
return null;
if (rows < 1 || features.Length < rows * cols || labels.Length < rows)
return null;
for (int i = 0; i < rows; i++) {
labels[i] = (float)Math.Round(labels[i]);
if (labels[i] < 0 || labels[i] >= maxClasses)
return null;
}
int[,] confusionMatrix = new int[maxClasses, maxClasses];
float[] predictions = new float[rows];
double[] probabilities = new double[rows * maxClasses];
predict(model, features, predictions, probabilities, rows);
for (int i = 0; i < rows; i++) {
predictions[i] = (float)Math.Round(predictions[i]);
if (predictions[i] >= 0 && predictions[i] < maxClasses) {
confusionMatrix[(int)labels[i], (int)predictions[i]]++;
if ((int)labels[i] == (int)predictions[i])
accuracy++;
}
}
accuracy /= (float)rows;
return confusionMatrix;
}
static public string FormatMatrix(int[,] matrix) {
return FormatMatrix(matrix, null);
}
static public string FormatMatrix(int[,] matrix, string[] labels) {
StringBuilder sb = new StringBuilder();
int rowLength = matrix.GetLength(0);
int colLength = matrix.GetLength(1);
int maxLableLen = 5;
if (labels != null) {
if (labels.Length != rowLength || labels.Length != colLength)
labels = null;
else {
foreach (string label in labels)
if (label.Length > maxLableLen)
maxLableLen = label.Length;
sb.Append("pred:".PadLeft(maxLableLen));
sb.Append(" ");
foreach (string label in labels) {
sb.Append(label.PadLeft(maxLableLen));
sb.Append(" ");
}
sb.Append(Environment.NewLine);
}
}
for (int r = 0; r < rowLength; r++) {
if (labels != null) {
sb.Append(labels[r].PadLeft(maxLableLen));
sb.Append(" ");
}
for (int c = 0; c < colLength; c++) {
string n = matrix[r,c].ToString();
sb.Append(n.PadLeft(maxLableLen));
sb.Append(" ");
}
sb.Append(Environment.NewLine);
}
return sb.ToString();
}
// features is a rows*cols long float array with rows written one after another.
public float[] Predict(float[] features, out double[] probabilities, int rows) {
probabilities = null;
if (!haveModel)
return null;
if (rows < 1 || features.Length != rows * cols)
return null;
float[] predictions = new float[rows];
probabilities = new double[rows * maxClasses];
predict(model, features, predictions, probabilities, rows);
return predictions;
}
public float[] Predict(float[] features, int rows) {
double[] probabilities;
return Predict(features, out probabilities, rows);
}
public bool Ready() {
return haveModel;
}
public SVMModel() {
}
public SVMModel(byte[] modelBytes) {
LoadModel(modelBytes);
}
~SVMModel() {
DestroyModel();
}
}
}

View file

@ -1,11 +0,0 @@
fileFormatVersion: 2
guid: a95b57bbe200b004dab9b21f0854082e
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

Binary file not shown.

View file

@ -1,92 +0,0 @@
fileFormatVersion: 2
guid: 930906668f1b67a42b2bb844bd098a26
PluginImporter:
externalObjects: {}
serializedVersion: 2
iconMap: {}
executionOrder: {}
isPreloaded: 0
isOverridable: 0
platformData:
- first:
'': Any
second:
enabled: 0
settings:
Exclude Editor: 0
Exclude Linux: 0
Exclude Linux64: 0
Exclude LinuxUniversal: 0
Exclude OSXUniversal: 0
Exclude WebGL: 0
Exclude Win: 1
Exclude Win64: 0
- first:
Any:
second:
enabled: 1
settings: {}
- first:
Editor: Editor
second:
enabled: 1
settings:
CPU: AnyCPU
DefaultValueInitialized: true
OS: AnyOS
- first:
Facebook: Win
second:
enabled: 0
settings:
CPU: None
- first:
Facebook: Win64
second:
enabled: 0
settings:
CPU: AnyCPU
- first:
Standalone: Linux
second:
enabled: 1
settings:
CPU: x86
- first:
Standalone: Linux64
second:
enabled: 1
settings:
CPU: x86_64
- first:
Standalone: LinuxUniversal
second:
enabled: 1
settings:
CPU: AnyCPU
- first:
Standalone: OSXUniversal
second:
enabled: 1
settings:
CPU: AnyCPU
- first:
Standalone: Win
second:
enabled: 0
settings:
CPU: None
- first:
Standalone: Win64
second:
enabled: 1
settings:
CPU: AnyCPU
- first:
WebGL: WebGL
second:
enabled: 1
settings: {}
userData:
assetBundleName:
assetBundleVariant:

View file

@ -1,71 +0,0 @@
using System;
using System.Collections.Generic;
using System.IO;
using System.IO.Compression;
using System.Runtime.InteropServices;
using System.Runtime.Serialization;
using System.Runtime.Serialization.Formatters.Binary;
using System.Text;
using OpenSee;
using UnityEngine;
public class ThunderSVMModel : SVMModel {
#region DllImport
[DllImport("ThunderSVMWrapper", CallingConvention = CallingConvention.Cdecl, EntryPoint = "trainModel")]
private static extern System.IntPtr trainModelDll(float[] features, float[] labels, float[] weights, int rows, int cols, int classes, int probability, float C);
protected override System.IntPtr trainModel(float[] features, float[] labels, float[] weights, int rows, int cols, int classes, int probability, float C) {
Debug.Log("Training ThunderSVM");
return trainModelDll(features, labels, weights, rows, cols, classes, probability, C);
}
[DllImport("ThunderSVMWrapper", CallingConvention = CallingConvention.Cdecl, EntryPoint = "predict")]
private static extern void predictDll(System.IntPtr model, float[] features, [Out] float[] predictions, [Out] double[] probabilities, int rows);
protected override void predict(System.IntPtr model, float[] features, [Out] float[] predictions, [Out] double[] probabilities, int rows) {
predictDll(model, features, predictions, probabilities, rows);
}
[DllImport("ThunderSVMWrapper", CallingConvention = CallingConvention.Cdecl, CharSet = CharSet.Ansi, EntryPoint = "loadModel")]
private static extern System.IntPtr loadModelDll([MarshalAs(UnmanagedType.LPStr)]string filename, int cols, int classes, double[] means, double[] sdevs);
protected override System.IntPtr loadModel([MarshalAs(UnmanagedType.LPStr)]string filename, int cols, int classes, double[] means, double[] sdevs) {
return loadModelDll(filename, cols, classes, means, sdevs);
}
[DllImport("ThunderSVMWrapper", CallingConvention = CallingConvention.Cdecl, CharSet = CharSet.Ansi, EntryPoint = "loadModelString")]
private static extern System.IntPtr loadModelStringDll([MarshalAs(UnmanagedType.LPStr)]string modelString, int cols, int classes, double[] means, double[] sdevs);
protected override System.IntPtr loadModelString([MarshalAs(UnmanagedType.LPStr)]string modelString, int cols, int classes, double[] means, double[] sdevs) {
Debug.Log("Loading ThunderSVM");
return loadModelStringDll(modelString, cols, classes, means, sdevs);
}
[DllImport("ThunderSVMWrapper", CallingConvention = CallingConvention.Cdecl, EntryPoint = "getScales")]
private static extern void getScalesDll(System.IntPtr model, [Out] double[] means, [Out] double[] sdevs);
protected override void getScales(System.IntPtr model, [Out] double[] means, [Out] double[] sdevs) {
getScalesDll(model, means, sdevs);
}
[DllImport("ThunderSVMWrapper", CallingConvention = CallingConvention.Cdecl, CharSet = CharSet.Ansi, EntryPoint = "saveModel")]
private static extern int saveModelDll(System.IntPtr model, [MarshalAs(UnmanagedType.LPStr)]string filename);
protected override int saveModel(System.IntPtr model, [MarshalAs(UnmanagedType.LPStr)]string filename) {
return saveModelDll(model, filename);
}
[DllImport("ThunderSVMWrapper", CallingConvention = CallingConvention.Cdecl, CharSet = CharSet.Ansi, EntryPoint = "saveModelString")]
private static extern string saveModelStringDll(System.IntPtr model);
protected override string saveModelString(System.IntPtr model) {
return saveModelStringDll(model);
}
[DllImport("ThunderSVMWrapper", CallingConvention = CallingConvention.Cdecl, EntryPoint = "destroyModel")]
private static extern void destroyModelDll(System.IntPtr model);
protected override void destroyModel(System.IntPtr model) {
destroyModelDll(model);
}
#endregion
public ThunderSVMModel() {
}
public ThunderSVMModel(byte[] modelBytes) {
LoadModel(modelBytes);
}
}

Binary file not shown.

View file

@ -1,63 +0,0 @@
fileFormatVersion: 2
guid: 9c58dd9d1f0cf3140bd004d536712abb
PluginImporter:
externalObjects: {}
serializedVersion: 2
iconMap: {}
executionOrder: {}
defineConstraints: []
isPreloaded: 0
isOverridable: 0
isExplicitlyReferenced: 0
validateReferences: 1
platformData:
- first:
: Any
second:
enabled: 0
settings:
Exclude Editor: 0
Exclude Linux64: 0
Exclude OSXUniversal: 0
Exclude Win: 1
Exclude Win64: 0
- first:
Any:
second:
enabled: 1
settings: {}
- first:
Editor: Editor
second:
enabled: 1
settings:
CPU: AnyCPU
DefaultValueInitialized: true
OS: AnyOS
- first:
Standalone: Linux64
second:
enabled: 1
settings:
CPU: x86_64
- first:
Standalone: OSXUniversal
second:
enabled: 1
settings:
CPU: x86_64
- first:
Standalone: Win
second:
enabled: 0
settings:
CPU: None
- first:
Standalone: Win64
second:
enabled: 1
settings:
CPU: x86_64
userData:
assetBundleName:
assetBundleVariant:

Binary file not shown.

View file

@ -1,27 +0,0 @@
fileFormatVersion: 2
guid: dd0c04eb3445c3048bfaa964c6bcb16f
PluginImporter:
externalObjects: {}
serializedVersion: 2
iconMap: {}
executionOrder: {}
defineConstraints: []
isPreloaded: 0
isOverridable: 0
isExplicitlyReferenced: 0
validateReferences: 1
platformData:
- first:
Any:
second:
enabled: 1
settings: {}
- first:
Editor: Editor
second:
enabled: 0
settings:
DefaultValueInitialized: true
userData:
assetBundleName:
assetBundleVariant:

Binary file not shown.

View file

@ -1,27 +0,0 @@
fileFormatVersion: 2
guid: a504a0f747083b54c99d6e91731ccecc
PluginImporter:
externalObjects: {}
serializedVersion: 2
iconMap: {}
executionOrder: {}
defineConstraints: []
isPreloaded: 0
isOverridable: 0
isExplicitlyReferenced: 0
validateReferences: 1
platformData:
- first:
Any:
second:
enabled: 1
settings: {}
- first:
Editor: Editor
second:
enabled: 0
settings:
DefaultValueInitialized: true
userData:
assetBundleName:
assetBundleVariant:

Binary file not shown.

View file

@ -1,27 +0,0 @@
fileFormatVersion: 2
guid: dd0c04eb3445c3048bfaa964c6bcb16f
PluginImporter:
externalObjects: {}
serializedVersion: 2
iconMap: {}
executionOrder: {}
defineConstraints: []
isPreloaded: 0
isOverridable: 0
isExplicitlyReferenced: 0
validateReferences: 1
platformData:
- first:
Any:
second:
enabled: 1
settings: {}
- first:
Editor: Editor
second:
enabled: 0
settings:
DefaultValueInitialized: true
userData:
assetBundleName:
assetBundleVariant:

Binary file not shown.

View file

@ -1,27 +0,0 @@
fileFormatVersion: 2
guid: a504a0f747083b54c99d6e91731ccecc
PluginImporter:
externalObjects: {}
serializedVersion: 2
iconMap: {}
executionOrder: {}
defineConstraints: []
isPreloaded: 0
isOverridable: 0
isExplicitlyReferenced: 0
validateReferences: 1
platformData:
- first:
Any:
second:
enabled: 1
settings: {}
- first:
Editor: Editor
second:
enabled: 0
settings:
DefaultValueInitialized: true
userData:
assetBundleName:
assetBundleVariant:

Binary file not shown.

View file

@ -1,27 +0,0 @@
fileFormatVersion: 2
guid: 51dc8f0c65df30d4daa188cdfd1dd220
PluginImporter:
externalObjects: {}
serializedVersion: 2
iconMap: {}
executionOrder: {}
defineConstraints: []
isPreloaded: 0
isOverridable: 0
isExplicitlyReferenced: 0
validateReferences: 1
platformData:
- first:
Any:
second:
enabled: 1
settings: {}
- first:
Editor: Editor
second:
enabled: 0
settings:
DefaultValueInitialized: true
userData:
assetBundleName:
assetBundleVariant:

Binary file not shown.

View file

@ -1,27 +0,0 @@
fileFormatVersion: 2
guid: fcfc753ca92169e48aa69c1ecc1b0d64
PluginImporter:
externalObjects: {}
serializedVersion: 2
iconMap: {}
executionOrder: {}
defineConstraints: []
isPreloaded: 0
isOverridable: 0
isExplicitlyReferenced: 0
validateReferences: 1
platformData:
- first:
Any:
second:
enabled: 1
settings: {}
- first:
Editor: Editor
second:
enabled: 0
settings:
DefaultValueInitialized: true
userData:
assetBundleName:
assetBundleVariant:

Binary file not shown.

View file

@ -1,63 +0,0 @@
fileFormatVersion: 2
guid: e549e6cbc6a547748abc7f1b05bfa7b4
PluginImporter:
externalObjects: {}
serializedVersion: 2
iconMap: {}
executionOrder: {}
defineConstraints: []
isPreloaded: 0
isOverridable: 0
isExplicitlyReferenced: 0
validateReferences: 1
platformData:
- first:
: Any
second:
enabled: 0
settings:
Exclude Editor: 0
Exclude Linux64: 0
Exclude OSXUniversal: 0
Exclude Win: 1
Exclude Win64: 0
- first:
Any:
second:
enabled: 1
settings: {}
- first:
Editor: Editor
second:
enabled: 1
settings:
CPU: AnyCPU
DefaultValueInitialized: true
OS: AnyOS
- first:
Standalone: Linux64
second:
enabled: 1
settings:
CPU: x86_64
- first:
Standalone: OSXUniversal
second:
enabled: 1
settings:
CPU: x86_64
- first:
Standalone: Win
second:
enabled: 0
settings:
CPU: None
- first:
Standalone: Win64
second:
enabled: 1
settings:
CPU: x86_64
userData:
assetBundleName:
assetBundleVariant:

View file

@ -1,31 +0,0 @@
echo "Started"
:: A venv is used so it's easy to add the onnxruntime dll to the binary
echo "Creating venv"
python -m venv venv
echo "Activating venv"
call venv\Scripts\activate.bat
echo "Installing dependencies"
pip install wheel
pip install onnxruntime opencv-python==4.5.4.60 pillow numpy==1.23.0 pyinstaller
echo "Running pyinstaller"
pyinstaller facetracker.py --clean ^
--onedir ^
--add-binary dshowcapture/*.dll;. ^
--add-binary escapi/*.dll;. ^
--add-binary venv/lib/site-packages/onnxruntime/capi/*.dll;onnxruntime\capi ^
--add-binary msvcp140.dll;. ^
--add-binary vcomp140.dll;. ^
--add-binary concrt140.dll;. ^
--add-binary vccorlib140.dll;. ^
--add-binary run.bat;.
echo "Deleting opencv dll"
del dist\facetracker\cv2\opencv_videoio_*
echo "Finished"

View file

@ -1,32 +0,0 @@
#!/bin/bash
set -e
PYTHON_BINARY=$(which python3)
if [[ -z "$PYTHON_BINARY" ]]; then
echo "python3 not found. Searching for python instead."
PYTHON_BINARY=$(which python)
if [[ -z "$PYTHON_BINARY" ]]; then
echo "Python 3 must be available on your path. Exiting."
exit 1
fi
fi
echo "Creating venv"
"$PYTHON_BINARY" -m venv venv
source venv/bin/activate
echo "Installing packages"
pip install wheel # Make sure this is installed beforehand
pip install onnxruntime opencv-python==4.5.4.60 pillow numpy==1.23.0 pyinstaller
echo "Creating binary"
pyinstaller --onedir --clean facetracker.py \
--add-binary venv/lib/python3.*/site-packages/onnxruntime/capi/*.so:onnxruntime/capi
echo "Files should be available in the dist/ folder"
echo "Done!"

16
run.bat
View file

@ -1,16 +0,0 @@
%ECHO OFF
facetracker -l 1
echo Make sure that nothing is accessing your camera before you proceed.
set /p cameraNum=Select your camera from the list above and enter the corresponding number:
facetracker -a %cameraNum%
set /p dcaps=Select your camera mode or -1 for default settings:
set /p fps=Select the FPS:
facetracker -c %cameraNum% -F %fps% -D %dcaps% -v 3 -P 1 --discard-after 0 --scan-every 0 --no-3d-adapt 1 --max-feature-updates 900
pause