que temos é o efeito parallax citado anteriormente.
O sensor utiliza este efeito, seus dois sensores de profundidade e um algoritmo para detectar a profundidade de cada objeto na imagem. Tanto o efeito parallax
quanto a técnica utilizada pelo Kinect são mais complexos do que estas breves explicações, mas iremos focar na implicação disso em uma aplicação final e não no modo como o Kinect foi concebido.
5.3
Aplicação
Agora iremos por em prática os conceitos vistos anteriormente neste capítulo, utilizaremos a mesma aplicação do capítulo anterior, mas inicialmente vamos desa-
bilitar o fluxo de cores e habilitar o fluxo de profundidade. O primeiro passo
será alterar o método InicializarKinect, que informamos na propriedade
MetodoInicializadorKinect de nosso inicializador.
Vamos comentar as linhas que inicia o fluxo de cores e substituí-las por linhas que iniciam o fluxo de profundidade e criam um método para interpretar seu evento, conforme código a seguir.
private void InicializarKinect(KinectSensor kinectSensor)
{
kinect = kinectSensor;
slider.Value = kinect.ElevationAngle;
kinect.DepthStream.Enable();
kinect.DepthFrameReady += kinect_DepthFrameReady;
//kinect.DepthStream.Range = DepthRange.Near;
//kinect.ColorStream.Enable();
//kinect.ColorFrameReady += kinect_ColorFrameReady;
}
51
5.3. Aplicação
Casa do Código
private void kinect_DepthFrameReady
(object sender, DepthImageFrameReadyEventArgs e)
{
}
Caso você possua um Kinect na versão para Windows e desejar ativar o modo
de proximidade você deve remover os comentários da linha de código que atribui o valor Near para a propriedade Range do fluxo de profundidade. Neste ponto, caso você inicialize a aplicação, irá perceber que a imagem de cores não está mais sendo exibida.
A primeira funcionalidade que vamos implementar será o reconhecimento de
humanos pelo Kinect utilizando o player segmentation data. Vamos criar um mé-
todo para fazer isso, mas antes é necessário também inicializar
o fluxo de esqueleto, conforme mencionamos anteriormente.
Este método se chamará ReconhecerHumanos, ele receberá por parâme-
tro um quadro de profundidade ( DepthImageFrame) e deverá retornar um ob-
jeto BitmapSource para preencher o componente de imagem de nossa apli-
cação.
Para poder fazer a validação do pixel de acordo com o player seg-
mentation data, devemos criar um array do tipo DepthImagePixel, que irá
receber todas as informações do quadro de profundidade através do método
CopyDepthImagePixelDataTo. Cada pixel deste array possui as propriedades
PlayerIndex, Depth e IsKnownDepth, que representam respectivamente: o ín-
dice do usuário a qual o pixel pertence (zero quando o pixel não pertence a nenhum usuário), a distância do pixel ao sensor em milímetros e se o sensor consegue identificar a distância do pixel.
Após receber estas informações precisamos criar um novo array de bytes para
gerar a imagem que será retornada no método. Este array deve ter quatro vezes o tamanho do array que representa os pixels de profundidade, pois conforme vimos
antes, cada pixel de cor possui 4 bytes. Iremos percorrer este novo array e verificare-mos se o byte referente ao mesmo pixel na imagem de profundidade pertence a um
usuário ou não, caso pertença iremos pintar este pixel de verde. O código a seguir ilustra como esta implementação deve ser feita.
private BitmapSource ReconhecerHumanos
(DepthImageFrame quadro)
{
52
Casa do Código
Capítulo 5. Fluxo de Profundidade
if (quadro == null) return null;
using (quadro)
{
DepthImagePixel[] imagemProfundidade =
new DepthImagePixel[quadro.PixelDataLength];
quadro.CopyDepthImagePixelDataTo(imagemProfundidade);
byte[] bytesImagem = new byte[imagemProfundidade.Length * 4];
for (int indice = 0; indice < bytesImagem.Length; indice+=4)
{
if (imagemProfundidade[indice / 4].PlayerIndex != 0)
{
bytesImagem[indice + 1] = 255;
}
}
return BitmapSource.Create(quadro.Width, quadro.Height,
96, 96, PixelFormats.Bgr32, null, bytesImagem,
quadro.Width * 4);
}
}
Você não deve ter muitos problemas em compreender o código do mé-
todo ReconhecerHumanos, pois em diversos pontos ele é similar ao método
ObterImagemSensorRGB criado no capítulo anterior. Note que nesta implemen-
tação inserimos o valor 255 apenas no byte referente à cor verde do RGB. Feito isso, você já deve conseguir executar a aplicação e obter um resultado semelhante ao da figura 5.2.
53
5.3. Aplicação
Casa do Código
Figura 5.2: Reconhecedor de Humanos
Como você pode notar, esta funcionalidade não é perfeita, mas possui um re-
sultado muito bom. Que tal agora fazermos uma combinação entre os dois sensores utilizados neste capítulo e no capítulo anterior? Pois bem, esta nova implementa-
ção fará com que o nosso componente de imagem da aplicação exiba todo o cenário através do sensor de cores (como fizemos no capítulo anterior), mas utilizará escala cinza somente nos pixels que estão em uma distância menor que 2 metros do sensor.
O primeiro passo para cumprir esta implementação é reativar o fluxo de cores.