Source code for plugins.savers.image_saver

# Copyright 2014 Diamond Light Source Ltd.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
#     http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.

"""
.. module:: image_saver
   :platform: Unix
   :synopsis: A class to save output as images

.. moduleauthor:: Dan Nixon, Nghia Vo <scientificsoftware@diamond.ac.uk>

"""

import logging
import skimage.exposure
import skimage.io
import numpy as np
from PIL import Image

from savu.plugins.savers.base_image_saver import BaseImageSaver
from savu.plugins.utils import register_plugin
from savu.plugins.driver.cpu_plugin import CpuPlugin
import savu.core.utils as cu


[docs]@register_plugin class ImageSaver(BaseImageSaver, CpuPlugin): def __init__(self, name='ImageSaver'): super(ImageSaver, self).__init__(name)
[docs] def setup(self): data_pattern = self.parameters['pattern'] in_pData, _ = self.get_plugin_datasets() try: in_pData[0].plugin_data_setup(data_pattern, 'single') except: msg = "\n***************************************************"\ "**********\n"\ "Can't find the data pattern: {}.\nThe pattern parameter of " \ "this plugin must be relevant to its \nprevious plugin" \ "\n*************************************************************"\ "\n".format(data_pattern) logging.warning(msg) cu.user_message(msg) raise ValueError(msg)
[docs] def pre_process(self): super(ImageSaver, self).pre_process() self.pData = self.get_plugin_in_datasets()[0] self.file_format = self.parameters['format'] num_bit = self.parameters['num_bit'] if not (num_bit == 8 or num_bit == 16 or num_bit == 32): self.num_bit = 32 msg = "\n***********************************************\n"\ "This option %s is not available. Reset to 32 \n"\ % str(num_bit) cu.user_message(msg) else: self.num_bit = num_bit self._data_range = self._get_min_and_max()
[docs] def process_frames(self, data): frame = self.pData.get_current_frame_idx()[0] filename = '%s%05i.%s' % (self.filename, frame, self.file_format) frame = np.nan_to_num(data[0]) if (self.file_format == "tiff") or (self.file_format == "tif"): global_min = self.parameters['min'] global_max = self.parameters['max'] if self.num_bit == 32: rescaled_image = frame else: if global_min is None: if self.the_min is not None: global_min = self.the_min else: global_min = np.min(frame) if global_max is None: if self.the_max is not None: global_max = self.the_max else: global_max = np.max(frame) rescaled_image = np.clip(frame, global_min, global_max) rescaled_image = (rescaled_image - global_min) \ / (global_max - global_min) if self.num_bit == 16: rescaled_image = np.clip( np.uint16(rescaled_image * 65535), 0, 65535) else: rescaled_image = np.clip( np.uint8(rescaled_image * 255), 0, 255) img = Image.fromarray(rescaled_image) img.save(filename) else: # Rescale image to (0.0, 1.0) range rescaled_image = skimage.exposure.rescale_intensity( frame, in_range=self._data_range, out_range=(0.0, 1.0)) # Save image skimage.io.imsave( filename, rescaled_image, quality=self.parameters['jpeg_quality'])
[docs] def _get_min_and_max(self): data = self.get_in_datasets()[0] pattern = self.parameters['pattern'] try: self.the_min = self.stats_obj.get_stats_from_dataset(data, "min") self.the_max = self.stats_obj.get_stats_from_dataset(data, "max") self._data_range = (self.the_min, self.the_max) except KeyError: self._data_range = 'image' if (self.file_format == "tiff") or (self.file_format == "tif"): self.the_min = None self.the_max = None msg = "\n***********************************************\n"\ "!!!Warning!!!-> No global maximum and global minimum found\n"\ "in the metadata. Please run savu with stats turned on\n" \ "or input manually. Otherwise, local minimum\n" \ "and local maximum will be used for rescaling. This may\n"\ "result the fluctuation of brightness between slices.\n"\ "***********************************************\n" if (self.num_bit == 8) or (self.num_bit == 16): cu.user_message(msg) return self._data_range
[docs] def executive_summary(self): if (self._data_range == 'image') and (self.num_bit != 32): return ["To rescale and normalise the data between global max and " "min values, please run savu with stats turned on."] return ["Nothing to Report"]