Java - 如何编写非常大(20,000x20,000像素或更大)的tif图像

时间:2013-09-24 15:50:12

标签: java image memory tiff imagej

我正在处理非常大的tif图像,我正在将它组成一个大的单个图像。我有一个由我的同事创建的库,它生成图像金字塔,并提供了一个非常方便的图像金字塔可视化工具。这个可视化器非常适合在大图像上获取峰值并在视觉上识别感兴趣的点,但客户对这些大图像的图像分析更感兴趣。

因此,有必要将非常大的图像导出到单个文件中。我发现这很麻烦,因为这些图像的大小可以从800 MB到多GB。只是将这个单个图像加载到内存中的任务很有挑战性,特别是在进行图像分析时。

我想知道,如果有可能在java中以块或逐行的方式写这个大的tiff图像。目前我的应用程序在小型(8 GB RAM)机器上的内存不足。

编写这些图像的当前方法是:

  1. 使用BufferedImage

    将像素值存储到WritableRaster
    short[][]pixels = ...
    BufferedImage image = new BufferedImage(width, height, type);
    WritableRaster = image.getRaster();
    for (int row = 0; row < height; row++)
    {
        for (int col = 0; col < width; col++)
        {
           raster.setSample(col, row, 0, pixel[row][col]);
        }
    }   
    
  2. 然后将缓冲的图像写入磁盘。对于这部分,我使用ImageJ将图像写为tif。如果有更好的方法支持16位灰度tif图像,那么我很乐意看看

    // BufferedImage image; from above
    ...
    ImagePlus img = new ImagePlus();
    img.setImage(image);
    FileSaver fs = new FileSaver(img);
    fs.saveAsTiff(file.getAbsolutePath());  
    
  3. 这种方法存在的问题是8GB的RAM机器占用的内存太大。

    理想情况下,我想要的只是一个short[][]pixels。这主要是因为我需要计算平均混合函数,因此会有一些内存占用。同样在将来我将添加一个线性混合。对于20k x 20k像素数据,short[][]pixels应该只占用~765 MB的RAM,我认为目前这是不可避免的,因此对于较大的图像,例如100k x 100k像素,我希望生物学家不希望导出此图像,因为它将占用18GB的RAM。

    稍后我会修改代码以支持导出像100k x 100k这样的超大图像。现在我可以假设一块内存来存储初始像素值。

    那么,将一部分tif图像写入磁盘的好方法是什么,这样我就可以支持写出核心图像,如100k x 100k图像。

    我确实看到了这篇文章:Write tiled output of TIFF, using ImageIO in Java

    但它只讨论了TIFF 6.0规范。但我会调查ImageOutputStreams。虽然Tif是野兽,但我可能会咬紧牙关并鼓励生物学家只出口感兴趣的区域。

    编辑: 找到了可行的解决方案:

    发信人: https://github.com/openmicroscopy/bioformats/blob/v4.4.8/components/scifio/src/loci/formats/out/TiffWriter.java

    READER: https://github.com/openmicroscopy/bioformats/blob/v4.4.8/components/scifio/src/loci/formats/in/TiffReader.java

    主要群组页面: https://github.com/openmicroscopy/bioformats

4 个答案:

答案 0 :(得分:3)

通过SCIFIO项目,我们将Bio-Formats图像I / O框架概括为一般目标科学成像,而不仅仅是显微镜和生命科学。 SCIFIO API现在处于测试阶段,而includes TIFF当然可以在平铺中readwrite。我们欢迎您对SCIFIO mailing list上的API和错误提出反馈!

答案 1 :(得分:2)

与您的评论相反,实施您自己的TIFF编写器并不困难。

规范可下载here。具体来说,第13-14页(几乎)只需要了解TIFF是什么以及如何编写它。

根据6.0规范(截至2013年9月的当前版本),最大图像大小为4GB。我建议转向BigTiff。规格的差异列在第二个链接上。

答案 2 :(得分:2)

好的,我在Java中找到了一个很好的解决方案。

感谢@bdares指出BigTiff。

但与FIJI打包在一起,生物制剂组实施了scifio。

他们提供了许多支持的读/写器,其中一个是TiffReader / Writer

https://github.com/openmicroscopy/bioformats/blob/v4.4.8/components/scifio/src/loci/formats/in/TiffReader.java

https://github.com/openmicroscopy/bioformats/blob/v4.4.8/components/scifio/src/loci/formats/out/TiffWriter.java

我已经编辑了我原来的帖子。谢谢大家的评论,这有助于我朝着正确的方向前进。

答案 3 :(得分:0)

你有一个双重数组。您需要将其存储在磁盘上并在磁盘上进行操作,而不是将其存储在内存中。 BufferedImage无济于事。您需要一个库(或编写库),允许在磁盘上处理图像,而无需将图像完全加载到内存中。

您不希望单独访问每个值。相反,你会想要做这样的事情:

  1. 阅读一个块(可能是4k,8k或40k,这是有意义的)。
  2. 处理整个区块。
  3. 将块写入磁盘。
  4. 转到步骤1直到完成。