座標映射
本文解釋瞭如何通過windows SDK將獲得到的原始數據進行座標空間的映射。
三個座標空間
相機空間
相機空間指的是kinect使用的3D空間座標。它是這樣定義的:
- 座標原點(x=0,y=0,z=0)位於kinect的紅外相機中心。
- X軸方向爲順着kinect的照射方向的左方向
- Y軸方向爲順着kinect的照射方向的上方向
- z軸方向爲順着kinect的照射方向
- 座標單位爲米(m)
注意!這是一個右手座標系,這與計算機圖形學中定義的相機空間是一致的,但是有的環境是使用左手座標系的,比如Unity。
深度圖像空間
深度圖像空間用來描述深度圖片上的位置。x代表列,y代表行,(x,y)就表示深度圖上的一個像素座標。(0,0)對應於圖片的左上角,而(511,423)代表着圖片的右下角。
In some cases, a z value is needed to map out of depth space. For
these cases, simply sample the depth image at the row/column in
question, and use that value (which is depth in millimeters) directly
as z.
我們經常會用深度圖來得到一個點雲,這種情況下就要用到深度圖像空間到相機空間的反投影。注意如果一個點一個點地去反投影,這樣開銷太大。所以推薦你使用MapDepthPointsToCameraSpace,GetDepthFrameToCameraSpaceTable這樣的函數。
如果你還想知道深度圖上每個像素對應的紅外強度值,你可以直接從紅外圖像中讀取相同座標位置的像素,因爲深度圖和紅外圖都是一個傳感器得到的。
如果你還想知道深度圖上每個像素對應的彩色值,你會用到Coordinate mapping類來獲得彩色圖上對應的像素位置。
彩色圖像空間
首先要知道在kinect上,彩色相機是和紅外相機有一定平移距離的,它們觀察的視角也就不相同,再加上深度圖和彩色圖的分辨率不同因此得到的圖像也就不能按像素直接對應。類似深度圖像空間。x代表列,y代表行,(x,y)就表示深度圖上的一個像素座標。(0,0)對應於圖片的左上角,而(1919,1079)代表着圖片的右下角。
深度空間映射到彩色圖像空間常用於背景消除。只需要先從人物索引圖像中確定哪些深度像素屬於用戶,然後通過座標映射,找到對應的彩色值。
Coordinate mapping類
Coordinate mapping類主要完成下面的兩個功能:
- 將3D相機座標空間中的座標投影到2D的深度圖中,或從深度圖中反投影到相機座標空間。
- 找到深度圖和彩色圖中的對應的像素位置。
成員函數:
- GetCoordinateMappingChangedEventData
- GetDepthCameraIntrinsics:獲得ir相機參數(出廠已寫入設備)
- GetDepthFrameToCameraSpaceTable
- MapCameraPointsToColorSpace
- MapCameraPointsToDepthSpace
- MapCameraPointToColorSpace
- MapCameraPointToDepthSpace
- MapColorFrameToCameraSpace
- MapColorFrameToDepthSpace
- MapDepthFrameToCameraSpace
- MapDepthFrameToColorSpace
- MapDepthPointsToCameraSpace
- MapDepthPointsToColorSpace
- MapDepthPointToCameraSpace
- MapDepthPointToColorSpace
- SubscribeCoordinateMappingChanged
- UnsubscribeCoordinateMappingChanged
深度圖映射到彩色圖
這裏用深度圖映射到彩色圖展示Coordinate mapping類的功能。
注意映射的概念,比如深度圖映射到彩色圖的意思是對於深度圖上的一個像素,找到彩色圖上的一個像素與之對應(與函數中x到y的映射概念類似)。
- 獲得深度幀:
hr = m_pDepthFrameReader->AcquireLatestFrame(&m_pDepthFrame);
- 保存深度數據到數組
UINT16 *depthData = new UINT16[424*512];
hr = m_pDepthFrame->CopyFrameDataToArray(424 * 512, depthData);
- 獲得座標映射器:
ICoordinateMapper* m_pCoordinateMapper;
hr = m_pKinectSensor->get_CoordinateMapper(&m_pCoordinateMapper);
- 進行映射:
HRESULT hr = m_pCoordinateMapper->MapDepthFrameToColorSpace(512 * 424, depthData, 512 * 424, m_pColorCoordinates);
這裏m_pColorCoordinates是最終得到的512*424大小的數組,元素爲一個個座標,代表了對應的彩色圖上的座標。
- 顯示:
Mat i_depthToRgb(424, 512, CV_8UC4);
if (SUCCEEDED(hr))
{
for (int i = 0; i < 424 * 512; i++)
{
ColorSpacePoint p = m_pColorCoordinates[i];
if (p.X != -std::numeric_limits<float>::infinity() && p.Y != -std::numeric_limits<float>::infinity())
{
int colorX = static_cast<int>(p.X + 0.5f);
int colorY = static_cast<int>(p.Y + 0.5f);
if ((colorX >= 0 && colorX < 1920) && (colorY >= 0 && colorY < 1080))
{
i_depthToRgb.data[i*4] = i_rgb.data[(colorY * 1920 + colorX)*4];
i_depthToRgb.data[i*4 + 1] = i_rgb.data[(colorY * 1920 + colorX) * 4+1];
i_depthToRgb.data[i*4 + 2] = i_rgb.data[(colorY * 1920 + colorX) * 4+2];
i_depthToRgb.data[i*4 + 3] = i_rgb.data[(colorY * 1920 + colorX) * 4+3];
}
}
}
}
imshow("rgb2depth", i_rgbToDepth);
if (waitKey(1) == VK_ESCAPE)
break;
下圖左側表示的是原始的深度圖,右側是深度圖映射到彩色圖後,得到的彩色圖。