Agora nossos três fluxos estarão ligados simultaneamente, mas não iremos interpretar os eventos ColorFrameReady e DepthFrameReady. Ao invés disso utili-
zaremos o evento AllFramesReady, pois através dele poderemos acessar tanto o
quadro de profundidade quanto o quadro de cores.
private void InicializarKinect(KinectSensor kinectSensor)
{
kinect = kinectSensor;
54
Casa do Código
Capítulo 5. Fluxo de Profundidade
slider.Value = kinect.ElevationAngle;
kinect.DepthStream.Enable();
kinect.SkeletonStream.Enable();
kinect.ColorStream.Enable();
kinect.AllFramesReady += kinect_AllFramesReady;
}
private void kinect_AllFramesReady
(object sender, AllFramesReadyEventArgs e)
{
}
Precisamos alterar o método ObterImagemSensorRGB para retornar o array
de bytes da imagem e não mais o objeto BitmapSource, pois agora precisamos
reutilizar os bytes da imagem no método que reconhecerá a distância dos objetos
além disso, não é mais necessário deixar a lógica de programação referente à escala cinza neste método. Após
estas alterações o método irá se parecer com o método
ilustrado a seguir.
private byte[] ObterImagemSensorRGB(ColorImageFrame quadro)
{
if (quadro == null) return null;
using (quadro)
{
byte[] bytesImagem = new byte[quadro.PixelDataLength];
quadro.CopyPixelDataTo(bytesImagem);
return bytesImagem;
}
}
O método ficou mais simples, pois agora ele apenas retorna os bytes da imagem.
Agora, é a vez de criarmos um novo método chamado ReconhecerDistância,
que deve receber por parâmetro os bytes da imagem e a distância máxima dos objetos para aplicar a escala cinza. A lógica para a escala cinza que foi removida do método anterior deve ser incorporada para este método dentro do bloco de validação da
distância do sensor conforme código.
55
5.3. Aplicação
Casa do Código
private void ReconhecerDistancia
(DepthImageFrame quadro, byte[] bytesImagem, int distanciaMaxima)
{
if (quadro == null || bytesImagem == null) return null;
using (quadro)
{
DepthImagePixel[] imagemProfundidade =
new DepthImagePixel[quadro.PixelDataLength];
quadro.CopyDepthImagePixelDataTo(imagemProfundidade);
for (int indice = 0;
indice < imagemProfundidade.Length;
indice++)
{
if (imagemProfundidade[indice].Depth < distanciaMaxima)
{
int indiceImageCores = indice * 4;
byte maiorValorCor =
Math.Max(bytesImagem[indiceImageCores],
Math.Max(bytesImagem[indiceImageCores + 1],
bytesImagem[indiceImageCores + 2]));
bytesImagem[indiceImageCores] = maiorValorCor;
bytesImagem[indiceImageCores + 1] = maiorValorCor;
bytesImagem[indiceImageCores + 2] = maiorValorCor;
}
}
}
Note que este método não retorna mais o objeto
BitmapSource, isso
ocorre pois criaremos a imagem dentro do método que interpreta o evento
AllFramesReady.
Neste método, sempre iremos captar a imagem do sen-
sor de cores, mas aplicaremos o filtro de escala cinza criado no método
ReconhecerDistância apenas quando o CheckBox Escala cinza estiver mar-
cado, conforme o código a seguir.
private void kinect_AllFramesReady
(object sender, AllFramesReadyEventArgs e)
{
56
Casa do Código
Capítulo 5. Fluxo de Profundidade
byte[] imagem = ObterImagemSensorRGB(e.OpenColorImageFrame());
if (chkEscalaCinza.IsChecked.HasValue &&
chkEscalaCinza.IsChecked.Value)
ReconhecerDistancia(e.OpenDepthImageFrame(), imagem, 2000);
if (imagem != null)
imagemCamera.Source =
BitmapSource.Create(kinect.ColorStream.FrameWidth,
kinect.ColorStream.FrameHeight,
96, 96, PixelFormats.Bgr32, null,
imagem,
kinect.ColorStream.FrameBytesPerPixel
* kinect.ColorStream.FrameWidth);
}
Se tudo foi implementado de maneira correta, o resultado que teremos deverá
ser similar ao resultado ilustrado pela figura 5.3.
57
5.3. Aplicação
Casa do Código
Figura 5.3: Escala cinza por distância
Você deve ter percebido que os pixels em escala cinza não estão perfeitamente
alinhados onde deveriam, isso fica bastante claro na figura 5.3. Este problema de alinhamento ocorre devido ao fato de que os dois sensores: cor e profundidade ficam em locais físicos diferentes. Para nos ajudar com este problema, existem técnicas de mapeamento, que são feitas através da classe CoordinateMapper.
A classe CoordinateMapper faz a transformação de um sistema de coordena-
das para outro entre os fluxos do Kinect. Infelizmente para fazer isso há uma perda no tamanho total da imagem, já que para equalizar os pontos é obrigatório que seja feita uma intersecção entre as visões dos diferentes sensores.
Utilizaremos a classe para mapear os pontos da imagem de profundidade em
um array de tamanho 640x480 (devido ao formato dos fluxos selecionados) e verificar a profundidade através destes pontos mapeados. Além disso, uma outra técnica que nos ajuda a melhorar a qualidade do resultado é verificar se o ponto de profundidade é um ponto reconhecido pelo Kinect. Após estas mudanças o método
ReconhecerDistancia deve ficar como o código adiante.
58
Casa do Código
Capítulo 5. Fluxo de Profundidade
private void