MATLAB 编写多页 tiff 呈指数级缓慢

use*_*918 6 matlab tiff libtiff

我正在尝试编写一个多页 tiff 文件,它是 128 像素 x 128 像素 x 122000 帧的 16 位无符号整数。ImageJ 或简短的 Python 脚本可以在不到一分钟的时间内在快速机器上完成此操作。在同一台机器上,使用我尝试过的任何方法,MATLAB 可能需要几天时间才能完成。这是我迄今为止尝试过的:

使用 imwrite 将 IMG 写入 test.tif(MATLAB 文档推荐)

    tic
    numframes=size(IMG,3);
    divider=10^(floor(log10(numframes))-1);
    imwrite(IMG(:,:,1),'test.tif');
    for i=2:numframes;
        imwrite(IMG(:,:,i),'test.tif','WriteMode','append');
        if (round(i/divider)==i/divider)
            fprintf('Frame %d written in %.0f seconds, %2d percent complete, time                 left=%.0f seconds \n', ...
                i, toc, i/numframes*100, (numframes - i)/(i/toc));
        end
    end
Run Code Online (Sandbox Code Playgroud)

这导致以下输出:

第 10000 帧在 104 秒内写入,8.196721e+00% 完成,剩余时间=1163 秒 20000 帧在 296 秒内写入,1.639344e+01% 完成,剩余时间=1509 秒 30000 帧写入 5.4509%,296 秒完成,剩余时间=1809 秒 40000 帧用 1035 秒写入,3.278689e+01% 完成,剩余时间=2121 秒 50000 帧用 1682 秒写入,4.098361e+01% 完成,剩余时间=2421 秒

请注意随着写入更多帧,时间呈指数增长。

直接使用 Tiff 类

    if bigtiff
        t = Tiff(fname,'w8');
    else
        t = Tiff(fname,'w');
    end
    tagstruct.ImageLength = size(image,1);
    tagstruct.ImageWidth = size(image,2);
    tagstruct.Photometric = Tiff.Photometric.MinIsBlack;
    if bitspersamp==16
        tagstruct.BitsPerSample = 16;
    end
    if bitspersamp==32
        tagstruct.BitsPerSample = 32;
    end
    tagstruct.SamplesPerPixel = 1;
    tagstruct.RowsPerStrip = 256;
    tagstruct.PlanarConfiguration = Tiff.PlanarConfiguration.Chunky;
    tagstruct.Software = 'MATLAB';
    t.setTag(tagstruct);
    t.write(image(:,:,1));
    numframes = size(image,3);
    divider = 10^(floor(log10(numframes))-1);
    tic
    for i=2:numframes
        t.writeDirectory();
        t.setTag(tagstruct);
        t.write(image(:,:,i));
        if (round(i/divider)==i/divider)
            fprintf('Frame %d written in %.0f seconds, %2d percent complete, time left=%.0f seconds \n', ...
                i, toc, i/numframes*100, (numframes - i)/(i/toc));
        end
    end
    t.close();
Run Code Online (Sandbox Code Playgroud)

这导致以下输出:

Frame 10000 written in 66 seconds, 8.196721e+00 percent complete, time left=743 seconds 
Frame 20000 written in 225 seconds, 1.639344e+01 percent complete, time left=1145 seconds 
Frame 30000 written in 481 seconds, 2.459016e+01 percent complete, time left=1474 seconds 
Frame 40000 written in 915 seconds, 3.278689e+01 percent complete, time left=1877 seconds 
Frame 50000 written in 1512 seconds, 4.098361e+01 percent complete, time left=2177 seconds
Run Code Online (Sandbox Code Playgroud)

尝试使用 BigTIFF 库不起作用

遵循此处的讨论:http : //blogs.mathworks.com/steve/2013/08/07/tiff-bigtiff-and-blockproc/

我试图通过将第 73 行更改为:

    obj.TiffObject.setTag('BitsPerSample', 16);
Run Code Online (Sandbox Code Playgroud)

但是写完之后

outFileWriter = bigTiffWriter('test.tif', inFileInfo(1).Height, inFileInfo(1).Width, tileSize(1), tileSize(2));
for i=1:122000
    blockproc(IMG(:,:,i),tileSize,@(b) b.data,'Destination',outFileWriter);
    if rem(i,10000)==0
        fprintf('Frame %d done\n',i)
    end
end
Run Code Online (Sandbox Code Playgroud)

尝试回读时出现以下错误:

Unexpected Standard exception from MEX file.
What() is:std::bad_alloc
..

Error in imtifinfo (line 27)
raw_tags = tifftagsread(filename,0,0,0);

Error in imfinfo (line 183)
info = feval(fmt_s.info, filename);

Error in TiffReader (line 11)
InfoImage=imfinfo(fname);
Run Code Online (Sandbox Code Playgroud)

在相关说明中,在磁盘上预先分配具有正确大小的文件没有区别

我认为这是一个文件 I/O 问题的可能性很小,在这种情况下,预先分配磁盘空间可能是相关的,所以我尝试了这里提到的内容:http : //www.mathworks.co.uk/matlabcentral/ newsreader/view_thread/241072,即:

% Create the file
fh = javaObject('java.io.RandomAccessFile', 'test.dat', 'rw');
% Allocate the right amount of space
fh.setLength(1024);
% Close the file
fh.close();
Run Code Online (Sandbox Code Playgroud)

但它没有任何区别。

任何帮助将不胜感激。

2di*_*com 0

我遇到了同样的问题,但更糟糕的是:即使你再写一个 tiff,写一帧的时间也会增加。

因此,一个解决方案(对于我的多个文件的情况效果更好)是为每个 shell 命令调用重新启动 matlab 会话。

因此,在“writeTIFF.m”中,您应该有一个变量“startFrame”,并在脚本末尾放置一个“exit”。您可以通过以下行使用此类批处理(或 linux/unix 下的等效命令)来解决它:

@echo off
setlocal EnableDelayedExpansion 
:: count to 5 storing the results in a variable
set _tst=0
FOR /l %%G in (100,100,300) Do (
    echo matlab -r "startFrame=%%G;writeTIFF"  -nosplash -nodesktop -wait
    matlab -r "startFrame=%%G;writeTIFF"  -nosplash -nodesktop -wait
)
echo Done
Run Code Online (Sandbox Code Playgroud)

我没有进行大量测试,但它应该执行预期的操作:重新启动 matlab 3 次,并依次使用值 100、200 和 300 初始化变量“startFrame”。