【Recommandation associée : Tutoriel vidéo Python3】
Récemment, lors de l'apprentissage du traitement des nuages de points, j'ai utilisé l'ensemble de données Modelnet40
, qui a un total de 40 catégories
, les données du nuage de points de chaque échantillon sont stockées dans un fichier TXT
, et les 3 premières données de chaque ligne représentent les coordonnées xyz
d'un point . Je dois lire chaque point du fichier TXT
, puis l'afficher en utilisant Open3D
. Comment lire les données du fichier TXT
? NumPy
fournit une fonction très puissante loadtxt
qui permet d'implémenter cette fonction très simplement. Jetons un coup d'œil au code : 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)
TXT
, puis vous pouvez appeler L'interface de Open3D
s'affiche. Avant d'introduire l'utilisation de la fonction loadtxt
, jetez un œil à l'effet d'affichage d'Open3D :
Utilisation de la fonction loadtxtUtilisation de base
Dans ce qui précède exemple, étant donné que les données de chaque ligne deTXT
sont séparées par des virgules, lors de l'appel de la fonctionloadtxt
, en plus de définir le chemin du fichier, vous devez également définir le paramètredelimiter=" ,"
. De plus, le type de données par défaut de cette fonction estfloat64
. S'il s'agit d'autres types de données, vous devez définirdtype
sur le type correspondant.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()Copier après la connexionCopier après la connexion
Résultat :
🎜forme : (10000, 6)🎜type de données : float64 🎜🎜CSV</code > Fichier : 🎜rrreee🎜Le type de données des trois premières colonnes de ce fichier est à virgule flottante et le type de données des deux dernières colonnes est entier. Il n'est donc pas approprié de définir <code>dtype
pour lire. de la manière précédente. Mais ce n'est pas grave. La fonction loadtxt
peut définir le type de données de chaque colonne de données, mais c'est un peu plus compliqué. Jetons un coup d'œil au code : 🎜rrreee🎜Le point clé. de ce code est dtype={}</ Dans le contenu du code>, <code>'names'
est utilisé pour définir le nom de chaque colonne de données, et 'formats'< /code> est utilisé pour définir le type de données de chaque colonne de données, où <code> 'f4'
signifie float32
et 'i4'
signifie < code>int32. De plus, la première ligne du fichier CSV
ne contient pas de données. Vous pouvez définir le paramètre skiprows=1
pour ignorer le contenu de la première ligne. 🎜🎜🎜Résultat de sortie : 🎜🎜🎜🎜données : [(-0.09879, -0.1823 , 0.1638 , 1, 1) ( 0.9946 , 0.07442, 0.01025, 0, 2)🎜 ( 0.1899 , 922 , -0,9263 , 3, 3 ) (-0.9892, 0.07461, -0.01235, 4, 4)]🎜type de données : [('x', 'tuple
. 🎜NumPy
, on peut savoir que le premier paramètre de la fonction loadtxt
peut être un objet fichier , nom de fichier ou générateur. A quoi sert de passer dans un générateur ? Regardons quelques exemples. 🎜🎜🎜Gestion de plusieurs délimiteurs🎜🎜🎜🎜Si le contenu de notre fichier est comme ceci, chaque ligne de données a 3 délimiteurs ",", "/" et "-": 🎜🎜rrreee🎜Pas possible dans ce cas Définir plusieurs délimiteurs via le paramètre delimiter
, 🎜Cette fois, vous pouvez le traiter via le générateur : 🎜🎜rrreee🎜Ce code construit un générateur pour remplacer tous les délimiteurs de chaque ligne du fichier par le délimiteur d'espace par défaut du < code>loadtxt, puis transmettez le générateur dans la fonction loadtxt
, afin que la fonction loadtxt
puisse analyser avec succès les données du fichier . 🎜🎜🎜Résultat de sortie : 🎜🎜🎜🎜[[ 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. ]]🎜🎜🎜🎜Lire la ligne spécifiée🎜🎜在某些情况下,我们需要读取指定几行的数据,那么也可以通过生成器来实现。还是上面的文件内容,我们通过生成器来读取第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视频教程 】
Ce qui précède est le contenu détaillé de. pour plus d'informations, suivez d'autres articles connexes sur le site Web de PHP en chinois!