SoFunction
Updated on 2024-10-29

How Python reads and saves point cloud data with NumPy

preamble

Recently, I used it when learning about point cloud processingModelnet40The dataset, which has a total of40categories, and the point cloud data for each sample is stored in aTXTfile, the first 3 data in each line represent a point in thexyzCoordinates. I need to put theTXTEach point in the file is read out, and then theOpen3DMake a display. How do you get the data from theTXTWhat about reading it out of the file?NumPyA very powerful function is providedloadtxtThis can be done very simply. Take a look at the code:

import open3d as o3d
import numpy as np

def main():
    points_data = ("airplane_0001.txt", delimiter=",", dtype=np.float32)
    pcd = ()
     = .Vector3dVector(points_data[:, :3])
    .draw_geometries([pcd])

if __name__ == '__main__':
    main()

As you can see from the code above, only one line of code is needed to put theTXTNow that the point cloud data in the file is read in, the next step is to call theOpen3Dof the interface is displayed. In the introduction of theloadtxtBefore the usage of the function

By the way, take a look at the Open3D display:

Usage of the loadtxt function

basic usage

In the above example, since theTXTEach line of data inside is separated by a comma, so when calling theloadtxtIn addition to setting the path to the file, you also need to set the parameterdelimiter=",". In addition, the default data type for this function isfloat64If you have other data types, you need to set thedtypeis the corresponding type.

points_data = ("airplane_0001.txt", delimiter=",") # No data type specified
print('shape: ', points_data.shape)
print('data type: ', points_data.dtype)

Results:

shape:  (10000, 6)
data type:  float64 

Specify the data type of each column

Suppose we have aCSVDocumentation:

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 last two columns is integer, so set it up in the same way as beforedtypeIt wouldn't be appropriate to come and read it. But that's okay.loadtxtfunction can set the data type of each column of data, only slightly more complex, look at the code:

data = ("", delimiter=",",
                      dtype={'names': ('x', 'y', 'z', 'label', 'id'), 
                            'formats': ('f4', 'f4', 'f4', 'i4', 'i4')},
                      skiprows=1)
print('data: ', data)
print('data type: ', )

The point of this code isdtype={}Inside.'names'used to set the name of each column of data.'formats'is used to set the data type of each column of data, where'f4'indicatefloat32'i4'indicateint32. Also.CSVThe first line in the file is not the data content, you can set the parameterskiprows=1Skip the first line.

Output results:

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', '<f4'), ('y', '<f4'), ('z', '<f4'), ('label', '<i4'), ('id', '<i4')]

As you can see, by setting up thedtype, each line of data read becomes atupleType.

Used in conjunction with generators

through (a gap)NumPyIt is known from the documentation of theloadtxtThe first argument to the function can be a file object, a filename, or a generator. What is the use of passing in a generator? Let's look at a couple of examples.

Handling multiple separators

Suppose the content of our file looks like this, with 3 separators ",", "/" and "-" for each line of data:

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

This case cannot be passeddelimiterparameter sets multiple separators.This is where the generator comes in:

def generate_lines(file_path, delimiters=[]):
    with open("") as f:
        for line in f:
            line = ()
            for d in delimiters:
                line = (d, " ")
            yield line

delimiters = [",", "/", "-"]
generator = generate_lines("", delimiters)
data = (generator)
print(data)

This code builds a generator that replaces all of the separators on each line of the file with aloadtxtfunction's default space separator, then pass the generator into theloadtxtfunction so that theloadtxtfunction will be able to successfully parse the data in the file.

Output results:

[[ 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.  ]]

Reads the specified line

In some cases, we need to read a specified number of rows of data, then you can also use the generator to achieve. Or the contents of the file above, we read the second and third line through the generator:

def generate_lines(file_path, delimiters=[], rows=[]):
    with open("") as f:
        for i, line in enumerate(f):
            line = ()
            for d in delimiters:
                line = (d, " ")
            if i in rows:
                yield line

delimiters = [",", "/", "-"]
rows = [1, 2]
generator = generate_lines("", delimiters, rows)
data = (generator)
print(data)

Output results:

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

As you can see by the example above, theloadtxtFunctions can accomplish a lot when used in conjunction with generators.

The tofile and fromfile functions

through (a gap)TXTAfter reading the point cloud data in the file, I want to save the data to a binary file, what do I need to do?NumPy(used form a nominal expression)ndarrayclass provides thetofileFunctions make it easy to save data to a binary file. How do you read in the data after saving it in a binary file?NumPyIt also provides afromfilefunction is used to read data from text files and binary files.

import open3d as o3d
import numpy as np

def main():
    points_data = (
        "airplane_0001.txt", delimiter=",", dtype=np.float32)

    bin_file = 'airplane_0001.bin'
    points_data = points_data[:, :3]
    points_data.tofile(bin_file)

    pc = (bin_file, dtype=np.float32)
    pc = (-1, 3)
    pcd = ()
     = .Vector3dVector(pc)
    .draw_geometries([pcd])

if __name__ == '__main__':
    main()

In this sample code above, I'm starting from theairplane_0001.txtThe point cloud data was read from the file and then passed through thetofilefunction saves data to a binary fileairplane_0001.binin, and then usefromfilefunction reads the point cloud data out of the binary file using theOpen3DMake a display.

For context, let's take another look at the display from a different angle:

This article on how to use Python NumPy to read and save point cloud data is introduced to this article, more related Python NumPy content, please search for my previous articles or continue to browse the following related articles I hope you will support me in the future!