Source code for edxia.io.loader.base_loader

# Copyright (c) 2019 Fabien Georget <fabien.georget@epfl.ch>, EPFL
# All rights reserved.
#
# Redistribution and use in source and binary forms, with or without
# modification, are permitted provided that the following conditions are met:
#
# 1. Redistributions of source code must retain the above copyright notice,
# this list of conditions and the following disclaimer.
#
# 2. Redistributions in binary form must reproduce the above copyright notice,
# this list of conditions and the following disclaimer in the documentation
# and/or other materials provided with the distribution.
#
# 3. Neither the name of the copyright holder nor the names of its contributors
# may be used to endorse or promote products derived from this software without
# specific prior written permission.
#
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
# ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
# LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
# CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
# SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
# BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER
# IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
# ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
# POSSIBILITY OF SUCH DAMAGE.


__all__ = ["AbstractLoader",]

from abc import ABC, abstractmethod

import numpy as np
from py_expression_eval import Parser

from ...composite import CompositeMap
from ...core.map import MapsStack, Map
from ...filters.scalers import ManualScaler


[docs]class AbstractLoader(ABC): """Abstract base class for a map loader. This class is not intended for use, instead the user should use one of the class in :mod:`edxia.io.loader`. """ def __init__(self, exp_manager, filters=None): self._exp_manager = exp_manager if filters is None: filters = [] self._filters = filters @property def exp_manager(self): """Return the experience manager""" return self._exp_manager @property def filters(self): """Return the list of filters to apply at loading.""" return self._filters @filters.setter def filters(self, filters): """Set the list of filters to apply at loading.""" self.reset_filters(filters)
[docs] def add_filter(self, afilter): """Add a filter to the list of filters to apply at loading.""" self._filters.append(afilter) self.reset_filters(self._filters)
[docs] def reset_filters(self, filters): """Reset the list of filters.""" self._filters = filters
[docs] def get_path_map(self, component): """Return the path to a component map.""" return self._exp_manager.get_path_map(component)
[docs] def load_edsmap(self, component): """Load the map of 'component'. It can be either a simple component (e.g. 'BSE', 'Ca'), or a combination of components (e.g. "Si+Al/Ca"). """ special_chars = ["+", "-", "*", "/"] for char in special_chars: if char in special_chars: return self.load_edsmap_complex(component) else: return self.load_edsmap_single(component)
[docs] def load_edsmap_complex(self, expr): """Load an expresion map.""" parser = Parser() toeval = parser.parse(expr) var_dict = dict([(ci, self.load_edsmap_single(ci).map) for ci in toeval.variables()]) comp_raw_map = toeval.evaluate(var_dict) eds_map = Map(expr, comp_raw_map, self.exp_manager) return eds_map
[docs] @abstractmethod def load_edsmap_single(self, component): """Load the map of a 'component'.""" pass
[docs] def load_composite(self, channels, is_rgb=True): """Load a composite map :param channels: the different channels to consider :param is_rgb: if true, the map is reduced to an RGB image """ if is_rgb: return self.load_composite_rgb(channels) else: stack = self.load_stack(channels.components, channels.factors) return CompositeMap(stack.maps, channels, self.exp_manager)
[docs] def load_composite_rgb(self, channels): """Load a composite map.""" maps = [] for color in ["red", "green", "blue", "gray"]: if getattr(channels, color) is None: maps.append(None) continue tmap = self.load_edsmap(getattr(channels, color)) # apply scaling after ManualScaler(getattr(channels, color+"_factor")).apply(tmap) maps.append(tmap) composite_img = None for i in range(3): if maps[i] is not None: if composite_img is None: composite_img = np.zeros((maps[i].nb_rows, maps[i].nb_cols, 3)) composite_img[:,:,i] = maps[i].map if maps[3] is not None: for i in range(3): composite_img[:,:,i] += maps[3].map/3 return CompositeMap(composite_img, channels, self.exp_manager)
[docs] def load_stack(self, components=None, factors=None): """ Load a stack of maps :param components: the list of components, if not provided it is the entire list of components available :param factors: the list of factors, default to 1 """ if components is None: components = self.exp_manager.list_components if factors is None: factors=np.ones((len(components),)) if not hasattr(components, "__len__"): raise ValueError("Components must be a list of components") map0 = self.load_edsmap(components[0]) ManualScaler(factors[0]).apply(map0) stack = MapsStack(components, map0.shape, self.exp_manager) stack.set_map(map0) for i in range(1,len(components)): mapi = self.load_edsmap(components[i]) ManualScaler(factors[i]).apply(mapi) stack.set_map(mapi) return stack