[PYTHON] Erstellen Sie mit PyQt5 und PyQtGraph einen 3D-Modell-Viewer

Einführung

Als ich mir die PyQt Graph-Dokumentation ansah, bemerkte ich irgendwie, dass die API eine 3D-Grafikfunktion enthielt. Ich war neugierig und habe versucht, eine einfache GUI-Anwendung zu erstellen, die ein 3D-Modell in Kombination mit PyQt5 anzeigt.

Da ich häufig 3D-Drucker verwende, bezieht sich das 3D-Modell hier auf das STL-Dateiformat.

Was ich gemacht habe

test2.gif

Sie können die STL-Datei im Drahtmodell anzeigen, indem Sie die STL-Datei auswählen oder ziehen und ablegen. Es ist ein einfaches Programm, das jeweils nur eine STL-Datei anzeigt. Der Code ist auch auf GitHub. GitHub:https://github.com/Be4rR/STLViewer

Was ist PyQtGraph?

PyQtGraph ist eine Bibliothek zum Zeichnen von Diagrammen und kann allein verwendet werden. Sie können das erstellte Diagramm jedoch problemlos in eine von PyQt erstellte GUI einbetten. Obwohl seine Funktion schwächer ist als die von Standard-Matplotlib, ist es sehr leicht und eignet sich zum Zeichnen von Daten in Echtzeit. Es ist eine wenig bekannte Bibliothek, aber ich persönlich finde sie nützlich. Offizielle Seite: http://www.pyqtgraph.org/ Offizielles Dokument: https://pyqtgraph.readthedocs.io/en/latest/index.html

Umgebung

Ich verwende Python3.8, PyQt5, PyQtGraph, PyOpenGL, Numpy und Numpy-STL. PyOpenGL ist erforderlich, um 3D-Grafikfunktionen mit PyQtGraph zu verwenden. Lesen Sie auch die STL-Datei mit Numpy-STL.

conda create -n stlviewer python=3.8 pyqt pyqtgraph numpy numpy-stl pyopengl 

Programm

Es ist ein bisschen lang.

stl-viewer.py
from pyqtgraph.Qt import QtCore, QtGui
import pyqtgraph as pg
import pyqtgraph.opengl as gl

from PyQt5.QtWidgets import *
from PyQt5.QtCore import *
from PyQt5.QtGui import *  

import numpy as np
from stl import mesh

from pathlib import Path
        
class MyWindow(QMainWindow):
    def __init__(self):
        super(MyWindow, self).__init__()
        self.setGeometry(0, 0, 700, 900) 
        self.setAcceptDrops(True)
        
        self.initUI()
        
        self.currentSTL = None
        self.lastDir = None
        
        self.droppedFilename = None
    
    def initUI(self):
        centerWidget = QWidget()
        self.setCentralWidget(centerWidget)
        
        layout = QVBoxLayout()
        centerWidget.setLayout(layout)
        
        self.viewer = gl.GLViewWidget()
        layout.addWidget(self.viewer, 1)
        
        self.viewer.setWindowTitle('STL Viewer')
        self.viewer.setCameraPosition(distance=40)
        
        g = gl.GLGridItem()
        g.setSize(200, 200)
        g.setSpacing(5, 5)
        self.viewer.addItem(g)

        btn = QPushButton(text="Load STL")
        btn.clicked.connect(self.showDialog)
        btn.setFont(QFont("Ricty Diminished", 14))
        layout.addWidget(btn)
            
    def showDialog(self):
        directory = Path("")
        if self.lastDir:
            directory = self.lastDir
        fname = QFileDialog.getOpenFileName(self, "Open file", str(directory), "STL (*.stl)")
        if fname[0]:
            self.showSTL(fname[0])
            self.lastDir = Path(fname[0]).parent
            
    def showSTL(self, filename):
        if self.currentSTL:
            self.viewer.removeItem(self.currentSTL)

        points, faces = self.loadSTL(filename)
        meshdata = gl.MeshData(vertexes=points, faces=faces)
        mesh = gl.GLMeshItem(meshdata=meshdata, smooth=True, drawFaces=False, drawEdges=True, edgeColor=(0, 1, 0, 1))
        self.viewer.addItem(mesh)
        
        self.currentSTL = mesh
        
    def loadSTL(self, filename):
        m = mesh.Mesh.from_file(filename)
        shape = m.points.shape
        points = m.points.reshape(-1, 3)
        faces = np.arange(points.shape[0]).reshape(-1, 3)
        return points, faces

    def dragEnterEvent(self, e):
        print("enter")
        mimeData = e.mimeData()
        mimeList = mimeData.formats()
        filename = None
        
        if "text/uri-list" in mimeList:
            filename = mimeData.data("text/uri-list")
            filename = str(filename, encoding="utf-8")
            filename = filename.replace("file:///", "").replace("\r\n", "").replace("%20", " ")
            filename = Path(filename)
            
        if filename.exists() and filename.suffix == ".stl":
            e.accept()
            self.droppedFilename = filename
        else:
            e.ignore()
            self.droppedFilename = None
        
    def dropEvent(self, e):
        if self.droppedFilename:
            self.showSTL(self.droppedFilename)

if __name__ == '__main__':
    app = QtGui.QApplication([])
    window = MyWindow()
    window.show()
    app.exec_()

Kommentar

Es ist nicht zu kompliziert, aber ich werde einige wichtige Punkte erklären.

Widget für 3D-Anzeige GLViewWidget

Verschiedene Grafikelemente sind in der 3D-Grafiksystem der PyQtGraph-Dokumentation aufgeführt.

Das erste GLViewWidget ist ein Widget zum Anzeigen von 3D-Modellen. Wir werden das zweite und nachfolgende Grafikelemente zu diesem Widget hinzufügen. Beispielsweise kann "GLGridItem" zum Hinzufügen einer Rasterebene und "GLMeshItem" zum Hinzufügen von Netzdaten wie einer STL-Datei verwendet werden. Einzelheiten finden Sie in der offiziellen Dokumentation.

Da GLViewWidget genauso behandelt werden kann wie das Widget von PyQt, kann es so wie es ist in die GUI von PyQt eingebettet werden.

3D-Modell mit GLMeshItem anzeigen

    def showSTL(self, filename):
        #Wenn bereits ein anderes 3D-Modell angezeigt wird, entfernen Sie dieses 3D-Modell.
        if self.currentSTL:
            self.viewer.removeItem(self.currentSTL)

        #Extrahieren Sie die Scheitelpunkte und Flächen aus der STL-Datei.
        points, faces = self.loadSTL(filename)

        #Ein Widget, das ein Netz erstellt und ein 3D-Modell anzeigt(self.viewer)Hinzufügen.
        meshdata = gl.MeshData(vertexes=points, faces=faces)
        mesh = gl.GLMeshItem(meshdata=meshdata, smooth=True, drawFaces=False, drawEdges=True, edgeColor=(0, 1, 0, 1))
        self.viewer.addItem(mesh)
        
        self.currentSTL = mesh

Die Funktion loadSTL extrahiert Scheitelpunkt- und Gesichtsinformationen aus der STL-Datei. Sowohl "Punkte" als auch "Flächen" sind Numpy-Arrays, wobei "Punkte" in Form von "(Anzahl der Eckpunkte, 3)" und "Flächen" in Form von "(Anzahl der Flächen, 3)" vorliegen.

Im obigen Programm werden die Informationen von Scheitelpunkten und Flächen an "MeshData" übergeben, um "MeshData" zu erstellen, und basierend darauf wird "gl.GLMeshItem" erstellt, um die Zeichenmethode (Gesichts- und Seitenfarben usw.) zu bestimmen. Es gibt zwei Schritte.

Fügen Sie dann das erstellte GLMeshItem zum GLViewWidget`` self.viewer hinzu.

self.viewer.addItem(mesh)

Raster anzeigen

Das Raster ist auch das gleiche Grafikelement wie "GLMeshItem", sodass es auf die gleiche Weise angezeigt werden kann.

Dies ist der Teil der Funktion initUI.

        g = gl.GLGridItem()
        g.setSize(200, 200)
        g.setSpacing(5, 5)
        self.viewer.addItem(g)

Nach dem Erstellen mit "GLGridItem ()" wird die Größe durch die Funktion "setSize" festgelegt, und die Größe eines Rasters wird durch die Funktion "setSpacing" festgelegt. Fügen Sie es schließlich mit der Funktion "addItem" zu "self.viewer" von "GLViewWidget" hinzu.

Recommended Posts

Erstellen Sie mit PyQt5 und PyQtGraph einen 3D-Modell-Viewer
Implementieren Sie ein Modell mit Status und Verhalten
Erstellen Sie mit Py2app und Tkinter eine native GUI-App
Erstellen Sie einen Stapel von Bildern und blasen Sie sie mit ImageDataGenerator auf
Ich habe mir eine Möglichkeit ausgedacht, ein 3D-Modell aus einem Foto zu erstellen. Teil 02 Laden von Bildern und Zeichnen von Scheitelpunkten
[Python] So erstellen Sie mit Matplotlib ein zweidimensionales Histogramm
Erstellen Sie eine 2D-CAD-Datei ".dxf" mit Python [ezdxf]
[Linux] Erstellen Sie ein Selbstzertifikat mit Docker und Apache
Erstellen Sie ein 3D-GIF mit Python3
Erstellen Sie eine Homepage mit Django
Erstellen Sie den Image Viewer mit Tkinter
Erstellen Sie ein Verzeichnis mit Python
Erstellen Sie eine WEB-Überwachungskamera mit Raspberry Pi und OpenCV
[Azure] Erstellen, Bereitstellen und erneutes Lernen eines Modells [ML Studio classic]
Erstellen Sie Anwendungen, registrieren Sie Daten und teilen Sie sie mit einer einzigen E-Mail
Lassen Sie uns ein PRML-Diagramm mit Python, Numpy und matplotlib erstellen.
Erstelle ein 2D-Rollenspiel mit Ren'Py (3) -Items and Tool Shop
Erstellen Sie ein Bereitstellungsskript mit Stoff und Küche und verwenden Sie es erneut
Ich habe mir eine Möglichkeit ausgedacht, aus einem Foto ein 3D-Modell zu erstellen. Teil 04 Generieren von Polygonen
Zeichne ein Diagramm mit Julia + PyQtGraph (2)
Lassen Sie uns mit Pylearn2 eine Drei-Wege-KI erstellen - Modell speichern und laden -
Erstellen Sie eine temporäre Datei mit Django als Zip und geben Sie sie zurück
Löse ABC166 A ~ D mit Python
Erstellen Sie eine gestreifte Illusion mit Gammakorrektur für Python3 und openCV3
Erstellen Sie eine virtuelle Umgebung mit Python!
Zeichne ein Diagramm mit Julia + PyQtGraph (1)
Ich habe mir eine Möglichkeit ausgedacht, ein 3D-Modell aus Fotos zu erstellen. Teil 01 Erstellen einer Umgebung
Zeichne ein Diagramm mit Julia + PyQtGraph (3)
Erstellen Sie mit BigQuery ein privates DMP ohne Anfangskosten und ohne Entwicklung
Ich habe versucht, Bulls and Cows mit einem Shell-Programm zu erstellen
Erstellen Sie mit PySide einen Modelliterator
Erstellen Sie einen Poisson-Stepper mit numpy.random
Erstellen Sie mit Django einen Datei-Uploader
Erstellen Sie eine CP932-CSV-Datei für Excel mit Chalice und geben Sie sie zurück
[AWS] Erstellen Sie mit CodeStar eine Python Lambda-Umgebung und führen Sie Hello World aus
Ich habe mir eine Möglichkeit ausgedacht, aus einem Foto ein 3D-Modell zu erstellen.
Erstellen Sie einen Stapel mit einer Warteschlange und eine Warteschlange mit einem Stapel (von LetCode / Implement Stack using Queues, Implement Queue using Stacks)
Todo-App mit Django erstellen ④ Ordner- und Aufgabenerstellungsfunktion implementieren
Erstellen Sie eine Python3-Umgebung mit pyenv auf einem Mac und zeigen Sie NetworkX-Diagramme an
Implementieren Sie ein Modell mit Status und Verhalten (3) - Beispiel für die Implementierung durch den Dekorateur
Erstellen Sie mit Python einen Entscheidungsbaum von 0 und verstehen Sie ihn (5. Information Entropy)
Erstellen Sie mit Class einen Python-Funktionsdekorator
Erstellen Sie mit Python + PIL ein Dummy-Image.
Erstellen Sie ein Modell für Ihren Django-Zeitplan
[Python] Erstellen Sie mit Anaconda eine virtuelle Umgebung
Erstellen wir mit Python eine kostenlose Gruppe
Erstellen Sie eine GUI-App mit Tkinter of Python
Ein Memo mit Python2.7 und Python3 in CentOS
Erstellen Sie eine große Textdatei mit Shellscript
Erstellen und entschlüsseln Sie Caesar-Code mit Python
Erstellen Sie ein Sternensystem mit Blender 2.80-Skript
VM mit YAML-Datei (KVM) erstellen
Erstellen Sie eine einfache Web-App mit Flasche
Löse AtCoder ABC168 mit Python (A ~ D)
Erstellen Sie mit Python 3.4 einen Worthäufigkeitszähler