Home > Article > Backend Development > How to use NumPy to read and save point cloud data in Python
[Related recommendations: Python3 video tutorial]
When I was learning point cloud processing recently The Modelnet40
data set is used. The data set has a total of 40
categories. The point cloud data of each sample is stored in a TXT
file. Each line The first 3 data represent the xyz
coordinates of a point. I need to read each point in the TXT
file and then display it using Open3D
. How to read data from the TXT
file? NumPy
provides a very powerful function loadtxt
that can implement this function very simply. Let’s take a look at the code:
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()
As you can see from the above code, only one line of code is needed to read the point cloud data in the TXT
file, and then you can call The interface of Open3D
is displayed. Before introducing the usage of the loadtxt
function,
take a look at the display effect of Open3D:
In the above example, since the data in each row of TXT
is separated by commas, so when calling loadtxt
In addition to setting the file path when using the function, you also need to set the parameters delimiter=","
. In addition, the default data type of this function is float64
. If it is other data types, you need to set dtype
to the corresponding type.
points_data = np.loadtxt("airplane_0001.txt", delimiter=",") #没有指定数据类型 print('shape: ', points_data.shape) print('data type: ', points_data.dtype)
Result:
shape: (10000, 6)
data type: float64
Suppose we have a CSV
file:
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
The data type of the first three columns of the file is floating point, and the data type of the next two columns is integer type, then it is not appropriate to set dtype
to read it in the previous way. But it doesn’t matter. The loadtxt
function can set the data type of each column of data, but it is a little more complicated. Let’s take a look at the code:
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)
The key point of this code is dtype={ }
The content inside, 'names'
is used to set the name of each column of data, 'formats'
is used to set the data type of each column of data, among which 'f4'
represents float32
, 'i4'
represents int32
. In addition, the first line in the CSV
file is not the data content. You can set the parameter skiprows=1
to skip the content of the first line.
Output result:
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', '
You can see that by setting dtype
in this way, each row of data read becomes a tuple
type.
From the documentation of NumPy
, we can know that the first parameter of the loadtxt
function can be a file object or a file name Or generator. What is the use of passing in a generator? Let's look at a few examples.
Handling multiple delimiters
If our file content is like this, each line of data has 3 delimiters ",", "/" and "-":
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
In this case, multiple delimiters cannot be set through the delimiter
parameter. In this case, it can be processed through the generator:
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)
This code builds a generator to replace all the delimiters of each line in the file with the default space delimiter of the loadtxt
function, and then passes the generator into loadtxt
function, so that the loadtxt
function can successfully parse the data in the file.
Output result:
[[ 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. ]]
Read the specified line
在某些情况下,我们需要读取指定几行的数据,那么也可以通过生成器来实现。还是上面的文件内容,我们通过生成器来读取第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视频教程 】
The above is the detailed content of How to use NumPy to read and save point cloud data in Python. For more information, please follow other related articles on the PHP Chinese website!