Sunteți pe pagina 1din 23

Desarrollo e Implementacin de un

Scanner 3D
Introduccin:
La reconstruccin 3D es el proceso mediante el cual, objetos reales, son
reproducidos en la memoria de una computadora, manteniendo sus
caractersticas fsicas (dimensiones, volumen y forma). Existen dentro de la
visin artificial, multitud de tcnicas de reconstruccin y mtodos de mallado
3D, cuyo objetivo principal es obtener un algoritmo que sea capaz de realizar la
conexin del conjunto de puntos representativos del objeto en forma de
elementos de superficie, ya sean tringulos, cuadrados o cualquier otra forma
geomtrica.
Los algoritmos desarrollados hasta el momento, se debaten entre el coste
computacional y la calidad del mallado obtenido. A priori, los algoritmos que
trabajan con nubes de puntos, tratan de obtener la denominada matriz de
conexiones. Esta matriz, almacena que puntos del conjunto inicial deben estar
conectados entre s. Si empleamos tringulos (mtodo bastante comn), esta
matriz tiene la forma de 3 x n (siendo el nmero total de tringulos que
contiene la pieza), es decir que cada fila de la matriz representa un tringulo
en el plano o en el espacio.
La eficiencia del algoritmo es la que define la calidad final del mallado. Si
suponemos un conjunto de puntos mal representado, existirn puntos definidos
que no cumplan las condiciones ptimas para el mallado. Los puntos que se
encuentran muy cercanos entre s, los puntos ruidosos y los puntos
redundantes, no ofrecen ninguna informacin para la reconstruccin.
Imaginemos por ejemplo, que si queremos representar un cubo en el espacio,
simplemente con ocho puntos y doce tringulos seran suficiente, el resto de la
informacin sera redundante.
En nuestro caso, la reconstruccin tridimensional, se realiza partiendo de
un conjunto de puntos demasiado grande, en el cual, una gran parte de los
puntos no ofrecen ninguna informacin y deben ser eliminados. Como se puede
ver en la Figura, la representacin de la nube de puntos (a la derecha), existen
puntos ruidosos y puntos innecesarios. El primer objetivo es la reduccin del
conjunto de puntos, que se detalla en el apartado siguiente.

Ejemplo de reduccin de puntos


Adquisicin de los datos
La adquisicin de los puntos, se ha realizado mediante un sistema de Luz
Estructurada (Range Image), el cual se encarga de realizar una serie de cortes
a la pieza, u objeto que se desea reconstruir, mediante un plano lser. Dentro
de este sistema un sensor CCD o cmara, se encarga de ir recogiendo las
imgenes que se producen cuando el plano lser incide sobre la pieza.
Despus, estas imgenes son debidamente procesadas aplicando una serie de
algoritmos cuyo resultado final es la obtencin de la nube de puntos del objeto.
Es muy importante realizar una buena calibracin del sistema ya que de
ello, depende fundamentalmente, el resultado obtenido. Dicha calibracin, se
ha realizado con un algoritmo bastante comn, mtodo de Tsai, el cual nos
proporciona los parmetros intrnsecos de la cmara, necesarios para realizar
el cambio, de coordenadas de la cmara 2D a coordenadas del mundo3D.

Sistema de luz estructurada

Sistema de luz estructurada del GVA


El formato de salida de los datos es un archivo ASCII que representa la matriz
de puntos ya en coordenadas X Y Z del mundo, estos puntos son la entrada de
los algoritmos de simplificacin. En ellos se ha tratado de reducir tanto el
volumen de la informacin, como el ruido producido por el sistema.
Una primera aplicacin para reducir el nmero de puntos, ha sido un algoritmo
de simplificacin que elimina puntos repetidos, puntos ruidosos que se
encuentran fuera de las dimensiones reales de la pieza y puntos en secciones
completas. El algoritmo est escrito en C++ y se muestra a continuacin:

Ejemplo de simplificacin de nube de puntos, se eliminan puntos del plano XZ


de valores menores a 15, as como 2 secciones de cada 4, puntos redundantes
y puntos del plano XY fuera de las coordenadas 25 y 150.
Otro mtodo empleado, ha sido la simplificacin de contornos. Est
basado en un script de Matlab, bastante recomendado para este caso ya que la
informacin, est contenida en planos paralelos al XY, sobre los cuales se
aplica la simplificacin y se obtiene resultados como los de la figura 6. El
algoritmo es bastante verstil ya que con dos parmetros que son la tolerancia
y el nmero de puntos por seccin, se simplifican los contornos de forma
variable.

Simplificacin de un contorno, el original tiene 166 puntos y se ha reducido en


el primer caso a 18, en el segundo a 14, en el tercero a y ltimo a 10.
Triangulacin Delaunay
Una vez minimizada y mejorada la calidad del conjunto de puntos, se
puede proceder a realizar el mallado triangular. En este caso se ha empleado el
algoritmo de Delaunay en 2D y 3D. Existe bastante informacin de cmo
aplicar el algoritmo en profundidad, por lo tanto no entraremos en detalles (ver
apartado Links). Como ejemplo de funcionamiento del algoritmo, en la figura,
se pueden introducir puntos y ver como se realiza la triangulacin.
La condicin de Delaunay dice que una red de tringulos es una triangulacin
de Delaunay si todas las circunferencias circunscritas de todos los tringulos de
la red son vacas. Esa es la definicin original para espacios bidimensionales.
Es posible ampliarla para espacios tridimensionales usando la esfera
circunscrita en vez de la circunferencia circunscrita. Tambin es posible
ampliarla para espacios con ms dimensiones pero no se usa en la prctica. La
arista p1p2 es legal mientras que p3p4 es una arista ilegal porque p2 cae
dentro del crculo que pasa por p3p1p4. Cuando se detecte una arista ilegal
hay que hacer un intercambio de la arista para convertirla en una legal.

Funcionamiento del algoritmo Delaunay.


La reconstruccin Delaunay 2D y 3D, se ha realizado con las libreras VTK
3.2, estn implementados en C++ utilizando las MFC, el cuadro de dialogo con
las opciones se muestran a continuacin:

Dialogo de la reconstruccin Delaunay 2D, 3D con opcin de exportar el


resultado a VRML.

Calibrar una cmara con OpenCV:

A la hora de trabajar con sistemas de visin 3D, uno de los primeros asuntos
que hay que abordar es la calibracin de las cmaras. Este es un factor
sumamente importante y, aunque uno quisiera ponerse manos a la obra lo
antes posible con el problema de visin 3D a resolver, es una tarea que hay
que realizar a conciencia para no comprometer la precisin de todo el sistema.
La calibracin puede ser un trabajo arduo especialmente cuando se tiene una
configuracin multiview, es decir, con muchas cmaras, pues hay que repetir el
proceso con cada una de ellas.
Afortunadamente, la librera OpenCV cuenta con un mdulo especial de
funciones para calibracin de cmaras y reconstruccin 3D que resulta de gran
ayuda: calib3d.
En esta entrada voy a explicar los pasos necesarios para hacer una buena
calibracin utilizando OpenCV.

La calibracin nos permite extraer informacin 3D a partir de imgenes 2D


capturadas con las cmaras. Esto es posible conociendo el modelo matemtico
de la figura anterior. La matriz de parmetros extrnsecos nos permite obtener

la proyeccin 2D sobre el plano de la cmara de las coordenadas 3D de un


punto de la escena. Mediante la matriz de parmetros intrnsecos conseguimos
las coordenadas 2D en pxeles de la imagen.
La realidad es que el modelo matemtico se complica con la inclusin de una
serie de coeficientes de distorsin intrnsecos de cada cmara. Pero no
necesitamos conocer a fondo el modelo matemtico para calibrar con OpenCV.
La idea es obtener todos estos parmetros una vez y almacenarlos. Los
intrnsecos se dividirn en: la matriz de la cmara (la matriz de intrnsecos de
la figura), y los coeficientes de distorsin. La matriz de extrnsecos se
descompone en 2 vectores: rotacin y traslacin. Los parmetros estarn
definidos de la siguiente manera:
//Intrnsecos:
cv::Mat cameraMatrix(3,3,CV_64FC1);
cv::Mat distCoeffs(8,1,CV_64FC1);
//Extrnsecos:
cv::Mat rvec(3,1,CV_64FC1);
cv::Mattvec(3,1,CV_64FC1);
Lo siguiente que vamos a necesitar es imprimir un patrn tipo tablero de
ajedrez (cuadrado o no) como el siguiente:

Este tablero debe ser un plano, por tanto es conveniente fijarlo sobre una base
plana rgida. En mi caso he usado una caja de cartn. Aunque en la imagen se
ve la esquina del papel algo despegada, lo importante es que se mantenga
plano el interior del patrn.
Funcin findChessboardCorners. Esta funcin recibe una imagen donde
aparezca el tablero, encuentra sus esquinas interiores y nos devuelve las
coordenadas en un vector. La imagen debe estar en niveles de gris. Adems,
hay que indicarle la cantidad de filas y columnas de nuestro tablero, pero no de
los casilleros, sino de las esquinas interiores:

const cv::Size patternsize(9,6);


vector<cv::Point2f> corners;
//Si la imagen es en color creamos una copia en gris:
cv::Mat gray;
cv::cvtColor(color, gray, CV_BGR2GRAY);//o CV_RGB2GRAY segn el caso.
bool found = cv::findChessboardCorners(gray,patternsize,corners);
La funcin devuelve true si encuentra el patrn en la imagen, false en caso
contrario. Una funcin complementaria esdrawChessboardCorners que nos
permite visualizar el resultado:
if(found) {
cv::drawChessboardCorners(color,patternsize,corners,found);
}

Esta funcin no es imprescindible, pero nos puede ayudar a comprobar si las


imgenes que vamos a utilizar para la calibracin son tiles o no. Tambin hay
que tener cuidado de guardarse una copia (copy=color.clone()) de cada imagen
antes de usar la funcin, ya que sta las modifica con esas lneas y crculos de
colores que se ven en la imagen.
Cuantas ms imgenes utilicemos ms precisa ser la calibracin. Adems, es
importante que el patrn aparezca en diferentes posiciones y poses para
obtener una buena dispersin de puntos sobre el plano de la cmara.

Una buena opcin es implementar una pequea funcin que nos permita con
un botn del teclado ir capturando imgenes en tiempo real a medida que
movemos el tablero enfrente de la cmara. Al pulsar el botn del teclado, la
funcin slo debera guardar una imagen si es til, o sea, si el patrn es
reconocido por la funcin findChessboardCorners.
Sobre bordes y gradiantes
El Gradiante de una imagen y los bordes de la misma: No son lo mismo!
Es cierto que el gradiante de una imagen revela la ubicacin de los bordes,
pero hay otras funciones que muestran los bordes de una imagen sin ser el
gradiante.
Por lo tanto, hay que tener cuidado, cuando algn algoritmo de procesamiento
requiere el clculo del gradiante, de no sustituirlo por un simple mapa de
bordes.
En Matlab: una forma de calcular el gradiente es el filtro de Sobel. Muy bien,
Matlab proporciona la funcin edge que, con la propiedad sobel, permite filtrar
una imagen y obtener sus bordes, sin embargo, aunque el gradiente
ciertamente es un detector de bordes, no es el gradiente lo que edge devuelve,
sino una imagen binarizada con cierto umbral que no refleja la magnitud ni el
signo de las derivadas del gradiente. La siguiente imagen muestra el resultado
que se obtendra. Observar que los bordes tienen magnitud 1 en todos sus
puntos.

Procedimiento de Calibracin de una cmara con OpenCV


1. Copia el archivo in_VID.xml
(OpenCV/samples/cpp/tutorial_code/calib3d/camera_calibration/in_VID.x
ml) a la siguiente ruta: OpenCV/build/bin.
2. Cambia el nombre a default.xml.

3. Abre una terminal y ve a la ruta OpenCV/build/bin.


4. Escribe:
$ ./calibration 0 -w 9 -h 6 -s 0.025 -o camera.yml -op oe
Details:
0 es el parmetro que identifica a tu cmara. Para ver cul es el nmero
de la cmara, abre una nueva terminal y escribe: ls /dev/video*. Si ves
/dev/video0 el nmero de la cmara ser el 0, para /dev/video1, nmero
1, y as ...
w 9. Es el ancho del tablero, en mi caso 9.
h 6. Es la altura del tablero.
s 0.024. Tamao en metros de los cuadrados.
o camera.yml. El archivo de calibracin de salida que ser creado.
Lo siguiente que vers ser una ventana con lo que ve tu cmara. Tendrs que
poner el tablero impreso en frente de ella en diferentes posiciones para que la
cmara
sea
calibrada.

Procedimiento realizado:

1. Usaremos como modelo a Scannear una silla de bicicleta

2. Calibrando el laser, con la cmara, procederemos


movimiento de rotacin que se hace sobre el objeto.

grabar

el

3. Esta grabacin servir para usarla en OpenCV, con lo cual podemos


extraer los puntos de las diferentes lneas dibujadas por el laser sobre la
superficie.
4. A continuacin haciendo uso del video, procedemos a usarlo con la
aplicacin.
#include
#include
#include
#include
#include
#include
#include
#define
#define
#define
#define
#define

"stdafx.h"
<opencv2\opencv.hpp>
<opencv\highgui.h>
<opencv\cv.h>
<opencv\cxcore.h>
<math.h>
<stdio.h>

PI 3.14159265
SIZE 200
// buffer size
MAXFRAMES 60
// maximum # video frames for 360 degrees
MAXCOLS 640
// video width
MAXROWS 480
// video heigth

CvPoint
centerPoint1, axisPoint1, axisPoint2, roiPoint1, roiPoint2;
IplImage*
frame, *frame2;
int
drag = 0; // defines if you are dragging the mouse
int
numPoints = 0; // used to count # of profile points found
CvScalar
c1;
const char* message = "";
char buf[SIZE];
CvFont font;
double hScale = 0.4; // font hScale
double vScale = 0.4; // font vScale
int lineWidth = 1; // font lineWidth
void on_mouse_axis(int event, int x, int y, int flags, void* param) {
/* user press left button */
if (event == CV_EVENT_LBUTTONDOWN && !drag) {
axisPoint1 = cvPoint(x, y);
drag = 1;
}

/* user drag the mouse */


if (event == CV_EVENT_MOUSEMOVE && drag) {
axisPoint2 = cvPoint(x, y);
frame2 = (IplImage*)cvClone(frame);
cvLine(
frame2,
axisPoint1,
axisPoint2,
CV_RGB(0, 0, 255),
1, CV_AA, 0
);
cvShowImage("3D SCANNER", frame2);
}

/* user release left button */


if (event == CV_EVENT_LBUTTONUP && drag) {
axisPoint2 = cvPoint(x, y);
frame2 = (IplImage*)cvClone(frame);
cvLine(
frame2,
axisPoint1,
axisPoint2,
CV_RGB(0, 0, 255),
1, CV_AA, 0
);
cvShowImage("3D SCANNER", frame2);
drag = 0;
}
/* user click right button: reset all */
if (event == CV_EVENT_RBUTTONUP) {
cvShowImage("3D SCANNER", frame);
drag = 0;
}

void on_mouse_center(int event, int x, int y, int flags, void* param) {


/* user press left button */
if (event == CV_EVENT_LBUTTONDOWN && !drag) {
centerPoint1 = cvPoint(x, y);
frame2 = (IplImage*)cvClone(frame);
cvLine(frame2, centerPoint1, centerPoint1, CV_RGB(0, 0, 255), 3, CV_AA,
0);
cvShowImage("3D SCANNER", frame2);
}
/* user click right button: reset all */
if (event == CV_EVENT_RBUTTONUP) {
cvShowImage("3D SCANNER", frame);
drag = 0;
}
}
void on_mouse_roi(int event, int x, int y, int flags, void* param) {
cvInitFont(&font, CV_FONT_HERSHEY_SIMPLEX | CV_FONT_ITALIC, hScale, vScale,
0, lineWidth);

/* user press left button */


if (event == CV_EVENT_LBUTTONDOWN && !drag) {
roiPoint1 = cvPoint(x, y);
drag = 1;
}
/* user drag the mouse */
if (event == CV_EVENT_MOUSEMOVE && drag) {
frame2 = (IplImage*)cvClone(frame);
cvRectangle(frame2, roiPoint1, cvPoint(x, y), CV_RGB(255, 0, 0), 1, 8, 0);
_snprintf_s(buf, SIZE, "X1=%d, X2=%d, Y1=%d, Y2=%d", roiPoint1.x, x,
roiPoint1.y, y); //windows
//snprintf(buf, SIZE, "X1=%d, X2=%d, Y1=%d, Y2=%d", roiPoint1.x, x,
roiPoint1.y, y); //linux
cvPutText(frame2, buf, cvPoint(40, 35), &font, cvScalar(0, 255, 0));
cvShowImage("3D SCANNER", frame2);
}
/* user release left button */
if (event == CV_EVENT_LBUTTONUP && drag) {
roiPoint2 = cvPoint(x, y);
frame2 = (IplImage*)cvClone(frame);
// allow user to draw rectangle from any corner, make sure point 1 is top
left corner

if (roiPoint2.x < roiPoint1.x) {


int xtemp = roiPoint2.x;
roiPoint2.x = roiPoint1.x;
roiPoint1.x = xtemp;
}
if (roiPoint2.y < roiPoint1.y) {
int xtemp = roiPoint2.y;
roiPoint2.y = roiPoint1.y;
roiPoint1.y = xtemp;
}
// Show Region of Interest
cvRectangle(frame2, roiPoint1, roiPoint2, CV_RGB(255, 0, 0), 1, 8, 0);
cvShowImage("3D SCANNER", frame2);
drag = 0;

/* user click right button: reset all */


if (event == CV_EVENT_RBUTTONUP) {
cvShowImage("3D SCANNER", frame);
drag = 0;
}
}
IplImage* rotateFrame(IplImage* frame, double angle) {
CvMat* rot_mat = cvCreateMat(2, 3, CV_32FC1);
frame2 = (IplImage*)cvClone(frame);
frame2->origin = frame->origin;
cvZero(frame2);

// change center to center of turn table?


CvPoint2D32f center = cvPoint2D32f(frame->width / 2, frame->height / 2);
cv2DRotationMatrix(center, -angle, 1, rot_mat);
cvWarpAffine(frame, frame2, rot_mat);
return frame2;

int main(int argc, char* argv[]) {


int erodeFactor, camAngle, calFrame;
if (argc<5) {
calFrame = 1;
}
else {
//
sscanf_s(argv[4], "%d", &calFrame); // Windows
sscanf(argv[4], "%d", &calFrame); // Linux
}
if (argc<4) {
camAngle = 15;
}
else {
//
sscanf_s(argv[3], "%d", &camAngle); // Windows
sscanf(argv[3], "%d", &camAngle); // Linux
}
if (argc<3) {
erodeFactor = 3;
}
else {
//
sscanf_s(argv[2], "%d", &erodeFactor); // Windows
sscanf(argv[2], "%d", &erodeFactor); // Linux
}
//if (argc<2){
//
printf("Usage: %s video-file-name.avi <Erode Factor> <Camera Angle>
<Calibration Frame> \n\7", argv[0]);
//
return 1;
//}
cvNamedWindow("3D SCANNER", 1);
//CvCapture* capture = cvCreateFileCapture(argv[1]);
CvCapture* capture = cvCreateFileCapture("sample.avi");
//
capture calibration frame (default 1)
cvSetCaptureProperty(capture, CV_CAP_PROP_POS_FRAMES, calFrame);
frame = cvQueryFrame(capture);
cvSmooth(frame, frame, CV_BLUR, 3);
//
setup video writer
double fps = cvGetCaptureProperty(
capture,
CV_CAP_PROP_FPS
);
CvSize imgSize;
imgSize.width = frame->width;
imgSize.height = frame->height;

CvVideoWriter *writer = cvCreateVideoWriter(


"out.avi",
//CV_FOURCC('P','I','M','1'), // MPEG-1
CV_FOURCC('D', 'I', 'V', 'X'), // MPEG-4
//CV_FOURCC('M','P','4','2'), // For MPEG-4.2
//CV_FOURCC('D','I','V','3'), // For MPEG-4.3
//CV_FOURCC('X','V','I','D'), // For Xvid
//CV_FOURCC('H','2','6','4'), // For H264
//CV_FOURCC('D','X','5','0'), // For Dvix ver5
//CV_FOURCC_PROMPT,
//
CV_FOURCC_DEFAULT, // use this default for Windows
//-1, //A codec code of "-1" will open a codec selection window (in
Windows)
fps,
imgSize
);
// Rotate image
//
frame = rotateFrame(frame,camAngle);
// Define vertical axis
frame2 = (IplImage*)cvClone(frame);
cvInitFont(&font, CV_FONT_HERSHEY_SIMPLEX | CV_FONT_ITALIC, hScale, vScale,
0, lineWidth);
cvSetMouseCallback("3D SCANNER", on_mouse_axis, NULL);
message = "Draw vertical axis (left-click, drag then release and hit any key)";
cvPutText(frame2, message, cvPoint(10, 15), &font, cvScalar(255, 255, 255));
cvShowImage("3D SCANNER", frame2);
cvWaitKey(0);
double axisAngle = 90.0 - (atan((double)(axisPoint2.y - axisPoint1.y) / (double)
(axisPoint2.x - axisPoint1.x)) * 180. / PI);
frame = rotateFrame(frame, axisAngle);
cvShowImage("3D SCANNER", frame);
// Define region of interest
frame2 = (IplImage*)cvClone(frame);
cvInitFont(&font, CV_FONT_HERSHEY_SIMPLEX | CV_FONT_ITALIC, hScale, vScale,
0, lineWidth);
cvSetMouseCallback("3D SCANNER", on_mouse_roi, NULL);
message = "Create Rectangle of Interest (left-click, drag then release and hit
any key)";
cvPutText(frame2, message, cvPoint(10, 15), &font, cvScalar(255, 255, 255));
cvShowImage("3D SCANNER", frame2);
cvWaitKey(0);
cvShowImage("3D SCANNER", frame);
// Define center of turn-table (0,0)
frame2 = (IplImage*)cvClone(frame);
cvSetMouseCallback("3D SCANNER", on_mouse_center, NULL);
message = "Left-click on center point of turn-table, release and hit Enter)";
cvPutText(frame2, message, cvPoint(10, 15), &font, cvScalar(255, 255, 255));
cvShowImage("3D SCANNER", frame2);
cvWaitKey(0);
cvShowImage("3D SCANNER", frame);

cvSetCaptureProperty(capture, CV_CAP_PROP_POS_FRAMES, 1);


int frameCount = 0;
int myPoints[MAXFRAMES][MAXCOLS] = { 0 };
double highestVal = 0;
double redVal = 0;
double brightnessVal = 0;
while (1) {
//
printf("Current Frame: %d \n", frameCount);
frame = cvQueryFrame(capture);
if (!frame) break;
cvSmooth(frame, frame, CV_BLUR, 3);
// Rotate image
frame = rotateFrame(frame, axisAngle);
// Draw rotation point
cvLine(frame, centerPoint1, centerPoint1, CV_RGB(0, 255, 0), 4, CV_AA,
0);
// Draw Region of Interest
cvRectangle(frame, roiPoint1, roiPoint2, CV_RGB(0, 255, 0), 1, 8, 0);

************

// cycle throught all pixels and find highest value in each row
// *********** convert myPoints array to vector to allow dynamic size

// y is height (Z)
for (int y = 0; y<frame->height; ++y) {
//next row, reset highest value
highestVal = 0;
// x is radius
for (int x = 0; x<frame->width; ++x) {
c1 = cvGetAt(frame, y, x);
// if point is inside region of interest
if (x >= roiPoint1.x && x <= roiPoint2.x && y >=
roiPoint1.y && y <= roiPoint2.y) {
/* DEBUG CODE BELOW */
/*
frame2 = (IplImage*)
cvClone(frame);
_snprintf_s(buf, SIZE, "b=%f g=%f r=%f\n",
c1.val[0], c1.val[1], c1.val[2]); //windows
message = buf;
cvPutText(frame2,message, cvPoint(10,15), &font,
cvScalar(255,255,255));
cvLine(frame2, cvPoint(x,y), cvPoint(x,y),
CV_RGB(255, 0, 0), 4, CV_AA, 0 );
cvShowImage( "3D SCANNER", frame2 );
cvWaitKey(0);*/
// if redness of point (2x red - blue - green = red)
redVal = c1.val[2] * 2 - c1.val[0] - c1.val[1];
// brightness of point
brightnessVal = c1.val[2] + c1.val[0] + c1.val[1];

if ((redVal > 25) && (brightnessVal > highestVal) &&


(c1.val[2] > 100)) { // enough red present
//
((c1.val[0] + c1.val[1] + c1.val[2]) <
600)) { // pixel not too bright
}

highestVal = brightnessVal;
myPoints[frameCount][y] = x;

}
}
// display best point found on last row processed
if (myPoints[frameCount][y] != 0) {
cvLine(frame, cvPoint(myPoints[frameCount][y], y),
cvPoint(myPoints[frameCount][y], y), CV_RGB(0, 0, 255), 2, CV_AA, 0);
}
}
cvShowImage("3D SCANNER", frame);
cvWriteFrame(writer, frame);
char myChar = cvWaitKey(33);
if (myChar == 27) break; // ESC to break
frameCount++;
}
for (int frameNum = 0; frameNum<frameCount; ++frameNum) {
for (int z = 0; z<MAXROWS; ++z) {
if (myPoints[frameNum][z] != 0) {
numPoints++;
}
}
}
// print ply header (use Meshlab to open PLY file)
printf("ply\nformat ascii 1.0\nelement vertex %d\nproperty float x\nproperty
float y\nproperty float z\nend_header\n", numPoints);
double dist = 0;
double x, y, z2;
for (int frameNum = 0; frameNum<frameCount; ++frameNum) {
for (int z = 0; z<MAXROWS; ++z) {
if (myPoints[frameNum][z] != 0) {
// dist is distance from profile point to axis of rotation (it
should now be vertical so use X)
// * PI / 180 TO CONVERT TO RADIANS
dist = ((double)centerPoint1.x (double)myPoints[frameNum][z]) / sin((double)camAngle * PI / 180.0);
if ((float)dist > 0) {
z2 = (double)z - abs(((double)dist * tan((double)
(camAngle)* PI / 180.0)));
}
else {
z2 = (double)z + abs(((double)dist * tan((double)
(camAngle)* PI / 180.0)));
}

x = dist*sin((double)(360.0 /
(double)frameCount*(double)frameNum) * PI / 180.0);
y = dist*cos((double)(360.0 /
(double)frameCount*(double)frameNum) * PI / 180.0);
printf("%f %f %f\n", x, y, z2);
}
}
}
cvReleaseCapture(&capture);
cvReleaseImage(&frame);
cvReleaseImage(&frame2);
//
cvReleaseMat( &rot_mat );
cvReleaseVideoWriter(&writer);
cvDestroyWindow("3D SCANNER");
return 0;
}

5. Al compilar el aplicativo, se generaran unas ventanas.


6. La primera de ellas nos pide trazar una lnea vertical que servir de
referencia en el video

7. La segunda ventana, nos pide que trazemos un cuadro, que ser la


regin que del video que nos importa enfocar para extraer los puntos.

8. La tercera ventana nos pide que ubiquemos el centro de dicha seleccin

9. Asi se empieza a leer el video frame por frame.

10.Se obtienen las coordenadas de puntos X, Y, Z, las cuales procedemos a


almacenarlas en un archivo .ply

11.Dicho archivo que se genera lo abrimos con un software para enmallado.

12.Vemos que la nube de puntos toma la forma del objeto inicial que
tenamos.

Referencias
http://docs.opencv.org/doc/tutorials/imgproc/shapedescriptors/find_contours/fin
d_contours.html
http://harismoonamkunnu.blogspot.in/2013/06/opencv-find-biggest-contourusing-c.html
http://tecnicasdevision.blogspot.com/2014/05/calibrar-una-camara-conopencv.html
http://docs.opencv.org/modules/calib3d/doc/calib3d.html
http://tecnicasdevision.blogspot.com/2014/09/sobre-los-bordes-y-elgradiante.html
http://dasl.mem.drexel.edu/~noahKuntz/openCVTut10.html
https://www.youtube.com/watch?v=DrXIQfQHFv0
http://cdn.oreillystatic.com/books/9780596516130/ch11.pdf
http://mesh.brown.edu/calibration/software.html
http://www.jesusllor.es/?p=37
http://maztories.blogspot.com/2013/07/calibracion-de-una-camara-conopencv.html
http://www.elai.upm.es/webantigua/spain/Investiga/GCII/personal/lrodriguez/we
b3D/reconstruccion_3d.htm
http://sabia.tic.udc.es/gc/Contenidos
%20adicionales/trabajos/Hardware/scanner3D/Escaner3D.html
http://www.efefuturo.com/noticia/una-camara-laser-que-mejora-y-abarata-lareconstruccion-3d/
http://www.redalyc.org/articulo.oa?id=47724934011
http://oefa.blogspot.com/2008/09/triangulacin-de-delaunay.html
http://personal.us.es/almar/docencia/practicas/triangulaciones/tema4.html
http://lands.asuni.es/help/html/Modelado%20de%20terreno.htm
http://littlecodes.wordpress.com/2013/06/24/calibracion-de-camaras-yprocesamiento-de-imagenes-ii/
http://web-sisop.disca.upv.es/imd/cursosAnteriors/2k32k4/copiaTreballs/serdelal/trabajoIMD.xml
http://nuigroup.com/forums/viewthread/3414/
http://szeliski.org/Book/
http://research.microsoft.com/en-us/um/people/zhang/Calib/

S-ar putea să vă placă și