Commit 843fef56 authored by Oleg Dzhimiev's avatar Oleg Dzhimiev
Browse files

1. parse xml data

2. stack tiles
3. 8bpp and 32bpp
4. extract values from specific layer named 'other'
5. test 8bpp against corresponding 32bpp
parent 10df8116
Loading
Loading
Loading
Loading
+181 −32
Original line number Original line Diff line number Diff line
#!/usr/bin/env python3
#!/usr/bin/env python3


'''
/**
 * @file imagej_tiff.py
 * @brief open multi layer tiff files, display layers and parse meta data
 * @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"

from PIL import Image
from PIL import Image
import xml.etree.ElementTree as ET
import xml.etree.ElementTree as ET
import numpy as np
import numpy as np
import matplotlib.pyplot as plt
import matplotlib.pyplot as plt


import sys
import xml.dom.minidom as minidom

import time

#http://stackoverflow.com/questions/287871/print-in-terminal-with-colors-using-python
class bcolors:
    HEADER = '\033[95m'
    OKBLUE = '\033[94m'
    OKGREEN = '\033[92m'
    WARNING = '\033[38;5;214m'
    FAIL = '\033[91m'
    ENDC = '\033[0m'
    BOLD = '\033[1m'
    BOLDWHITE = '\033[1;37m'
    UNDERLINE = '\033[4m'

# reshape to tiles
def get_tile_images(image, width=8, height=8):
  _nrows, _ncols, depth = image.shape
  _size = image.size
  _strides = image.strides

  nrows, _m = divmod(_nrows, height)
  ncols, _n = divmod(_ncols, width)
  if _m != 0 or _n != 0:
    return None

  return np.lib.stride_tricks.as_strided(
    np.ravel(image),
    shape=(nrows, ncols, height, width, depth),
    strides=(height * _strides[0], width * _strides[1], *_strides),
    writeable=False
  )

# TiffFile has no len exception
# TiffFile has no len exception
#import imageio
#import imageio


@@ -67,6 +78,12 @@ class imagej_tiff:
    self.labels = []
    self.labels = []
    # infos will contain xml data Elphel stores in some of tiff files
    # infos will contain xml data Elphel stores in some of tiff files
    self.infos = []
    self.infos = []
    # dictionary from decoded infos[0] xml data
    self.props = {}

    # bits per sample, type int
    self.bpp = tif.tag[258][0]

    self.__split_labels(tif.n_frames,tif.tag)
    self.__split_labels(tif.n_frames,tif.tag)
    self.__parse_info()
    self.__parse_info()
    # image layers stacked along depth - (think RGB)
    # image layers stacked along depth - (think RGB)
@@ -77,7 +94,21 @@ class imagej_tiff:
      tif.seek(i)
      tif.seek(i)
      a = np.array(tif)
      a = np.array(tif)
      a = np.reshape(a,(a.shape[0],a.shape[1],1))
      a = np.reshape(a,(a.shape[0],a.shape[1],1))

      #a = a[:,:,np.newaxis]
      #a = a[:,:,np.newaxis]

      # scale for 8-bits
      # exclude layer named 'other'
      if self.bpp==8:
        _min = self.data_min
        _max = self.data_max
        _MIN = 1
        _MAX = 255
        a = a.astype(float)
        if self.labels[i]!='other':
          a[a==0]=np.nan
          a = (_max-_min)*(a-_MIN)/(_MAX-_MIN)+_min

      # init
      # init
      if i==0:
      if i==0:
        self.image = a
        self.image = a
@@ -88,12 +119,37 @@ class imagej_tiff:
    # init done, close the image
    # init done, close the image
    tif.close()
    tif.close()


  # label == tiff layer name
  def getvalues(self,label=""):
    l = self.getstack([label],shape_as_tiles=True)
    res = np.empty((l.shape[0],l.shape[1],3))

    for i in range(res.shape[0]):
      for j in range(res.shape[1]):
        # 9x9 -> 81x1
        m = np.ravel(l[i,j])
        if self.bpp==32:
          res[i,j,0] = m[0]
          res[i,j,1] = m[2]
          res[i,j,2] = m[4]
        elif self.bpp==8:
          res[i,j,0] = ((m[0]-128)*256+m[1])/128
          res[i,j,1] = ((m[2]-128)*256+m[3])/128
          res[i,j,2] = (m[4]*256+m[5])/65536.0
        else:
          res[i,j,0] = np.nan
          res[i,j,1] = np.nan
          res[i,j,2] = np.nan

    return res


  # get ordered stack of images by provided items
  # get ordered stack of images by provided items
  # by index or label name
  # by index or label name
  def getstack(self,items=[]):
  def getstack(self,items=[],shape_as_tiles=False):
    a = ()
    a = ()
    if len(items)==0:
    if len(items)==0:
      return self.image
      b = self.image
    else:
    else:
      for i in items:
      for i in items:
        if type(i)==int:
        if type(i)==int:
@@ -102,8 +158,12 @@ class imagej_tiff:
          j = self.labels.index(i)
          j = self.labels.index(i)
          a += (self.image[:,:,j],)
          a += (self.image[:,:,j],)
      # stack along depth
      # stack along depth
      return np.stack(a,axis=2)
      b = np.stack(a,axis=2)


    if shape_as_tiles:
      b = get_tile_images(b,self.tileW,self.tileH)

    return b


  # get np.array of a channel
  # get np.array of a channel
  # * do not handle out of bounds
  # * do not handle out of bounds
@@ -152,7 +212,7 @@ class imagej_tiff:
    #tmp_im.show()
    #tmp_im.show()




  # puts etrees in infos
  # puts etrees in infoss
  def __parse_info(self):
  def __parse_info(self):


    infos = []
    infos = []
@@ -161,6 +221,21 @@ class imagej_tiff:


    self.infos = infos
    self.infos = infos


    # specifics
    # properties dictionary
    pd = {}

    for child in infos[0]:
      #print(child.tag+"::::::"+child.text)
      pd[child.tag] = child.text

    self.props = pd

    # tiles are squares
    self.tileW = int(self.props['tileWidth'])
    self.tileH = int(self.props['tileWidth'])
    self.data_min = float(self.props['data_min'])
    self.data_max = float(self.props['data_max'])


  # makes arrays of labels (strings) and unparsed xml infos
  # makes arrays of labels (strings) and unparsed xml infos
  def __split_labels(self,n,tag):
  def __split_labels(self,n,tag):
@@ -188,24 +263,98 @@ class imagej_tiff:
        skip -= 1
        skip -= 1
      tag_labels = tag_labels[l:]
      tag_labels = tag_labels[l:]



#MAIN
#MAIN
if __name__ == "__main__":
if __name__ == "__main__":

  try:
    fname = sys.argv[1]
  except IndexError:
    fname = "1521849031_093189-ML_DATA-32B-O-OFFS1.0.tiff"
    fname = "1521849031_093189-ML_DATA-08B-O-OFFS1.0.tiff"

  #fname = "1521849031_093189-DISP_MAP-D0.0-46.tif"
  #fname = "1521849031_093189-DISP_MAP-D0.0-46.tif"
  fname = "test.tiff"
  #fname = "1526905735_662795-ML_DATA-08B-AIOTD-OFFS2.0.tiff"
  #fname = "test.tiff"

  print(bcolors.BOLDWHITE+"time: "+str(time.time())+bcolors.ENDC)


  ijt = imagej_tiff(fname)
  ijt = imagej_tiff(fname)


  print(bcolors.BOLDWHITE+"time: "+str(time.time())+bcolors.ENDC)

  print(ijt.labels)
  print(ijt.labels)
  print(ijt.infos)
  print(ijt.infos)

  rough_string = ET.tostring(ijt.infos[0], "utf-8")
  reparsed = minidom.parseString(rough_string)
  print(reparsed.toprettyxml(indent="\t"))

  print(ijt.props)

  # needed properties:
  print("Tiles shape: "+str(ijt.tileW)+"x"+str(ijt.tileH))
  print("Data min: "+str(ijt.data_min))
  print("Data max: "+str(ijt.data_max))

  print(ijt.image.shape)
  print(ijt.image.shape)


  #ijt.show_images()
  # layer order: ['diagm-pair', 'diago-pair', 'hor-pairs', 'vert-pairs', 'other']
  # now split this into tiles:

  #tiles = get_tile_images(ijt.image,ijt.tileW,ijt.tileH)
  #print(tiles.shape)

  tiles = ijt.getstack(['diagm-pair','diago-pair','hor-pairs','vert-pairs'],shape_as_tiles=True)
  print("Stack of images shape: "+str(tiles.shape))

  print(bcolors.BOLDWHITE+"time: "+str(time.time())+bcolors.ENDC)
  # provide layer name
  values = ijt.getvalues(label='other')
  print("Stack of values shape: "+str(values.shape))

  print(bcolors.BOLDWHITE+"time: "+str(time.time())+bcolors.ENDC)
  #print(values)

  #print(value_tiles[131,162].flatten())
  #print(np.ravel(value_tiles[131,162]))

  #values = np.empty((vt.shape[0],vt.shape[1],3))

  #for i in range(values.shape[0]):
  #  for j in range(values.shape[1]):
  #    values[i,j,0] = get_v1()


  #print(tiles[121,160,:,:,0].shape)
  #_nrows = int(ijt.image.shape[0] / ijt.tileH)
  #_ncols = int(ijt.image.shape[1] / ijt.tileW)
  #_nrows = 32
  #_ncols = 32
  #print(str(_nrows)+" "+str(_ncols))
  #fig, ax = plt.subplots(nrows=_nrows, ncols=_ncols)
  #for i in range(_nrows):
  #  for j in range(_ncols):
  #    ax[i,j].imshow(tiles[i+100,j,:,:,0])
  #    ax[i,j].set_axis_off()

  #for i in range(5):
  #  fig = plt.figure()
  #  plt.imshow(tiles[121,160,:,:,i])
  #  plt.colorbar()

  #ijt.show_images(['other'])


  #ijt.show_images([0,3])
  #ijt.show_images([0,3])
  ijt.show_images(['X-corr','Y-corr'])
  #ijt.show_images(['X-corr','Y-corr'])
  #ijt.show_images(['R-vign',3])
  #ijt.show_images(['R-vign',3])


  plt.show()
  #ijt.show_images()
  #plt.show()






  # Examples
  # Examples


test_8bpp_vs_32bpp.py

0 → 100644
+155 −0
Original line number Original line Diff line number Diff line
#!/usr/bin/env python3

from PIL import Image
import xml.etree.ElementTree as ET
import numpy as np
import matplotlib.pyplot as plt

import sys
import xml.dom.minidom as minidom

import time

from imagej_tiff import imagej_tiff

fname08bpp = "1521849031_093189-ML_DATA-08B-O-OFFS1.0.tiff"
fname32bpp = "1521849031_093189-ML_DATA-32B-O-OFFS1.0.tiff"

im08 = imagej_tiff(fname08bpp)
im32 = imagej_tiff(fname32bpp)

print(im08.props)

THRESHOLD = 0.01
THRESHOLD2 = 0.1

values08 = im08.getvalues(label='other')
values32 = im32.getvalues(label='other')

# compare values

print("test1: Compare values layers")

values32[np.isnan(values32)] = 0
values08[np.isnan(values08)] = 0
values08[values08==-256.0] = 0

delta = abs(values32 - values08)
#print(delta)
#print(delta.shape)

error_counter = 0
for i in range(delta.shape[0]):
  for j in range(delta.shape[1]):
    for k in range(delta.shape[2]):
      if delta[i,j,k]>THRESHOLD:
        error_counter += 1
        print("Fail ("+str(error_counter)+"): "+str((i,j,k))+" "+str(delta[i,j,k]))
        print(str(values32[i,j,k])+" vs "+str(values08[i,j,k]))

if error_counter==0:
  print("Values are OK")

#v08 = im08.getstack(['other'],shape_as_tiles=True)
#v32 = im32.getstack(['other'],shape_as_tiles=True)

#print(v08.shape)

#_nrows = 1
#_ncols = 1

#fig = plt.figure()
#plt.imshow(v08[241,321,:,:,0])
#plt.colorbar()

#fig = plt.figure()
#plt.imshow(v32[241,321,:,:,0])
#plt.colorbar()

# compare layers

print("test2: Compare layers")

tiles08 = im08.getstack(['diagm-pair','diago-pair','hor-pairs','vert-pairs'],shape_as_tiles=True)
tiles32 = im32.getstack(['diagm-pair','diago-pair','hor-pairs','vert-pairs'],shape_as_tiles=True)

delta2 = abs(tiles32-tiles08)
error_counter = 0
for i in range(delta2.shape[0]):
  for j in range(delta2.shape[1]):
    for k in range(delta2.shape[2]):
      for l in range(delta2.shape[3]):
        for m in range(delta2.shape[4]):
          if delta2[i,j,k,l,m]>THRESHOLD2:
            error_counter += 1
            print("Fail ("+str(error_counter)+"): "+str((i,j,k,l,m))+" "+str(delta2[i,j,k,l,m]))
            print(str(tiles32[i,j,k,l,m])+" vs "+str(tiles08[i,j,k,l,m]))

if error_counter==0:
  print("Layers are OK")

#fig = plt.figure()
#plt.imshow(tiles08[121,187,:,:,1])
#plt.colorbar()

#fig = plt.figure()
#plt.imshow(tiles32[121,187,:,:,1])
#plt.colorbar()

plt.show()