Commit 2c44046d authored by Andrey Filippov's avatar Andrey Filippov

Updating for LWIR data

parent d5384e3f
This source diff could not be displayed because it is too large. You can view the blob instead.
......@@ -55,19 +55,63 @@ class bcolors:
BOLD = '\033[1m'
BOLDWHITE = '\033[1;37m'
UNDERLINE = '\033[4m'
class IJML:
# as devined in ImageDtt.java
ML_OTHER_TARGET = 0 # Offset to target disparity data in ML_OTHER_INDEX layer tile
ML_OTHER_GTRUTH = 2 # Offset to ground truth disparity data in ML_OTHER_INDEX layer tile
ML_OTHER_GTRUTH_STRENGTH = 4 # Offset to ground truth confidence data in ML_OTHER_INDEX layer tile
ML_OTHER_GTRUTH_RMS = 6 # Offset to ground truth RMS in ML_OTHER_INDEX layer tile
ML_OTHER_GTRUTH_RMS_SPLIT = 8 # Offset to ground truth combined FG/BG RMS in ML_OTHER_INDEX layer tile
ML_OTHER_GTRUTH_FG_DISP = 10 # Offset to ground truth FG disparity in ML_OTHER_INDEX layer tile
ML_OTHER_GTRUTH_FG_STR = 12 # Offset to ground truth FG strength in ML_OTHER_INDEX layer tile
ML_OTHER_GTRUTH_BG_DISP = 14 # Offset to ground truth BG disparity in ML_OTHER_INDEX layer tile
ML_OTHER_GTRUTH_BG_STR = 16 # Offset to ground truth BG strength in ML_OTHER_INDEX layer tile
ML_OTHER_AUX_DISP = 18 # Offset to AUX heuristic disparity in ML_OTHER_INDEX layer tile
ML_OTHER_AUX_STR = 20 # Offset to AUX heuristic strength in ML_OTHER_INDEX layer tile
# indices
TARGET = ML_OTHER_TARGET // 2
GTRUTH = ML_OTHER_GTRUTH // 2
STRENGTH = ML_OTHER_GTRUTH_STRENGTH // 2
RMS = ML_OTHER_GTRUTH_RMS // 2
RMS_SPLIT = ML_OTHER_GTRUTH_RMS_SPLIT // 2
FG_DISP = ML_OTHER_GTRUTH_FG_DISP // 2
FG_STR = ML_OTHER_GTRUTH_FG_STR // 2
BG_DISP = ML_OTHER_GTRUTH_BG_DISP // 2
BG_STR = ML_OTHER_GTRUTH_BG_STR // 2
AUX_DISP = ML_OTHER_AUX_DISP // 2
AUX_STR = ML_OTHER_AUX_STR // 2
SIGNED = (TARGET, GTRUTH, FG_DISP, BG_DISP)
UNSIGNED_RMS = (RMS, RMS_SPLIT)
NUM_VALUES = 11
class IJFGBG:
DSI_NAMES = ["disparity","strength","rms","rms-split","fg-disp","fg-str","bg-disp","bg-str","aux-disp","aux-str"]
DISPARITY = 0
STRENGTH = 1
RMS = 2
RMS_SPLIT = 3
FG_DISP = 4
FG_STR = 5
BG_DISP = 6
BG_STR = 7
AUX_DISP = 8
AUX_STR = 9
# 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(
_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),
......@@ -95,460 +139,463 @@ Examples:
'''
class imagej_tiff:
# imagej stores labels lengths in this tag
__TIFF_TAG_LABELS_LENGTHS = 50838
# imagej stores labels conents in this tag
__TIFF_TAG_LABELS_STRINGS = 50839
# init
def __init__(self,filename, layers = None, tile_list = None):
# file name
self.fname = filename
tif = Image.open(filename)
# total number of layers in tiff
self.nimages = tif.n_frames
# labels array
self.labels = []
# infos will contain xml data Elphel stores in some of tiff files
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.__parse_info()
try:
self.nan_bug = self.props['VERSION']== '1.0' # data between min and max is mapped to 0..254 instead of 1.255
except:
self.nan_bug = False # other files, not ML ones
# image layers stacked along depth - (think RGB)
self.image = []
if layers is None:
# fill self.image
for i in range(self.nimages):
tif.seek(i)
a = np.array(tif)
a = np.reshape(a,(a.shape[0],a.shape[1],1))
#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
if (self.nan_bug):
_MIN = 0
_MAX = 254
else:
if self.labels[i]!='other':
a[a==0]=np.nan
a = a.astype(float)
if self.labels[i]!='other':
# a[a==0]=np.nan
a = (_max-_min)*(a-_MIN)/(_MAX-_MIN)+_min
# init
if i==0:
self.image = a
# stack along depth (think of RGB channels)
else:
self.image = np.append(self.image,a,axis=2)
else:
if tile_list is None:
indx = 0
for layer in layers:
tif.seek(self.labels.index(layer))
# imagej stores labels lengths in this tag
__TIFF_TAG_LABELS_LENGTHS = 50838
# imagej stores labels conents in this tag
__TIFF_TAG_LABELS_STRINGS = 50839
# init
def __init__(self,filename, layers = None, tile_list = None):
# file name
self.fname = filename
tif = Image.open(filename)
# total number of layers in tiff
self.nimages = tif.n_frames
# labels array
self.labels = []
# infos will contain xml data Elphel stores in some of tiff files
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.__parse_info()
try:
self.nan_bug = self.props['VERSION']== '1.0' # data between min and max is mapped to 0..254 instead of 1.255
except:
self.nan_bug = False # other files, not ML ones
# image layers stacked along depth - (think RGB)
self.image = []
if layers is None:
# fill self.image
for i in range(self.nimages):
tif.seek(i)
a = np.array(tif)
if not indx:
self.image = np.empty((a.shape[0],a.shape[1],len(layers)),a.dtype)
self.image[...,indx] = a
indx += 1
a = np.reshape(a,(a.shape[0],a.shape[1],1))
#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
if (self.nan_bug):
_MIN = 0
_MAX = 254
else:
if self.labels[i]!='other':
a[a==0]=np.nan
a = a.astype(float)
if self.labels[i]!='other':
# a[a==0]=np.nan
a = (_max-_min)*(a-_MIN)/(_MAX-_MIN)+_min
# init
if i==0:
self.image = a
# stack along depth (think of RGB channels)
else:
self.image = np.append(self.image,a,axis=2)
else:
other_label = "other"
# print(tile_list)
num_tiles = len(tile_list)
num_layers = len(layers)
tiles_corr = np.empty((num_tiles,num_layers,self.tileH*self.tileW),dtype=float)
# tiles_other=np.empty((num_tiles,3),dtype=float)
tiles_other=self.gettilesvalues(
tif = tif,
tile_list=tile_list,
label=other_label)
for nl,label in enumerate(layers):
tif.seek(self.labels.index(label))
layer = np.array(tif) # 8 or 32 bits
tilesX = layer.shape[1]//self.tileW
for nt,tl in enumerate(tile_list):
ty = tl // tilesX
tx = tl % tilesX
# tiles_corr[nt,nl] = np.ravel(layer[self.tileH*ty:self.tileH*(ty+1),self.tileW*tx:self.tileW*(tx+1)])
a = np.ravel(layer[self.tileH*ty:self.tileH*(ty+1),self.tileW*tx:self.tileW*(tx+1)])
#convert from int8
if self.bpp==8:
a = a.astype(float)
if np.isnan(tiles_other[nt][0]):
# print("Skipping NaN tile ",tl)
a[...] = np.nan
else:
_min = self.data_min
_max = self.data_max
_MIN = 1
_MAX = 255
if (self.nan_bug):
_MIN = 0
_MAX = 254
else:
a[a==0] = np.nan
a = (_max-_min)*(a-_MIN)/(_MAX-_MIN)+_min
tiles_corr[nt,nl] = a
if tile_list is None:
indx = 0
for layer in layers:
tif.seek(self.labels.index(layer))
a = np.array(tif)
if not indx:
self.image = np.empty((a.shape[0],a.shape[1],len(layers)),a.dtype)
self.image[...,indx] = a
indx += 1
else:
other_label = "other"
# print(tile_list)
num_tiles = len(tile_list)
num_layers = len(layers)
tiles_corr = np.empty((num_tiles,num_layers,self.tileH*self.tileW),dtype=float)
# tiles_other=np.empty((num_tiles,3),dtype=float)
tiles_other=self.gettilesvalues( # returns nparray of 11 floats (was 3)
tif = tif,
tile_list=tile_list,
label=other_label)
for nl,label in enumerate(layers):
tif.seek(self.labels.index(label)) #'hor-pairs' is not in list
layer = np.array(tif) # 8 or 32 bits
tilesX = layer.shape[1]//self.tileW
for nt,tl in enumerate(tile_list):
ty = tl // tilesX
tx = tl % tilesX
a = np.ravel(layer[self.tileH * ty : self.tileH * (ty+1),
self.tileW * tx : self.tileW * (tx+1)])
#convert from int8
if self.bpp==8:
a = a.astype(float)
if np.isnan(tiles_other[nt][0]):
# print("Skipping NaN tile ",tl)
a[...] = np.nan
else:
_min = self.data_min
_max = self.data_max
_MIN = 1
_MAX = 255
if (self.nan_bug):
_MIN = 0
_MAX = 254
else:
a[a==0] = np.nan
a = (_max-_min)*(a-_MIN)/(_MAX-_MIN)+_min
tiles_corr[nt,nl] = a
pass
pass
self.corr2d = tiles_corr
self.target_disparity = tiles_other[...,0]
self.gt_ds = tiles_other[...,1:3]
self.payload = tiles_other#[...,0:12]
pass
self.corr2d = tiles_corr
self.target_disparity = tiles_other[...,0]
self.gt_ds = tiles_other[...,1:3]
pass
# init done, close the image
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
# NaNize
a = res[:,:,0]
a[a==-256] = np.nan
b = res[:,:,1]
b[b==-256] = np.nan
c = res[:,:,2]
c[c==0] = np.nan
return res
# init done, close the image
tif.close()
# 3 values per tile: target disparity, GT disparity, GT confidence
def gettilesvalues(self,
# 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], IJML.NUM_VALUES)) # was just 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:
for k in range(res.shape[2]):
res[i,j,k] = m[k * 2]
elif self.bpp==8:
for k in range(res.shape[2]):
if k in IJML.SIGNED:
res[i,j,k] = ((m[2 * k] - 128) * 256 + m[2 * k + 1]) / 128
elif k in IJML.UNSIGNED_RMS:
res[i,j,k] = (m[2 * k]*256+m[2 * k + 1])/4096.0
else:
res[i,j,k] = (m[2 * k]*256+m[2 * k + 1])/65536.0
else:
for k in range(res.shape[2]):
res[i,j,k] = np.nan
# NaNize - TODO: update !
if self.bpp==8:
a = res[:,:,0]
a[a==-256] = np.nan
b = res[:,:,1]
b[b==-256] = np.nan
c = res[:,:,2]
c[c==0] = np.nan
return res
# 3 values per tile: target disparity, GT disparity, GT confidence
# With LWIR/aux there are more!
def gettilesvalues(self,
tif,
tile_list,
label=""):
res = np.empty((len(tile_list),3),dtype=float)
tif.seek(self.labels.index(label))
layer = np.array(tif) # 8 or 32 bits
tilesX = layer.shape[1]//self.tileW
for i,tl in enumerate(tile_list):
ty = tl // tilesX
tx = tl % tilesX
m = np.ravel(layer[self.tileH*ty:self.tileH*(ty+1),self.tileW*tx:self.tileW*(tx+1)])
if self.bpp==32:
res[i,0] = m[0]
res[i,1] = m[2]
res[i,2] = m[4]
elif self.bpp==8:
res[i,0] = ((m[0]-128)*256+m[1])/128
res[i,1] = ((m[2]-128)*256+m[3])/128
res[i,2] = (m[4]*256+m[5])/65536.0
res = np.empty((len(tile_list), IJML.NUM_VALUES),dtype=float) # was only 3
tif.seek(self.labels.index(label))
layer = np.array(tif) # 8 or 32 bits
tilesX = layer.shape[1]//self.tileW
for i,tl in enumerate(tile_list):
ty = tl // tilesX
tx = tl % tilesX
m = np.ravel(layer[self.tileH*ty:self.tileH*(ty+1),self.tileW*tx:self.tileW*(tx+1)])
if self.bpp==32:
for k in range(res.shape[1]):
res[i,k] = m[k * 2]
elif self.bpp==8:
for k in range(res.shape[1]):
if k in IJML.SIGNED:
res[i,k] = ((m[2 * k] - 128) * 256 + m[2 * k + 1]) / 128
elif k in IJML.UNSIGNED_RMS:
res[i,k] = (m[2 * k]*256+m[2 * k + 1])/4096.0
else:
res[i,k] = (m[2 * k]*256+m[2 * k + 1])/65536.0
else:
for k in range(res.shape[1]):
res[i,k] = np.nan
# NaNize update!
if self.bpp==8:
a = res[...,0]
a[a==-256] = np.nan
b = res[...,1]
b[b==-256] = np.nan
c = res[...,2]
c[c==0] = np.nan
return res
# get ordered stack of images by provided items
# by index or label name
def getstack(self,items=[],shape_as_tiles=False):
a = ()
if len(items)==0:
b = self.image
else:
res[i,0] = np.nan
res[i,1] = np.nan
res[i,2] = np.nan
# NaNize
a = res[...,0]
a[a==-256] = np.nan
b = res[...,1]
b[b==-256] = np.nan
c = res[...,2]
c[c==0] = np.nan
return res
# get ordered stack of images by provided items
# by index or label name
def getstack(self,items=[],shape_as_tiles=False):
a = ()
if len(items)==0:
b = self.image
else:
for i in items:
if type(i)==int:
a += (self.image[:,:,i],)
elif type(i)==str:
j = self.labels.index(i)
a += (self.image[:,:,j],)
# stack along depth
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
# * do not handle out of bounds
def channel(self,index):
return self.image[:,:,index]
# display images by index or label
def show_images(self,items=[]):
# show listed only
if len(items)>0:
for i in items:
if type(i)==int:
self.show_image(i)
elif type(i)==str:
j = self.labels.index(i)
self.show_image(j)
# show all
else:
for i in range(self.nimages):
self.show_image(i)
# display single image
def show_image(self,index):
# display using matplotlib
t = self.image[:,:,index]
mytitle = "("+str(index+1)+" of "+str(self.nimages)+") "+self.labels[index]
fig = plt.figure()
fig.canvas.set_window_title(self.fname+": "+mytitle)
fig.suptitle(mytitle)
#plt.imshow(t,cmap=plt.get_cmap('gray'))
plt.imshow(t)
plt.colorbar()
# display using Pillow - need to scale
# remove NaNs - no need
#t[np.isnan(t)]=np.nanmin(t)
# scale to [min/max*255:255] range
#t = (1-(t-np.nanmax(t))/(t-np.nanmin(t)))*255
#tmp_im = Image.fromarray(t)
#tmp_im.show()
# puts etrees in infoss
def __parse_info(self):
infos = []
for info in self.infos:
infos.append(ET.fromstring(info))
self.infos = infos
# specifics
# properties dictionary
pd = {}
if infos:
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
def __split_labels(self,n,tag):
# list
tag_lens = tag[self.__TIFF_TAG_LABELS_LENGTHS]
# string
tag_labels = tag[self.__TIFF_TAG_LABELS_STRINGS].decode()
# remove 1st element: it's something like IJIJlabl..
tag_labels = tag_labels[tag_lens[0]:]
tag_lens = tag_lens[1:]
# the last ones are images labels
# normally the difference is expected to be 0 or 1
skip = len(tag_lens) - n
self.labels = []
self.infos = []
for l in tag_lens:
string = tag_labels[0:l].replace('\x00','')
if skip==0:
self.labels.append(string)
else:
self.infos.append(string)
skip -= 1
tag_labels = tag_labels[l:]
for i in items:
if type(i)==int:
a += (self.image[:,:,i],)
elif type(i)==str:
j = self.labels.index(i)
a += (self.image[:,:,j],)
# stack along depth
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
# * does not handle out of bounds
def channel(self,index):
return self.image[:,:,index]
# display images by index or label
def show_images(self,items=[]):
# show listed only
if len(items)>0:
for i in items:
if type(i)==int:
self.show_image(i)
elif type(i)==str:
j = self.labels.index(i)
self.show_image(j)
# show all
else:
for i in range(self.nimages):
self.show_image(i)
# display single image
def show_image(self,index):
# display using matplotlib
t = self.image[:,:,index]
mytitle = "("+str(index+1)+" of "+str(self.nimages)+") "+self.labels[index]
fig = plt.figure()
fig.canvas.set_window_title(self.fname+": "+mytitle)
fig.suptitle(mytitle)
#plt.imshow(t,cmap=plt.get_cmap('gray'))
plt.imshow(t)
plt.colorbar()
# display using Pillow - need to scale
# remove NaNs - no need
#t[np.isnan(t)]=np.nanmin(t)
# scale to [min/max*255:255] range
#t = (1-(t-np.nanmax(t))/(t-np.nanmin(t)))*255
#tmp_im = Image.fromarray(t)
#tmp_im.show()
# puts etrees in infoss
def __parse_info(self):
infos = []
for info in self.infos:
infos.append(ET.fromstring(info))
self.infos = infos
# specifics
# properties dictionary
pd = {}
if infos:
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'])
if self.bpp==8:
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
def __split_labels(self,n,tag):
# list
tag_lens = tag[self.__TIFF_TAG_LABELS_LENGTHS]
# string
tag_labels = tag[self.__TIFF_TAG_LABELS_STRINGS].decode()
# remove 1st element: it's something like IJIJlabl..
tag_labels = tag_labels[tag_lens[0]:]
tag_lens = tag_lens[1:]
# the last ones are images labels
# normally the difference is expected to be 0 or 1
skip = len(tag_lens) - n
self.labels = []
self.infos = []
for l in tag_lens:
string = tag_labels[0:l].replace('\x00','')
if skip==0:
self.labels.append(string)
else:
self.infos.append(string)
skip -= 1
tag_labels = tag_labels[l:]
#MAIN
if __name__ == "__main__":
try:
fname = sys.argv[1]
except IndexError:
fname = "/mnt/dde6f983-d149-435e-b4a2-88749245cc6c/home/eyesis/x3d_data/data_sets/train/1527182807_896892/v02/ml/1527182807_896892-ML_DATA-08B-O-FZ0.05-OFFS0.40000.tiff"
# 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 = "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)
print(bcolors.BOLDWHITE+"time: "+str(time.time())+bcolors.ENDC)
print("TIFF stack labels: "+str(ijt.labels))
#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))