我正在搜索能够读取图像文件区域(任何格式)的库(任何语言),而无需最初读取整个图像文件。
我遇到了一些选项,例如 vips,它确实不会将整个图像保存在内存中,但似乎仍然需要完全阅读它才能开始。
我意识到这可能不适用于 jpeg 等压缩格式,但理论上听起来 bmps 或 tiffs 应该允许这种类型的阅读。
我正在搜索能够读取图像文件区域(任何格式)的库(任何语言),而无需最初读取整个图像文件。
我遇到了一些选项,例如 vips,它确实不会将整个图像保存在内存中,但似乎仍然需要完全阅读它才能开始。
我意识到这可能不适用于 jpeg 等压缩格式,但理论上听起来 bmps 或 tiffs 应该允许这种类型的阅读。
libvips会在可能的情况下只读取您需要的部分。例如,如果您从大 PNG 的左上角裁剪 100x100 像素,则速度很快:
$ time vips crop wtc.png x.jpg 0 0 100 100
real 0m0.063s
user 0m0.041s
sys 0m0.023s
(四个数字分别是要裁剪wtc.png
和写入的区域的左、上、宽、高x.jpg
)
但是底部附近的 100x100 像素区域相当慢,因为它必须在您想要到达文件中正确点的像素之前读取和解压缩像素:
$ time vips crop wtc.png x.jpg 0 9000 100 100
real 0m3.063s
user 0m2.884s
sys 0m0.181s
JPG 和 strip TIFF 以相同的方式工作,但由于它们是更快的格式,所以不太明显。
某些格式支持真正的随机访问读取。例如,平铺 TIFF 在任何地方都很快,因为 libvips 可以使用 libtiff 只读取它需要的平铺:
$ vips copy wtc.png wtc.tif[tile]
$ time vips crop wtc.tif x.jpg 0 0 100 100
real 0m0.033s
user 0m0.013s
sys 0m0.021s
$ time vips crop wtc.tif x.jpg 0 9000 100 100
real 0m0.037s
user 0m0.021s
sys 0m0.017s
OpenSlide、vips、平铺 OpenEXR、FITS、二进制 PPM/PGM/PBM、HDR、RAW、Analyze、Matlab 和可能其他一些都支持像这样的真正随机访问。
如果您对更多细节感兴趣,API 文档中有一个章节描述了 libvips 如何打开文件:
http://libvips.github.io/libvips/API/current/How-it-opens-files.md.html
这是使用pyvips在 Python 中进行的裁剪加保存:
import pyvips
image = pyvips.Image.new_from_file(input_filename, access='sequential')
tile = image.crop(left, top, width, height)
tile.write_to_file(output_filename)
这access=
是一个标志,提示 libvips 可以流式传输此图像,以防底层文件格式不支持随机访问。对于支持随机访问的格式,例如平铺的 TIFF,您不需要它。
您不需要写入文件。例如,这将创建一个缓冲区对象,其中包含编码为 JPG 的文件:
buffer = tile.write_to_buffer('.jpg', Q=85)
或者这将直接写入stdout
:
target = pyvips.Target.new_from_descriptor(0)
tile.write_to_target('.jpg', Q=85)
这Q=85
是设置 JPG Q 因子的可选参数。您可以设置任何文件保存选项。
ITK可以使用某些格式来做到这一点。有一个方法CanStreamRead对于支持流的格式返回 true ,例如MetaImageIO。一个例子可以在这里找到。您可以在 ITK 的论坛上提出更详细的问题。
如果可以控制文件格式,我建议您使用平铺的 TIFF 文件。这些通常用于数字病理学全幻灯片图像,平均大小为 100kx30k 像素左右。
LibTiff可以轻松读取与选定 ROI 对应的图块。可以压缩切片,而不会降低读取小区域的效率(无需解码整个扫描线)。
BMP 格式(未压缩)非常简单,您可以自己编写函数。
TIFF 不太容易,因为有很多子格式。但是 TIFF 库 (TIFFlib) 支持“面向切片”的 I/O 模式。http://www.libtiff.org/libtiff.html#Tiles
我不知道这样的图书馆解决方案。
低级别的文件读取访问是特定于格式的,特别是文件映射是特定于操作系统的。
如果您可以访问原始字节,那么假设您知道通道的宽度、高度、深度和数量等。那么计算文件偏移量是微不足道的,所以只需自己动手。
如果您要通过网络传输提取的数据,您可能会考虑在内存中压缩提取的 ROI(如果它相对较大),然后再通过网络发送。