在众多图像库中,FreeImage具有以下优势:开源;比OpenCV稳定;比CxImage调用简单(一个.h文件、一个dll文件、一个lib文件);相比于CxImage,还提供参考文档,学习起来更加方便(另外一个原因则是运用CxImage在Picture Control中显示Kinect的彩色数据搞了半天没成功)。所以最后选择FreeImage作为图像库进行Kinect的开发。
1、创建基于对话框的应用程序,添加一个picture control,ID为IDC_COLOR_PICBOX;
2、配置好Kinect SDK和FreeImage的包含目录、库目录、附加依赖项,添加#include"FreeImage.h";
3、定义结构体,便于在多线程中传递参数;
struct ColorDisplayPara
{
CStatic *picBox;
INuiSensor* pNuiSensor;
HANDLE hColorStreamHandle;
HANDLE hNextColorFrameEvent;
};
4、按照Toolkit提供的demo编写创建Kinect联接的函数
HRESULT CKinectMultiThreadDisplayColorFrameDlg::CreateFirstConnected(void)
{
INuiSensor * pNuiSensor;
HRESULT hr;
int iSensorCount = 0;
hr = NuiGetSensorCount(&iSensorCount);
if (FAILED(hr))
{
return hr;
}
// Look at each Kinect sensor
for (int i = 0; i < iSensorCount; ++i)
{
// Create the sensor so we can check status, if we can't create it, move on to the next
hr = NuiCreateSensorByIndex(i, &pNuiSensor);
if (FAILED(hr))
{
continue;
}
// Get the status of the sensor, and if connected, then we can initialize it
hr = pNuiSensor->NuiStatus();
if (S_OK == hr)
{
m_ColorDisPlayPara.pNuiSensor = pNuiSensor;
break;
}
// This sensor wasn't OK, so release it since we're not using it
pNuiSensor->Release();
}
if (NULL != m_ColorDisPlayPara.pNuiSensor)
{
// Initialize the Kinect and specify that we'll be using color
hr = m_ColorDisPlayPara.pNuiSensor->NuiInitialize(NUI_INITIALIZE_FLAG_USES_COLOR);
if (SUCCEEDED(hr))
{
// Create an event that will be signaled when color data is available
m_ColorDisPlayPara.hNextColorFrameEvent = CreateEvent(NULL, TRUE, FALSE, NULL);
// Open a color image stream to receive color frames
hr = m_ColorDisPlayPara.pNuiSensor->NuiImageStreamOpen(
NUI_IMAGE_TYPE_COLOR,
NUI_IMAGE_RESOLUTION_640x480,
0,
2,
m_ColorDisPlayPara.hNextColorFrameEvent,
&m_ColorDisPlayPara.hColorStreamHandle);
}
}
if (NULL == m_ColorDisPlayPara.pNuiSensor || FAILED(hr))
{
//SetStatusMessage(L"No ready Kinect found!");
return E_FAIL;
}
m_ColorDisPlayPara.picBox=(CStatic*)GetDlgItem(IDC_COLOR_PICBOX);
return hr;
}
主要是把对话框上添加的picturecontrol赋给结构体的picBox变量;
5、在OnInitialDialog函数中加入下面两行代码,第二行的函数代码创建一个新的线程显示彩色数据
CreateFirstConnected();
HANDLE hThread=CreateThread(NULL,0,(LPTHREAD_START_ROUTINE)processColor,&m_ColorDisPlayPara,0,NULL);
6、第五步对应的线程函数为:
DWORD processColor(ColorDisplayPara* param)
{
ColorDisplayPara* myPara=(ColorDisplayPara*)param;
while(1)
{
if (0 == WaitForSingleObject(myPara->hNextColorFrameEvent, INFINITE) )
{
HRESULT hr;
NUI_IMAGE_FRAME imageFrame;
// Attempt to get the color frame
hr = myPara->pNuiSensor->NuiImageStreamGetNextFrame(myPara->hColorStreamHandle, 0, &imageFrame);
if (FAILED(hr))
{
//return;
}
INuiFrameTexture * pTexture = imageFrame.pFrameTexture;
NUI_LOCKED_RECT LockedRect;
// Lock the frame data so the Kinect knows not to modify it while we're reading it
pTexture->LockRect(0, &LockedRect, NULL, 0);
// Make sure we've received valid data
if (LockedRect.Pitch != 0)
{
FIBITMAP *freeImage=FreeImage_Allocate(640,480,24);
BYTE* pData=FreeImage_GetBits(freeImage);
for (int i=0;i<FreeImage_GetHeight(freeImage);i++)
{
uchar *pBuffer = (uchar*)(LockedRect.pBits) + i * LockedRect.Pitch;
for (int j=0;j<FreeImage_GetWidth(freeImage);j++)
{
pData[(FreeImage_GetHeight(freeImage)-i)*FreeImage_GetPitch(freeImage)+3*j] = pBuffer[4*j]; //内部数据是4个字节,0-1-2是BGR,第4个现在未使用
pData[(FreeImage_GetHeight(freeImage)-i)*FreeImage_GetPitch(freeImage)+3*j+1] = pBuffer[4*j+1];
pData[(FreeImage_GetHeight(freeImage)-i)*FreeImage_GetPitch(freeImage)+3*j+2] = pBuffer[4*j+2];
}
}
int w=FreeImage_GetWidth(freeImage);
int h=FreeImage_GetHeight(freeImage);
BITMAPINFO info;
memset(&info,0,sizeof(BITMAPINFO));
info.bmiHeader.biSize=sizeof(BITMAPINFOHEADER);
info.bmiHeader.biBitCount=24;
info.bmiHeader.biPlanes=1;
info.bmiHeader.biWidth=w;
info.bmiHeader.biHeight=h;
HDC Hdc=myPara->picBox->GetDC()->GetSafeHdc();
RECT rect;
GetClientRect(myPara->picBox->GetSafeHwnd(),&rect);
int desW=rect.right-rect.left;
int desH=rect.bottom-rect.top;
SetStretchBltMode(Hdc,COLORONCOLOR);
if (desH==h&&desW==w)
{
StretchDIBits(Hdc,0,0,w,h,0,0,w,h,pData,&info,DIB_RGB_COLORS,SRCCOPY);
}
else
{
float fScale=(float)(w*desH)/(float)(h*desW);
if (fScale>1.0f)
{
desH=(int)(desH/fScale);
}
else
{
desW=(int)(desW*fScale);
}
StretchDIBits(Hdc,0,0,desW,desH,0,0,w,h,pData,&info,DIB_RGB_COLORS,SRCCOPY);
}
if (freeImage)
{
FreeImage_Unload(freeImage);
freeImage=NULL;
}
}
// We're done with the texture so unlock it
pTexture->UnlockRect(0);
// Release the frame
myPara->pNuiSensor->NuiImageStreamReleaseFrame(myPara->hColorStreamHandle, &imageFrame);
}
}
}
注意bmp格式像素的位置,需要上下颠倒位图数据(红色部分)才能正常的显示,否则显示的图像是倒立的。
运行结果如下,对话框可以随意移动。