Tabla de contenido:

Escáner 3D básico para mapeo digital 3D: 5 pasos
Escáner 3D básico para mapeo digital 3D: 5 pasos

Video: Escáner 3D básico para mapeo digital 3D: 5 pasos

Video: Escáner 3D básico para mapeo digital 3D: 5 pasos
Video: 🔔LOS 6 MEJORES PROGRAMAS GRATUITOS PARA DISEÑAR EN 3D✍ | Básicos de impresión 3D ⚙️ 2024, Septiembre
Anonim
Escáner 3D básico para mapeo digital 3D
Escáner 3D básico para mapeo digital 3D

En este proyecto, describiré y explicaré los fundamentos básicos del escaneo y reconstrucción 3D aplicados principalmente al escaneo de pequeños objetos semiplanos, y cuyo funcionamiento se puede extender a sistemas de escaneo y reconstrucción que se pueden instalar en aviones de control remoto para obtener un modelo 3D. de los lugares donde vuela el avión que los lleva instalado

La idea final es obtener un escaneo 3D de algún lugar o zona, ya sea su exterior o su interior, para utilizarlo como mapa digital (como en la película de Prometeus)

Paso 1:

Imagen
Imagen

la idea es instalar todo el sistema de escaneo 3d en un plano teledirigido, con el fin de digitalizar el mapa virtual de cualquier zona sobre la que vuele en 3d, pero para ello partimos desde el inicio de la operación de la triangulación láser el método de exploración o reconstrucción 3d por triangulación láser consiste básicamente en pasar un rayo láser a través de un prisma que genera una franja láser para obtener una franja láser completa que se proyectará sobre un objeto a escanear, y una vez obtenida esta proyección láser en el superficie superficie Desde el lugar a escanear, la imagen debe ser capturada con algún tipo de cámara y preferiblemente conociendo el ángulo que se forma con respecto al ángulo de proyección de la franja láser emitida, ya que cada una de estas imágenes captura las franjas láser proyectadas. Sobre la superficie del objeto, serán preprocesados para extraer las características dimensionales del objeto a escanear, y simplemente escanear tira a tira encima del objeto para obtener el perfil de su superficie en ese segmento transversal del objeto, y posteriormente capturar la franja proyectada de la siguiente sección transversal del objeto, para sumar todas las franjas proyectadas juntas Antes de todas las secciones transversales del obto obtenemos un escaneo tridimensional de su superficie

Paso 2:

Imagen
Imagen

Ya que hemos identificado nuestro objetivo, el siguiente paso sabiendo que para despegar primero debes tener los pies firmes en el suelo, por eso empezamos en el suelo con un prototipo experimental de un escáner 3d lineal, para validar el correcto funcionamiento del básico. Escáner 3d y como se puede ver en la imagen de arriba, utilicé un PC, OpenCV, Glut de OpenGL, una webcam, un láser, un generador de granja láser (en este caso a través de un espejo rotacional) un sistema electrónico de desplazamiento lineal (hecho con un riel). y sistema extraído de una impresora antigua) de una base sobre la que coloco los objetos a escanear, madera y plastilina y como se puede ver en la foto, en la computadora: logré generar y mostrar con Glut desde OpenGL un tres- modelo dimensional reproducido en base al objeto real escaneado (en este caso, una araña de juguete)

por lo que es más que evidente que el principio de funcionamiento es funcional, y que con sus respectivos ajustes y adaptaciones a un sistema de vuelo podrá escanear y reproducir un mapa 3d de la zona en la que vuela.

Pero este sistema solo servirá para obtener mapas en 3D de la superficie externa de los lugares sobre los que sobrevuela ???…

Paso 3:

Imagen
Imagen

mapeo del interior de las cuevas y conductos (como en la película Prometeus) Este sistema de escaneo 3D también sirve para reconstruir modelos tridimensionales del interior de objetos grandes y huecos como cuevas, edificios, túneles, etc. su principio de funcionamiento es exactamente igual al ya descrito y que básicamente consiste en lo siguiente:

  1. capturar la foto de cada proyección de la franja láser en la superficie a escanear
  2. filtrar y eliminar el color de la imagen
  3. binarizar el color con un umbral de imagen dinámico
  4. aplicar un detector de bordes para reconocer el perfil capturado de cada sección transversal de proyección láser
  5. y utilizando la segmentación, seleccione el borde apropiado para la representación en 3D de esa sección transversal del objeto que se escaneará y reconstruirá en el mapa virtual en 3D.
  6. luego, estos pasos simplemente se repiten para cada foto tomada en una subsección de las rayas láser proyectadas continuamente por cada subsección en la subsección.
  7. capa a capa de la representación de las secciones transversales se van añadiendo sucesivamente hasta obtener una nube de puntos formada por muchas representaciones de las secciones transversales del objeto a cartografiar

Paso 4:

Imagen
Imagen

Luego paso los programas para el procesamiento de imágenes de las proyecciones de las tiras láser superficiales. y de la reconstrucción virtual en 3D de estas representaciones transversales en el elaborado modelo de mapa tridimensional:

procesamiento de imágenes:

norte

#include #include "cv.h" #include "highgui.h" #include // # include #include #include #include

char f = 0; char name = {"0.jpg"}; int n = 0, s, x, y; CvScalar sp; ARCHIVO * NuPu;

Void Writepoints () {char bufferx [33], buffery [33]; itoa (x, bufferx, 10); itoa (y, buffery, 10); fprintf (NuPu, bufferx); fprintf (NuPu, "\ t"); fprintf (NuPu, búfer); fprintf (NuPu, "\ n"); }

anular noteblockInit () {NuPu = fopen ("NuPu.txt", "w"); fseek (NuPu, 0, 0); fprintf (NuPu, "NP:"); fprintf (NuPu, "\ n"); }

int main () {char argstr [128]; noteblockInit (); cout << "¡Teklea!…:" f; nombre [0] = f; cout <

IplImage * img0 = cvLoadImage ("00.jpg", 0); if (f == '0') {for (y = 1; yheight-2; y ++) {for (x = 1; xwidth-2; x ++) {sp = cvGet2D (img0, y, x); if (sp.val [0]> 50) {Writepoints (); n ++;}}}} else {for (y = 1; yheight-2; y ++) {for (x = 1; xwidth-2; x ++) { sp = cvGet2D (img1, y, x); if (sp.val [0]> 50) {Writepoints (); n ++;}}}} búfer de caracteres [33]; itoa (n, tampón, 10); fprintf (NuPu, "Fin:"); fprintf (NuPu, búfer); fprintf (NuPu, "\ n"); fclose (NuPu);

cvWaitKey (0); //_execlp("calc.exe "," calc.exe ", argstr, NULL); cvDestroyAllWindows (); cvReleaseImage (& imagen); cvReleaseImage (& img); cvReleaseImage (& img0); cvReleaseImage (& img1); cvReleaseImage (& img2); return 0; }

Reconstrucción 3D:

#include ////////////////// #ifdef _APPLE_ #include #else #include #include #endif #include #include #include #include #include #include

#define violeta glColor3f (1, 0, 1) #define azul glColor3f (0, 0, 1) #define turkeza glColor3f (0, 1, 1) #define verde glColor3f (0, 1, 0) #define amarillo glColor3f (1, 1, 0) #define naranja glColor3f (1,.3, 0) #define rojo glColor3f (1, 0, 0) using namespace std; int s, Boton = 1, Pulbut = 1; flotar mx = 0, my = 0, mtx = 0, mty = 0, mtz = -5.0; const int Avance = 1; línea de cuerda, Aux; char Caracter = 'H'; ARCHIVO * NuPu; int NP, h, w; flotante G = 0, n = 0, cx [5000], cy [5000], x, y, ax, ay, az; int fuente = (int) GLUT_BITMAP_8_BY_13; etiqueta de carbón estático [100]; tampón de carbón [3]; GLfloat anguloCuboX = 0.0f; GLfloat anguloCuboY = 0.0f; GLfloat anguloEsfera = 0.0f; GLint ancho = 500; GLint alto = 500; int hazPerspectiva = 0; remodelación vacía (ancho int, alto int) {glViewport (0, 0, ancho, alto); glMatrixMode (GL_PROJECTION); glLoadIdentity (); if (hazPerspectiva) gluPerspective (23.0f, (GLfloat) width / (GLfloat) height, 1.0f, 20.0f); más glOrtho (-1, 1, -1, 1, -10, 10); glMatrixMode (GL_MODELVIEW); ancho = ancho; alto = altura; } void Kolorear (int K) {flotar Hip; x = (cx [s] -320) / 480; y = (cy [s] -240) / 640; Cadera = raíz cuadrada (pow (x, 2) + pow (y, 2)); si ((Cadera> = 0) && (Cadera =.07) && (Cadera =.14) && (Cadera =.21) && (Cadera =.28) && (Cadera =.35) && (Cadera =.42) && (Hip <=. 49)) {violeta;}} vacío drawNuPu (vacío) {glColor3f (1, 1, 1); glBegin (GL_LINES); glVertex3f (.2, 0, 0); glVertex3f (-. 2, 0, 0); glVertex3f (0,.2, 0); glVertex3f (0, -2, 0); glEnd (); rojo; glBegin (GL_POINTS); for (n = 0; n <10; n ++) {for (s = 0; s void setOrthographicProjection () {glMatrixMode (GL_PROJECTION); glPushMatrix (); glLoadIdentity (); gluOrtho2D (0, w, 0, h); glScalef (1, -1, 1); glTranslatef (0, -h, 0); glMatrixMode (GL_MODELVIEW);} void renderBitmapString (float x, float y, void * font, char * string) {char * c; glRasterPos2f (x, y); for (c = string; * c! = '\ 0'; c ++) {glutBitmapCharacter (font, * c);}} void display () {// mx = 468; itoa (mx, buffer, 10); glClear (GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); // glLoadIdentity (); glColor3f (1.0, 1.0, 1.0); glRasterPos2f (-1,.9); // glutBitmapString (GLUT_BITMAP_TIMES; for_ROM; s <3; s ++) {glutBitmapCharacter (GLUT_BITMAP_TIMES_ROMAN_24, buffer [s]);} glTranslatef (mty, -mtx, mtz); glRotatef (mx, 1.0f, 0.0f, 0.0f); glRotatef (my, 0.0f, 1.0f, 0.0f); drawNuPu (); /*glColor3f(1.0, 1.0, 1.0); glRasterPos2f (.5,.5); // glutBitmapString (GLUT_BITMAP_TIMES_ROMAN_24, "Texto de saludo"); glutBitmapCharacter '(GLUT_24, MAP_7); * / / * glColor3f (1. 0f, 1.0f, 1.0f); setOrthographicProjection (); glPushMatrix (); glLoadIdentity (); renderBitmapString (30, 15, (void *) fuente, "Tutorial GLUT ---_ ------ _ @ 3D Tech"); * / glFlush (); glutSwapBuffers (); anguloCuboX + = 0.1f; anguloCuboY + = 0.1f; anguloEsfera + = 0.2f; } void init () {glClearColor (0, 0, 0, 0); glEnable (GL_DEPTH_TEST); ancho = 500; alto = 500; } void leer () {ifstream myfile ("A: / Respaldo sept 2016 / D / Respaldos / Respaldo compu CICATA abril 2015 / usb1 / rekostruccion 3D en Especialidad CICATA / Software / Reconstruccion 3D / R3d_0 / bin / Debug / NuPu.txt"); if (miarchivo.is_open ()) {s = 0; while (getline (miarchivo, línea)) {if ((línea [0]! = 'N') && (línea [0]! = 'F')) {Aux = línea; línea [0] = 48; línea [1] = 48; línea [2] = 48; línea [3] = 48; cy [s] = atoi (línea.c_str ()); Aux [4] = 48; Aux [5] = 48; Aux [6] = 48; // Aux [7] = 48; cx [s] = atoi (Aux.c_str ()); s ++; }} myfile.close (); } más cout <1780) NP = 1700; cout <vacío inactivo () {pantalla (); } teclado vacío (tecla de carácter sin firmar, int x, int y) {interruptor (tecla) {caso 'p': caso 'P': hazPerspectiva = 1; remodelar (ancho, alto); rotura; caso 'o': caso 'O': hazPerspectiva = 0; remodelar (ancho, alto); rotura; caso 27: // escape exit (0); rotura; }} void raton (int button, int state, int x, int y) {/ * GLUT_LEFT_BUTTON 0 GLUT_MIDDLE_BUTTON 1 GLUT_RIGHT_BUTTON 2 GLUT_DOWN 0 GLUT_UP 1 * / Boton = botón; Pulbut = estado; // mx = y; monitor(); } void ratmov (int x, int y) {if ((Boton == 0) & (Pulbut == 0)) {mx = y; mi = x; } if ((Boton == 2) & (Pulbut == 0)) {mtx = (y / 200) -1; mty = (x / 200) -1; } if ((Boton == 1) & (Pulbut == 0)) {mtz = - (y / 40) -5; } monitor(); } int main (int argc, char ** argv) {/ * glutAddMenuEntry () glutAddSubMenu () glutAttachMenu () glutCreateMenu () glutSetMenu () glutStrokeCharacter () glutStrokeLength () * / / * bloque de píxeles readPix () frame buffer glGetPixelMapfv () devuelve el mapa de píxeles especificado glGetPixelMapuiv () devuelve el mapa de píxeles especificado glGetPointerv () Devuelve la dirección del puntero especificado. * / Init (); mirada lasciva(); glutInit (& argc, argv); glutInitDisplayMode (GLUT_DOUBLE | GLUT_RGB); glutInitWindowPosition (50, 50); glutInitWindowSize (ancho, alto); glutCreateWindow ("Cubo 1"); en eso(); glutDisplayFunc (pantalla); glutReshapeFunc (remodelar); glutIdleFunc (inactivo); glutMouseFunc (raton); glutMotionFunc (ratmov); glutKeyboardFunc (teclado); glutMainLoop (); return 0; }

Paso 5:

Imagen
Imagen

por el momento tengo que parar! … Pero en el próximo capítulo te prometo que lo implementaré en mi raspberry pi 3 o mi nanoboard jetson, ya montado en algún avión teledirigido, o en algún robot araña para escanear el interior de cuevas

Recomendado: