Maison > développement back-end > Tutoriel Python > Comment utiliser NumPy pour lire et enregistrer des données de nuages ​​de points en Python

Comment utiliser NumPy pour lire et enregistrer des données de nuages ​​de points en Python

WBOY
Libérer: 2022-09-02 16:52:16
avant
2525 Les gens l'ont consulté

【Recommandation associée : Tutoriel vidéo Python3

Avant-propos

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()
Copier après la connexion

从上面的代码可以看到,只需要一行代码就可以把TXT文件中的点云数据读取进来了,接下来就可以调用Open3D的接口进行显示了。在介绍loadtxt函数的用法之前,

顺便看一下Open3D的显示效果:

loadtxt函数的用法

基本用法

在上面的例子中,由于TXT里面每一行的数据是用逗号分割的,所以在调用loadtxt函数的时候除了设置文件路径外,还需要设置参数delimiter=","。另外,该函数默认的数据类型为float64,如果是其他数据类型的话还需要设置dtype为对应类型。

points_data = np.loadtxt("airplane_0001.txt", delimiter=",") #没有指定数据类型
print('shape: ', points_data.shape)
print('data type: ', points_data.dtype)
Copier après la connexion

结果:

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
Copier après la connexion

该文件前面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)
Copier après la connexion

这段代码的重点是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
Copier après la connexion

这种情况下不能通过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)
Copier après la connexion

这段代码构建了一个生成器将文件中每一行的分隔符全部替换成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)
Copier après la connexion
Copier après la connexion

Comme vous pouvez le voir dans le code ci-dessus, une seule ligne de code est nécessaire pour lire les données du nuage de points dans le fichier 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 loadtxt

Utilisation de base


Dans ce qui précède exemple, étant donné que les données de chaque ligne de TXT sont séparées par des virgules, lors de l'appel de la fonction loadtxt, en plus de définir le chemin du fichier, vous devez également définir le paramètre delimiter=" ,". De plus, le type de données par défaut de cette fonction est float64. S'il s'agit d'autres types de données, vous devez définir dtype 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 connexion
Copier après la connexion

Résultat :

🎜forme : (10000, 6)🎜type de données : float64 🎜🎜

Spécifiez le type de données de chaque colonne

🎜Si nous avons un 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', 'dtype de cette façon, chaque ligne de données lues devient un type tuple. 🎜

Utilisé en combinaison avec des générateurs

🎜D'après la documentation de 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)
Copier après la connexion
Copier après la connexion

输出结果:

[[ 9.94 7.44 1.02 1. 11. 2. ]
[ 1.89 2.92 9.26 1. 11. 3. ]]

通过上面的例子可以知道,loadtxt函数结合生成器使用可以实现很多的功能。

tofile和fromfile函数

TXT文件中读取到点云数据后,我想把数据保存到二进制文件中,需要怎么操作呢?NumPyndarray类提供了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 = &#39;airplane_0001.bin&#39;
    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__ == &#39;__main__&#39;:
    main()
Copier après la connexion
Copier après la connexion

在上面这段示例代码中,我从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!

Étiquettes associées:
source:jb51.net
Déclaration de ce site Web
Le contenu de cet article est volontairement contribué par les internautes et les droits d'auteur appartiennent à l'auteur original. Ce site n'assume aucune responsabilité légale correspondante. Si vous trouvez un contenu suspecté de plagiat ou de contrefaçon, veuillez contacter admin@php.cn
Tutoriels populaires
Plus>
Derniers téléchargements
Plus>
effets Web
Code source du site Web
Matériel du site Web
Modèle frontal