SLAMflex SE  0.1.0
SLAMflex provides detection and tracking of dominant planes for smartphone devices. This plane can then be used to show AR content relative to the plane orientation. The detection of plane is performed in the field of view of the smartphone camera. In subsequent frames it is tracked. The interface returns the plane position and orientation.
SlamFlexAdapter.cs
Go to the documentation of this file.
1 #define TRANSLATION
2 //#define GYRO
3 //#define GYRO_WITH_TRANSLATION
4 //#define NO_GYRO
5 //#define NO_GYRO_WITH_ROT
6 //#define CORNER_TEX
7 
8 using UnityEngine;
9 using System;
10 using System.Collections;
11 using System.IO;
12 using System.Collections.Generic;
13 using System.Runtime.InteropServices;
14 
15 
19 public class SlamFlexAdapter : MonoBehaviour
20 {
21  private GameObject _bg_panel;
22  private GameObject _bg_panel_corner_points;
23 
24  protected Color32[] _buf;
25  private WebCamTexture w;
26  private GCHandle m_PixelsHandle;
27 
28 
29  public GameObject _ground_plane;
30  private int screen_width = 640;
31  private int screen_height = 480;
32  private float aspect = 1.38188006064344f;
33  private bool autoend = false;
34  private Vector3 orginalPlainePosition;
35 
36  private bool textureOk = false;
37  private bool planeRotationFound = false;
38  private Vector3 planeRotation, planeTranslation = Vector3.zero;
39  private string userMessagesTextInstr = "Translate the camera slowly sideways";
40  private string userMessagesText = "";
41  private string userMessagesText1 = "";
42 
43  private Texture2D cornerPoints;
44  private GyroCam gyroCam;
45 
46  private string logFileData = "";
47  public bool enable_logging = false;
48 
50 
51 
56 
60  void Awake()
61  {
62  //setup unity3D webcam
63  WebCamDevice[] devices= WebCamTexture.devices;
64  if (devices.Length > 0)
65  {
66  w=new WebCamTexture(screen_width, screen_height, 15);
67 
68  //setup background
69  camera.aspect = aspect;
70  this._bg_panel=GameObject.Find("Plane");
71  this._bg_panel.renderer.material.mainTexture=w;
72  w.Play();
73 
74 #if CORNER_TEX
75  //setup texture for rendering corner points on separate texture
76  this._bg_panel_corner_points = GameObject.Find ("TrackingCornerPoints");
77 
78  cornerPoints = new Texture2D(screen_width, screen_height);
79  Color[] data = new Color[screen_width*screen_height];
80  Color c = new Color(255, 255, 255, 0);
81  for (int i = 0; i<data.Length; i++)
82  {
83  data[i] = c;
84  }
85 
86  cornerPoints.SetPixels(data);
87  cornerPoints.Apply();
88 
89  this._bg_panel_corner_points.renderer.material.mainTexture = cornerPoints;
90 #endif
91 
92  }
93  else
94  {
95  Debug.LogError("No Webcam.");
96  }
97 
98 #if GYRO || GYRO_WITH_TRANSLATION
99  gyroCam = transform.GetComponent<GyroCam>();
100  gyroCam.enabled = true;
101 #endif
102  }
103 
104 
108  void Start ()
109  {
110  //Setup logger
111  //load previous settings
112  if (enable_logging)
113  {
114  StreamReader fileReader = null;
115  string logFile = Application.persistentDataPath + "/log.txt";
116 
117 
118  if (File.Exists(logFile))
119  {
120  fileReader = new StreamReader(logFile);
121 
122  logFileData = fileReader.ReadToEnd();
123  fileReader.Close();
124  }
125  }
126 
127  //first few frames is not valid, have to wait for valid frame
128  StartCoroutine (CheckTheValidityOfTexture());
129 
130  //implement SlamFlex hooks
135 
136  //initialize SLAMflex plugin
138 
139 
140  }
141 
142 
143 
144  void Update ()
145  {
146  //we have valid texture as input, each update send one frame to plugin
147  if (textureOk && !planeRotationFound)
148  {
149  this._buf = (Color32[])this.w.GetPixels32 ();
150  m_PixelsHandle = GCHandle.Alloc (this._buf, GCHandleType.Pinned);
151  current_State = SlamFlexWrapper.SetNewFrame (m_PixelsHandle.AddrOfPinnedObject (), this.w.width, this.w.height);
152  m_PixelsHandle.Free ();
153  }
154  }
155 
156 
161  private IEnumerator CheckTheValidityOfTexture()
162  {
163  while (true)
164  {
165  if (w.height < 100)
166  {
167  Debug.Log("WebTexture not initialized");
168  yield return null;
169  }
170  else
171  {
172  textureOk = true;
173  break;
174  }
175  }
176  }
177 
178 
179 
184  private void ReciveStringFromPlugin(string message)
185  {
186 
187  if(message == "Tracker_ResetMM")
188  {
189  StopAllCoroutines();
190  StartCoroutine(AutoEnd());
191  }
192  else if(message.StartsWith("Corners"))
193  {
194  userMessagesText = message;
195  }
196  else
197  {
198  Debug.Log("Message from plugin: " + message);
199  }
200  }
201 
202 
209  private void ReciveArrayPointsFromPlugin(IntPtr pointer, int size )
210  {
211  int [] corners = new int[size];
212  Marshal.Copy(pointer, corners, 0, size);
213 
214  SetCornerTexturePoints(corners);
215  }
216 
217 
222  private void SetCornerTexturePoints(int[] corners)
223  {
224 
225  Color[] data = new Color[screen_width*screen_height];
226  Color c = new Color(255, 255, 255, 0);
227  for (int i = 0; i<data.Length; i++)
228  {
229  data[i] = c;
230  }
231 
232  for(int i = 0; i < corners.Length; i++)
233  {
234  data[corners[i]] = Color.red;
235  }
236 
237  cornerPoints.SetPixels(data);
238  cornerPoints.Apply();
239  }
240 
250  private void RecivePoseFromPlugin (float r1, float r2, float r3, double t1, double t2, double t3)
251  {
252 
253  planeRotation.x = r1;
254  planeRotation.y = r2;
255  planeRotation.z = r3;
256 
257  planeTranslation.x = (float)t2;
258  planeTranslation.y = (float)t1;
259 // planeTranslation.z = (float)t3; for later
260 
261 
262  if(autoend)
263  {
264  //Debug.Log("Pose: "+r1.ToString()+" "+r2.ToString()+" "+r3.ToString()+" "+t1.ToString()+" "+t2.ToString()+" "+t3.ToString());
265  this._ground_plane.SetActive (true);
266  this._ground_plane.transform.eulerAngles = planeRotation + this._bg_panel.transform.eulerAngles;
267 
268 
269 
270 #if GYRO || GYRO_WITH_TRANSLATION
271 
272  Vector3 planePosition = this._bg_panel.transform.position;
273 
274  if (planePosition.x > 0)
275  planePosition.x -= 1000f;
276  else
277  planePosition.x += 1000f;
278 
279  if (planePosition.y > 0)
280  planePosition.y -= 1000f;
281  else
282  planePosition.y += 1000f;
283 
284  if (planePosition.z > 0)
285  planePosition.z -= 1000f;
286  else
287  planePosition.z += 1000f;
288 #endif
289 
290 
291  Debug.Log ("Unity_ Plane found");
292  // SlamFlexWrapper.Stop ();
293 
294  StopAllCoroutines();
295 
296 #if GYRO || GYRO_WITH_TRANSLATION
297  this._ground_plane.transform.position = planePosition;
298  orginalPlainePosition = planePosition;
299 #else
300 
301  orginalPlainePosition = this._ground_plane.transform.position;
302 #endif
303 // planeRotationFound = true;
304  }
305  autoend = false;
306 
307 #if GYRO_WITH_TRANSLATION
308  planeTranslation.x *= 4140f;
309  planeTranslation.y *= -3000f;
310  if(!gyroCam.GyroAngleDetected)
311  {
312  this._ground_plane.transform.position = orginalPlainePosition + planeTranslation;
313  }
314 #endif
315 
316 #if TRANSLATION
317  float offset = 1;
318  if((float)t3 < 1.75f)
319  {
320  offset = 2;
321  }
322  planeTranslation.x *= 4140f * offset;
323  planeTranslation.y *= -3000f * offset;
324  this._ground_plane.transform.position = orginalPlainePosition + planeTranslation;
325 
326 #endif
327 
328 #if NO_GYRO_WITH_ROT
329  this._ground_plane.transform.eulerAngles = planeRotation + this._bg_panel.transform.eulerAngles;
330 #endif
331  //userMessagesText1 = "t1: " + t1.ToString()+" t2: " + t2.ToString() + "\nt3: " + t3.ToString();
332 
333 
334  }
335 
336 
341  private IEnumerator AutoEnd()
342  {
343  autoend = true;
344  while (autoend)
345  {
346  yield return new WaitForSeconds(1f);
348  Debug.Log ("AutoEnd finished");
349  }
350 
351  }
352 
353 
358  private void Logging (string message)
359  {
360  if(enable_logging)
361  {
362  logFileData += message;
363  }
364  }
365 
366 
367 
372  public void UserMessages (string message)
373  {
374  userMessagesText = message;
375  }
376 
377 
381  void OnGUI()
382  {
383  if( GUI.Button(new Rect(Screen.width*0.9f, 0, Screen.width*0.1f, Screen.width*0.1f), "Exit"))
384  {
385  Debug.Log("Unity_ App exits");
386  Application.Quit();
387  }
388 
389  if( GUI.Button(new Rect(Screen.width - (Screen.width*0.3f),(Screen.height-(Screen.width*0.3f)),Screen.width*0.3f,Screen.width*0.3f), "Start Plane Detection"))
390  {
391  Debug.Log("Unity_ Tracking started");
392  planeRotationFound = false;
393  this._ground_plane.SetActive(false);
394  Camera.main.transform.eulerAngles = Vector3.zero;
396  StartCoroutine(AutoEnd());
397  }
398 
399  if( GUI.Button(new Rect(0,(Screen.height-(Screen.width*0.3f)),Screen.width*0.3f,Screen.width*0.3f), "Stop Plane Detection"))
400  {
401  Debug.Log("Unity_ Tracking stoped");
402  planeRotationFound = false;
403  this._ground_plane.transform.position = orginalPlainePosition;
404  this._ground_plane.SetActive(false);
405  Camera.main.transform.eulerAngles = Vector3.zero;
407  }
408 
409  string text = "";
410  if(autoend)
411  {
412  text = "\nMessages: "+userMessagesTextInstr+"\n"+userMessagesText+"\n" + userMessagesText1;
413  }
414  else
415  {
416  text = "\nMessages: "+userMessagesText+"\n" + userMessagesText1;
417  }
418 
419 
420  GUI.Label (new Rect (0f, 0f, 200, 200), "Current tracking state: " + current_State.ToString());
421  GUI.Label (new Rect (0, 100, 400, 400), text);
422  }
423 
424 
429  {
430  if(enable_logging)
431  {
432  string logFile = Application.persistentDataPath + "/log.txt";
433  var sr = File.CreateText(logFile);
434  sr.WriteLine (logFileData);
435  sr.Flush();
436  sr.Close();
437  }
438  }
439 
440 
441 
442  private List<Vector2> ParseCoordinates(string array)
443  {
444 
445  List<Vector2> ret = new List<Vector2>();
446 
447  string[] coordinates = array.Split(new char[]{';'});
448 
449  foreach(string s in coordinates)
450  {
451  string[] coor = s.Split(new char[]{','});
452  if(coor.Length == 2)
453  {
454  int x = Convert.ToInt32(coor[0]);
455  int y = Convert.ToInt32(coor[1]);
456  if(x<screen_width+1 && x>0 && y<screen_height+1 && y>0)
457  {
458  ret.Add(new Vector2(x, y));
459  }
460 
461  }
462  }
463 
464  return ret;
465  }
466 
467 }
void Logging(string message)
Function for logging data on Application.persistentDataPath + "/log.txt"
string userMessagesText1
Vector3 orginalPlainePosition
SlamFlexWrapper.SendLogDelegate mSendLogDelegate
SlamFlexWrapper.SendArrayPointsDelegate mSendArrayPointsDelegate
List< Vector2 > ParseCoordinates(string array)
delegate void SendLogDelegate(string text)
Definition of delegate used from plugin to send log to Unity3D
delegate void SendPoseDelegate(float r1, float r2, float r3, double t1, double t2, double t3)
Definition of delegate used from plugin to send pose to Unity3D
delegate void SendStringDelegate(string s)
Definition of delegate used from plugin to send string to Unity3D
SlamFlexWrapper.DetectionState current_State
Vector3 planeTranslation
void Awake()
Function for unity3D code initialization
SlamFlexWrapper.SendStringDelegate mSendStringDelegate
IEnumerator AutoEnd()
Function for starting SLAMflex until enough points for generation of map is found ...
GameObject _bg_panel
SlamFlexWrapper.SendPoseDelegate mSendPoseDelegate
string userMessagesTextInstr
void SetCornerTexturePoints(int[] corners)
Function for drawing corners on separate texture
Texture2D cornerPoints
void UserMessages(string message)
Function for presentation of user messages on GUI
DetectionState
Enum for state of SLAM detection process
void OnGUI()
Function for unity3D GUI
WebCamTexture w
GameObject _bg_panel_corner_points
Gyroscope-controlled camera for iPhone Android revised 2.26.12
Definition: GyroCam.cs:23
int transform(const BasicImage< S > &in, BasicImage< T > &out, const TooN::Matrix< 2 > &M, const TooN::Vector< 2 > &inOrig, const TooN::Vector< 2 > &outOrig, const T defaultValue=T())
Definition: vision.h:304
IEnumerator CheckTheValidityOfTexture()
Function for yield of unity3D update until webtexture is initialized
void ReciveArrayPointsFromPlugin(IntPtr pointer, int size)
Function for communication between plugin and Unity, plugin sends array of points (corners) to Unity ...
void OnApplicationQuit()
Function for unity3D OnApplicationQuit event
GCHandle m_PixelsHandle
SlamFlexWrapper implements interface to native implementation and public interface for use inside C# ...
static void StartSlam(SendStringDelegate ssd, SendPoseDelegate spd, SendLogDelegate sLogd, SendArrayPointsDelegate arrayPoints)
Starts SLAM detection
delegate void SendArrayPointsDelegate(IntPtr pointer, int size)
Definition of delegate used from plugin to send array of points to Unity3D
void ReciveStringFromPlugin(string message)
Function for communication between plugin and Unity, plugin sends plain string
static DetectionState SetNewFrame(IntPtr pointer, int width, int height)
Send image data to plugin for SLAM detection
GameObject _ground_plane
static void StopSlam()
Stops SLAM detection
static void StartPlaneDetection()
Initiate SLAM detection
SlamFlexAdapter is example how setup SLAMflex library, setup image data from webtexture and every fra...
void RecivePoseFromPlugin(float r1, float r2, float r3, double t1, double t2, double t3)
Function for reciving pose from plugin, rotation in euler angles and translation
void Start()
Function for unity3D code initialization
Definition: Bundle.h:40