Heim > Artikel > Backend-Entwicklung > So verwenden Sie NumPy zum Lesen und Speichern von Punktwolkendaten in Python
【Verwandte Empfehlung: Python3-Video-Tutorial】
Vor kurzem habe ich beim Erlernen der Punktwolkenverarbeitung den Datensatz Modelnet40
verwendet, der insgesamt enthält 40
Kategorien, die Punktwolkendaten jeder Probe werden in einer TXT
-Datei gespeichert und die ersten 3 Daten in jeder Zeile repräsentieren die xyz
-Koordinaten eines Punktes . Ich muss jeden Punkt in der TXT
-Datei lesen und ihn dann mit Open3D
anzeigen. Wie lese ich Daten aus einer TXT
-Datei? NumPy
bietet eine sehr leistungsstarke Funktion loadtxt
, die diese Funktion sehr einfach implementieren kann. Schauen wir uns den Code an: Modelnet40
数据集,该数据集总共有40
个类别,每个样本的点云数据存放在一个TXT
文件中,每行的前3个数据代表一个点的xyz
坐标。我需要把TXT
文件中的每个点读取出来,然后用Open3D
进行显示。怎么把数据从TXT
文件中读取出来呢?NumPy
提供了一个功能非常强大的函数loadtxt
可以非常简单地实现这个功能。来看一下代码:
import open3d as o3d import numpy as np def main(): points_data = np.loadtxt("airplane_0001.txt", delimiter=",", dtype=np.float32) pcd = o3d.geometry.PointCloud() pcd.points = o3d.utility.Vector3dVector(points_data[:, :3]) o3d.visualization.draw_geometries([pcd]) if __name__ == '__main__': main()
从上面的代码可以看到,只需要一行代码就可以把TXT
文件中的点云数据读取进来了,接下来就可以调用Open3D
的接口进行显示了。在介绍loadtxt
函数的用法之前,
顺便看一下Open3D的显示效果:
在上面的例子中,由于TXT
里面每一行的数据是用逗号分割的,所以在调用loadtxt
函数的时候除了设置文件路径外,还需要设置参数delimiter=","
。另外,该函数默认的数据类型为float64
,如果是其他数据类型的话还需要设置dtype
为对应类型。
points_data = np.loadtxt("airplane_0001.txt", delimiter=",") #没有指定数据类型 print('shape: ', points_data.shape) print('data type: ', points_data.dtype)
结果:
shape: (10000, 6)
data type: float64
假如我们有一个CSV
文件:
x,y,z,label,id -0.098790,-0.182300,0.163800,1,1 0.994600,0.074420,0.010250,0.2,2 0.189900,-0.292200,-0.926300,3,3 -0.989200,0.074610,-0.012350,4,4
该文件前面3列的数据类型是浮点型,后面2列的数据类型为整型,那么按照前面的方式设置dtype
来读取就不合适了。不过没关系,loadtxt
函数可以设置每一列数据的数据类型,只不过稍微复杂一点,来看一下代码:
data = np.loadtxt("test.txt", delimiter=",", dtype={'names': ('x', 'y', 'z', 'label', 'id'), 'formats': ('f4', 'f4', 'f4', 'i4', 'i4')}, skiprows=1) print('data: ', data) print('data type: ', data.dtype)
这段代码的重点是dtype={}
里面的内容,'names'
用来设置每一列数据的名称,'formats'
则用来设置每一列数据的数据类型,其中'f4'
表示float32
,'i4'
表示int32
。另外,CSV
文件中的第一行不是数据内容,可以设置参数skiprows=1
跳过第一行的内容。
输出结果:
data: [(-0.09879, -0.1823 , 0.1638 , 1, 1) ( 0.9946 , 0.07442, 0.01025, 0, 2)
( 0.1899 , -0.2922 , -0.9263 , 3, 3) (-0.9892 , 0.07461, -0.01235, 4, 4)]
data type: [('x', '
可以看到,通过这样的方式设置dtype
,读取的每一行数据变成了一个tuple
类型。
从NumPy
的文档中可以知道,loadtxt
函数的第一个参数可以是文件对象、文件名或者生成器。传入生成器有什么用呢?我们来看几个例子。
处理多个分隔符
假如我们的文件内容是这样的,每一行数据有3个分隔符",","/"和"-":
9.87,1.82,1.63,1/11-1 9.94,7.44,1.02,1/11-2 1.89,2.92,9.26,1/11-3 0.98,7.46,1.23,1/11-4
这种情况下不能通过delimiter
参数设置多个分隔符,这时候就可以通过生成器来进行处理:
def generate_lines(file_path, delimiters=[]): with open("test.txt") as f: for line in f: line = line.strip() for d in delimiters: line = line.replace(d, " ") yield line delimiters = [",", "/", "-"] generator = generate_lines("test.txt", delimiters) data = np.loadtxt(generator) print(data)
这段代码构建了一个生成器将文件中每一行的分隔符全部替换成loadtxt
函数默认的空格分隔符,然后把生成器传入loadtxt
函数,这样loadtxt
def generate_lines(file_path, delimiters=[], rows=[]): with open("test.txt") as f: for i, line in enumerate(f): line = line.strip() for d in delimiters: line = line.replace(d, " ") if i in rows: yield line delimiters = [",", "/", "-"] rows = [1, 2] generator = generate_lines("test.txt", delimiters, rows) data = np.loadtxt(generator) print(data)Wie Sie dem obigen Code entnehmen können, ist nur eine Codezeile erforderlich, um die Punktwolkendaten in der
TXT
-Datei zu lesen, und dann können Sie sie aufrufen Die Benutzeroberfläche von Open3D
wird angezeigt. Bevor Sie die Verwendung der Funktion loadtxt
vorstellen, werfen Sie einen Blick auf den Anzeigeeffekt von Open3D: Verwendung der Loadtxt-Funktion
Grundlegende Verwendung
Im Obigen Beispiel: Da die Daten in jeder Zeile von
TXT
durch Kommas getrennt sind, müssen Sie beim Aufruf der Funktionloadtxt
zusätzlich zum Festlegen des Dateipfads auch den Parameter delimiter=" ,". Darüber hinaus ist der Standarddatentyp dieser Funktionfloat64
. Wenn es sich um andere Datentypen handelt, müssen Siedtype
auf den entsprechenden Typ festlegen.import open3d as o3d import numpy as np def main(): points_data = np.loadtxt( "airplane_0001.txt", delimiter=",", dtype=np.float32) bin_file = 'airplane_0001.bin' points_data = points_data[:, :3] points_data.tofile(bin_file) pc = np.fromfile(bin_file, dtype=np.float32) pc = pc.reshape(-1, 3) pcd = o3d.geometry.PointCloud() pcd.points = o3d.utility.Vector3dVector(pc) o3d.visualization.draw_geometries([pcd]) if __name__ == '__main__': main()
Ergebnis:
Form: (10000, 6)Datentyp: float64
🎜CSV
haben > Datei: 🎜rrreee🎜Der Datentyp der ersten drei Spalten dieser Datei ist Gleitkomma und der Datentyp der letzten beiden Spalten ist Ganzzahl. Daher ist es nicht angemessen, dtype
auf zu setzen Lesen Sie es auf die vorherige Art und Weise. Aber das spielt keine Rolle. Die Funktion loadtxt
kann den Datentyp jeder Datenspalte festlegen, aber es ist etwas komplizierter. Schauen wir uns den Code an: 🎜rrreee🎜Der entscheidende Punkt Dieser Code lautet dtype={}Im Inhalt des Codes> wird <code>'names'
verwendet, um den Namen jeder Datenspalte und 'formats' wird verwendet, um den Datentyp jeder Datenspalte festzulegen, wobei <code> 'f4'
für float32
und 'i4'
für int32. Darüber hinaus enthält die erste Zeile in der Datei CSV
keinen Dateninhalt. Sie können den Parameter skiprows=1
festlegen, um den Inhalt der ersten Zeile zu überspringen. 🎜🎜🎜Ausgabeergebnis: 🎜🎜🎜🎜Daten: [(-0,09879, -0,1823, 0,1638, 1, 1) (0,9946, 0,07442, 0,01025, 0, 2)🎜 (0,1899, -0,2 922, -0,9263, 3, 3 ) (-0,9892, 0,07461, -0,01235, 4, 4)]🎜Datentyp: [('x', 'tuple
. 🎜NumPy
können wir wissen, dass der erste Parameter der Funktion loadtxt
ein Dateiobjekt sein kann , Dateiname oder Generator. Welchen Nutzen hat die Einschaltung eines Generators? Schauen wir uns ein paar Beispiele an. 🎜🎜🎜Umgang mit mehreren Trennzeichen🎜🎜🎜🎜Wenn unser Dateiinhalt so ist, hat jede Datenzeile 3 Trennzeichen „“, „/“ und „-“: 🎜🎜rrreee🎜In diesem Fall nicht möglich. Setzen Sie mehrere Trennzeichen durch der delimiter
-Parameter, 🎜Dieses Mal können Sie ihn über den Generator verarbeiten: 🎜🎜rrreee🎜Dieser Code erstellt einen Generator, um alle Trennzeichen in jeder Zeile der Datei durch das Standard-Leerzeichentrennzeichen des loadtxt-Funktion und übergeben Sie dann den Generator an die loadtxt
-Funktion, damit die loadtxt
-Funktion die Daten in der Datei erfolgreich analysieren kann. 🎜🎜🎜Ausgabeergebnis: 🎜🎜🎜🎜[[ 9,87 1,82 1,63 1. 11. 1. ]🎜 [ 9,94 7,44 1,02 1. 11. 2. ]🎜 [ 1,89 2,92 9,26 1. 11. 3. ]🎜 [ 0,98 7,46 1.23 1. 11. 4. ]]🎜🎜🎜🎜Lesen Sie die angegebene Zeile🎜🎜在某些情况下,我们需要读取指定几行的数据,那么也可以通过生成器来实现。还是上面的文件内容,我们通过生成器来读取第2行和第3行:
def generate_lines(file_path, delimiters=[], rows=[]): with open("test.txt") as f: for i, line in enumerate(f): line = line.strip() for d in delimiters: line = line.replace(d, " ") if i in rows: yield line delimiters = [",", "/", "-"] rows = [1, 2] generator = generate_lines("test.txt", delimiters, rows) data = np.loadtxt(generator) print(data)
输出结果:
[[ 9.94 7.44 1.02 1. 11. 2. ]
[ 1.89 2.92 9.26 1. 11. 3. ]]
通过上面的例子可以知道,loadtxt
函数结合生成器使用可以实现很多的功能。
从TXT
文件中读取到点云数据后,我想把数据保存到二进制文件中,需要怎么操作呢?NumPy
的ndarray
类提供了tofile
函数可以非常方便地将数据保存到二进制文件中。把数据以二进制文件保存后又怎么读进来呢?NumPy
还提供了一个fromfile
函数用于从文本文件和二进制文件中读取数据。
import open3d as o3d import numpy as np def main(): points_data = np.loadtxt( "airplane_0001.txt", delimiter=",", dtype=np.float32) bin_file = 'airplane_0001.bin' points_data = points_data[:, :3] points_data.tofile(bin_file) pc = np.fromfile(bin_file, dtype=np.float32) pc = pc.reshape(-1, 3) pcd = o3d.geometry.PointCloud() pcd.points = o3d.utility.Vector3dVector(pc) o3d.visualization.draw_geometries([pcd]) if __name__ == '__main__': main()
在上面这段示例代码中,我从airplane_0001.txt
文件中读取了点云数据,然后通过tofile
函数将数据保存到二进制文件airplane_0001.bin
中,再用fromfile
函数从二进制文件中把点云数据读取出来用Open3D
进行显示。
为了前后呼应,让我们换个角度再看一眼显示效果:
【相关推荐:Python3视频教程 】
Das obige ist der detaillierte Inhalt vonSo verwenden Sie NumPy zum Lesen und Speichern von Punktwolkendaten in Python. Für weitere Informationen folgen Sie bitte anderen verwandten Artikeln auf der PHP chinesischen Website!