diff --git a/brick/processing/input.py b/brick/processing/input.py index a9a1a11a1e6837beefeb61df9fa8291acf8c70a6..56a081f7c94f9c49f86bd2a6ff35369f2e8d48db 100644 --- a/brick/processing/input.py +++ b/brick/processing/input.py @@ -32,9 +32,11 @@ from brick.general.type import array_t import numpy as np_ import sys as sy_ +from PIL import Image +from PIL.ExifTags import TAGS -def ImageVerification(image, channel): +def ImageVerification(image: array_t, channel: str) -> array_t: if image.ndim == 3: print('Your image has only one color channel.') if channel == 'RGB': @@ -59,6 +61,7 @@ def ImageVerification(image, channel): print('The image dimensions are not correct:', image.ndim, ', instead of 3 or 4.') sy_.exit(0) + # if channel != 'RGB' and image.ndim == 4: # print('The image has multiple color channels. The channel', channel, 'was specified in the parameters.') # for idx, color in enumerate('RGB'): @@ -70,12 +73,13 @@ def ImageVerification(image, channel): def IntensityNormalizedImage(image: array_t) -> array_t: # - print('Relative Intensity Normalization between 0 and 1 (Not a standardization). Need to reevaluate the parameters !!!') + print( + 'Relative Intensity Normalization between 0 and 1 (Not a standardization). Need to reevaluate the parameters !!!') value_max = image.astype(np_.float32).max() value_min = image.astype(np_.float32).min() - result = (image.astype(np_.float32) - value_min)/(value_max - value_min) + result = (image.astype(np_.float32) - value_min) / (value_max - value_min) return result @@ -92,9 +96,32 @@ def IntensityNormalizedImage(image: array_t) -> array_t: # # return result -def MetricNormalizedImage(image: array_t) -> array_t: # TODO - # - print('Image metric in converted to micrometers.') + +def VoxelDimensionInMicrons(data_path: str) -> array_t: + # TODO Verify if metadata are in the same format for all the images - if not, add a raise error ? + + with Image.open(data_path) as img: # Find the voxels dimensions in micron in the metadata. + meta_dict = {TAGS.get(key, 'missing'): img.tag[key] for key in + img.tag} # Use the exif tags into the image metadata + + # Decode the tags text + metadata = meta_dict['missing'].decode('utf8') # Decode the tags text + metadata = metadata.replace('\x00', '') + + voxel_size = ['', '', ''] # Initialize the list of voxel size in str + for idaxe, axe in enumerate('XYZ'): + idvox = metadata.find('dblVoxel' + axe) # Get the index of the voxel size for the axe X, Y, Z + idvox += 15 + while metadata[idvox] != '\n': + voxel_size[idaxe] += metadata[idvox] + idvox += 1 + voxel_size = np_.asarray(list(map(float, voxel_size))) + voxel_size_microns = 1.0e6 * voxel_size + print('Voxel dimension in the image is [X Y Z] =', voxel_size_microns, 'in microns. WARNING this method highly ' + 'depends on the format of the metadata.') + + return voxel_size_microns + def DijkstraCosts(image: array_t, som_map: array_t, ext_map: array_t) -> array_t: # diff --git a/nutrimorph.py b/nutrimorph.py index ca15e448674f0962f4498c11023a5ccd93dd2465..52d993cc9f79bfa0dc56ae930b038f6b0bc719e5 100644 --- a/nutrimorph.py +++ b/nutrimorph.py @@ -54,6 +54,7 @@ import numpy as np_ import skimage.io as io_ import skimage.measure as ms_ from skimage.segmentation import relabel_sequential +import exifread as xf_ print(sy_.argv, sy_.argv.__len__()) @@ -89,6 +90,9 @@ start_time = tm_.time() # --- Images +voxel_micron = in_.VoxelDimensionInMicrons(data_path) + + image = io_.imread(data_path) # Image size verification - simple version without user interface