Taula de continguts:

Escàner 3D bàsic per a mapatge digital 3D: 5 passos
Escàner 3D bàsic per a mapatge digital 3D: 5 passos

Vídeo: Escàner 3D bàsic per a mapatge digital 3D: 5 passos

Vídeo: Escàner 3D bàsic per a mapatge digital 3D: 5 passos
Vídeo: M1 iPad Pro Setup 2024, Setembre
Anonim
Escàner 3D bàsic per a mapatge digital 3D
Escàner 3D bàsic per a mapatge digital 3D

En aquest projecte, descriuré i explicaré els fonaments bàsics de l'escaneig i la reconstrucció en 3D aplicats principalment a l'escaneig d'objectes semiplans petits, i el funcionament dels quals es pot estendre als sistemes d'escaneig i reconstrucció que es poden instal·lar en avions de control remot per obtenir un model 3D. dels llocs on l’avió que els porta instal·lats vola

La idea final és obtenir un escaneig 3D d'algun lloc o zona, ja sigui exterior o interior, per utilitzar-lo com a mapa digital (com a la pel·lícula de Prometeu)

Pas 1:

Imatge
Imatge

la idea és instal·lar tot el sistema d’escaneig 3D en un pla controlat a distància, per tal de digitalitzar el mapa virtual de qualsevol àrea sobre la qual vola en 3d, però per a això vam començar des del començament de l’operació de la triangulació làser. d’escaneig o reconstrucció en 3D mitjançant triangulació làser consisteix bàsicament a fer passar un feix làser a través d’un prisma que genera una banda làser per obtenir una franja làser sencera que es projectarà sobre un objecte a escanejar i, una vegada obtinguda aquesta projecció làser a la superfície superficial Des del lloc on s’escaneja, la imatge s’ha de capturar amb algun tipus de càmera i, preferentment, conèixer l’angle que es forma respecte a l’angle de projecció de la banda làser emesa, ja que cadascuna d’aquestes imatges captura les tires làser projectades. A la superfície de l'objecte, es processaran prèviament per extreure les característiques dimensionals de l'objecte a escanejar i simplement escanejar tira per tira per sobre de l'objecte per obtenir el perfil de la seva superfície en aquest segment transversal de l'objecte i posteriorment capturar la franja projectada de la següent secció transversal de l’objecte, per afegir totes les franges projectades juntes Abans de totes les seccions transversals de l’obto obtenim una exploració tridimensional de la seva superfície

Pas 2:

Imatge
Imatge

Com que hem identificat el nostre objectiu, el següent pas sabent que per enlairar-se primer s’ha de tenir els peus ferms a terra, de manera que vam començar a terra amb un prototip experimental d’un escàner lineal en 3D, per validar el correcte funcionament del sistema bàsic. Escàner 3D i, com podeu veure a la imatge superior, he utilitzat un PC, OpenCV, Glut d’OpenGL, una càmera web, un làser, un generador de làser (en aquest cas a través d’un mirall rotatori) un sistema de desplaçament lineal electrònic (fet amb un rail i sistema extret d’una antiga impressora) d’una base sobre la qual col·loco els objectes a escanejar, fusta i plastilina i, com podeu veure a la foto, a l’ordinador: he aconseguit generar i mostrar amb Glut d’OpenGL un tres- model dimensional reproduït basat en l'objecte real escanejat (en aquest cas una aranya de joguina)

per tant, és més que evident que el principi de funcionament és funcional i que, amb els seus respectius ajustos i adaptacions a un sistema de vol, podrà escanejar i reproduir un mapa en 3D de la zona on vola.

Però aquest sistema només servirà per obtenir mapes 3D de la superfície externa dels llocs sobre els quals sobrevola ??? …

Pas 3:

Imatge
Imatge

cartografiar l'interior de les coves i conductes (igual que a la pel·lícula Prometeus) Aquest sistema d'escaneig 3D també serveix per reconstruir models tridimensionals de l'interior d'objectes grans i buits com coves, edificis, túnels, etc. exactament el mateix que ja s’ha descrit i que consisteix bàsicament en el següent:

  1. captura la foto de cada projecció de la franja làser a la superfície a escanejar
  2. filtreu i elimineu el color de la imatge
  3. binaritzar el color amb un llindar d'imatge dinàmica
  4. apliqueu un detector de vores per reconèixer el perfil capturat de cada secció transversal de projecció làser
  5. i mitjançant la segmentació, seleccioneu la vora adequada per a la representació en 3D d'aquesta secció transversal de l'objecte que voleu escanejar i reconstruir al mapa 3D virtual
  6. llavors aquests passos es repeteixen simplement per a cada fotografia feta d'una manera secundària de les ratlles làser projectades contínuament per cada sub-secció en la sub-secció.
  7. capa per capa de la representació de les seccions transversals s’afegeixen successivament fins a obtenir un núvol de punts format per moltes representacions de seccions transversals de l’objecte a cartografiar

Pas 4:

Imatge
Imatge

Després passo els programes per al processament d’imatges de les projeccions de les tires làser superficials. i de la reconstrucció virtual 3D d'aquestes representacions transversals sussives en el model de mapa tridimensional elaborat:

processament d'imatge:

n

#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; FITXA * NuPu;

void Writepoints () {char bufferx [33], buffery [33]; itoa (x, bufferx, 10); itoa (y, buffery, 10); fprintf (NuPu, bufferx); fprintf (NuPu, "\ t"); fprintf (NuPu, memòria intermèdia); fprintf (NuPu, "\ n"); }

void 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; nom [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 ++;}}}} buff buff [33]; itoa (n, buffer, 10); fprintf (NuPu, "Fin:"); fprintf (NuPu, memòria intermèdia); fprintf (NuPu, "\ n"); fclose (NuPu);

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

Reconstrucció 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; float mx = 0, my = 0, mtx = 0, mty = 0, mtz = -5,0; const int Avance = 1; línia de corda, Aux; char Caracter = 'H'; FITXA * NuPu; int NP, h, w; float G = 0, n = 0, cx [5000], cy [5000], x, y, ax, ay, az; int font = (int) GLUT_BITMAP_8_BY_13; etiqueta de caràcters estàtics [100]; buff buffer [3]; GLfloat anguloCuboX = 0,0f; GLfloat anguloCuboY = 0,0f; GLfloat anguloEsfera = 0,0f; GLint ancho = 500; GLint alt=500; int hazPerspectiva = 0; void reshape (int width, int height) {glViewport (0, 0, width, height); glMatrixMode (GL_PROJECTION); glLoadIdentity (); if (hazPerspectiva) gluPerspective (23.0f, (GLfloat) width / (GLfloat) height, 1.0f, 20.0f); else glOrtho (-1, 1, -1, 1, -10, 10); glMatrixMode (GL_MODELVIEW); ancho = ample; alt=alçada; } void Kolorear (int K) {flotador Hip; x = (cx [s] -320) / 480; y = (cy [s] -240) / 640; Hip = sqrt (pow (x, 2) + pow (y, 2)); if ((Hip> = 0) && (Hip =.07) && (Hip =.14) && (Hip =.21) && (Hip =.28) && (Hip =.35) && (Hip =.42) && (Hip <=. 49)) {violeta;}} void drawNuPu (void) {glColor3f (1, 1, 1); glBegin (GL_LINES); glVertex3f (.2, 0, 0); glVertex3f (-. 2, 0, 0); glVertex3f (0,.2, 0); glVertex3f (0, -.2, 0); glEnd (); vermell; 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;; 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, "Hello Text"); glutBitmapCharacter (GLUT_B_MAP); * / / * glColor3f (1. 0f, 1.0f, 1.0f); setOrthographicProjection (); glPushMatrix (); glLoadIdentity (); renderBitmapString (30, 15, font (void *), "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; alt=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 (myfile.is_open ()) {s = 0; while (getline (myfile, line)) {if ((line [0]! = 'N') && (line [0]! = 'F')) {Aux = line; línia [0] = 48; línia [1] = 48; línia [2] = 48; línia [3] = 48; cy [s] = atoi (line.c_str ()); Aux [4] = 48; Aux [5] = 48; Aux [6] = 48; // Aux [7] = 48; cx [s] = atoi (Aux.c_str ()); s ++; }} myfile.close (); } else cout <1780) NP = 1700; cout <void idle () {display (); } void keyboard (tecla de caràcter sense signar, int x, int y) {commutador (tecla) {cas 'p': cas 'P': hazPerspectiva = 1; remodelar (ancho, alto); trencar; cas 'o': cas 'O': hazPerspectiva = 0; remodelar (ancho, alto); trencar; cas 27: // escape escape (0); trencar; }} void raton (botó int, estat int, int x, int y) {/ * GLUT_LEFT_BUTTON 0 GLUT_MIDDLE_BUTTON 1 GLUT_RIGHT_BUTTON 2 GLUT_DOWN 0 GLUT_UP 1 * / Boton = botó; Pulbut = estat; // mx = y; display (); } void ratmov (int x, int y) {if ((Boton == 0) & (Pulbut == 0)) {mx = y; el meu = x; } if ((Boton == 2) & (Pulbut == 0)) {mtx = (y / 200) -1; mty = (x / 200) -1; } if ((Boton == 1) & (Pulbut == 0)) {mtz = - (y / 40) -5; } display (); } int main (int argc, char ** argv) {/ * glutAddMenuEntry () glutAddSubMenu () glutAttachMenu () glutCreateMenu () glutSetMenu () glutStrokeCharacter () glutStrokeLength () * / / * glReadPixels () llegir un bloc de píxels () frame buffer glGetPixelMapfv () retorna el mapa de píxels especificat glGetPixelMapuiv () retorna el mapa de píxels especificat glGetPointerv () Retorna l'adreça del punter especificat. * / Init (); leer (); glutInit (& argc, argv); glutInitDisplayMode (GLUT_DOUBLE | GLUT_RGB); glutInitWindowPosition (50, 50); glutInitWindowSize (ancho, alto); glutCreateWindow ("Cubo 1"); init (); glutDisplayFunc (pantalla); glutReshapeFunc (remodelació); glutIdleFunc (inactiu); glutMouseFunc (raton); glutMotionFunc (ratmov); glutKeyboardFunc (teclat); glutMainLoop (); retorn 0; }

Pas 5:

Imatge
Imatge

de moment he de parar! … però al capítol següent us prometo que ho implementaré al meu raspberry pi 3 o al meu jetson nanoboard, ja muntat en algun avió controlat a distància, o en algun robot aranya per escanejar l'interior de les coves

Recomanat: