TIFF文件

发布时间 2023-06-01 08:55:07作者: Liang-ml

1. 什么是TIFF文件

TIFF (Tagged Image File Format) 标记图像文件格式,以tif或tiff为扩展名,通常由四部分组成,分别为:文件头信息区(IFH)、图像文件目录(IFD)、目录项(DE)和图像数据。

 

                

图像文件头信息区(IFH)

在每一个TIFF文件中第一个数据结构称为图像文件头或IFH (Image File Header),它是图像文件体系结构的最高层,位于文件的开始部分,这个位置是唯一的、固定的,包含着文件其他部分所需的必要信息。

图像文件目录(IFD)

IFD (Image File Directory)是TIFF文件的第2个数据结构,是一个名为标记 (tag) 的用于区分一个或多个可变长度数据块的表,tag中包含了有关图像的所有信息。

由于一个TIFF文件可以有多个图像,而一个IFD只标识一个图像的所有属性,故一个TIFF文件有几个图像就有几个IFD

IFD提供了一系列的指针,这些指针指向各种数据字段在文件中的起始位置,并给出每个字段的数据类型和长度,该方法允许数据字段定义在文件的任何地方,且可以为任意长度,因此文件格式十分灵活。

目录项(DE)

Byte 0-1: tag, 即该属性的标签编号,在文件目录中按升序排列

Byte 2-3: 数据类型

Byte 4-7: 数量,确定存储此tag的数据需要占据的字节数

Byte 8-11: 如果占用的字节数少于4,则数据直接存在此处,大于4则存放指向数据的指针

图像数据(Value)

根据IFD指向的地址,存储图像的具体信息。

TIFF的可扩展性很强,如jpeg、lossless jpeg以及任意数据宽度的原始无压缩数据都可以方便的嵌入到TIFF中去,对图像信息的存放灵活多变,能够使图像包含丰富的各类信息,所以在遥感、医学等数字影像领域都获得了广泛的应用。

2. Python与tiff

2.1 tiff文件的读取

tiff图像的编码格式为16bit, 使用python读取tiff图像通常有两种方法,一种是使用opencv进行读取,如下

import cv2

img = cv2.imread('img.tif', -1)     # -1为保留图像原始格式读取,其余会将图像的编码格式转为8bit
print(img.dtype)

>> uint16

另一种方法为使用tifffile库进行读取,如下

import tifffile as tiff

a = tiff.imread('img.tif')

2.1 tiff文件的保存

可以使用tifffile库中TiffWriter将任意 numpy array保存为tiff文件

TiffWriter是一个将Numpy array转成tiff文件的类,初始化如下

from tifffile import TiffWriter
import cv2
import numpy as np

img = cv2.imread(img_path)
writer = TiffWriter(file,
                    bigtiff = False,
                    byteorder = None,
                    append = False,
                    imagej = False,
                    ome = None)

file : 文件的保存路径
bigtiff : bool  当创建的文件大于4GB时使用True
byteorder : {'<', '>', '=', '/'}  系统的字节顺序,默认就行
append : bool 如果设置为True并且file是一个现有的标准tiff文件,则会将 
              图片数据和tag添加到文件中
imagej : bool 理论上和下面那个我用不到,默认就完事了 
ome : bool 

初始化之后就可以将需要转化的图像使用write函数进行保存了

img_writer.write(data,
                 photometric = 'rgb',
                 compression = 'jpeg',
                 planarconfig = 'CONTIG',
                 tile = (256,256),
                 subsampling = (1, 1),
                 subfiletype = 9)

# write里的参数实在是太多了,详见源码
data : numpy.ndarray
photometric : {MINSBLACK, MINSWHITE, RGB, PALETTE, SEPARATED, CFA}
compression : {str, (str, int), (str, int, dict)}
              如果默认或None,数据写入不压缩
              如果是一个str,可写为'JPEG''ZSTD'
              如果是一个元组,str同上,第二项是压缩级别,第三项字典是传递给压缩编解码器的参数
planarconfig : {'CONTIG', 'SEPARATE'}
               CONTIG:最后一个维度包含的样本
               SEPARATE:第三或第四个最后维度包含的样本
tile : tuple或int  
       要写入的图像块的形状,感觉应该是输入的图像块序列大小,然后拼 
       接成最终图像的感觉,长宽必须是16的倍数
subsampling : {(1, 1), (2, 1), (2, 2), (4, 1)} 二次采样
              默认为(2, 2), 只是哦那个与RGB图像的JPEG压缩          
subfiletype : int
              如果图像是另一个图像的降低分辨率版本,则设置为0
              如果图像是多页图像的一部分,则设置为1
              如果图像是透明蒙版的另一个图像,则设置为2