Funcionamento do DataManager
Input
O módulo DataManager é responsável por manipular os dados, sejam os dados capturados dos dispositivos, persistindo os mesmos em disco, importando os dados de um arquivo externo para a aplicação, ou simplesmente usando os dados capturados diretamente na aplicação.

O framework utiliza o mesmo padrão de 20 articulações do Kinect, entretanto, o framework é flexível e permite utilizar outros padrões, como o padrão de rastreamento corporal e de mão do Mediapipe.

O rastreamento de mão do Mediapipe é interessante porque captura 21 partes, conseguindo capturar com precisão a movimentação da mão.

Essa flexibilidade é importante caso queira fazer a captura de outras partes não previstas com as 20 articulações padrões do framework, importante notar que o mapeamento também é diferente, ou seja, para uma mesma parte do corpo pode ter outra numeração, assim, é importante o desenvolvedor escolher adequadamente os padrões.
using UnityEngine;
public class Poses : MonoBehaviour
{
//Mediapipe Standard
public enum PoseMediapipe
{
NOSE = 0,
L_EYE_INNER = 1,
L_EYE = 2,
L_EYE_OUTER = 3,
R_EYE_INNER = 4,
R_EYE = 5,
R_EYE_OUTER = 6,
L_EAR = 7,
R_EAR = 8,
L_MOUTH = 9,
R_MOUTH = 10,
L_SHOULDER = 12,
R_SHOULDER = 11,
L_ELBOW = 14,
R_ELBOW = 13,
L_WRIST = 16,
R_WRIST = 15,
L_PINKY = 17,
R_PINKY = 18,
L_INDEX = 19,
R_INDEX = 20,
L_THUMB = 21,
R_THUMB = 22,
L_HIP = 24,
R_HIP = 23,
L_KNEE = 26,
R_KNEE = 25,
L_ANKLE = 28,
R_ANKLE = 27,
L_HEEL = 30,
R_HEEL = 29,
L_FINDEX = 32,
R_FINDEX = 31
}
//Mediapipe Only
public enum PoseHand
{
WRIST = 0,
THUMB_CMC = 1,
THUMB_MCP = 2,
THUMB_IP = 3,
THUMP_TIP = 4,
INDEX_FINGER_MCP = 5,
INDEX_FINGER_PIP = 6,
INDEX_FINGER_DIP = 7,
INDEX_FINGER_TIP = 8,
MIDDLE_FINGER_MCP = 9,
MIDDLE_FINGER_PIP = 10,
MIDDLE_FINGER_DIP = 11,
MIDDLE_FINGER_TIP = 12,
RING_FINGER_MCP = 13,
RING_FINGER_PIP = 14,
RING_FINGER_DIP = 15,
RING_FINGER_TIP = 16,
PINKY_MCP = 17,
PINKY_PIP = 18,
PINKY_DIP = 19,
PINKY_TIP = 20
}
// BTS Standard = Kinect - Mediapipe different mapping
public enum PoseBts
{
HipCenter = 1,
Spine = 2,
ShoulderCenter = 3,
Head = 4,
LeftShoulder = 5,
LeftElbow = 6,
LeftWrist = 7,
LeftHand = 8,
RightShoulder = 9,
RightElbow = 10,
RightWrist = 11,
RightHand = 12,
LeftHip = 13,
LeftKnee = 14,
LeftAnkle = 15,
LeftFoot = 16,
RightHip = 17,
RightKnee = 18,
RightAnkle = 19,
RightFoot = 20
}
}
No DataManager foi utilizado o padrão de projeto Repository que é usado para criar uma camada de abstração entre a camada de acesso a dados e a camada de negócios de um aplicativo. Tem-se como vantagem da utilização desse padrão: testes facilitados; gerenciamento mais simples da aplicação com o armazenamento de dados e permite facilmente trocar por vários data stores sem alterar a API.
A interface IRepository é uma interface genérica que define alguns métodos, como Insert responsável por inserir no SGBD, Remove para deletar, List para pesquisar na lista e o ApiRequest para trabalhar com API. Note que em vez da entidade Poses, estamos usando T em todos os lugares de forma genérica.
using System.Collections.Generic;
using System.Linq;
using System;
public interface IRepository<T> where T : class
{
void Insert(T obj);
void Remove(T obj);
List<T> List(Func<T, bool> expression = null);
void ApiRequest(String con);
}
O Repository é uma classe genérica e implementa a interface IRepository. Note que o repositório genérico não possui funções especificas para funcionar com as articulações.
public class Repository<T> : IRepository<T> where T : class
{
List<T> lt;
public Repository()
{
lt = new List<T>();
}
public void Insert(T obj)
{
lt.Add(obj);
}
public void Remove(T obj)
{
lt.Remove(obj);
}
public List<T> List(Func<T, bool> expression = null)
{
return expression != null ? lt.Where(expression).ToList() : lt;
}
public void ApiRequest(String con)
{
// Waiting for the new rebase to be ready
}
}
A interface IPoseRepository é uma interface específica que define alguns métodos próprios para trabalhar com as articulações, como GetPose, responsável por retornar uma articulação específica; GetHandPose que retorna as articulações da mão; PoseFound que verifica se algum rastreamento já foi feito; SaveToTxt que persiste em disco em um arquivo txt; SaveToXml, persiste em disco em um arquivo XML (Extensible Markup Language). O LoadTxt e LoadXml carregam as articulações de um arquivo de texto e XML respectivamente.
using System;
using UnityEngine;
using System.IO;
using System.Xml;
public interface IPoseRepository : IRepository<Poses>
{
Vector3 GetPose(Poses.PoseBts obj);
Vector2 GetPoseHand(Poses.PoseHand obj);
bool PoseFound();
void SaveToTxt(String data, String fileName);
void SaveToXml(String data, String fileName);
void LoadTxt(String fileName);
void LoadXml(String fileName);
}
O PoseRepository é um repositório específico que implementa a interface IPoseRepository, com métodos próprios para lidar com articulações, ao contrário do Repository, que é um repositório genérico. O PoseRepository faz uso do KinectManager, classe desenvolvida pela Microsoft para utilizar os recursos do Kinect, e também utiliza o MediapipeManager, análogo a classe anterior porém foi criada para o framework, pois não havia algo semelhante para explorar os recursos do Mediapipe. Como foi adotado o padrão de articulações do framework quando utilizado o Mediapipe precisamos converter um padrão para o outro, assim, foi utilizado o método ConvertKinectMapToMediaPipe, dessa forma fica transparante para o desenvolvedor independente do dispositivo óptico que ele esteja usando.
public class PoseRepository : Repository<Poses>, IPoseRepository
{
// Get pose from optical device
public Vector3 GetPose(Poses.PoseBts obj)
{
if (InputSelector.inputFactory.GetInput("Mediapipe")
.IsReady())
{
return MediapipeManager.
GetPoint(MediapipeManager.
ConvertKinectMapToMediaPipe(obj));
}
else if (InputSelector.inputFactory.GetInput("Kinect")
.IsReady())
{
return KinectManager.
GetRawSkeletonJointPos(KinectManager.
GetPlayer1ID(), (int)obj);
}
else
{
return Vector3.zero;
}
}
//Mediapipe only
public Vector2 GetPoseHand(Poses.PoseHand obj)
{
if (MediapipeManager.VectorHand.Count > 0)
{
return new Vector2(
MediapipeManager.VectorHand[(int)obj].X,
MediapipeManager.VectorHand[(int)obj].Y
);
}
else
{
return Vector2.zero;
}
}
// If PoseFound return true
public bool PoseFound()
{
if (InputSelector.inputFactory.
GetInput("Mediapipe").IsReady())
{
return MediapipeManager.HasPose();
}
else if (InputSelector.inputFactory.
GetInput("Kinect").IsReady())
{
return KinectManager.Player1Calibrated;
}
else
{
return false;
}
}
// Save to txt file
public void SaveToTxt(String data, String fileName)
{
string path = Application.dataPath + "/" + fileName + ".txt";
File.AppendAllText(path, data + "\n\n");
}
// Save to xml file
public void SaveToXml(String data, String fileName)
{
XmlDocument xmlDocument = new XmlDocument();
XmlElement root = xmlDocument.CreateElement("Save");
root.SetAttribute("FileName", fileName);
// Begin node
XmlElement pose = xmlDocument.CreateElement("Pose");
pose.InnerText = data;
root.AppendChild(pose);
// End node
xmlDocument.AppendChild(root);
xmlDocument.Save(Application.dataPath + "/" + fileName + ".xml");
}
// Load txt file
public void LoadTxt(String fileName)
{
string path = Application.dataPath + "/" + fileName + ".txt";
string textFromFile = File.ReadAllText(path);
Debug.Log(textFromFile);
}
// Load xml file
public void LoadXml(String fileName)
{
string path = Application.dataPath + "/" + fileName + ".xml";
XmlDocument xmlDocument = new XmlDocument();
xmlDocument.Load(path);
XmlNodeList pose = xmlDocument.GetElementsByTagName("Pose");
Debug.Log(pose[0].InnerText);
}
}
How can we help?
A premium WordPress theme with an integrated Knowledge Base,
providing 24/7 community-based support.



