# Copyright or © or Copr. IETR/INSA Rennes (2019)
#
# Contributors :
# Eduardo Fernandes-Montesuma eduardo.fernandes-montesuma@insa-rennes.fr (2019)
# Florian Lemarchand florian.lemarchand@insa-rennes.fr (2019)
#
#
# OpenDenoising is a computer program whose purpose is to benchmark image
# restoration algorithms.
#
# This software is governed by the CeCILL-C 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-C
# 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-C license and that you accept its terms.
import os
import numpy as np
from skimage.io import imread
from skimage.color import rgb2gray
from skimage.util import img_as_float32
from OpenDenoising.data import module_logger
from OpenDenoising.data import AbstractDatasetGenerator
[docs]class FullDatasetGenerator(AbstractDatasetGenerator):
"""Dataset generator based on Keras library. This class is used for non-blind denoising problems. Unlike
ClenDatasetGenerator class, this class corresponds to the case where both clean and noisy samples are available and
paired (for each noisy image, there is one and only one clean image with same filename).
Attributes
----------
path : str
String containing the path to image files directory.
batch_size : int
Size of image batch.
n_channels : int
1 for grayscale, 3 for RGB.
shuffle : bool
Whether to shuffle the dataset at each epoch or not.
name : str
String containing the dataset's name.
preprocessing : list
List of preprocessing functions, which will be applied to each image.
"""
[docs] def __init__(self, path, batch_size=32, shuffle=True, name="FullDataset", n_channels=1, preprocessing=None):
super().__init__(path, batch_size, shuffle, name, n_channels)
self.n_channels = n_channels
self.filenames = np.array(os.listdir(os.path.join(self.path, "in")))
self.preprocessing = [] if preprocessing is None else preprocessing
self.on_epoch_end()
module_logger.info("Generating data from {}".format(os.path.join(self.path)))
[docs] def __getitem__(self, i):
""" Generate batches of data """
# Get batch_filenames
batch_filenames = self.filenames[i * self.batch_size: (i + 1) * self.batch_size]
module_logger.debug("[{}] Got following batch names: {}".format(self, batch_filenames))
# Get data batches
inp, ref = self.__data_generation(batch_filenames)
return inp, ref
def __data_generation(self, batch_filenames):
"""Data generation method
Parameters
----------
batch_filenames : list
List of strings containing filenames to read. Note that, for each noisy image filename there must be a clean
image with same filename.
Returns
-------
noisy_batch : :class:`numpy.ndarray`
Batch of noisy images.
clean_batch : :class:`numpy.ndarray`
Batch of reference images.
"""
# Noised image and ground truth initialization
ref_batch = []
inp_batch = []
for filename in batch_filenames:
# Compose path
clean_filepath = os.path.join(self.path, "in", filename)
noisy_filepath = os.path.join(self.path, "ref", filename)
# Read images
ref = imread(clean_filepath)
ref = img_as_float32(ref)
inp = imread(noisy_filepath)
inp = img_as_float32(inp)
# Corrects shape of reference
if ref.ndim == 3 and ref.shape[-1] == 3 and self.n_channels == 1:
# Converts RGB to Gray
ref = rgb2gray(ref)
if ref.ndim == 2 and self.n_channels == 1:
# Expand last dim if image is grayscale
ref = np.expand_dims(ref, axis=-1)
elif ref.ndim == 2 and self.n_channels == 3:
raise ValueError("Expected RGB image but got Grayscale (image shape: {})".format(ref.shape))
# Corrects shape of input image
if inp.ndim == 3 and inp.shape[-1] == 3 and self.n_channels == 1:
# Converts RGB to Gray
inp = rgb2gray(inp)
if inp.ndim == 2 and self.n_channels == 1:
# Expand last dim if image is grayscale
inp = np.expand_dims(inp, axis=-1)
elif inp.ndim == 2 and self.n_channels == 3:
raise ValueError("Expected RGB image but got Grayscale (image shape: {})".format(inp.shape))
# Apply preprocessing functions
for func in self.preprocessing:
inp, ref = func(inp, ref)
# Append images to lists
ref_batch.append(ref)
inp_batch.append(inp)
ref_batch = np.array(ref_batch) if ref_batch[0].ndim == 3 else np.concatenate(ref_batch, axis=0)
inp_batch = np.array(inp_batch) if inp_batch[0].ndim == 3 else np.concatenate(inp_batch, axis=0)
module_logger.debug("Data shape: {}".format(ref_batch.shape))
if not inp.shape == ref.shape:
raise ValueError("Expected {} to have same shape of {}, but got {} and {}".format(clean_filepath,
noisy_filepath,
ref.shape, inp.shape))
return ref_batch, inp_batch
[docs] def __next__(self):
"""Returns image batches sequentially."""
while True:
for input_batch, output_batch in self:
return input_batch, output_batch
[docs] def __repr__(self):
return "Dataset name: {}, Dataset type: {}, Path: {}, " \
"Batch Size: {}, preprocessing: {}".format(self, "Full", self.path, self.batch_size,
self.preprocessing)