简体   繁体   中英

Cannot get tiff image resolution

I'm trying to read 16 bit .tif microscope images from https://data.broadinstitute.org/bbbc/BBBC006/ and analyze them using https://github.com/sakoho81/pyimagequalityranking/tree/master/pyimq however I got an error in the part of the code that loads the tif image. It uses the PIL tiffimageplugin: https://pillow.readthedocs.io/en/3.0.0/_modules/PIL/TiffImagePlugin.html and when it tries to get the resolution tag, it gives me a keyerror Any ideas why? Advice? Fixes?

Thanks!

import os
import numpy
import scipy.ndimage.interpolation as itp
import argparse
from PIL import Image
from PIL.TiffImagePlugin import X_RESOLUTION, Y_RESOLUTION
from matplotlib import pyplot as plt
from math import log10, ceil, floor



def get_image_from_imagej_tiff(cls, path):
    """
    A class method for opening a ImageJ tiff file. Using this method
    will enable the use of correct pixel size during analysis.
    :param path: Path to an image
    :return:     An object of the MyImage class
    """
    assert os.path.isfile(path)
    assert path.endswith(('.tif', '.tiff'))
    print(path) #my own little debug thingamajig
    image = Image.open(path)

    xresolution = image.tag.tags[X_RESOLUTION][0][0] #line that errors out
    yresolution = image.tag.tags[Y_RESOLUTION][0][0]

    #data = utils.rescale_to_min_max(numpy.array(image), 0, 255)

    if data.shape[0] == 1:
        data = data[0]

    return cls(images=data, spacing=[1.0/xresolution, 1.0/yresolution])

terminal input:

pyimq.main --mode=directory --mode=analyze --mode=plot --working-directory=/home/myufa/predxion/BBBC/a_1_s1 --normalize-power --result=fstd --imagej

output:

Mode option is ['directory', 'analyze', 'plot']
/home/myufa/predxion/BBBC/a_1_s1/z0_a_1_s1_w1.tif
Traceback (most recent call last):
  File "/home/myufa/.local/bin/pyimq.main", line 11, in <module>
    load_entry_point('PyImageQualityRanking==0.1', 'console_scripts', 'pyimq.main')()
  File "/home/myufa/anaconda3/lib/python3.7/site-packages/PyImageQualityRanking-0.1-py3.7.egg/pyimq/bin/main.py", line 148, in main
  File "/home/myufa/anaconda3/lib/python3.7/site-packages/PyImageQualityRanking-0.1-py3.7.egg/pyimq/myimage.py", line 81, in get_image_from_imagej_tiff
KeyError: 282

Edit: Here's what I got when I tried some suggestions/indexed the tag, which makes even less sense

I guess the tiff in question isn't following the normal image conventions. The [XY]Resolution tags, number 282 and 283, are mandatory or required in a whole bunch of specifications, but none the less may not be present in all applications. I have some TIFFs (DNG format) that wouldn't load with PIL (Pillow) at all; that prompted me to write a script to dump the primary tag structure:

# TIFF structure program
import struct
import PIL.TiffTags

class DE:
    def __init__(self, tiff):
        self.tiff = tiff
        (self.tag, self.type, self.count, self.valueoroffset) = struct.unpack(
            tiff.byteorder+b'HHI4s', self.tiff.file.read(12))
        # TODO: support reading the value
    def getstring(self):
        offset = struct.unpack(self.tiff.byteorder+b'I', self.valueoroffset)[0]
        self.tiff.file.seek(offset)
        return self.tiff.file.read(self.count)

class IFD:
    def __init__(self, tiff):
        self.tiff = tiff
        self.offset = tiff.file.tell()
        (self.len,) = struct.unpack(self.tiff.byteorder+b'H', self.tiff.file.read(2))
    def __len__(self):
        return self.len
    def __getitem__(self, index):
        if index>=self.len or index<0:
            raise IndexError()
        self.tiff.file.seek(self.offset+2+12*index)
        return DE(self.tiff)
    def nextoffset(self):
        self.tiff.file.seek(self.offset+2+12*self.len)
        (offset,) = struct.unpack(self.tiff.byteorder+b'I', self.tiff.file.read(4))
        return (offset if offset!=0 else None)

class TIFF:
    def __init__(self, file):
        self.file = file
        header = self.file.read(8)
        self.byteorder = {b'II': b'<', b'MM': b'>'}[header[:2]]
        (magic, self.ifdoffset) = struct.unpack(self.byteorder+b'HI', header[2:])
        assert magic == 42
    def __iter__(self):
        offset = self.ifdoffset
        while offset:
            self.file.seek(offset)
            ifd = IFD(self)
            yield ifd
            offset = ifd.nextoffset()

def main():
    tifffile = open('c:/users/yann/pictures/img.tiff', 'rb')
    tiff = TIFF(tifffile)
    for ifd in tiff:
        print(f'IFD at {ifd.offset}, {ifd.len} entries')
        for entry in ifd:
            print(f' tag={entry.tag} {PIL.TiffTags.lookup(entry.tag).name}')

if __name__=='__main__':
    main()

A quicker way, since you at least have the image object, might be:

import pprint, PIL.TiffTags
pprint.pprint(list(map(PIL.TiffTags.lookup, img.tag)))

One of these might give you a clue what the actual contents of the TIFF are. Since PIL could load it, it probably has pixel counts but not physical resolution.

Figured out a quick fix, writing

image.tag[X_RESOLUTION]

before

xresolution = image.tag.tags[X_RESOLUTION][0][0]

made the info available in the tag.tags dictionary for some reason. Can anyone chime in and explain why this might be? Would love to learn/make sure I didn't mess it up

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM