imagej_tiffwriter.py 3.68 KB
Newer Older
Oleg Dzhimiev's avatar
Oleg Dzhimiev committed
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26
#!/usr/bin/env python3

'''
/**
 * @file imagej_tiff_saver.py
 * @brief save tiffs for imagej (1.52d+) - with stacks and hyperstacks
 * @par <b>License</b>:
 *  This program is free software: you can redistribute it and/or modify
 *  it under the terms of the GNU General Public License as published by
 *  the Free Software Foundation, either version 3 of the License, or
 *  (at your option) any later version.
 *
 *  This program is distributed in the hope that it will be useful,
 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 *  GNU General Public License for more details.
 *
 *  You should have received a copy of the GNU General Public License
 *  along with this program.  If not, see <http://www.gnu.org/licenses/>.
*/
'''

__copyright__ = "Copyright 2018, Elphel, Inc."
__license__   = "GPL-3.0+"
__email__     = "oleg@elphel.com"

27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42
'''
Usage example:
  import imagej_tiffwriter
  import numpy as np

  # have a few images in the form of numpy arrays
  # make sure to stack them as:
  #   - (t,z,h,w,c)
  #   - (z,h,w,c)
  #   - (h,w,c)
  #   - (h,w)

  imagej_tiffwriter.save(path,images)

'''

Oleg Dzhimiev's avatar
Oleg Dzhimiev committed
43 44 45 46
from PIL import Image, TiffImagePlugin
import numpy as np
import math

47 48
# DO NOT USE?
# thing is the old ImageJs <1.52d poorly handle tags directories or something like that
Oleg Dzhimiev's avatar
Oleg Dzhimiev committed
49 50 51
def __get_IJ_IFD(t,z,c):

  ifd = TiffImagePlugin.ImageFileDirectory_v2()
52 53 54 55 56 57 58 59 60 61 62 63 64

  ijheader = [
    'ImageJ=',
    'hyperstack=true',
    'images='+str(t*z*c),
    'channels='+str(c),
    'slices='+str(z),
    'frames='+str(t),
    'loop=false'
  ]

  ifd[270] = ("\n".join(ijheader)+"\n")

Oleg Dzhimiev's avatar
Oleg Dzhimiev committed
65 66
  #is_hyperstack = 'true' if len(shape)>1 else 'false'
  #if (len(shape)>0):
67

Oleg Dzhimiev's avatar
Oleg Dzhimiev committed
68 69 70
  return ifd


71 72
#def save(path,images,force_stack=False,force_hyperstack=False):
def save(path,images):
Oleg Dzhimiev's avatar
Oleg Dzhimiev committed
73 74 75 76 77 78 79 80

  # Got images, analyze shape:
  #   - possible formats (c == depth):
  #     -- (t,z,h,w,c)
  #     -- (t,h,w,c), t or z does not matter
  #     -- (h,w,c)
  #     -- (h,w)

81 82 83 84 85

  # 0 or 1 images.shapes are not handled
  #
  # save single channel image in the form of numpy array
  #   -
Oleg Dzhimiev's avatar
Oleg Dzhimiev committed
86 87
  if   len(images.shape)==2:
    # (h,w) -> (h,w,c=1)
88 89 90
    image = Image.fromarray(images)
    image.save(path)

Oleg Dzhimiev's avatar
Oleg Dzhimiev committed
91 92
  elif len(images.shape)>2:

93 94 95 96 97 98 99 100 101
    h,w,c  = images.shape[-3:]

    if len(images.shape)==3:
      images = np.reshape(images,(1,h,w,c))

    z = images.shape[-4]

    if len(images.shape)==4:
      images = np.reshape(images,(1,z,h,w,c))
Oleg Dzhimiev's avatar
Oleg Dzhimiev committed
102

103
    t  = images.shape[-5]
Oleg Dzhimiev's avatar
Oleg Dzhimiev committed
104

105
    c_axis = len(images.shape)-1
Oleg Dzhimiev's avatar
Oleg Dzhimiev committed
106

107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122
    if c>1:
      channels = np.squeeze(np.split(images,c,axis=c_axis))
    else:
      channels = np.squeeze(images,axis=c_axis)


    split_channels = np.concatenate(channels,axis=-3)
    images_flat = np.reshape(split_channels,(-1,h,w))

    imlist = []
    for i in range(images_flat.shape[0]):
      imlist.append(Image.fromarray(images_flat[i]))

    imlist[0].save(path,save_all=True,append_images=imlist[1:])
    # thing is the old ImageJs <1.52d poorly handle tags directories or something like that
    #imlist[0].save(path,save_all=True,append_images=imlist[1:],tiffinfo=__get_IJ_IFD(t,z,c))
Oleg Dzhimiev's avatar
Oleg Dzhimiev committed
123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150

# Testing
if __name__ == "__main__":

  def hamming_window(x,N):
    y = 0.54 - 0.46*math.cos(2*math.pi*x/(N-1))
    return y

  hw = hamming_window

  NT = 5
  NC = 2
  NZ = 3
  NX = 512
  NY = 512

  images = np.empty((NT,NZ,NY,NX,NC))

  import time
  print(str(time.time())+": Generating test images")
  for t in range(NT):
    for z in range(NZ):
      for c in range(NC):
        images[t,z,:,:,c] = np.array([[(255-t*25)*hw(i,512)*hw(j,512) for i in range(NX)] for j in range(NY)],np.float32)
  print(str(time.time())+": Test images generated")
  print("Images shape: "+str(images.shape))

  v = save("result_2.tiff",images)