Si vous n’avez pas déjà téléchargé le SDK Kinect il est disponible à cette adresse :http://research.microsoft.com/en-us/um/redmond/projects/kinectsdk/ mais attention il ne peut pas être utilisé à des fins commerciales.
Télécharger le code source.
La procédure d’installation est simple et rapide, moins de 100MB,
La documentation, les librairies et les fichiers d’entêtes sont disponibles ici
C:\Program Files (x86)\Microsoft Research KinectSDK
Les exemples de code ici :
C:\Users\Public\Documents\Microsoft Research KinectSDK Samples
Architecture
Le capteur Kinect envoie vers le système un ensemble de trois flux :
Quand Kinect suit précisément une personne, elle peut fournir au développeur un squelette formé de points 20 points clefs détectés sur la personne comme illustré en couleur sur la figure suivante:
En bas à droite le capteur de profondeur.
Mise en œuvre.
Tout d’abord, il faut inclure le fichier d’entête MSR_NuiApi.h, puis se lier à la librairie MSRKinectNUI.lib
Ces deux fichiers ont pour préfixe MSR, ce qui indique leur provenance, Microsoft Research. A n’utiliser donc qu’à des fins de recherches et non commerciales.
Remarques: L’installation du SDK Kinect créée une variable d’environnement $(MSRKINECTSDK) que vous pouvez utiliser en tant que référence aux fichiers d’entête et librairie. $(MSRKINECTSDK)\inc $(MSRKINECTSDK)\lib
Bien que vous puissiez utiliser le SDK Kinect sur un Windows 7 32/64 Bits, la librairie n’existe qu’en 32 Bits.
Il faut tout d’abord initialiser Kinect, à l’aide de l’API NuiInitialize() en lui passant une combinaison de drapeau. Ici nous décidons de recevoir des images (NUI_INITIALIZE_FLAG_USES_COLOR), de traquer le squelette, c’est-à-dire les 20 points (NUI_INITIALIZE_FLAG_USES_SKELETON) et de recevoir du capteur de profondeur, à la fois les informations de profondeurs, mais également l’index du « player », c’est-à-dire des personnes qui seront reconnues NUI_INITIALIZE_FLAG_USES_DEPTH_AND_PLAYER_INDEX), comme nous le détaillerons dans un second billet.
hr = NuiInitialize(NUI_INITIALIZE_FLAG_USES_DEPTH_AND_PLAYER_INDEX | NUI_INITIALIZE_FLAG_USES_SKELETON | NUI_INITIALIZE_FLAG_USES_COLOR);
Pour arrêter la capture il faut utiliser l’API NuiShutdown().
NuiShutdown();
Pour débuter avec le SDK Kinect, la première opération que nous allons faire c’est de capturer les images afin de les afficher et en créer une vidéo. Pour récupérer les images, il faut ouvrir un flux à l’aide de l’API NuiImageStreamOpen() comme suit :
Pour récupérer la trame suivante, nous allons utiliser le mode polling, c’est-à-dire dans une boucle sans fin, l’API NuiImageStreamGetNextFrame de la manière suivante :
HRESULT hr = NuiImageStreamGetNextFrame( _videoStreamHandle, 0, &pImageFrame );
HRESULT DPEKinectHelper::KinDemarrerVideo() { while(true) { if (Context::IsCurrentTaskCollectionCanceling ()) { break; } _pD2D1Helper->D2D1GetContexteRendu()->BeginDraw (); _pD2D1Helper->D2D1PeindreArrierePlan (); const NUI_IMAGE_FRAME * pImageFrame = NULL; WaitForSingleObject (_videoNextFrame,INFINITE); HRESULT hr = NuiImageStreamGetNextFrame( _videoStreamHandle, 0, &pImageFrame ); if(SUCCEEDED(hr)) { NuiImageBuffer * pTexture = pImageFrame->pFrameTexture; KINECT_LOCKED_RECT LockedRect; pTexture->LockRect( 0, &LockedRect, NULL, 0 ); if( LockedRect.Pitch != 0 ) { BYTE * pBuffer = (BYTE*) LockedRect.pBits; hr=_pD2D1Helper->D2D1DrawFrame (pBuffer,LockedRect.Pitch,640,480); hr=pTexture->UnlockRect (0); } else { OutputDebugString( L"Longueur du buffer erronée\r\n" ); } hr=NuiImageStreamReleaseFrame(_videoStreamHandle, pImageFrame ); } _pD2D1Helper->D2D1GetContexteRendu()->EndDraw(); }
}
Notes : Avant de récupérer la trame suivante, nous attendons que le runtime NUI nous signale sa disponibilité. WaitForSingleObject (_videoNextFrame,INFINITE);
Et pour éviter de figer l’interface graphique, j’encapsule tout ce petit monde dans une tâche que je peux arrêter à n’importe quel moment. _tasks=new task_group (); _tasks->run ([=]() { HRESULT hr=S_OK; hr=_KinectHelper->KinDemarrerVideo(); if (FAILED(hr)) { AfficherMessageErreur(_hWnd,hr,_hInst); _tasks->cancel (); } });
Pour savoir si une tâche est en cours d’arrêt, j’utilise ici le contexte courant if (Context::IsCurrentTaskCollectionCanceling ()) { break; }
Dans le second billet nous abordons la manière de manipuler les informations de profondeurs. Comment développer avec le SDK Kinect en C++ Part II
Eric Vernié
Pour information, voici le listing Direct2D (incomplet) de la méthode d’affichage d’une trame HRESULT DPEDirectD2D1helper::D2D1DrawFrame(BYTE* frame, UINT32 pitch,UINT32 width,UINT32 height) { HRESULT hr=S_OK; D2D1_SIZE_U size; size.height =height; size.width =width; D2D1_BITMAP_PROPERTIES properties=D2D1::BitmapProperties (); properties.pixelFormat.format =DXGI_FORMAT_B8G8R8A8_UNORM ; properties.pixelFormat.alphaMode =D2D1_ALPHA_MODE_PREMULTIPLIED; hr=_pcontexteRenduD2D1->CreateBitmap(size, frame, pitch, properties,&_pD2D1Frame); _pD2D1Frame->AddRef (); if (SUCCEEDED(hr)) { RECT rc; GetClientRect(_pcontexteRenduD2D1->GetHwnd (),&rc); D2D1_RECT_F rect; rect.top =(FLOAT)rc.top ; rect.bottom =(FLOAT)rc.bottom ; rect.right =(FLOAT)rc.right; rect.left =(FLOAT)rc.left; _pcontexteRenduD2D1->DrawBitmap (_pD2D1Frame,&rect); } SafeRelease (&_pD2D1Frame); return hr; }