Kinect + Emgu

Descupem lá a inactividade nos ultimos tempos. mas ter um trabalho a tempo inteiro e ter namorada as vezes deixa-nos sem tempo.

Comecei a brincar com Computer Vision e Kinect, não fiz grande coisa e desconhecia por completo como CV funciona e depois de ler um um pouco soube que o Emgu é um grande wrapper para a biblioteca do OpenCV.
De facto é possivel fazer reconhecimento facial sem grandes stresses.
Vamos la meter as mãos à obra neste biblioteca
Para este exemplo precisamos de:
e para tornar as coisas ainda mais faceis Coding4Fun Kinect Toolkit
Este ultima dll é excelent para passar os dados raw do kinect para bitmaps
Recomendo vivamente a lerem a documentação do Emgu, pode ser tricky para usar.
Então vamos começar por criar um novo windows project, depois vamos inserir todas as referencias
Adicionamo o Microsoft.Research.Kinect que pode ser encontrado nas referencias .NET. Depois é Coding4Fun dll, e todas as dlls necessarias para o Emgu.
Como podem ver o Emgu tem montes de referencias na pasta bin e devem colocar tambem as unmanage libraries como a
cvextern.dll, opencv_calib3d220 e por ai a fora… Como já referi, leiam a documentação do emgu…
Na vista de design adicionei o controlo EmguCV.UI.ImageBox e chamei-o de imageBox1.
No codigo adicionei isto:
using Emgu.CV;
using Emgu.CV.UI;
using Emgu.CV.Structure;
using Emgu.Util;
using Emgu.CV.CvEnum;
using Microsoft.Research.Kinect.Nui;
using Coding4Fun.Kinect.WinForm;
Estes são os usings que necessitam
e para isto tudo funcionar precisam destes objectos
Kinect.Nui.Runtime,
Emgu.CV.Image
e visto que vamos tentar detectar caras usando o algoritmo HaarCascade vamos usar o objecto HaarCascade.
O algortimo HaarCascade necessita de um ficheiro xml para aprender os padrões de moo a reconhecer caras, existem montes de ficheiros desses na internet e podem criar o vosso proprio ficheiro usando este  guia como exemplo (Existem muitos mais guias acerca deste topico)
ok então…
haar = new HaarCascade("haarcascade_frontalface_alt_tree.xml");

vai pupolar o objecto haar com o ficheiro xml

Bom agora vamos inicializar o kinect. Para isto apenas necessitamos da camera RGBpor isso vamos usar r RuntimeOption.UseColor.
Precisamos tambem de criar  evento VideoFrameReady para conseguir capturar a imagem e de seguia abrimos um VideoStream
Para quem não esta familiarizado com o metodo VideoStream.Open,  ele suporta 4 parametros: ImageStreamType, poolSize (o valor minimo é  2, isto vai funcionar como backbuffer para gravar dados em memoria), ImageResolution e finalmente ImageType:
kinect.Initialize(RuntimeOptions.UseColor);
kinect.VideoFrameReady += new EventHandler(kinect_VideoFrameReady);
kinect.VideoStream.Open(ImageStreamType.Video, 2, ImageResolution.Resolution640x480, ImageType.Color);
e pronto, o constructor deve ter este aspecto:
public Form1()
{
      InitializeComponent();
      haar = new HaarCascade("haarcascade_frontalface_alt_tree.xml");
      kinect.Initialize(RuntimeOptions.UseColor);
      kinect.VideoFrameReady += new EventHandler(kinect_VideoFrameReady);
      kinect.VideoStream.Open(ImageStreamType.Video, 2, ImageResolution.Resolution640x480, ImageType.Color);
}

Agora que ja temos o event hanler do VideoFrameReady, ele vai receber no ImageFreameReayEventArgs todos os dados relevantes acerca da imagem. A primeira tarefa vai ser converter a imagem capturada num bitmap e converte-la outra vez para uma imagem do Emgu, de modo a podermos processa-la

 

 

 Image kinImage = new Image(e.ImageFrame.ToBitmap());
Ok ja temos uma image RGB no emgu e agora temos de converte-la para uma imagem em escala de cinzentos de modo a que o processamento do Emgu seja feito com melhor performance
Image grayframe = nextFrame.Convert();
e usamos o haarcascade para detectar todas as faces num determinado frame
 grayframe.DetectHaarCascade(
                                    haar, 1.4, 4,
                                    HAAR_DETECTION_TYPE.DO_CANNY_PRUNING,
                                    new Size(grayframe.Width / 8, grayframe.Height / 8)
                                    )[0];
…desenhamos um rectangulo a volta de cada face
  foreach (var face in faces)
{                         
    nextFrame.Draw(face.rect, new Bgr(0, double.MaxValue, 0), 3);                    
}
e finalmente desenhamos a imagem na imageBox1
imageBox1.Image = nextFrame;
para quem não gosta de ter trabalho aqui esta a source completa para fazer copy/paste:
void kinect_VideoFrameReady(object sender, ImageFrameReadyEventArgs e)
      {
            Image kinImage = new Image(e.ImageFrame.ToBitmap());
            using (Image; nextFrame = kinImage)
            {
                if (nextFrame != null)
                {
                    // there's only one channel (greyscale), hence the zero index
                    Image grayframe = nextFrame.Convert();
                    var faces =
                            grayframe.DetectHaarCascade(
                                    haar, 1.4, 4,
                                    HAAR_DETECTION_TYPE.DO_CANNY_PRUNING,
                                    new Size(grayframe.Width / 14, grayframe.Height / 14)
                                    )[0];
                    foreach (var face in faces)
                    {
                        nextFrame.Draw(face.rect, new Bgr(0, double.MaxValue, 0), 3);
                    }
                    imageBox1.Image = nextFrame;
                }
            }
        }
Como podem ver é codigo facil 😀
podem fazer o download do ficheiro .cs
Aqui esta uma demo deste codigo a funcionar, peço desculpa pelo framerate baixo, o software de captura que usei é muito mau, tambem a luminusidade não é a melhor mas são 2 a manha e a minha namorada ja dorme no sofa ao meu lado por isso é melhor não meter mais luz a menos que queira levar com o rolo da massa.
No entanto é um excente proof-of-concept pois mesmo com má iluminação funcionou :)
Em excelentes condições de luminusidade a detecção de faces funciona na perfeição

Kinect SDK + EmguCV

Acho que é melhor começar pelo basico

Vamos la tentar fazer login na aplicação atráves de detecção de faces :)

Hoje vou começa a criar alguns controlos para brincar com o kinect. O primeiro vai ser um controlo para login, acho que vai ficar brutal sobretudo se fizer reconhecimento facial e reconhecimento de voz para inserir a password.

Mais tarde irei colocar codigo sobre estes controlos :)