【问题标题】:MATLAB write multipage tiff exponentially slowMATLAB 写多页 tiff 指数级慢
【发布时间】:2014-04-18 22:00:03
【问题描述】:

我正在尝试编写一个 128 像素 x 128 像素 x 122000 帧的 16 位无符号整数的多页 tiff 文件。 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

导致以下输出:

第 10000 帧在 104 秒内写入,8.196721e+00% 完成, 剩余时间=1163 秒第 20000 帧在 296 秒内写入, 1.639344e+01% 完成,剩余时间=1509 秒帧 30000 在 590 秒内写入,2.459016e+01% 完成,剩余时间=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();

导致以下输出:

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

尝试使用 BigTIFF 库不起作用

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

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

将代码转换为使用 uint16 数据:
    obj.TiffObject.setTag('BitsPerSample', 16);

但是写完之后

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

我在尝试回读时收到以下错误:

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);

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

我认为这是文件 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();

但这并没有什么不同。

任何帮助将不胜感激。

【问题讨论】:

标签: matlab tiff libtiff


【解决方案1】:

我也曾经遇到过这个问题。 Matlab 2018b 似乎有两个可以处理 tiff 写入的 .mexw64 文件。

\toolbox\matlab\imagesci\private\toolbox\matlab\imagesci\private中的wtifc.mexw64被imwrite使用的writetif.m调用

tifflib.mexw64,同一位置,由 Tiff 对象使用。

使用多图像 tiff 文件都会减慢速度。使用fwrite写入所有图像数据并以指向该数据的指针结束时要快得多。

我用这个脚本测试了三种方法,差别还是蛮大的。 这是使用 matlab 2018b 完成的。

clear all;close all; clc; fclose all;
%generate some data
N=1E3;
IM=imread('landOcean.jpg');
IM = uint16(sum(IM,3));
IM = IM(100:310,960:1170);
IM = IM-min(IM(:));
IM=IM*(2^15/max(IM(:)));
IM = repmat(IM,[1,1,N])+randi((2^15)-1,[size(IM,1),size(IM,2),N],'uint16');
S = (numel(IM)/N*2)/2^20;


%imread writespeed
methods = {'imwrite','tifflib','fTIF'};
for M = 1:length(methods)
    method = methods{M};
    %file
    filename = [method,'.tif'];
    if exist(filename,'file'), delete(filename);end
    switch method
        case 'imwrite'
            %timing vector
            t = zeros(1,100+1);
            tic;
            imwrite(IM(:,:,1),filename);
            t(2)=toc;
            for ct = 2:100
                imwrite(IM(:,:,ct),filename,'WriteMode','append');
                t(ct+1)=toc;
            end
        case 'tifflib'
            %timing vector
            t = zeros(1,200+1);
            tic;
            tf = Tiff(filename,'w');
            for ct = 1:200
                if ct>1,tf.writeDirectory;end
                tf.setTag('Photometric',Tiff.Photometric.MinIsBlack);
                tf.setTag('Compression',Tiff.Compression.None);
                tf.setTag('BitsPerSample',16);
                tf.setTag('SamplesPerPixel',1);
                tf.setTag('SampleFormat',Tiff.SampleFormat.UInt);
                tf.setTag('ExtraSamples',Tiff.ExtraSamples.Unspecified);
                tf.setTag('ImageLength',size(IM,1));
                tf.setTag('ImageWidth',size(IM,2));
                tf.setTag('PlanarConfiguration',Tiff.PlanarConfiguration.Chunky);
                tf.setTag('ImageDescription',sprintf('ImageJ=1.51j\nchannels=%.0f',size(IM,3)));
                tf.write(IM(:,:,ct));
                t(ct)=toc;
            end
            tf.close();
        case 'fTIF'
            %timing vector
            t = zeros(1,size(IM,3)+1);
            tic
            fTIF = Fast_Tiff(filename);
            for ct = 1:size(IM,3)
                fTIF = fTIF.WriteIMG(IM(:,:,ct)');
                t(ct)=toc;
            end
            tic
            fTIF.close;
            toc
        otherwise
            error('unknown method')
    end
    S = (size(IM,1)*size(IM,2)*2)/2^20; %MB/frame
    y = S./diff(t);
    subplot(1,length(methods),M)
    plot([1:length(y)],y);
    title(sprintf('Writing with %s; mean = %.2f MB/s',method,mean(y)))
    ylabel('Writing speed (MB/s)')
    xlabel('Frame');
    drawnow;
end

fTIF 方法的代码:

https://github.com/rharkes/Fast_Tiff_Write

【讨论】:

  • 不错的代码!如果imread 没有读取文件,则可能是缺少标签,或者标签格式错误。你检查TIFF 6.0 specification了吗?
  • 谢谢!我确实检查了 tiff 规范,并认为我正确实现了所有标签。使用imfinfo 确实给了我正确的信息。对于 BitDepth(短)和 StripByteCounts(长)。我可以将来自 imfinfo 的指针提供给 fopen、fseek、fread 以检索数据。但是除了 ImageJ,没有读者会阅读该文件。稍后我会重新审视一下,希望能看到错误。
  • 这是一个错误的压缩标签。没有压缩 = 1,而不是我预期的 0。
  • 太棒了!很高兴你找到了!这是一段非常好的代码,写得很好,非常有用!我很确定我需要在某个时候“借用”它。 ;)
  • 这将是最好的赞美!如果您在借用时发现任何可以改进的地方,请告诉我,以便我也可以实施。
【解决方案2】:

我遇到了同样的问题,但更糟糕的是:即使你再写一个 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

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

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多