1. IntroduçãoO Kinect é um aparelho desenvolvido para o videogame Xbox360 da microsoft. Estedisponibiliza uma série de car...
Este trabalho tem como objetivo explicar como se utiliza o aparelho Kinect em um computadore as possibilidades para a cria...
Para configurar o driver do kinect, basta plugar o usb em seu computador e esperar oreconhecimento do driver pelo windows....
O SDK beta fornece uma biblioteca de software sofisticados e ferramentas para ajudar osdesenvolvedores a utilizar o kinect...
de reconhecimento de localização através do som.5.Windows 7 standard APIsAPIs de áudio, voz, e mídia do windows 7.3.4.1 In...
C++:1. NuiInitialize - Inicializa a primeira instancia do sensor kinect no sistema.2. NuiXxx - funções para fazer o stream...
Caso sua aplicação necessite recuperar um frame com mais frequencia do que ele fica pronto,você pode escolher entre espera...
Imagem 5: Conjunto de pontos do esqueleto[4]Recuperando informação de esqueleto:Semelhante a coleta de imagem, recuperar u...
Imagem 6: 2 esqueletos reconhecidos ativamente[4]A informação de esqueleto é retornada em um skeleton frame que contem um ...
Imagem 7: esquema de reconhecimento de profundidade de objetos[4]Esqueleto:As posicões do esqueleto são representadas em c...
zero. Tal vetor pode ser encontrado em vFloorClipPlane que é um campo da estruturaNUI_SKELETON_FRAME.Espelhamento de esque...
● App.xaml, onde declara os níveis da aplicação ● App.xaml.cs que contém a codificação por trás d App.xaml ● MainWindo...
Construir e rodar o exemplo1. No Windows Explorer, navegue ate SkeletalViewerCS directory.2. De um duplo clique no arquivo...
{JointID.KneeRight, new SolidColorBrush(Color.FromRgb(71, 222, 76))}, {JointID.AnkleRight, new SolidColorBrush(Color...
nui.DepthFrameReady += new EventHandler<ImageFrameReadyEventArgs> (nui_DepthFrameReady); nui.SkeletonFrameReady ...
Processando dados do VídeoQuando o frame do vídeo esta pronto, o runtime sinaliza o evento VideoFrameReady echama a nui_Co...
seguinte forma:● Os 3 primeiros bits contem o ID do esqueleto.● Os bits restantes contem o valor da profundidade em milíme...
depthFrame32[i32 + BLUE_IDX] = (byte)(intensity / 4); break; case 5: depthFrame32[i32 + RED_IDX] = (byte)(intens...
skeleton.Children.Add(getBodySegme nt(data.Joints, brush, JointID.ShoulderCenter, JointID.ShoulderLeft, JointI...
no espaço do esqueleto para o espaço da imagem, seguindo esses passos: 1. Converter as coordenadas do esqueleto no inter...
ProgrammingGuide_KinectSDK.pdf, acessado em 21/10/2011[5] http://research.microsoft.com/apps/video/default.aspx?id=150286,...
of 21

Kinect

Published on: Mar 3, 2016
Source: www.slideshare.net


Transcripts - Kinect

  • 1. 1. IntroduçãoO Kinect é um aparelho desenvolvido para o videogame Xbox360 da microsoft. Estedisponibiliza uma série de características: Sensor de movimentos (possibilitando rastreare reconhecer movimentos do corpo todo); Rastreamento de esqueleto (reconhece e poderepresentar o esqueleto); Reconhecimento facial (Podendo a partir da leitura facial fazer o logindo usuário); Reconhecimento de voz (microfones estrategicamente posicionados dentro dosensor).Sendo o único videogame de mercado em que é possível jogar sem o uso de controles, okinect foi um grande sucesso de vendas. Curiosamente seu projeto inicialmente se chamavaprojeto Natal, em alusão a cidade de Natal no Brasil. A Microsoft explica o porque do nome daempresa: “Um de nossos pesquisadores, Alex Kipman, é do Brasil e ele escolheu a cidade deNatal como um tributo a seu País. Além disso, ele sabia que Natal também significa nascer,em latim. Considerando o novo público que será atraído ao Xbox 360 pela novidade, o nomeencaixou perfeitamente”.O Sensor Kinect conta com uma câmera, um sensor de profundidade, um microfone embutidoe o próprio processador e software. Possui paroximadamente 23cm de comprimento horizontal.Apesar do sensor ter sido projetado para Xbox360 existirão futuras aplicações para Windows.Já é possível utilizar o kinect com objetivos de desenvolvimento no windows 7 com o uso doKinect SDK. Imagem 1: Kinect Sensor [3]2. Objetivos
  • 2. Este trabalho tem como objetivo explicar como se utiliza o aparelho Kinect em um computadore as possibilidades para a criação de um desenvolvedor criar seu próprio aplicativo.Será realizado um estudo sobre o Kinect SDK com os seguinte passos: A instalação serárealizada seguindo o guia disponibilizado no site oficial do Kinect SDK [4]; Espera-se apósa instalação ser possível rodar o Demo da kinect SDK [5]; Serão realizados testes demodificação de código após a compreensão dos tutoriais [6]; Caso todos os passos acimaforem executados com sucesso, será feito uma aplicação própria usando as bibliotecas e oaparelho Kinect.3. Kinect SDKAqui será apresentado um guia sucinto sobre os requerimentos, instalação, configuraçãoe as principais funções do kinect SDK. É sugerido que o leitor já tenha noções básicas deprogramação em C++ e seja familiar com o windows e o microsoft visual studio.3.1 RequerimentosApenas o sistema operacional windows 7 (x86, x64) é compatível. Não é possível rodar o SDKem uma máquina virtual pois o driver do kinect e o sdk devem estar instalados no computador.Os requerimentos de hardware são: computador dual-core, 2,66GHz ou mais; placa de cídeocompátivel com o windows 7 e o directx 9.0; 2GB de memória RAM; sensor Kinect paraxbox360. Os requerimentos de software são: Microsoft visual studio 2010; microsoft .NETframework 4 (instalado com o visual studio); Directx SDK.3.2 Instalação1. Obter as últimas atualizações para o Windows 7 da Microsoft Update.2. Certifique-se que o dispositivo Kinect não está conectado à porta USB no seu computador.3. Remova todos os outros drivers que você possa ter instalado anteriormente para odispositivo Kinect.4. Certifique-se de todo o software necessário foi instalado no seu computador, conformedescrito em "Requerimentos ", anteriormente neste guia.5. Fechar o Visual Studio antes de instalar o SDK beta.6. Na página de download do SDK Beta, clique na opção download para o seu computador(x86 ou x64).7. Para iniciar a instalação do SDK beta imediatamente, clique em Executar.8. Siga o assistente para completar a instalação.
  • 3. Para configurar o driver do kinect, basta plugar o usb em seu computador e esperar oreconhecimento do driver pelo windows. Lembrando que o kinect deve estar ligado com umafonte externa de energia. Se instalado corretamente, o kinect apresenta´ra um led verdepiscando.3.3 Protegendo seu KinectO sensor kinect é protegido contra o aquecimento por uma ventoinha. Caso a temperaturachegue acima de 90° celsius, a câmera desliga automaticamente. Não existe uma interface desoftware que controle a ventoinha.O controle da câmera é realizado através de API’s, o mecanismo de rotação do aparelho paramelhor visualização da câmera não é projetado para uso frequente, caso isso ocorra poderesultar na quebra do aparelho.Posicione o kinect em uma superfície plana e longe de possíveis quedas. Não coloque osensor perto de soms ou fortes vibrações e mantenha em lugar protegido do sol. Enquanto okinect está em uso, lembre-se que este funciona apenas para reconhecimento de esqueletode pessoas em pé e que sua áre de reconhecimento está entre 1.2 e 3.5 metros. Abaixo maisespecificações: Imagem 2: Especificações do Kinect[4]3.4 NUI API
  • 4. O SDK beta fornece uma biblioteca de software sofisticados e ferramentas para ajudar osdesenvolvedores a utilizar o kinect. O sensor e a biblioteca NUI interagem para gerar aaplicação, como mostrado abaixo: Imagem 3: Interação Hardware, Software e aplicação[4]Abaixo os componentes do SDK: Imagem 4: Principais componentes[4]1.Kinect hardwareComponentes de Hardware, incluind o kinect e a porta USB.2.Microsoft Kinect driversDrivers do kinect no widows 7 que foram instalados durante a instalação do kinect SDK.3.NUI APIUm conjunto de APIs que recebem dados dos sensores de imagem e controla o kinect.4.KinectAudio DMOKinect DMO que extende o suporte para microfone no Windows 7 para fazer a funcionalidade
  • 5. de reconhecimento de localização através do som.5.Windows 7 standard APIsAPIs de áudio, voz, e mídia do windows 7.3.4.1 InicializaçãoPara implementar sua aplicação são necessários os seguintes passos:C#:1) Referencie o Microsoft.Research.Kinect.dll.2) Inclua usando diretivas o seguinte:Para o NUI API, inclua: using Microsoft.Research.Kinect.NuiPara o Audio API, inclua: using Microsoft.Research.Kinect.AudioC++:1) Inclua <windows.h> no código fonte.2) Para usar o NUI API, inclua o MSR_NuiApi.h.Local: Program FilesMicrosoft Research KinectSDKinc3) Para usar o Kinect Audio API, inclua MSRKinectAudio.h.Local: Program FilesMicrosoft Research KinectSDKinc4) Link com o MSRKinectNUI.lib.Local: Program FilesMicrosoft Research KinectSDKlib5) Certifique-se de que as beta SDK DLLs estão no mesmo caminho quando for rodar o projeto.Local: Program FilesMicrosoft Research KinectSDKA tabela a seguir descreve o que incluir em seu projeto: ..Program Files (x86)Microsoft Research KinectSDKinc MSR_NuiApi.h MSR_NuiImageCamera.h MSR_NuiProps.h MSR_NuiSkeleton.h MSRKinectAudio.h NuiImageBuffer.hPara usar a API você pode usar as seguintes funções:
  • 6. C++:1. NuiInitialize - Inicializa a primeira instancia do sensor kinect no sistema.2. NuiXxx - funções para fazer o stream de imagem , dados do esqueleto e gerenciar acâmera.3. NuiShutdown - Chamar quando o uso do kinect for finalizado.C#:1.Crie um novo objeto Runtime e deixe a lista de parâmetros vazia, como a seguir:nui = new Runtime();2.Chame Runtime.Initialize para inicializar o NUI API.3Chame métodos adicionais na interface para fazer o stream da imagem e administrar osdados de esqueleto e câmeras.4.Chame Runtime.Shutdown quando o uso do sensor Kinect estiver terminado.3.4.2 Streams de dados de imagensNa inicialização deverá ser especificado quais os subsistemas serão utilizados na aplicação.Esses subsistemas são divididos em cor, profundidade, profundidade e player index, esqueleto.Após a especificação, o NUI retorna do kinect um stream de dados em forma de uma sucessãode imagens. Também é fornecido insofrmações adicionais sobre a stream como resolução, tipode imagem, buffer e etc. Uma aplicação tem acesso 3 tipos de dados de imagem:Color data - Formatos RGB e YUVDepth data - Retorna uma imagem em que cada pixel representa a distancia Cartesiana(mm)do plano da camera para o objeto mais próximo naquela coordena x e y. Aplicações podemurilizar dos dados de profundidade para suportar funcionalidades personalizadas diversas, taiscomo rastreamento de movimentos dos usuários ou identificação de objetos de fundo paraignorar durante o funcionamento da aplicação.Player segmentation data - Identifica duas figuras humanas em frente ao sensor e, emseguida, cria um mapa de Segmentação do jogador. Este mapa é um quadro de bits em que ovalor do pixel corresponde ao jogador no campo de visão que está mais próximo da câmera.Coletando imagens:Os códigos conseguem coletar o último frame de dados de uma imagem chmando um métodode recuperação de frame e passando um buffer. O último frame de dados é copiado no buffer.
  • 7. Caso sua aplicação necessite recuperar um frame com mais frequencia do que ele fica pronto,você pode escolher entre esperar pelo próximo frame ou retornar e tentar de novo mais tarde.O NUI API nunca repete a mesma informação de frame mais de uma vez.Existem dois modelos que podem ser usados:Polling Model - Opção mais simples para ler frames. Primeiro a aplicação abre a strem deimagens, então chama por um frame e especifica o tempo máximo de espera. Caso o tempomáximo for colocado como infinito, a aplicação aguardará o quanto for necessário pelo próximoframe. Quando a requisição for retornada com sucesso, o novo frame estará disponível paraprocessamento.Em uma aplicação em C++ chama-se NuiImageStreamOpen para abrir uma stream de cor ouprofundidade. NuiImageStreamGetNextFrame é usado para fazer o polling.Event Model - Possibilita recuperar o frame de um esqueleto com mais flexibilidade e precisão.Em C++ passa-se um evento NuiImageStreamOpen. Quando um novo frame de dados deimagem está pronto, o evento é avisado. Qauqluer thread a espera acorda e recebe o quadrode esqueleto dados chamando NuiImageGetNextFrame. Durante este período, o evento éreiniciado pelo NUI API.3.4.3 Reconhecimento de esqueletoO NUI Skeleton API fornece a localização de até dois jogadores com a informação detalhadade posição e orientação. A informação é dada para a plicação como um conjunto de pontos quecompõem o esqueleto. Aplicações que usam informações de esqueleto devem incicializar noNUI Initialization e devem habilitar o skeleton tracking.
  • 8. Imagem 5: Conjunto de pontos do esqueleto[4]Recuperando informação de esqueleto:Semelhante a coleta de imagem, recuperar uma informação de esqueleto basta chama umfunção passando o buffer e o tempo máximo de espera. Podendo ser usado o polling ou oevent model.Em C++ para usar o polling model é usado NuiSkeletonGetNextFrame e para usar o eventmodel é usado NuiSkeletonTrackingEnable.Reconhecimento de esqueleto ativo e passivo:O Kinect reconhece apenas o esqueleto 2 jogadores ativamente. Quando um esqueleto éreconhecido ativamente, é fornecido uma informação completa sobre esse esqueleto. Oreconhecimento de esqueleto passivo pode reconhecer até 4 jogadores. Por padrão o Kinectescolhe ativamente 2 esqueletos como mostrado abaixo:
  • 9. Imagem 6: 2 esqueletos reconhecidos ativamente[4]A informação de esqueleto é retornada em um skeleton frame que contem um vetor deestrutura de dados, um para cada esqueleto reconhecido. As seguintes informaçõessão fornecidas:Estado de tracking de cada esqueleto; Um ID único para cada esqueletoencontrado; Um posição a partir do centro de massa do jogador.3.4.4 TransformaçõesProfundidade:Frames da imagem de profundidade são 640x480, 320×240, ou 80x60 pixels. Cada pixelrepresenta a distância cartesiana em mm do plano da câmera até o objeto mais próximonaquela coordenada x e y. Um pixel de valor 0 indica que nenhum objeto foi encontradonaquela posição.
  • 10. Imagem 7: esquema de reconhecimento de profundidade de objetos[4]Esqueleto:As posicões do esqueleto são representadas em coordenadas x, y e z e em metros.Caso osensor seja posicionado em uma superfície não plana, pode ser possível que o eixo y nãoesteja perpendicular ao chão, podendo resultar em um efeito que pessoas em pé possamaparecer tortas. Imagem 8: Eixo x, y e z [4]Determinação do chão:Em um frame de esqueleto podemos encontrar um vetor chamado floor clip plane quedetermina a localização do chão. A equação geral do plano é Ax + By + Cz + D = 0, onde:A = vFloorClipPlane.xB = vFloorClipPlane.yC = vFloorClipPlane.zD = vFloorClipPlane.wA equação é normalizada para que D seja interpretado como a altura da câmera em relaçãoao chão, em metros. Caso o chão não esteja visível. o floor clip plane é um vetor com valor
  • 11. zero. Tal vetor pode ser encontrado em vFloorClipPlane que é um campo da estruturaNUI_SKELETON_FRAME.Espelhamento de esqueleto:Por padrão o esqueleto espelha o usuário. Dependendo da aplicação pode ser interessanteusar uma matriz de transformação para mudar o espelhamento.4. Exemplo: SkeletalViewerC++: Imagem 9: SkeletalViewer[4]O aplicativo SkeletalViewer é dividido em 3 arquivos.SkeletalViewer.cpp(Começo da aplicação,janela principal e funções de callback); NUIImpl.cpp e SkeletalViewer.h (implementam aclasse CSkeletalViewerApp que captura dados do kinect e transforma para renderização);DrawDevice.cpp e DrawDevice.h (implementam a classe DrawDevice que usa Direct3D para arenderização de imagens).Fluxo do programa:1. Cria a janela principal em que o programa exibe imagens do sensor Kinect.2. Inicializar o sensor Kinect, abre streams para cada tipo de dados e cria uma thread paraprocessar os dados.3. Processa dados do sensor e renderiza imagens na janela assim que chegam novos frames.4. Limpa e sai quando o usuário fecha a janela.C#:Em C#, o exemplo da Microsoft do SkeletalViewer tem alguns programas básicos:
  • 12. ● App.xaml, onde declara os níveis da aplicação ● App.xaml.cs que contém a codificação por trás d App.xaml ● MainWindow.xaml declara o layout da aplicação principal ● MainWindow.xaml.cs que contém a codificação por trás da jánela principal, e também inicialização NUI API ● e o SkeletalViewer.ico, definida como icone da aplicação Imagem 10: SkeletalViewer[4]O EsqueletalViewer em C# usa a NUI API para capturar dados, cor e movimentos do esqueletoe assim transformar em imagens utilizando o WPF.A aplicação C# SkeletalViewer é instalada com Kinect for Windows Software Development Kit(SDK) Beta que esta no arquivo KINECTSDK_DIR%SamplesKinectSDKSamples.zipA implementação é feita nos seguintes arquivos:
  • 13. Construir e rodar o exemplo1. No Windows Explorer, navegue ate SkeletalViewerCS directory.2. De um duplo clique no arquivo com extensão .sln (solution) para abrir no Visual Studio.3. Rode a aplicação4. Clique em CTRL+F5 para rodar o código.O arquivo solução atinge x86 platform, pois o beta SDK inclui somente a x86 libraries.Criar janela principalO C# SkeletalViewer usa WPF para criar a janela que mostra a imagem real, em profundidade,e os frames do esqueleto, e faz uma aproximação destes por segundo. è usado oSystem.Windows para classes elementares e também para adição de característicasespecificas. è de extrema importância incluir a Microsoft.Research.Kinect.Nui para acessar ocódigo de interface do beta SDK.O código abaixo mostra a inicialização do código MainWindownamespace SkeletalViewerpublic partial class MainWindow : Window{ public MainWindow() { InitializeComponent(); } Runtime nui; int totalFrames = 0; int lastFrames = 0; DateTime lastTime = DateTime.MaxValue; const int RED_IDX = 2; const int GREEN_IDX = 1; const int BLUE_IDX = 0; byte[] depthFrame32 = new byte[320 * 240 * 4]; Dictionary<JointID,Brush> jointColors = new Dictionary<JointID,Brush>() { {JointID.HipCenter, new SolidColorBrush(Color.FromRgb(169, 176, 155))}, {JointID.Spine, new SolidColorBrush(Color.FromRgb(169, 176, 155))}, {JointID.ShoulderCenter, new SolidColorBrush(Color.FromRgb(168, 230,29))}, {JointID.Head, new SolidColorBrush(Color.FromRgb(200, 0, 0))} {JointID.ShoulderLeft, new SolidColorBrush(Color.FromRgb(79, 84, 33))}, {JointID.ElbowLeft, new SolidColorBrush(Color.FromRgb(84, 33, 42))}, {JointID.WristLeft, new SolidColorBrush(Color.FromRgb(255, 126, 0))}, {JointID.HandLeft, new SolidColorBrush(Color.FromRgb(215, 86, 0))}, {JointID.ShoulderRight, new SolidColorBrush(Color.FromRgb(33, 79, 84))}, {JointID.ElbowRight, new SolidColorBrush(Color.FromRgb(33, 33, 84))}, {JointID.WristRight, new SolidColorBrush(Color.FromRgb(77, 109, 243))}, {JointID.HandRight, new SolidColorBrush(Color.FromRgb(37, 69, 243))}, {JointID.HipLeft, new SolidColorBrush(Color.FromRgb(77, 109, 243))}, {JointID.KneeLeft, new SolidColorBrush(Color.FromRgb(69, 33, 84))}, {JointID.AnkleLeft, new SolidColorBrush(Color.FromRgb(229, 170, 122))}, {JointID.FootLeft, new SolidColorBrush(Color.FromRgb(255, 126, 0))}, {JointID.HipRight, new SolidColorBrush(Color.FromRgb(181, 165, 213))},
  • 14. {JointID.KneeRight, new SolidColorBrush(Color.FromRgb(71, 222, 76))}, {JointID.AnkleRight, new SolidColorBrush(Color.FromRgb(245, 228, 156))}, {JointID.FootRight, new SolidColorBrush(Color.FromRgb(77, 109, 243))} };// . . . SkeletalViewer namespace code continuesO metodo Window_Loaded manuseia a Window.Loaded e inicializa a NUI APIO nui_DepthFrameReady, nui_SkeletonFrameReady, e nui_ColorFrameReady sãomanipuladores de eventos.O método convertDepthFrame converte dados em 16-bit para dados em formato 32-bit.O método getBodySegment desenha partes do esqueleto.O método Window_Closed deriva do evento Window.Closed.A classe MainWindow inicializa a janela e cria variáveis globais: Declara nui como um objeto Runtime, que representa o sensor do Kinect no momento.Inicializa diversas variáveis—totalFrames, lastFrames, e lastTime—que são usadas paracalcular o numero de frames por segundoDefine depthFrame32 como um vetor de bytes, suficiente para armazenar o frame de 32 bitspor pixel e define o RED_IDX, GREEN_IDX, e BLUE_IDX como constantes para indexar ovetor.Cria jointColors como uma classe System.Collections.Generic.Dictionary que associa cor aoesqueletoInicialização RunTime O método Window_Loaded cria o nui objeto runtime, abrindo o vídeo e streams, setando oevento que são chamados quando um vídeo ou frame esta pronto: private void Window_Loaded(object sender, EventArgs e ) { nui = new Runtime(); try { nui.Initialize(RuntimeOptions.UseDepthAndPlayerIndex | RuntimeOptions.UseSkeletalTracking | RuntimeOptions.UseColor); } catch (InvalidOperationException) { // Display error message; omitted for space return; } try { nui.VideoStream.Open(ImageStreamType.Video, 2, ImageResolution.Resolution640x480, ImageType.Color); nui.DepthStream.Open(ImageStreamType.Depth, 2, ImageResolution.Resolution320x240, ImageType.DepthAndPlayerIndex); } catch (InvalidOperationException) { // Display error message; omitted for space return; } lastTime = DateTime.Now;
  • 15. nui.DepthFrameReady += new EventHandler<ImageFrameReadyEventArgs> (nui_DepthFrameReady); nui.SkeletonFrameReady += new EventHandler<SkeletonFrameReadyEventArgs> (nui_SkeletonFrameReady); nui.VideoFrameReady += new EventHandler<ImageFrameReadyEventArgs> (nui_ColorFrameReady);}A aplicação tem que inicializar o sensor do Kinect chamando Runtime.Initialize antes dachamada qualquer outro método do objeto. Runtime.Initialize inicializa uma aplicaçãointerna que recupera dados do sensor e sinais quando um frame esta pronto. O métodoInitialize possui uma exceção InvalidOperationException senão encontrar o sensor Kinect.O único parâmetro de Runtime.Initialize e opções de bit a bit ou, combinação dos seguintes: · UseDepthAndPlayerIndex · UseColor · UseSkeletalTracking · UseDepth · O exemplo usa cor, profundidade, índice do jogador e do esqueleto assim especifica as UseDepthAndPlayerIndex, UseColor, and UseSkeletalTracking. · Na próxima chamada o método Window_Loaded abre o fluxo de vídeo e profundidade através da nui.VideoStream.Open e nui.DepthStream.Open. VideoStream e DepthStream são propriedade do objeto Runtime. · O método ImageStream.Open possui os seguintes parâmetros: · O tipo de fluxo pode ser ImageStreamType.Video ou ImageStreamType.Depth. · Possuem 2 buffers, um para desenhar e outro que captura. · A resolução da imagem, ImageResolution. · O tipo da imagem, ImageType. · Se a aplicação especifica um tipo de resolução ou imagem não compatível com as especificações o ImageStream.Open lança uma exceção. · Para obter imagens coloridas: · A opção deve incluir UseColor. · Resoluções validas são 1280x1024 e 640x480. · Tipos validos de cor: ColorYUV e ColorYUVRaw.SkeletalViewer Walkthrough – 30 · Para transmitir profundidade e dados do jogador: · Deve incluir UseDepthAndPlayerIndex. · Resoluções validas de profundidade e dados do índice do jogador são 320x240 e 80x60. · O único tipo de imagem valida e DepthAndPlayerIndex.Na próxima etapa o Window_Loaded salva o tempo corrente em lastTime para calcular osframes por segundo.Existem dois modos para recuperar frames. Uma aplicação pode usar oImageStream.GetNextFrame ou SkeletonEngine.GetNextFrame que espera ate que oframe esteja pronto, ou a orientada a eventos. O SkeletalViewer usa o tipo orientadoa eventos. Para implementar o modelo orientado a evento, o método Window_Loadedcria eventos: DepthFrameReady, SkeletonFrameReady, e VideoFrameReady para anui Runtime e associa com manipuladores que são nomeados nui_DepthFrameReady,nui_SkeletonFrameReady, e nui_ColorFrameReady.
  • 16. Processando dados do VídeoQuando o frame do vídeo esta pronto, o runtime sinaliza o evento VideoFrameReady echama a nui_ColorFrameReady. Abaixo esta o código:void nui_ColorFrameReady(object sender, ImageFrameReadyEventArgs e){ PlanarImage Image = e.ImageFrame.Image; video.Source = BitmapSource.Create( Image.Width, Image.Height, 96, 96, PixelFormats.Bgr32, null, Image.Bits, Image.Width * Image.BytesPerPixel);}O parâmetro e é passado como argumento não função acima pertence à classeImageFrameReadyEventArgs que possui uma propriedade ImageFrame. OImageFrame.Image é objeto PlanarImage que representa apropria imagem. A imagem éplana no RGB com 32 bits por pixel.O método nui_ColorFrameReady chama o WPF BitmapSource, que cria umbitmap para a tela, passando os parâmetros: · Largura e altura da imagem que estão no objeto PlanarImage. · Resolução vertical e horizontal do bitmap—96 pontos por polegadas em cada direção. · O formato do pixel identificado por PixelFormats.Bgr32 no System.Windows.Media. · A paleta deve ser nula, pois não é usada na imagem. · O vetor de bits que forma a imagem.WPF lida com exibição do bitmap resultante.Processando dados de profundidadeQuando a imagem da câmera de profundidade esta pronta, o runtime sinaliza oDepthFrameReady e chama nui_DepthFrameReady. Este manipulador de evento recuperaa imagem converte no formato desejado e chama o método BitmapSource. O métodonui_DepthFrameReady também atualiza os frames-por-segundo. Abaixo a demonstraçãodo código:void nui_DepthFrameReady(object sender, ImageFrameReadyEventArgs e){ PlanarImage Image = e.ImageFrame.Image; byte[] convertedDepthFrame = convertDepthFrame(Image.Bits); depth.Source = BitmapSource.Create(Image.Width, Image.Height, 96, 96, PixelFormats.Bgr32, null, convertedDepthFrame, Image.Width * 4); ++totalFrames; DateTime cur = DateTime.Now; if (cur.Subtract(lastTime) > TimeSpan.FromSeconds(1)) { int frameDiff = totalFrames - lastFrames; lastFrames = totalFrames; lastTime = cur; frameRate.Text = frameDiff.ToString() + " fps"; }}Quando uma aplicação tem dados de profundidade então possui um vetor de 16-bit, da
  • 17. seguinte forma:● Os 3 primeiros bits contem o ID do esqueleto.● Os bits restantes contem o valor da profundidade em milímetros.Se a aplicação exibir um quadro de profundidade em escala cinza, os usuários acham difícildistinguir os indivíduos na tela, então a amostra converte a 16-bit na escala cinza para 32-bit RGB, com cada pessoa em uma cor diferente. A conversão opera em um vetor de bytesde dados de profundidade. Segue os passos:1. Guarda o numero do jogador a partir dos 3 primeiros bits na variável players. Valores sãoentre 0-6. Valor igual a 0 significa que nenhum jogador esta presente.2. Recupera 11 bits dos dados de profundidade guarda na variável realDepth.3. Inverte o resultado para gerar um valor de 8 bits de intensidade que é melhor paraexibição de imagens, assim objetos mais pertos ficam mais brilhantes e objetos maisdistantes parecem mais escuros.4. Zero inicializa os elementos do 32-bit frame.5. Atribuir às cores vermelha verde, e azul para o resultado com base no numero dojogador, usando as constantes RED_IDX, GREEN_IDX, e BLUE_IDX no vetor.O método abaixo refere ao convertDepthFrame:byte[] convertDepthFrame(byte[] depthFrame16){ for (int i16 = 0, i32 = 0) i16 < depthFrame16.Length && i32 < depthFrame32.Length; i16 += 2, i32 += 4) { int player = depthFrame16[i16] & 0x07; int realDepth = (depthFrame16[i16+1] << 5) | (depthFrame16[i16] >> 3); byte intensity = (byte)(255 - (255 * realDepth / 0x0fff)); depthFrame32[i32 + RED_IDX] = 0; depthFrame32[i32 + GREEN_IDX] = 0; depthFrame32[i32 + BLUE_IDX] = 0; switch (player) { case 0: depthFrame32[i32 + RED_IDX] = (byte)(intensity / 2); depthFrame32[i32 + GREEN_IDX] = (byte)(intensity / 2); depthFrame32[i32 + BLUE_IDX] = (byte)(intensity / 2); break; case 1: depthFrame32[i32 + RED_IDX] = intensity; break; case 2: depthFrame32[i32 + GREEN_IDX] = intensity; break; case 3: depthFrame32[i32 + RED_IDX] = (byte)(intensity / 4); depthFrame32[i32 + GREEN_IDX] = (byte)(intensity); depthFrame32[i32 + BLUE_IDX] = (byte)(intensity); break; case 4: depthFrame32[i32 + RED_IDX] = (byte)(intensity); depthFrame32[i32 + GREEN_IDX] = (byte)(intensity);
  • 18. depthFrame32[i32 + BLUE_IDX] = (byte)(intensity / 4); break; case 5: depthFrame32[i32 + RED_IDX] = (byte)(intensity); depthFrame32[i32 + GREEN_IDX] = (byte)(intensity / 4); depthFrame32[i32 + BLUE_IDX] = (byte)(intensity); break; case 6: depthFrame32[i32 + RED_IDX] = (byte)(intensity / 2); depthFrame32[i32 + GREEN_IDX] = (byte)(intensity / 2); depthFrame32[i32 + BLUE_IDX] = (byte)(intensity); break; case 7: depthFrame32[i32 + RED_IDX] = (byte)(255 - intensity); depthFrame32[i32 + GREEN_IDX] = (byte)(255 - intensity); depthFrame32[i32 + BLUE_IDX] = (byte)(255 - intensity); break; } }return depthFrame32;}Processando dados do SkeletonO método nui_SkeletonFrameReady manipula o evento SkeletonFrameReady. Estemétodo recupera os dados do esqueleto, limpa o display, e em seguida desenha linhas querepresenta as partes do esqueleto, abaixo o algoritmo:void nui_SkeletonFrameReady(object sender, SkeletonFrameReadyEventArgs e){ SkeletonFrame skeletonFrame = e.SkeletonFrame; int iSkeleton = 0; Brush[] brushes = new Brush[6]; brushes[0] = new SolidColorBrush(Color.FromRgb(255, 0, 0)); brushes[1] = new SolidColorBrush(Color.FromRgb(0, 255, 0)); brushes[2] = new SolidColorBrush(Color.FromRgb(64, 255, 255)); brushes[3] = new SolidColorBrush(Color.FromRgb(255, 255, 64)); brushes[4] = new SolidColorBrush(Color.FromRgb(255, 64, 255)); brushes[5] = new SolidColorBrush(Color.FromRgb(128, 128, 255));skeleton.Children.Clear(); foreach (SkeletonData data in skeletonFrame.Skeletons) { if (SkeletonTrackingState.Tracked == data.TrackingState) { // Draw bones Brush brush = brushes[iSkeleton % brushes.Length]; skeleton.Children.Add(getBodySegment(data.Joints, brush, JointID.HipCenter, JointID.Spine, JointID.ShoulderCenter, JointID.Head));
  • 19. skeleton.Children.Add(getBodySegme nt(data.Joints, brush, JointID.ShoulderCenter, JointID.ShoulderLeft, JointID.ElbowLeft, JointID.WristLeft, JointID.HandLeft)); skeleton.Children.Add(getBodySegment(data.Joints, brush, JointID.ShoulderCenter, JointID.ShoulderRight, JointID.ElbowRight, JointID.WristRight, JointID.HandRight)); skeleton.Children.Add(getBodySegment(data.Joints, brush, JointID.HipCenter, JointID.HipLeft, JointID.KneeLeft, JointID.AnkleLeft, JointID.FootLeft)); skeleton.Children.Add(getBodySegment(data.Joints, brush, JointID.HipCenter, JointID.HipRight, JointID.KneeRight, JointID.AnkleRight, JointID.FootRight)); // Draw joints foreach (Joint joint in data.Joints) { Point jointPos = getDisplayPosition(joint); Line jointLine = new Line(); jointLine.X1 = jointPos.X - 3 ; jointLine.X2 = jointLine.X1 + 6; jointLine.Y1 = jointLine.Y2 = jointPos.Y; jointLine.Stroke = jointColors[joint.ID]; jointLine.StrokeThickness = 6; skeleton.Children.Add(jointLine); } } iSkeleton++; }}O método nui_SkeletonFrameReady primeiro recupera os dados do esqueleto e armazenaem um objeto SkeletonFrame. Em seguida analisa as variáveis iSkeleton e brushes paraelaboração do esqueleto. A variável brushes é um vetor de System. Windows.Media.Brush,e assim cada elemento do vetor é do tipo SolidColorBrush objeto. Em seguidanui_SkeletonFrameReady limpa o display chamando Children.Clear no esqueleto WPFcanvas.Agora o método desenha o esqueleto: primeiro os ossos e depois as articulações.O skeletonFrame.Skeletons é uma matriz de estrutura de SkeletonData que contemdados para um único esqueleto. Se o campo TrackingState do SkeletonData indicar que oesqueleto esta sendo monitorado, o nui_SkeletonFrameReady escolhe uma cor e chama ométodo getBodySegment diversas vezes para desenhar as linhas do esqueleto.O método getBodySegment tem 3 parâmetros:● Uma cloacae de articulacoes Microsoft.Research.Kinect.Nui.JointsCollection● A escova com qual desenha esta linha.● Um numero de variáveis JointID, onde cada valor identifica um determinado conjunto sobre o esqueleto.A maior parte do código no getBodySegment envolve chamadas para métodosPointCollection e. PolylineSystem.Windows.Media. O método getBodySegment coletapontos e os junta com segmento de linha. Esse method retorna uma Polyline que conectaas articulações.Os dados do esqueleto, cor, imagem, profundidade são baseados em diferentes sistemasde coordenadas. Para mostrar uma imagem consistente, o programa converte coordenadas
  • 20. no espaço do esqueleto para o espaço da imagem, seguindo esses passos: 1. Converter as coordenadas do esqueleto no intervalo [-1.0, 1.0] para as coordenadas de profundidade chamando o SkeletonEngine. SkeletonToDepthImage. Essa função retorna coordenadas x e y como números de ponto flutuante no intervalo 0.0 ate 1.0. 2. Converter as coordenadas em ponto flutuante para valores no espaço 320x240 que é o intervalo que o NuiCamera.GetColorPixelCoordinatesFromDepthPixel requer. 3. Converter a coordenada de profundidade para coordenada de imagem colorida chamando NuiCamera.GetColorPixelCoordinatesFromDepthPixel. Esse método retorna a coordenada de imagem colorida no intervalo de 640x480. 4. Dimensionar a coordenada da imagem colorida para o tamanho do display do esqueleto na tela dividindo a coordenada x por 640 em a coordenada y por 480 e multiplicando o resultado pela altura e largura da área de exibição do esqueleto. A funcao getDisplayPosition esta descrita abaixo: private Point getDisplayPosition(Joint joint) { float depthX, depthY; nui.SkeletonEngine.SkeletonToDepthImage(joint.Position, out depthX, out depthY); depthX = Math.Max(0, Math.Min(depthX * 320, 320)); depthY = Math.Max(0, Math.Min(depthY * 240, 240)); int colorX, colorY; ImageViewArea iv = new ImageViewArea(); // only ImageResolution.Resolution640x480 is supported at this point nui.NuiCamera.GetColorPixelCoordinatesFromDepthPixel( ImageResolution.Resolution640x480, iv, (int)depthX, (int)depthY, (short)0, out colorX, out colorY); return new Point((int)(skeleton.Width * colorX / 640.0), (int)(skeleton.Height * colorY / 480)); } Quando todos os ossos foram desenhados o nui_SkeletonFrameReady desenha as articulações. Cada conjunto é desenhado como uma caixa 6X6. O método nui_SkeletonFrameReady transforma a posição inicial (x, y) de cada conjunto chamado getDisplayPosition, assim como o getBodySegment transformou a posição dos ossos. WPF lida com redenrizacao na tela, resultando cavas na tela.Referências:[1] Real-Time Human Pose Recognition in Parts from Single Depth Images; Microsoft ResearchCambridge & Xbox Incubation.[2] http://research.microsoft.com/en-us/um/redmond/projects/kinectsdk/guides.aspx, acessadoem 21/10/2011[3] http://www.neuronik.com.br/produtos/255-video, acessado em 21/10/2011[4]http://research.microsoft.com/en-us/um/redmond/projects/kinectsdk/docs/
  • 21. ProgrammingGuide_KinectSDK.pdf, acessado em 21/10/2011[5] http://research.microsoft.com/apps/video/default.aspx?id=150286, acessado em 21/10/2011[6] http://research.microsoft.com/enus/um/redmond/projects/kinectsdk/guides.aspx, acessadoem 21/10/2011

Related Documents