我一直在尝试将使用laspy读取的点云列表的点附加到另一个点列表中,基本上是合并两个点云。当合并多个点云时,我一直在将所有点附加到同一个np.ndarray中,以便将其保存回laspy文件。现在,一旦要合并的所有点云的组合大小超过约350 MB,我就会收到“MemoryError”错误。
我尝试使用不同的方法编写点云文件,以便不必一次性将所有点都读入内存,但失败了,因为laspy在编写点云文件时确实很奇怪,以下是我发现的一些事情: laspy.File.points具有以下格式:
现在我的电脑有16 GB的RAM,其中在合并开始时大约有10 GB是空闲的。使用
几乎所有我使用的用例都可以完美地工作。它将提供的所有点云合并到一个新文件中的新点云中。然而,当生成的点云稍微有点过大时,尽管拥有比所需内存更多的内存,我会出现“MemoryError”错误。
这是我使用这些点云(下载.laz文件)启动程序时的日志,你需要使用laszip解压缩.laz文件才能在使用laspy时使用(至少在Windows上)。
如果有人知道这个问题的原因,任何帮助都将不胜感激。
我尝试使用不同的方法编写点云文件,以便不必一次性将所有点都读入内存,但失败了,因为laspy在编写点云文件时确实很奇怪,以下是我发现的一些事情: laspy.File.points具有以下格式:
array([((24315, 12245, 12080, 0, 24, 0, 0, 0, 202, 23205, 24735, 21930),),
...,
((15155, -23292, -6913, 0, 56, 0, 0, 0, 343, 36975, 37230, 37485),)],
dtype=[('point', [('X', '<i4'), ('Y', '<i4'), ('Z', '<i4'), ('intensity', '<u2'), ('flag_byte', 'u1'), ('raw_classification', 'u1'), ('scan_angle_rank', 'i1'), ('user_data', 'u1'), ('pt_src_id', '<u2'), ('red', '<u2'), ('green', '<u2'), ('blue', '<u2')])])
laspy.File.points
的变量类型是numpy.ndarray
。
laspy.File.points
的形状是(<numberOfRows>,)
,即一维数组,尽管每行有12个值(?)。
行的类型为numpy.void
。
为了写入laspy.File
,您需要创建一个新的以写模式打开的文件,从现有文件中复制标题,并将File.points设置为与上述完全相同的numpy数组。在设置点之后,不能再次设置它们,这意味着在设置点时需要知道最终行数。
您可以使用laspy.File.set_x(<arrayOfXValues>)
(类似方法)更改行的值,需要与laspy.File.points
具有相同的长度。现在我的电脑有16 GB的RAM,其中在合并开始时大约有10 GB是空闲的。使用
psutils
我可以获取到我的已用和可用内存,而且我从不低于9 GB的自由内存。使用psutil.Process(os.getpid()).memory_info().rss
我可以获取此进程所使用的内存,其最大值不超过650 MB。
在合并时,我首先读取第一个文件,然后迭代其他文件,逐个读取它们,并调用numpy.append(combinedPoints, otherPointcloudPoints)
将所有点堆叠在一起。然而,当上述条件为真时,这会抛出MemoryError
。
以下是将多个点云合并为一个新点云的代码(所有这些都发生在类PointCloudFileIO
中,self.file
是laspy.File
的实例)。util.inMB
将字节转换为兆字节的大小。
def mergePointClouds(self, listPaths, newPath):
realSize = util.inMB(psutil.Process(os.getpid()).memory_info().rss)
print("Process Memory used at start: {:.2f}MB".format(realSize))
print("Available memory at start: {:.2f}MB".format(util.inMB(psutil.virtual_memory().available)))
pointsOwn = self.file.points
firstOtherReader = PointCloudFileIO(listPaths[0])
pointsCombined = np.append(pointsOwn, firstOtherReader.file.points)
realSize = util.inMB(psutil.Process(os.getpid()).memory_info().rss)
print("Process Memory used after first merge: {:.2f}MB".format(realSize))
print("Available memory after first merge: {:.2f}MB".format(util.inMB(psutil.virtual_memory().available)))
for i in range(1, len(listPaths)):
otherReader = PointCloudFileIO(listPaths[i])
otherPoints = otherReader.file.points
pointsCombined = np.append(pointsCombined, otherPoints)
realSize = util.inMB(psutil.Process(os.getpid()).memory_info().rss)
print("Process Memory used in loop: {:.2f}MB".format(realSize))
print("Available memory in loop: {:.2f}MB | Used: {:.2f}MB | Percent: {}%".format(util.inMB(psutil.virtual_memory().available), util.inMB(psutil.virtual_memory().used), psutil.virtual_memory().percent))
outFile = File(newPath, mode='w', header=self.file.header)
outFile.points = pointsCombined
outFile.close()
几乎所有我使用的用例都可以完美地工作。它将提供的所有点云合并到一个新文件中的新点云中。然而,当生成的点云稍微有点过大时,尽管拥有比所需内存更多的内存,我会出现“MemoryError”错误。
这是我使用这些点云(下载.laz文件)启动程序时的日志,你需要使用laszip解压缩.laz文件才能在使用laspy时使用(至少在Windows上)。
Process Memory used at start: 21.18MB
Available memory at start: 9793.35MB | Used: 6549.50MB | Percent: 40.1%
Process Memory used after first merge: 381.63MB
Available memory after first merge: 9497.64MB | Used: 6845.20MB | Percent: 41.9%
Process Memory used in loop: 559.52MB
Available memory in loop: 9309.36MB | Used: 7033.48MB | Percent: 43.0%
Process Memory used in loop: 637.05MB
Available memory in loop: 9301.00MB | Used: 7041.85MB | Percent: 43.1%
Traceback (most recent call last):
File "optimization_test.py", line 7, in <module>
f1.mergePointClouds(paths, "someShiet.las")
File "C:\Users\viddie\Desktop\git\GeoLeo\geoleo\pointcloud.py", line 175, in mergePointClouds
pointsCombined = np.append(pointsCombined, otherPoints)
File "C:\Users\viddie\AppData\Local\Programs\Python\Python36-32\lib\site-packages\numpy\lib\function_base.py", line 5166, in append
return concatenate((arr, values), axis=axis)
MemoryError
如果有人知道这个问题的原因,任何帮助都将不胜感激。
concatenate
调用中。np.append
只是一个覆盖函数,它只接受2个数组。concatenate
接受整个数组列表。 在任何情况下,每次调用都会创建一个全新的数组。 它不像列表附加一样就地修改基础。 通常我们建议将数组收集到列表中,并在最后执行一个concatenate
。 通常这样更快。 我不能说它是否会避免ME-对于大数据,这种情况迟早会发生。 - hpauljdtype
,你就有了一个带有多个字段的一维结构化数组
。itemsize
给出了每个记录的大小(大约为4*12字节)。正如你发现的那样,当你连接这些数组时,它们都必须具有相同的复合dtype
。 - hpauljPython36-32
看来,您正在使用 32 位版本的 Python。在这种情况下,您的可用内存是无关紧要的,因为 Windows 只会分配比 32 位应用程序所需的内存少得多的内存。(请参见此帖子) - eaglesear