逐像素读取数组,获取UnpicklingError

时间:2018-08-29 20:12:39

标签: python arrays python-3.x numpy pickle

我以前使用pickle将数千个2D numpy数组(600x600)保存到二进制文件中。由于内存限制,我一张一张地保存它们,现在我想一张一张地读取它们,执行一些操作,然后将新数组(也一张一张地)保存到一个新文件中。然后,我的最后一个目标是逐个读取这些新数组,并将像素值附加到与给定位置相对应的新列表中。但是由于某种原因,我得到了UnpickingError,但不确定为什么。

import numpy as np
import pickle

def normalize(data_set):
    data_set *= 1/data_set.max()
    with open('final_images.data', 'a+b') as f:
        pickle.dump(data_set, f)
    return data_set

with open('initial_data.data', 'rb') as f:
    while True:
        try:
            data_set = pickle.load(f)
            # other operations
            final_img = normalize(data_set)
        except EOFError:
            break

filename = 'final_images.data'
def sort_by_pixel(i, j):
    pixels_at_position = []
    with open(filename, 'rb') as f:
        while True:
            try:
                array = pickle.load(f) #GET ERROR HERE
                fp = np.memmap(filename, dtype='float32', mode='w+', shape=(600,600))
                fp[:] = array[:]
                pixels_at_position.append(fp[i][j])
            except EOFError:
                break
    return pixels_at_position

stacked = []
for i in range(600):
    for j in range(600):
        stacked.append(np.median(sort_by_pixel(i, j)))

我在指示的行出现的错误是:

pickle.UnpicklingError: invalid load key, '\x00'.

我在做什么错了?

1 个答案:

答案 0 :(得分:1)

您有一个完全有效的泡菜文件final_images.data,您已在其中附加了泡菜转储。因此,第一次通过循环,array = pickle.load(f)将起作用。

但是您随后映射了相同的文件:

fp = np.memmap(filename, dtype='float32', mode='w+', shape=(600,600))

fp将充满垃圾,试图将泡菜流解释为原始数组数据,但是由于您实际上并不使用该数据,所以没关系。

但是随后,您使用上次加载的泡菜的原始数组数据覆盖了整个文件:

fp[:] = array[:]

现在,该文件不再是有效的泡菜文件,而是原始数据。

因此,下一次遍历循环时,当您pickle.load退出循环时,它将失败,从而给您恰到好处的错误。 1


如果您实际上在这里需要一个mmap,则要将其存储在一个不同的文件中,而不要覆盖您正在阅读的腌制文件:

fp = np.memmap(filename + '.raw', dtype='float32', mode='w+', shape=(600,600))

但是,实际上,我一开始看不到mmap有什么用。您已经在内存中获得了与array完全相同的数组。制作一个memmap,然后将数据复制到其中,只是浪费资源,没有我看到的好处。如果您只是完全删除该行,然后执行pixels_at_position.append(array[i][j]),则它应该具有您想要的效果。 2

我实际上并不是要确保您要这样做,因为您的代码似乎想做的是在其中建立每个数组的第(i, j)个值的列表泡菜,但函数的名称sort_by_pixel听起来像您真正想要的东西完全不同(某种东西经过排序)。


1。实际上,只有当您幸运时,它才会失败。如果原始数据足够小。 f文件指针可能已经结束了,您将获得一个EOF。而且,如果您真的很倒霉,那么原始数据可能会被解释为日期时间对象元组或某些疯狂对象的泡菜,而您只会无声地产生大量垃圾。 sub>

2。除非您确实应该使用[i, j],而不是[i][j]。后者必须创建一个行对象,以便可以对其进行索引。这并不太昂贵,因为该行只是与原始数组相同的内存切片,但是它仍然不是免费的。而且它也不太习惯,因此也不太清楚-读[i, j]的人知道您正在索引2D数组;读[i][j]的人会期望您正在索引一个(可能是锯齿状的)序列序列,因此必须弄清楚它实际上是一个2D数组。