Mentions légales du service

Skip to content
Snippets Groups Projects
unit.py 4.18 KiB
Newer Older
DEBREUVE Eric's avatar
DEBREUVE Eric committed
# Copyright CNRS/Inria/UNS
# Contributor(s): Eric Debreuve (since 2019), Morgane Nadal (2020)
#
# eric.debreuve@cnrs.fr
#
# This software is governed by the CeCILL  license under French law and
# abiding by the rules of distribution of free software.  You can  use,
# modify and/ or redistribute the software under the terms of the CeCILL
# license as circulated by CEA, CNRS and INRIA at the following URL
# "http://www.cecill.info".
#
# As a counterpart to the access to the source code and  rights to copy,
# modify and redistribute granted by the license, users are provided only
# with a limited warranty  and the software's author,  the holder of the
# economic rights,  and the successive licensors  have only  limited
# liability.
#
# In this respect, the user's attention is drawn to the risks associated
# with loading,  using,  modifying and/or developing or reproducing the
# software by the user in light of its specific status of free software,
# that may mean  that it is complicated to manipulate,  and  that  also
# therefore means  that it is reserved for developers  and  experienced
# professionals having in-depth computer knowledge. Users are therefore
# encouraged to load and test the software's suitability as regards their
# requirements in conditions enabling the security of their systems and/or
# data to be ensured and,  more generally, to use and operate it in the
# same conditions as regards security.
#
# The fact that you are presently reading this means that you have had
# knowledge of the CeCILL license and that you accept its terms.

import math as mt_
import re as re_

import numpy as np_
from PIL import Image
from PIL.ExifTags import TAGS

from brick.general.type import array_t


def FindVoxelDimensionInMicron(
    data_path: str, size_voxel_in_micron: list = None
) -> array_t:
    """
    Find Voxel dimension in micron from the image metadata.
    """
    #
    if size_voxel_in_micron is not None:
        print("VOXEL DIM: [X Y Z] =", size_voxel_in_micron, "micron.")
        return np_.array(size_voxel_in_micron)

    else:  # TODO if not found, try to make something more general
        print("Warning: The size of a voxel is not specified in the parameters.")

        try:
            # Find the voxels dimensions in micron in the metadata.
            # /!\ Very specific to one type of microscope metadata !

            with Image.open(data_path) as img:
                # Use the exif tags into the image metadata
                meta_dict = {TAGS.get(key, "missing"): img.tag[key] for key in img.tag}

            # Decode the tags text
            metadata = meta_dict["missing"].decode("utf8")
            metadata = metadata.replace("\x00", "")

            # Initialize the list of voxel size in str
            voxel_size = []

            for axe in "XYZ":
                pattern = (
                    "Voxel" + axe + ".+\= (\d.+E.\d.)"
                )  # Regular expression found in metadata
                voxel_size.append(re_.findall(pattern, metadata)[0])

            voxel_size = np_.array(list(map(float, voxel_size)))
            # Conversion meters in micron
            voxel_size_micron = 1.0e6 * voxel_size

            print("VOXEL DIM: [X Y Z] =", voxel_size_micron, "micron.")

            return voxel_size_micron

        except Exception as exception:
            raise ValueError(
                f"{exception}: /!\ Unable to find the voxel dimensions in micron. Specify it in the parameters."
            )


def ToPixel(
    micron: float,
    voxel_size_micron: array_t,
    dimension: tuple = (0,),
    decimals: int = None,
) -> int:
    """
    Dimension correspond to the axis (X,Y,Z) = (0,1,2). Can be used for distance, area and volumes.
    """
    # Conversion of micron into pixels.
    return round(
        micron / (mt_.prod(voxel_size_micron[axis] for axis in dimension)), decimals
    )


def ToMicron(
    pixel: float, voxel_size_micron: list, dimension: tuple = (0,), decimals: int = None
) -> float:
    """
    Dimension correspond to the axis (X,Y,Z) = (0,1,2). Can be used for distance, area and volumes.
    """
    # Conversion of pixels into microns
    return round(
        pixel * (mt_.prod(voxel_size_micron[axis] for axis in dimension)), decimals
    )