"TypeError: buffer is too small for requested array" when attempting to read a .mat file using scipy.io.loadmat

"TypeError: buffer is too small for requested array" when attempting to read a .mat file using scipy.io.loadmat

我有这样一段代码:

import tempfile
import subprocess
import shlex
import os
import numpy as np
import scipy.io

script_dirname = os.path.abspath(os.path.dirname(__file__))


def get_windows(image_fnames, cmd='selective_search'):
    f, output_filename = tempfile.mkstemp(suffix='.mat')
    os.close(f)
    fnames_cell = '{' + ','.join("'{}'".format(x) for x in image_fnames) + '}'
    command = "{}({}, '{}')".format(cmd, fnames_cell, output_filename)
    print(command)

    mc = "matlab -nojvm -r \"try; {}; catch; exit; end; exit\"".format(command)
    pid = subprocess.Popen(
        shlex.split(mc), stdout=open('/dev/null', 'w'), cwd=script_dirname)
    retcode = pid.wait()
    if retcode != 0:
        raise Exception("Matlab script did not exit successfully!")

    all_boxes = list(scipy.io.loadmat(output_filename)['all_boxes'][0])
    subtractor = np.array((1, 1, 0, 0))[np.newaxis, :]
    all_boxes = [boxes - subtractor for boxes in all_boxes]

    os.remove(output_filename)
    if len(all_boxes) != len(image_fnames):
        raise Exception("Something went wrong computing the windows!")
    return all_boxes

if __name__ == '__main__':

    import time

    image_filenames = [
        script_dirname + '/000015.jpg',
        script_dirname + '/cat.jpg'
    ] * 4
    t = time.time()
    boxes = get_windows(image_filenames)
    print(boxes[:2])
    print("Processed {} images in {:.3f} s".format(
        len(image_filenames), time.time() - t))

代码已经过测试,必须可以运行。

当我 运行 代码时,出现以下错误:

Traceback (most recent call last):
  File "selective_search.py", line 62, in <module>
    boxes = get_windows(image_filenames)

  File "selective_search.py", line 42, in get_windows
    all_boxes = list(scipy.io.loadmat(output_filename)['all_boxes'][0])

  File "/usr/lib/python2.7/dist-packages/scipy/io/matlab/mio.py", line 131, in loadmat
    MR = mat_reader_factory(file_name, appendmat, **kwargs)

  File "/usr/lib/python2.7/dist-packages/scipy/io/matlab/mio.py", line 55, in mat_reader_factory
    mjv, mnv = get_matfile_version(byte_stream)

  File "/usr/lib/python2.7/dist-packages/scipy/io/matlab/miobase.py", line 218, in get_matfile_version
    buffer = fileobj.read(4))

TypeError: buffer is too small for requested array

我正在使用 MATLAB 2015。

我该如何解决这个问题?

此脚本构建一个命令行,用它调用 MATLAB,然后读取生成的 .mat

我觉得你需要试一下:

  • MATLAB调用命令看起来对吗?

  • MATLAB 运行 可以吗?

  • .mat 是否有效(使用 MATLAB 读取)?

  • 你能从 Python 读到它吗 - 只是一个普通的 loadmat?

运行是多久以前的事了?适用于什么 MATLAB 版本?您可能需要更改此脚本,使其不会破坏临时文件,让您有机会以交互方式对其进行测试。

一种可能是 .mat 的格式 loadmat 无法处理。 MATLAB 一直在更改 .mat 格式,最新的是某种形式的 hd5?。您可能需要更改 MATLAB 脚本,使其使用较早的格式。我不记得加载较新的不兼容版本时会产生什么样的错误 loadmat


TypeError: buffer is too small for requested array 错误是我期望从 np.ndarray() 调用中得到的错误,而不是通常的 np.array。但是深入研究 loadmat 代码,scipy/io/matlab/mio5.py 我发现它确实使用了 ndarray。这确实表明某种文件格式不兼容,要么是 MATLAB 文件版本,要么是 32/64 位机器差异。


错误在

def get_matfile_version(fileobj):

函数,就在它尝试读取文件的前 4 个字节的开始处:

# Mat4 files have a zero somewhere in first 4 bytes
fileobj.seek(0)
mopt_bytes = np.ndarray(shape=(4,),
                       dtype=np.uint8,
                       buffer = fileobj.read(4))

它正在读取字节,并试图直接从中创建一个数组。这看起来像是一个直接的操作。除了,如果文件为空会发生什么?缓冲区将为 0 字节,太小了。如果是,则问题是 MATLAB 无法 运行 或无法保存其文件。我得试试。


宾果 - .mat 文件为空

In [270]: with open('test.mat','w') as f:pass  # empty file
In [271]: matlab.loadmat('test.mat')
---------------------------------------------------------------------------
...
/usr/lib/python3/dist-packages/scipy/io/matlab/miobase.py in get_matfile_version(fileobj)
    216     mopt_bytes = np.ndarray(shape=(4,),
    217                            dtype=np.uint8,
--> 218                            buffer = fileobj.read(4))
    219     if 0 in mopt_bytes:
    220         fileobj.seek(0)

TypeError: buffer is too small for requested array

所以由于某种原因,MATLAB 脚本失败了。 mkstemp 创建一个空的临时文件。通常 MATLAB 脚本会覆盖它(或追加?)。但是如果脚本失败(到 运行),那么这个文件仍然是空的,当你试图读取它时会产生这个错误。

如果您使用 tempfile 获取文件名,而不是创建文件,您将得到 OSError、'no such file'.

我认为 scipy 开发人员没有预料到有人会尝试加载一个空的 .mat 文件,否则他们会发现并解决这个错误。运行

我已经解决了问题

我告诉过你,我有 运行 在装有 MATLAB 2014 的不同计算机上的代码,并且它有效。

在那台电脑上,gcc版本是4.7,但在当前有MATLAB 2015的电脑上,gcc版本是4.9。

我把gcc 4.9去掉,装了4.7,问题解决了。 :)