8

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

因此,有必要将非常大的图像导出到单个文件中。考虑到这些图像的大小可以从 800 MB 到数 GB 不等,我觉得这很麻烦。仅将单个图像加载到内存的任务就具有挑战性,尤其是在进行图像分析时。

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

构成这些图像的当前方法是:

  1. BufferedImage使用 a将像素值存储到aWritableRaster

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

这种方法的问题是它对于 8GB RAM 机器的内存占用太大。

理想情况下,我想要的是只有一个short[][]pixels. 这主要是因为我需要计算一个平均混合函数,所以会有一些内存占用。同样在未来我将添加一个线性混合。对于short[][]pixels20k x 20k 像素数据,应该只占用约 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

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

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

4

4 回答 4

3

通过SCIFIO项目,我们将 Bio-Formats 图像 I/O 框架推广到一般的科学成像,而不仅仅是显微镜和生命科学。SCIFIO API 现在处于测试阶段,包括 TIFF,它当然可以在瓷砖中读取写入。欢迎对SCIFIO 邮件列表中的 API 和错误提供反馈!

于 2013-09-26T17:07:55.840 回答
2

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

该规范可在此处下载。具体来说,第 13-14 页(几乎)是您了解 TIFF 是什么以及如何编写它所需的全部内容。

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

于 2013-09-24T16:33:35.660 回答
2

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

感谢@bdares 指出 BigTiff。

但是与 FIJI 打包在一起,有实现 scifio 的 bioformats 组。

它们提供了许多受支持的读取器/写入器,其中一个是 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

我已经编辑了我的原始帖子。谢谢大家的评论,它帮助我找到了正确的方向。

于 2013-09-24T19:03:13.403 回答
0

你有一个双短数组。您需要将其存储在磁盘上并在磁盘上进行操作,而不是将其存储在内存中。BufferedImage 不会有帮助。您需要一个库(或编写一个库)来允许操作磁盘上的图像,而无需将图像完全加载到内存中。

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

  1. 读取一个块(可能是 4k、8k 或 40k 有意义的)。
  2. 处理整个块。
  3. 将块写入磁盘。
  4. 转到步骤 1 直到完成。
于 2013-09-24T15:59:05.893 回答