Inhaltsverzeichnis:

Grundlegender 3D-Scanner für digitales 3D-Mapping - Gunook
Grundlegender 3D-Scanner für digitales 3D-Mapping - Gunook

Video: Grundlegender 3D-Scanner für digitales 3D-Mapping - Gunook

Video: Grundlegender 3D-Scanner für digitales 3D-Mapping - Gunook
Video: Photogrammetry 2 – 3D scanning with just PHONE/CAMERA simpler, better than ever! 2024, September
Anonim
Einfacher 3D-Scanner für digitales 3D-Mapping
Einfacher 3D-Scanner für digitales 3D-Mapping

In diesem Projekt beschreibe und erkläre ich die grundlegenden Grundlagen des 3D-Scannens und der Rekonstruktion, die hauptsächlich auf das Scannen kleiner halbflächiger Objekte angewendet werden und deren Betrieb auf Scan- und Rekonstruktionssysteme ausgedehnt werden kann, die auf ferngesteuerten Flugzeugen installiert werden können, um zu erhalten ein 3D-Modell. der Orte, an denen das Flugzeug, das sie befördert, installiert fliegt

Die letzte Idee besteht darin, einen 3D-Scan eines Ortes oder einer Umgebung zu erhalten, entweder von außen oder von innen, um ihn als digitale Karte zu verwenden (wie im Film von Prometeus).

Schritt 1:

Bild
Bild

Die Idee ist, das gesamte 3D-Scansystem auf einer ferngesteuerten Ebene zu installieren, um die virtuelle Karte eines beliebigen Gebiets, über das es fliegt, in 3D zu digitalisieren, aber dafür haben wir von Anfang an mit dem Betrieb der Lasertriangulation der Methode begonnen des Scannens oder der 3D-Rekonstruktion durch Lasertriangulation besteht im Wesentlichen darin, einen Laserstrahl durch ein Prisma zu führen, das einen Laserstreifen erzeugt, um einen gesamten Laserstreifen zu erhalten, der auf ein zu scannendes Objekt projiziert wird, und sobald diese Laserprojektion auf dem Oberflächenoberfläche Von der zu scannenden Stelle muss das Bild mit einer Art Kamera aufgenommen werden und vorzugsweise in Kenntnis des Winkels, der in Bezug auf den Projektionswinkel des emittierten Laserstreifens gebildet wird, da jedes dieser Bilder die projizierten Laserstreifen erfasst. Auf der Oberfläche des Objekts werden sie vorverarbeitet, um die Dimensionsmerkmale des zu scannenden Objekts zu extrahieren, und einfach streifenweise über dem Objekt scannen, um das Profil seiner Oberfläche in diesem Quersegment des Objekts zu erhalten, und anschließend erfassen den projizierten Streifen des folgenden Querschnitts des Objekts, um alle projizierten Streifen zusammenzuzählen Vor allen Querschnitten des Obto erhalten wir einen dreidimensionalen Scan seiner Oberfläche

Schritt 2:

Bild
Bild

Da wir unser Ziel identifiziert haben, den nächsten Schritt in dem Wissen, dass Sie zum Abheben zuerst fest auf dem Boden stehen müssen, haben wir mit einem experimentellen Prototyp eines linearen 3D-Scanners auf dem Boden begonnen, um die korrekte Funktionsweise der Basis zu validieren 3D-Scannerund wie Sie im Bild oben sehen können, habe ich einen PC, OpenCV, Glut von OpenGL, eine Webcam, einen Laser, einen Laserfarmgenerator (in diesem Fall durch einen Rotationsspiegel) ein elektronisches Linearverschiebungssystem (hergestellt mit einer Schiene) verwendet und System aus einem alten Drucker) von einem Sockel, auf dem ich die zu scannenden Objekte Holz und Plastilin platziere und, wie auf dem Foto zu sehen, auf dem Computer: Ich habe es geschafft, mit Glut aus OpenGL eine drei- auf Basis des gescannten realen Objekts reproduziertes Maßmodell (in diesem Fall eine Spielzeugspinne)

Es ist also mehr als offensichtlich, dass das Funktionsprinzip funktioniert und es mit seinen entsprechenden Anpassungen und Anpassungen an ein Flugsystem in der Lage sein wird, eine 3D-Karte des Fluggebietes zu scannen und zu reproduzieren.

Aber dieses System wird nur dazu dienen, 3D-Karten der äußeren Oberfläche der Orte zu erhalten, über die es fliegt???…

Schritt 3:

Bild
Bild

Kartierung des Inneren von Höhlen und Kanälen (wie im Prometeus-Film) Dieses 3D-Scansystem dient auch dazu, dreidimensionale Modelle des Inneren von großen und hohlen Objekten wie Höhlen, Gebäuden, Tunneln usw. zu rekonstruieren. Sein Funktionsprinzip ist genau wie bereits beschrieben und besteht im Wesentlichen aus:

  1. Nehmen Sie das Foto jeder Projektion des Laserstreifens auf der zu scannenden Oberfläche auf
  2. filtern und Farbe aus dem Bild entfernen
  3. Binarisieren der Farbe mit einem dynamischen Bildschwellenwert
  4. Wenden Sie einen Kantendetektor an, um das erfasste Profil jedes Laserprojektionsquerschnitts zu erkennen
  5. und unter Verwendung der Segmentierung den geeigneten Rahmen für die 3D-Darstellung des zu scannenden und zu rekonstruierenden Objektquerschnitts auf der virtuellen 3D-Karte auswählen
  6. dann werden diese Schritte einfach für jedes Foto wiederholt, das in einer Unterart der Laserstreifen aufgenommen wird, die kontinuierlich von jedem Unterabschnitt in Unterabschnitt projiziert werden.
  7. Schicht für Schicht der Darstellung der Querschnitte werden sukzessive hinzugefügt, bis eine Punktwolke erhalten wird, die aus vielen Darstellungen von Querschnitten des abzubildenden Objekts gebildet wird

Schritt 4:

Bild
Bild

Dann übergebe ich die Programme zur Bildverarbeitung der Projektionen der oberflächlichen Laserstreifen. und der virtuellen 3D-Rekonstruktion dieser sussiven transversalen Darstellungen im ausgearbeiteten dreidimensionalen Kartenmodell:

Bildverarbeitung:

n

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

Zeichen f=0; Zeichenname={"0.jpg"}; int n = 0, s, x, y; CvScalar sp; DATEI *NuPu;

void Writepoints() { char bufferx[33], buffery[33]; itoa (x, Pufferx, 10); itoa (y, gepuffert, 10); fprintf(NuPu, Pufferx); fprintf(NuPu, "\t"); fprintf(NuPu, gepuffert); 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; name[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++;} } } } Zeichenpuffer[33]; itoa (n, Puffer, 10); fprintf(NuPu, "Fin:"); fprintf(NuPu, Puffer); 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); 0 zurückgeben; }

3D-Rekonstruktion:

#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; Schnurleitung, Aux; char Zeichen='H'; DATEI *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; statisches Zeichenlabel[100]; Zeichenpuffer [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 Breite, int Höhe) { glViewport (0, 0, Breite, Höhe); glMatrixMode(GL_PROJECTION); glLoadIdentity(); if(hazPerspectiva) gluPerspective(23.0f, (GLfloat)width/(GLfloat)height, 1.0f, 20.0f); sonst glOrtho(-1, 1, -1, 1, -10, 10); glMatrixMode(GL_MODELVIEW); Anker = Breite; Alt = Höhe; aufrechtzuerhalten. Void Kolorear (int K) { Float Hüfte; x = (cx[s]-320)/480; y = (cy[s]-240)/640; Hüfte=sqrt(pow(x, 2)+pow(y, 2)); if((Hüfte>=0)&&(Hüfte=.07)&&(Hüfte=.14)&&(Hüfte=.21)&&(Hüfte=.28)&&(Hüfte=.35)&&(Hüfte=.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(); 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_ROMAN_24, "Hello Text";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_BITMAP_TIMES_ROMAN_24, '7');*/ /*glColor3f(1. 0f, 1.0f, 1.0f); setOrthographicProjection(); glPushMatrix(); glLoadIdentity(); renderBitmapString(30, 15, (void *)font, "GLUT Tutorial ---_------_@ 3D Tech");*/ glFlush(); glutSwapBuffers(); anguloCuboX+=0,1f; AnguloCuboY+=0,1f; AnguloEsfera+=0,2f; aufrechtzuerhalten. Void init () { glClearColor (0, 0, 0, 0); glEnable(GL_DEPTH_TEST); Anker = 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; line[0]=48; Zeile[1]=48; Zeile [2] = 48; Zeile [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++; } } meinedatei.close(); } sonst cout <1780)NP=1700; cout< Void im Leerlauf () { Display (); } void keyboard (unsigned char key, int x, int y) { switch (key) { case 'p': case 'P': hazPerspectiva=1; umformen (Ancho, Alt); brechen; Fall 'o': Fall 'O': hazPerspectiva=0; umformen (Ancho, Alt); brechen; Fall 27: // Escape-Exit (0); brechen; }} 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=button; Pulbut=Zustand; //mx=y; Anzeige(); aufrechtzuerhalten. Void ratmov (int x, int y) { if ((Boton = = 0) & (Pulbut = = 0)) { mx = y; mein=x; aufrechtzuerhalten. Wenn ((Boton==2)&(Pulbut==0)) {mtx=(y/200)-1; mty=(x/200)-1; } if((Boton==1)&(Pulbut==0)) {mtz=-(y/40)-5; } Anzeige(); } int main(int argc, char **argv) { /*glutAddMenuEntry() glutAddSubMenu() glutAttachMenu() glutCreateMenu() glutSetMenu() glutStrokeCharacter() glutStrokeLength()*/ /*glReadPixels() liest einen Pixelblock aus dem Framebuffer glGetPixelMapfv() gibt die angegebene Pixelmap zurück glGetPixelMapuiv() gibt die angegebene Pixelmap zurück glGetPointerv() Gibt die Adresse des angegebenen Pointers zurück.*/ Init(); leer(); glutInit(&argc, argv); glutInitDisplayMode(GLUT_DOUBLE | GLUT_RGB); glutInitWindowPosition(50, 50); glutInitWindowSize (Ancho, Alt); glutCreateWindow("Cubo 1"); drin(); glutDisplayFunc (Anzeige); glutReshapeFunc (umformen); glutIdleFunc(leer); glutMouseFunc(raton); glutMotionFunc(ratmov); glutKeyboardFunc (Tastatur); glutMainLoop(); 0 zurückgeben; }

Schritt 5:

Bild
Bild

im Moment muss ich aufhören! …aber im nächsten Kapitel verspreche ich dir, dass ich es auf meinem Raspberry Pi 3 oder meinem Jetson Nanoboard implementieren werde, das bereits auf einem ferngesteuerten Flugzeug montiert ist, oder auf einem Spinnenroboter, um das Innere von Höhlen zu scannen

Empfohlen: