尝试使用scipy.io.loadmat读取.mat文件时,“TypeError:缓冲区对于请求的数组来说太小”

时间:2015-08-27 23:23:25

标签: python matlab numpy scipy

我有这样的代码:

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.

我该如何解决问题?

2 个答案:

答案 0 :(得分:4)

这个脚本构造一个命令行,用它调用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无法运行或保存其文件。我必须进行实验。

BINGO - .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,并且没有此类文件&#39;。

我不认为scipy开发人员预计有人会尝试加载一个空的.mat文件,否则他们会抓住并翻译此错误。

答案 1 :(得分:2)

我已经解决了这个问题。

我告诉过你,我已经在具有MATLAB 2014的不同计算机上运行了代码,并且它运行良好。

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

我已经删除了gcc 4.9,并安装了4.7,问题已经解决了。 :)