Tifffile é uma biblioteca Python para
Imagens e metadados podem ser lidos em TIFF, BigTIFF, OME-TIFF, GeoTIFF, Adobe DNG, ZIF (Zoomable Image File Format), MetaMorph STK, Zeiss LSM, ImageJ hyperstack, Micro-Manager MMStack e NDTiff, SGI, NIHImage, Olympus FluoView e SIS, ScanImage, Molecular Dynamics GEL, Aperio SVS, Leica SCN, Roche BIF, Arquivos formatados PerkinElmer QPTIFF (QPI, PKI), Hamamatsu NDPI, Argos AVS e Philips DP.
Os dados de imagem podem ser lidos como matrizes NumPy ou matrizes/grupos Zarr de tiras, blocos, páginas (IFDs), SubIFDs, séries de ordem superior e níveis piramidais.
Os dados de imagem podem ser gravados em arquivos compatíveis com hiperstack TIFF, BigTIFF, OME-TIFF e ImageJ em formato de várias páginas, volumétrico, piramidal, mapeável em memória, lado a lado, previsto ou compactado.
Muitos esquemas de compactação e predição são suportados pela biblioteca imagecodecs, incluindo LZW, PackBits, Deflate, PIXTIFF, LZMA, LERC, Zstd, JPEG (8 e 12 bits, sem perdas), JPEG 2000, JPEG XR, JPEG XL, WebP, PNG , EER, Jetraw, ponto flutuante de 24 bits e diferenciação horizontal.
Tifffile também pode ser usado para inspecionar estruturas TIFF, ler dados de imagem de sequências de arquivos multidimensionais, escrever fsspec ReferenceFileSystem para arquivos TIFF e sequências de arquivos de imagem, corrigir valores de tags TIFF e analisar muitos formatos de metadados proprietários.
Autor: | Christoph Gohlke |
---|---|
Licença: | BSD 3 cláusulas |
Versão: | 2024.9.20 |
DOI: | 10.5281/zenodo.6795860 |
Instale o pacote tifffile e todas as dependências do Índice de Pacotes Python:
python -m pip install -U tifffile[todos]
Tifffile também está disponível em outros repositórios de pacotes, como Anaconda, Debian e MSYS2.
A biblioteca tifffile tem anotação de tipo e é documentada por meio de docstrings:
python -c "importar arquivo tiff; ajuda(tifffile)"
Tifffile pode ser usado como um script de console para inspecionar e visualizar arquivos TIFF:
python -m arquivo tiff --help
Consulte Exemplos de uso da interface de programação.
O código-fonte e o suporte estão disponíveis no GitHub.
O suporte também é fornecido no fórum image.sc.
Esta revisão foi testada com os seguintes requisitos e dependências (outras versões podem funcionar):
2024.9.20
2024.8.30
2024.8.28
2024.8.24
2024.8.10
2024.7.24
2024.7.21
2024.7.2
2024.6.18
2024.5.22
2024.5.10
2024.5.3
2024.4.24
2024.4.18
2024.2.12
30/01/2024
2023.12.9
2023.9.26
2023.9.18
2023.8.30
2023.8.25
2023.8.12
2023.7.18
Consulte o arquivo CHANGES para revisões mais antigas.
TIFF, o formato de arquivo de imagem marcado, foi criado pela Aldus Corporation e Adobe Systems Incorporated.
Tifffile suporta um subconjunto da especificação TIFF6, principalmente imagens inteiras de 8, 16, 32 e 64 bits, flutuantes de 16, 32 e 64 bits, imagens em tons de cinza e multiamostra. Especificamente, compactação CCITT e OJPEG, subamostragem de croma sem compactação JPEG, transformações de espaço de cores, amostras com tipos diferentes ou metadados IPTC, ICC e XMP não são implementados.
Além do TIFF clássico, o tifffile suporta vários formatos semelhantes ao TIFF que não aderem estritamente à especificação TIFF6. Alguns formatos permitem que os tamanhos de arquivos e dados excedam o limite de 4 GB do TIFF clássico:
Outras bibliotecas para ler, escrever, inspecionar ou manipular arquivos TIFF científicos do Python são aicsimageio, apeer-ometiff-library, bigtiff, fabio.TiffIO, GDAL, imread, large_image, openslide-python, opentile, pylibtiff, pylsm, pymimage, python -bioformatos, pytiff, scanimagetiffreader-python, SimpleITK, slideio, tiffslide, tifftools, tyf, xtiff e ndtiff.
Escreva um array NumPy em um arquivo TIFF RGB de página única:
>> > data = numpy . random . randint ( 0 , 255 , ( 256 , 256 , 3 ), 'uint8' )
>> > imwrite ( 'temp.tif' , data , photometric = 'rgb' )
Leia a imagem do arquivo TIFF como array NumPy:
>> > image = imread ( 'temp.tif' )
>> > image . shape
( 256 , 256 , 3 )
Use os argumentos fotométrico e planarconfig para escrever uma matriz NumPy 3x3x3 em um RGB intercalado, um RGB planar ou um TIFF em escala de cinza de 3 páginas:
>> > data = numpy . random . randint ( 0 , 255 , ( 3 , 3 , 3 ), 'uint8' )
>> > imwrite ( 'temp.tif' , data , photometric = 'rgb' )
>> > imwrite ( 'temp.tif' , data , photometric = 'rgb' , planarconfig = 'separate' )
>> > imwrite ( 'temp.tif' , data , photometric = 'minisblack' )
Use o argumento extrasamples para especificar como os componentes extras são interpretados, por exemplo, para uma imagem RGBA com canal alfa não associado:
>> > data = numpy . random . randint ( 0 , 255 , ( 256 , 256 , 4 ), 'uint8' )
>> > imwrite ( 'temp.tif' , data , photometric = 'rgb' , extrasamples = [ 'unassalpha' ])
Escreva uma matriz NumPy tridimensional em um arquivo TIFF de várias páginas em escala de cinza de 16 bits:
>> > data = numpy . random . randint ( 0 , 2 ** 12 , ( 64 , 301 , 219 ), 'uint16' )
>> > imwrite ( 'temp.tif' , data , photometric = 'minisblack' )
Leia toda a pilha de imagens do arquivo TIFF de várias páginas como array NumPy:
>> > image_stack = imread ( 'temp.tif' )
>> > image_stack . shape
( 64 , 301 , 219 )
>> > image_stack . dtype
dtype ( 'uint16' )
Leia a imagem da primeira página do arquivo TIFF como array NumPy:
>> > image = imread ( 'temp.tif' , key = 0 )
>> > image . shape
( 301 , 219 )
Leia imagens de um intervalo selecionado de páginas:
>> > images = imread ( 'temp.tif' , key = range ( 4 , 40 , 2 ))
>> > images . shape
( 18 , 301 , 219 )
Itere todas as páginas do arquivo TIFF e leia as imagens sucessivamente:
>> > with TiffFile ( 'temp.tif' ) as tif :
... for page in tif . pages :
... image = page . asarray ()
...
Obtenha informações sobre a pilha de imagens no arquivo TIFF sem ler nenhum dado de imagem:
>> > tif = TiffFile ( 'temp.tif' )
>> > len ( tif . pages ) # number of pages in the file
64
>> > page = tif . pages [ 0 ] # get shape and dtype of image in first page
>> > page . shape
( 301 , 219 )
>> > page . dtype
dtype ( 'uint16' )
>> > page . axes
'YX'
>> > series = tif . series [ 0 ] # get shape and dtype of first image series
>> > series . shape
( 64 , 301 , 219 )
>> > series . dtype
dtype ( 'uint16' )
>> > series . axes
'QYX'
>> > tif . close ()
Inspecione a tag "XResolution" da primeira página do arquivo TIFF:
>> > with TiffFile ( 'temp.tif' ) as tif :
... tag = tif . pages [ 0 ]. tags [ 'XResolution' ]
...
>> > tag . value
( 1 , 1 )
>> > tag . name
'XResolution'
>> > tag . code
282
>> > tag . count
1
>> > tag . dtype
< DATATYPE . RATIONAL : 5 >
Itere sobre todas as tags no arquivo TIFF:
>> > with TiffFile ( 'temp.tif' ) as tif :
... for page in tif . pages :
... for tag in page . tags :
... tag_name , tag_value = tag . name , tag . value
...
Substitua o valor de uma tag existente, por exemplo, XResolution:
>> > with TiffFile ( 'temp.tif' , mode = 'r+' ) as tif :
... _ = tif . pages [ 0 ]. tags [ 'XResolution' ]. overwrite (( 96000 , 1000 ))
...
Escreva uma matriz de ponto flutuante de 5 dimensões usando o formato BigTIFF, componentes de cores separados, ladrilhos, nível de compactação Zlib 8, preditor de diferenciação horizontal e metadados adicionais:
>> > data = numpy . random . rand ( 2 , 5 , 3 , 301 , 219 ). astype ( 'float32' )
>> > imwrite (
... 'temp.tif' ,
... data ,
... bigtiff = True ,
... photometric = 'rgb' ,
... planarconfig = 'separate' ,
... tile = ( 32 , 32 ),
... compression = 'zlib' ,
... compressionargs = { 'level' : 8 },
... predictor = True ,
... metadata = { 'axes' : 'TZCYX' },
... )
Escreva uma série temporal de volumes de 10 fps com tamanho de voxel xyz de 2,6755x2,6755x3,9474 mícron ^ 3 em um arquivo TIFF formatado em hiperstack ImageJ:
>> > volume = numpy . random . randn ( 6 , 57 , 256 , 256 ). astype ( 'float32' )
>> > image_labels = [ f' { i } ' for i in range ( volume . shape [ 0 ] * volume . shape [ 1 ])]
>> > imwrite (
... 'temp.tif' ,
... volume ,
... imagej = True ,
... resolution = ( 1.0 / 2.6755 , 1.0 / 2.6755 ),
... metadata = {
... 'spacing' : 3.947368 ,
... 'unit' : 'um' ,
... 'finterval' : 1 / 10 ,
... 'fps' : 10.0 ,
... 'axes' : 'TZYX' ,
... 'Labels' : image_labels ,
... },
... )
Leia o volume e os metadados do arquivo hiperstack ImageJ:
>> > with TiffFile ( 'temp.tif' ) as tif :
... volume = tif . asarray ()
... axes = tif . series [ 0 ]. axes
... imagej_metadata = tif . imagej_metadata
...
>> > volume . shape
( 6 , 57 , 256 , 256 )
>> > axes
'TZYX'
>> > imagej_metadata [ 'slices' ]
57
>> > imagej_metadata [ 'frames' ]
6
Mapeie na memória os dados de imagem contíguos no arquivo hiperstack ImageJ:
>> > memmap_volume = memmap ( 'temp.tif' )
>> > memmap_volume . shape
( 6 , 57 , 256 , 256 )
>> > del memmap_volume
Crie um arquivo TIFF contendo uma imagem vazia e grave no array NumPy mapeado na memória (nota: isso não funciona com compactação ou mosaico):
>> > memmap_image = memmap (
... 'temp.tif' , shape = ( 256 , 256 , 3 ), dtype = 'float32' , photometric = 'rgb'
... )
>> > type ( memmap_image )
< class 'numpy.memmap' >
>> > memmap_image [ 255 , 255 , 1 ] = 1.0
>> > memmap_image . flush ()
>> > del memmap_image
Escreva duas matrizes NumPy em um arquivo TIFF multissérie (nota: outros leitores TIFF não reconhecerão as duas séries; use o formato OME-TIFF para melhor interoperabilidade):
>> > series0 = numpy . random . randint ( 0 , 255 , ( 32 , 32 , 3 ), 'uint8' )
>> > series1 = numpy . random . randint ( 0 , 255 , ( 4 , 256 , 256 ), 'uint16' )
>> > with TiffWriter ( 'temp.tif' ) as tif :
... tif . write ( series0 , photometric = 'rgb' )
... tif . write ( series1 , photometric = 'minisblack' )
...
Leia a segunda série de imagens do arquivo TIFF:
>> > series1 = imread ( 'temp.tif' , series = 1 )
>> > series1 . shape
( 4 , 256 , 256 )
Grave sucessivamente os quadros de uma série contígua em um arquivo TIFF:
>> > data = numpy . random . randint ( 0 , 255 , ( 30 , 301 , 219 ), 'uint8' )
>> > with TiffWriter ( 'temp.tif' ) as tif :
... for frame in data :
... tif . write ( frame , contiguous = True )
...
Anexe uma série de imagens ao arquivo TIFF existente (nota: isso não funciona com hiperstack ImageJ ou arquivos OME-TIFF):
>> > data = numpy . random . randint ( 0 , 255 , ( 301 , 219 , 3 ), 'uint8' )
>> > imwrite ( 'temp.tif' , data , photometric = 'rgb' , append = True )
Crie um arquivo TIFF a partir de um gerador de blocos:
>> > data = numpy . random . randint ( 0 , 2 ** 12 , ( 31 , 33 , 3 ), 'uint16' )
>> > def tiles ( data , tileshape ):
... for y in range ( 0 , data . shape [ 0 ], tileshape [ 0 ]):
... for x in range ( 0 , data . shape [ 1 ], tileshape [ 1 ]):
... yield data [ y : y + tileshape [ 0 ], x : x + tileshape [ 1 ]]
...
>> > imwrite (
... 'temp.tif' ,
... tiles ( data , ( 16 , 16 )),
... tile = ( 16 , 16 ),
... shape = data . shape ,
... dtype = data . dtype ,
... photometric = 'rgb' ,
... )
Escreva um arquivo OME-TIFF multidimensional, multirresolução (piramidal) e multissérie com metadados opcionais. Imagens de sub-resolução são gravadas em SubIFDs. Limite a codificação paralela a 2 threads. Escreva uma imagem em miniatura como uma série de imagens separada:
>> > data = numpy . random . randint ( 0 , 255 , ( 8 , 2 , 512 , 512 , 3 ), 'uint8' )
>> > subresolutions = 2
>> > pixelsize = 0.29 # micrometer
>> > with TiffWriter ( 'temp.ome.tif' , bigtiff = True ) as tif :
... metadata = {
... 'axes' : 'TCYXS' ,
... 'SignificantBits' : 8 ,
... 'TimeIncrement' : 0.1 ,
... 'TimeIncrementUnit' : 's' ,
... 'PhysicalSizeX' : pixelsize ,
... 'PhysicalSizeXUnit' : 'µm' ,
... 'PhysicalSizeY' : pixelsize ,
... 'PhysicalSizeYUnit' : 'µm' ,
... 'Channel' : { 'Name' : [ 'Channel 1' , 'Channel 2' ]},
... 'Plane' : { 'PositionX' : [ 0.0 ] * 16 , 'PositionXUnit' : [ 'µm' ] * 16 },
... 'Description' : 'A multi-dimensional, multi-resolution image' ,
... 'MapAnnotation' : { # for OMERO
... 'Namespace' : 'openmicroscopy.org/PyramidResolution' ,
... '1' : '256 256' ,
... '2' : '128 128' ,
... },
... }
... options = dict (
... photometric = 'rgb' ,
... tile = ( 128 , 128 ),
... compression = 'jpeg' ,
... resolutionunit = 'CENTIMETER' ,
... maxworkers = 2 ,
... )
... tif . write (
... data ,
... subifds = subresolutions ,
... resolution = ( 1e4 / pixelsize , 1e4 / pixelsize ),
... metadata = metadata ,
... ** options ,
... )
... # write pyramid levels to the two subifds
... # in production use resampling to generate sub-resolution images
... for level in range ( subresolutions ):
... mag = 2 ** ( level + 1 )
... tif . write (
... data [..., :: mag , :: mag , :],
... subfiletype = 1 ,
... resolution = ( 1e4 / mag / pixelsize , 1e4 / mag / pixelsize ),
... ** options ,
... )
... # add a thumbnail image as a separate series
... # it is recognized by QuPath as an associated image
... thumbnail = ( data [ 0 , 0 , :: 8 , :: 8 ] >> 2 ). astype ( 'uint8' )
... tif . write ( thumbnail , metadata = { 'Name' : 'thumbnail' })
...
Acesse os níveis de imagem no arquivo piramidal OME-TIFF:
>> > baseimage = imread ( 'temp.ome.tif' )
>> > second_level = imread ( 'temp.ome.tif' , series = 0 , level = 1 )
>> > with TiffFile ( 'temp.ome.tif' ) as tif :
... baseimage = tif . series [ 0 ]. asarray ()
... second_level = tif . series [ 0 ]. levels [ 1 ]. asarray ()
... number_levels = len ( tif . series [ 0 ]. levels ) # includes base level
...
Itere e decodifique blocos compactados JPEG únicos no arquivo TIFF: