Modo de captura.
En este documento explicaremos como funciona el código para la captura de imágenes en 3D, guardarlas en un archivo .pcd y su representación gráfica para su visualización a través de librería VTK.#include <iostream>
#include <pcl/io/pcd_io.h>
#include <pcl/point_types.h>
#include <pcl/io/openni_grabber.h>
#include <pcl/visualization/cloud_viewer.h>
#include <string>
#include <sstream>
#include<pcl/common/time.h> //este include para compilar en pcl1.7
#ifdef _WIN32
# define sleep(x) Sleep((x)*1000)
#endif
class SimpleOpenNIViewer
{
public:
SimpleOpenNIViewer () : viewer ("PCL OpenNI Viewer") {}
void cloud_cb_ (const pcl::PointCloud<pcl::PointXYZRGBA>::ConstPtr &cloud)
{
static unsigned count = 0;
static unsigned int pcd_count = 1;
static double last = pcl::getTime ();
if (++count == 30)
{
double now = pcl::getTime ();
std::cout << "distance of center pixel :" << cloud->points [(cloud->width >> 1) * (cloud->height + 1)].z << " mm. Average framerate: " << double(count)/double(now - last) << " Hz" << std::endl;
count = 0;
last = now;
std::string name("nube_");
std::ostringstream number;
number << pcd_count;
name.append(number.str());
name.append(".pcd");
pcl::io::savePCDFileASCII (name, *cloud);
std::cout<<"Saved PCD: "<< name << endl;
pcd_count++;
}
if (!viewer.wasStopped())
viewer.showCloud (cloud);
}
void run ()
{
pcl::Grabber* interface = new pcl::OpenNIGrabber();
boost::function<void (const pcl::PointCloud<pcl::PointXYZRGBA>::ConstPtr&)> f =
boost::bind (&SimpleOpenNIViewer::cloud_cb_, this, _1);
interface->registerCallback (f);
interface->start ();
while (!viewer.wasStopped())
{
boost::this_thread::sleep (boost::posix_time::seconds (1));
}
interface->stop ();
}
pcl::visualization::CloudViewer viewer;
};
int main ()
{
SimpleOpenNIViewer v;
v.run ();
return 0;
}
En el encabezado tenemos:
#include <iostream>
#include <pcl/io/pcd_io.h>
#include <pcl/point_types.h>
#include <pcl/io/openni_grabber.h>
#include <pcl/visualization/cloud_viewer.h>
#include <string>
#include <sstream>
Donde vemos que utilizamos los paquetes io y visualization de la librería PCL, el paquete de openni_grabber.h, servirá para comunicarse con el sensor de captura y convertir los datos en el formato que utiliza PCL, luego el pcd_io.h servirá para operaciones de almacenamiento de la nube en archivos. Para visualizar la nube tenemos pcl/visualization/cloud_viewer.h. El resto de las librerías servirá para operaciones y declaración de variables sencillas.Es importante recordar que debemos añadir
#include<pcl/common/time.h> en el encabezado solo cuando compilemos con la nueva versión 1.7 en adelante.
Luego se declaran dos funciones dentro de una clase, la clase es llamada SimpleOpenNIViewer donde tiene dos funciones de llamada en las cuales se realizan las operaciones de adquisición de datos y almacenamiento en archivos.
Empecemos a ver lo que ocurre desde el cuerpo principal del código:
int main ()
{
SimpleOpenNIViewer v;
v.run ();
return 0;
}
Como vemos es un código muy corto en el cual primero se declara que vamos a realizar llamadas a la clase objetos de SimpleOpenNIViewer lo declaramos como "v" y luego llamamos a la función run().
Ahora vamos a ver que sucede en la función run(), que está definida con el código:
void run ()
{
pcl::Grabber* interface = new pcl::OpenNIGrabber();
boost::function<void (const pcl::PointCloud<pcl::PointXYZRGBA>::ConstPtr&)> f =
boost::bind (&SimpleOpenNIViewer::cloud_cb_, this, _1);
interface->registerCallback (f);
interface->start ();
while (!viewer.wasStopped())
{
boost::this_thread::sleep (boost::posix_time::seconds (1));
}
interface->stop ();
}
En esta función primero se declara que vamos a utilizar funciones de pcl::Grabber y la declaramos como puntero.Luego con ayuda de la biblioteca boost declaramos los datos que se utilizaran para entregar los datos de recogida de las funciones de Grabber. Finalmente vez declarados los datos que se utilizaran en la función, llamamos al sensor y entramos en el bucle hasta que se detenga por algún tipo de desbordamiento definido, y cada vez que entre ha este se detendrá un segundo, para refrescar la imagen.
Como vemos cada vez que entramos en el bucle no salimos por desbordamiento de variables ya explicadas, si no por la función viewer que no se ha ha explicado, pero es una etiqueta publica que esta descrita antes de entrar al cuerpo principal del código.
Luego que hemos activado la zona de visualizacion y activacion de adquisicion de la imagen, vamos a ver como funciona el algoritmo que guarda en un archivo pcd, y este esta enmascrado de la siguiente manera:
boost::function<void (const pcl::PointCloud<pcl::PointXYZRGBA>::ConstPtr&)> f =
boost::bind (&SimpleOpenNIViewer::cloud_cb_, this, _1);
Donde la función enmascarada es llamada cloud_cb_ el cual esta dentro de la clase definida en nuestro código:
void cloud_cb_ (const pcl::PointCloud<pcl::PointXYZRGBA>::ConstPtr &cloud)
{
static unsigned count = 0;
static unsigned int pcd_count = 1;
static double last = pcl::getTime ();
if (++count == 30)
{
double now = pcl::getTime ();
std::cout << "distance of center pixel :" << cloud->points [(cloud->width >> 1) * (cloud->height + 1)].z << " mm. Average framerate: " << double(count)/double(now - last) << " Hz" << std::endl;
count = 0;
last = now;
std::string name("nube_");
std::ostringstream number;
number << pcd_count;
name.append(number.str());
name.append(".pcd");
pcl::io::savePCDFileASCII (name, *cloud);
std::cout<<"Saved PCD: "<< name << endl;
pcd_count++;
}
if (!viewer.wasStopped())
viewer.showCloud (cloud);
}
Como vemos se definen variables estáticas, para que no desaparezca la zona de memoria cada vez que salimos de la función, estas variables nos servirán para formar la cadena de caracteres que dará nombre al archivo y para definir el tiempo que tarda cada imagen ser llamada.
Luego se hace un pequeño calculo de la distancia del pixel centrar y lo que hemos tardado en refrescarlo.
Posteriormente montamos la cadena de caracteres que formará la nube, que guardaremos mediante la expresión:
pcl::io::savePCDFileASCII (name, *cloud);
Por ultimo refrescamos los datos de la imagen que veremos mediantela consola de VTK.
Para poder compilar este archivo debemos de seguir las intruciones que se han dado en la entrada como usar pcl en su proyecto.
Consideraciones a la hora de capturar imágenes
Antes de empezar a correr el ejecutable debemos tener un dispositivo de captura dee imagenes 3D, los que se han probado que funcionan son los siguiente:- Microsoft Kinect.
-Asus XTionPRO.
- PSDK Reference.
-Fuji w3 3D.
-Minolta Range 5 3D.
Los errores de medida serán generados por la tecnología y no por el algoritmos.
Cuando tomemos imágenes con la kinect debemos de tener en cuenta que tiene una precisión limitada de 1cm de error para distancias comprendidas entre 1 a 7 metros.
La kinect genera una imagen de 640x480, generando píxeles con coordenadas y colores, cuando las coordenadas generan error las almacena como NaN , esto sucede en bordes o en distancias que no es capaz de llegar(sup a 7 metros).
No hay comentarios:
Publicar un comentario