c++ - kinect opengl tutorial
Kinect SDK: alinea la profundidad y colorea los marcos (5)
Estoy trabajando con el sensor Kinect y estoy tratando de alinear los marcos de profundidad y color para poder guardarlos como imágenes que "encajan" entre sí. He pasado mucho tiempo revisando los foros de MSDN y la documentación modesta de Kinect SDK y no estoy llegando a ningún lado.
Basado en esta respuesta: Kinect: conversión de coordenadas RGB a coordenadas de profundidad
Tengo la siguiente función, donde depthData
y colorData
se obtienen de NUI_LOCKED_RECT.pBits
y mappedData
es la salida que contiene un nuevo marco de color, asignado a las coordenadas de profundidad:
bool mapColorFrameToDepthFrame(unsigned char *depthData, unsigned char* colorData, unsigned char* mappedData)
{
INuiCoordinateMapper* coordMapper;
// Get coordinate mapper
m_pSensor->NuiGetCoordinateMapper(&coordMapper);
NUI_DEPTH_IMAGE_POINT* depthPoints = new NUI_DEPTH_IMAGE_POINT[640 * 480];
HRESULT result = coordMapper->MapColorFrameToDepthFrame(NUI_IMAGE_TYPE_COLOR, NUI_IMAGE_RESOLUTION_640x480, NUI_IMAGE_RESOLUTION_640x480, 640 * 480, reinterpret_cast<NUI_DEPTH_IMAGE_PIXEL*>(depthData), 640 * 480, depthPoints);
if (FAILED(result))
{
return false;
}
int pos = 0;
int* colorRun = reinterpret_cast<int*>(colorData);
int* mappedRun = reinterpret_cast<int*>(mappedData);
// For each pixel of new color frame
for (int i = 0; i < 640 * 480; ++i)
{
// Find the corresponding pixel in original color frame from depthPoints
pos = (depthPoints[i].y * 640) + depthPoints[i].x;
// Set pixel value if it''s within frame boundaries
if (pos < 640 * 480)
{
mappedRun[i] = colorRun[pos];
}
}
return true;
}
Todo lo que obtengo al ejecutar este código es un marco de color sin cambios con todos los píxeles eliminados (en blanco) donde depthFrame no tenía información.
Con el framework OpenNI existe una opción de registro de llamadas.
IMAGE_REGISTRATION_DEPTH_TO_IMAGE: la imagen de profundidad se transforma para tener el mismo punto de vista aparente que la imagen RGB.
OpenNI 2.0 y Nite 2.0 funcionan muy bien para capturar información de Kinect y hay muchos tutoriales.
Puedes echar un vistazo a esto:
Y OpenNi tiene un ejemplo en SimplerViewer que combina Profundidad y Color, tal vez solo puedas mirar eso y probarlo.
Creo que el problema es que estás llamando a MapColorFrameToDepthFrame, cuando deberías llamar a MapDepthFrameToColorFrame.
La pistola humeante es esta línea de código:
mappedRun[i] = colorRun[pos];
La lectura de pos
y la escritura a i
es al revés, ya que pos = depthPoints[i]
representa las coordenadas de profundidad correspondientes a las coordenadas de color en i
. Realmente desea iterar sobre escribir todas las coordenadas de profundidad y leer desde la imagen de color de entrada en las coordenadas de color correspondientes.
Creo que en tu código hay diferentes líneas no correctas.
En primer lugar, ¿qué tipo de mapa de profundidad está pasando a su función?
Los datos de profundidad se almacenan utilizando dos bytes para cada valor, lo que significa que el tipo correcto de puntero que debe usar para sus datos de profundidad no está corto .
El segundo punto es que, por lo que he entendido, usted desea asignar un marco de profundidad a un marco de color, por lo que la función correcta que debe llamar desde kinect sdk es MapDepthFrameToColorFrame en lugar de MapColorFrameToDepthFrame.
Finalmente, la función devolverá un mapa del punto donde para cada dato de profundidad en la posición [i], tiene la posición x y la posición y donde se debe asignar ese punto.
Para hacer esto no necesitas el puntero colorData .
Por lo que su función debe ser modificada como sigue:
/** Method used to build a depth map aligned to color frame
@param [in] depthData : pointer to your data;
@param [out] mappedData : pointer to your aligned depth map;
@return true if is all ok : false whene something wrong
*/
bool DeviceManager::mapColorFrameToDepthFrame(unsigned short *depthData, unsigned short* mappedData){
INuiCoordinateMapper* coordMapper;
NUI_COLOR_IMAGE_POINT* colorPoints = new NUI_COLOR_IMAGE_POINT[640 * 480]; //color points
NUI_DEPTH_IMAGE_PIXEL* depthPoints = new NUI_DEPTH_IMAGE_PIXEL[640 * 480]; // depth pixel
/** BE sURE THAT YOU ARE WORKING WITH THE RIGHT HEIGHT AND WIDTH*/
unsigned long refWidth = 0;
unsigned long refHeight = 0;
NuiImageResolutionToSize( NUI_IMAGE_RESOLUTION_640x480, refWidth, refHeight );
int width = static_cast<int>( refWidth ); //get the image width in a right way
int height = static_cast<int>( refHeight ); //get the image height in a right way
m_pSensor>NuiGetCoordinateMapper(&coordMapper); // get the coord mapper
//Map your frame;
HRESULT result = coordMapper->MapDepthFrameToColorFrame( NUI_IMAGE_RESOLUTION_640x480, width * height, depthPoints, NUI_IMAGE_TYPE_COLOR, NUI_IMAGE_RESOLUTION_640x480, width * height, colorPoints );
if (FAILED(result))
return false;
// apply map in terms of x and y (image coordinates);
for (int i = 0; i < width * height; i++)
if (colorPoints[i].x >0 && colorPoints[i].x < width && colorPoints[i].y>0 && colorPoints[i].y < height)
*(mappedData + colorPoints[i].x + colorPoints[i].y*width) = *(depthData + i );
// free your memory!!!
delete colorPoints;
delete depthPoints;
return true;
}
Asegúrese de que su mappedData se haya inicializado correctamente, por ejemplo, como sigue.
mappedData = (USHORT*)calloc(width*height, sizeof(ushort));
Recuerde que kinect sdk no proporciona una función de alineación precisa entre los datos de color y profundidad.
Si desea una alineación precisa entre dos imágenes, debe utilizar un modelo de calibración. En ese caso, le sugiero que utilice la Caja de herramientas de calibración de Kinect, basada en el modelo de calibración de Heikkilä.
Lo puedes encontrar en el siguiente enlace:
http://www.ee.oulu.fi/~dherrera/kinect/ .
En primer lugar, debe calibrar su dispositivo. Eso significa que debe calibrar el RGB y el sensor de IR y luego encontrar la transformación entre RGB e IR. Una vez que conozca esta información, puede aplicar la función:
RGBPoint = RotationMatrix * DepthPoint + TranslationVector
Consulte los proyectos OpenCV o ROS para obtener más detalles al respecto.
Puede que esta no sea la respuesta rápida que está esperando, pero esta transformación se realiza con éxito dentro del complemento ofxKinectNui para openFrameworks (consulte aquí) .
Parece que los delegados de ofxKinectNui
a la función GetColorPixelCoordinatesFromDepthPixel
definen here .