public static Skeleton ObterEsqueletoUsuario
(this SkeletonFrame quadro)
{
Skeleton esqueletoUsuario = null;
Skeleton[] esqueletos =
new Skeleton[quadro.SkeletonArrayLength];
quadro.CopySkeletonDataTo(esqueletos);
IEnumerable<Skeleton> esqueletosRastreados =
esqueletos.Where( esqueleto =>
esqueleto.TrackingState ==
SkeletonTrackingState.Tracked);
if (esqueletosRastreados.Count() > 0)
esqueletoUsuario =
esqueletosRastreados.First();
return esqueletoUsuario;
}
Agora, iremos alterar o método DesenharEsqueletoUsuario para que ele
reaproveite este método, de modo que, quando precisarmos somente do esqueleto
do usuário sem desenhá-lo, podemos obtê-lo através do método deste método de
extensão.
public static void DesenharEsqueletoUsuario
( this SkeletonFrame quadro,
KinectSensor kinectSensor,
Canvas canvasParaDesenhar )
{
if (kinectSensor == null)
throw new ArgumentNullException("kinectSensor");
76
Casa do Código
Capítulo 6. Fluxo de Esqueleto do Usuário
if (canvasParaDesenhar == null)
throw new ArgumentNullException("canvasParaDesenhar");
Skeleton esqueleto = ObterEsqueletoUsuario(quadro);
if (esqueleto != null)
{
EsqueletoUsuarioAuxiliar esqueletoUsuarioAuxiliar =
new EsqueletoUsuarioAuxiliar(kinectSensor);
foreach (Joint articulacao in esqueleto.Joints)
esqueletoUsuarioAuxiliar
.DesenharArticulacao(articulacao, canvasParaDesenhar);
}
Agora precisamos atualizar o método DesenharEsqueletoUsuario de nossa
janela. Toda a lógica para obter o esqueleto do usuário já foi transferida para os mé-
todos mostrados anteriormente, então não é mais necessário mantê-la no código da janela, basta que dentro do bloco using utilizemos o método de extensão, conforme o exemplo.
private void DesenharEsqueletoUsuario(SkeletonFrame quadro)
{
if (quadro == null) return;
using (quadro)
quadro.DesenharEsqueletoUsuario(kinect, canvasKinect);
}
Note que retiramos toda a complexidade deste método e encapsulamos em um
método de extensão, agora ficará muito mais fácil desenhar o esqueleto sempre que for necessário. Se você executar a aplicação, verá que todas as articulações já são exibidas e que a articulação da cabeça possui um diâmetro bem maior que as outras, conforme ilustra a figura 6.3
77
6.2. Desenhando o Esqueleto do Usuário
Casa do Código
Figura 6.3: Desenhando todas as articulações
Como podemos notar na imagem acima já é possível ter uma boa noção de como
ficará nosso resultado, agora para finalizarmos esta funcionalidade precisamos desenhar todos os ossos do esqueleto. Antes de fazermos isso, é preciso saber que há uma hierarquia coerente entre as articulações. Essa hierarquia define a relação entre as articulações, por exemplo, a articulação da cabeça está relacionada a articulação do centro dos ombros, que por sua vez está relacionada com o ombro direito e esquerdo e assim por diante. A figura 6.4 ilustra esta hierarquia.
78
Casa do Código
Capítulo 6. Fluxo de Esqueleto do Usuário
Figura 6.4: Hierarquia dos ossos
Através desta hierarquia também conseguimos obter informações sobre a re-
lação das articulações, como por exemplo, a rotação de uma articulação em re-
lação a outra. Para acessarmos estas informações devemos utilizar a propriedade BoneOrientations da classe Skeleton, esta propriedade é uma coleção de objetos do tipo BoneOrientation. Utilizaremos este objeto para obtermos a arti-
culação inicial e final de cada osso de nosso esqueleto, então podemos
alterar o laço de repetição do nosso método de extensão para percorrer a coleção de ossos. Dessa forma, teremos as informações sobre os ossos e sobre as articulações, fazendo o desenho completo do esqueleto do usuário, de acordo com o código abaixo.
public static void DesenharEsqueletoUsuario
( this SkeletonFrame quadro,
79
6.2. Desenhando o Esqueleto do Usuário
Casa do Código
KinectSensor kinectSensor,
Canvas canvasParaDesenhar )
{
if (kinectSensor == null)
throw new ArgumentNullException("kinectSensor");
if (canvasParaDesenhar == null)
throw new ArgumentNullException("canvasParaDesenhar");
Skeleton esqueleto = ObterEsqueletoUsuario(quadro);
if (esqueleto != null)
{
EsqueletoUsuarioAuxiliar esqueletoUsuarioAuxiliar =
new EsqueletoUsuarioAuxiliar(kinectSensor);
foreach (BoneOrientation osso in esqueleto.BoneOrientations)
{
esqueletoUsuarioAuxiliar
.DesenharOsso(esqueleto.Joints[osso.StartJoint],
esqueleto.Joints[osso.EndJoint],
canvasParaDesenhar);
esqueletoUsuarioAuxiliar
.DesenharArticulacao
(esqueleto.Joints[osso.EndJoint], canvasParaDesenhar);
}
}
Enfim temos o resultado esperado. O esqueleto já pode ser desenhado total-
mente com uma simples chamada ao método de extensão, o resultado é ilustrado
pela figura 6.5.
80
Casa do Código
Capítulo 6. Fluxo de Esqueleto do Usuário
Figura 6.5: Desenhando o esqueleto do usuário
Agora vamos criar um novo CheckBox para identificar quando o esqueleto do
usuário deve ser desenhado. Em nossa janela iremos agrupar o CheckBox já exis-
tente para aplicar o filtro de escala cinza em um StackPanel. O trecho de XAML