def test_read_image_mode(self):
     """Tests the function `read_image_mode`.
     
     The test is successful if the file "tools/pseudo_data/rgb_web.jpg"
     is read normally. However, the reading of "tools/pseudo_data/cmyk_snake.jpg"
     and the reading of "tools/pseudo_data/cmyk_mushroom.jpg" each
     raises a `ValueError` exception.
     
     """
     path_to_rgb = 'tools/pseudo_data/rgb_web.jpg'
     paths_to_cmyks = (
         'tools/pseudo_data/cmyk_snake.jpg',
         'tools/pseudo_data/cmyk_mushroom.jpg'
     )
     
     rgb_uint8 = tls.read_image_mode(path_to_rgb,
                                     'RGB')
     print('The reading of "{0}" yields a Numpy array with shape {1} and data-type {2}.'.format(path_to_rgb, rgb_uint8.shape, rgb_uint8.dtype))
     for path_to_cmyk in paths_to_cmyks:
         try:
             cmyk_uint8 = tls.read_image_mode(path_to_cmyk,
                                              'RGB')
         except ValueError as err:
             print('The reading of "{}" raises a `ValueError` exception.'.format(path_to_cmyk))
             print(err)
 def test_fit_maps(self):
     """Tests the function `fit_maps` in the file "eae/analysis.py".
     
     The test is successful if, in the images saved in the
     directory at "eae/pseudo_visualization/fit_maps/", the
     distributions of the feature maps latent variables are
     all similar.
     
     """
     luminance_0_uint8 = tls.rgb_to_ycbcr(tls.read_image_mode('eae/pseudo_data/peppers.png', 'RGB'))[:, :, 0:1]
     luminance_1_uint8 = tls.rgb_to_ycbcr(tls.read_image_mode('eae/pseudo_data/mandrill.png', 'RGB'))[:, :, 0:1]
     luminances_uint8 = numpy.stack((luminance_0_uint8, luminance_1_uint8),
                                    axis=0)
     
     # When the entropy autoencoder model is not a loaded one,
     # the sixth argument of the constructor below is an empty
     # string.
     entropy_ae = EntropyAutoencoder(2,
                                     luminances_uint8.shape[1],
                                     luminances_uint8.shape[2],
                                     1.,
                                     8000.,
                                     '',
                                     False)
     with tf.Session() as sess:
         entropy_ae.initialization(sess, '')
         y_float32 = sess.run(
             entropy_ae.node_y,
             feed_dict={entropy_ae.node_visible_units:luminances_uint8.astype(numpy.float32)}
         )
     eae.analysis.fit_maps(y_float32,
                           'eae/pseudo_visualization/fit_maps/laplace_locations.png',
                           'eae/pseudo_visualization/fit_maps/laplace_scales.png',
                           ['eae/pseudo_visualization/fit_maps/fitting_map_{}.png'.format(i + 1) for i in range(y_float32.shape[3])])
def compute_rate_psnr(path_to_reference, path_to_reconstruction, is_2000):
    """Computes the rate and the PSNR associated to the compression of the RGB image via either JPEG or JPEG2000.
    
    The compression of a single RGB image
    via either JPEG or JPEG2000 at a single
    compression quality is considered.
    
    Parameters
    ----------
    path_to_reference : str
        Path to the RGB image before
        being compressed via either
        JPEG or JPEG2000.
    path_to_reconstruction : str
        Path to the RGB image after
        being compressed via either
        JPEG or JPEG2000. If JPEG is
        used, `path_to_reconstruction`
        must end with ".jpg". Otherwise,
        it must end with ".jp2".
    is_2000 : bool
        Is it JPEG2000?
    
    Returns
    -------
    tuple
        numpy.float64
            Rate associated to the compression of
            the RGB image via either JPEG or JPEG2000.
        numpy.float64
            PSNR associated to the compression of
            the RGB image via either JPEG or JPEG2000.
    
    """
    reference_uint8 = tls.read_image_mode(path_to_reference, 'RGB')
    reference_float64 = reference_uint8.astype(numpy.float64)

    # `Glymur` is needed to read JPEG2000 images.
    if is_2000:
        file = glymur.Jp2k(path_to_reconstruction)
        reconstruction_uint8 = file[:]
    else:
        reconstruction_uint8 = tls.read_image_mode(path_to_reconstruction,
                                                   'RGB')
    reconstruction_float64 = reconstruction_uint8.astype(numpy.float64)
    psnr = 10. * numpy.log10((255.**2) / numpy.mean(
        (reference_float64 - reconstruction_float64)**2))
    nb_bytes = os.stat(path_to_reconstruction).st_size
    rate = float(8 * nb_bytes) / numpy.prod(reference_uint8.shape)
    return (rate, psnr)
Beispiel #4
0
 def test_visualize_rotated_luminance(self):
     """Tests the function `visualize_rotated_luminance`.
     
     A 1st image is saved at
     "tools/pseudo_visualization/visualize_rotated_luminance/luminance_rotation.png".
     A 2nd image is saved at
     "tools/pseudo_visualization/visualize_rotated_luminance/luminance_crop_0.png".
     A 3rd image is saved at
     "tools/pseudo_visualization/visualize_rotated_luminance/luminance_crop_1.png".
     The test is successful if the 2nd and the 3rd
     image are two distinct crops of the 1st image.
     
     """
     positions_top_left = numpy.array([[10, 10], [200, 200]], dtype=numpy.int32)
     paths = [
         'tools/pseudo_visualization/visualize_rotated_luminance/luminance_rotation.png',
         'tools/pseudo_visualization/visualize_rotated_luminance/luminance_crop_0.png',
         'tools/pseudo_visualization/visualize_rotated_luminance/luminance_crop_1.png'
     ]
     
     rgb_uint8 = tls.read_image_mode('tools/pseudo_data/rgb_web.jpg',
                                     'RGB')
     luminance_before_rotation_uint8 = tls.rgb_to_ycbcr(rgb_uint8)[:, :, 0]
     tls.visualize_rotated_luminance(luminance_before_rotation_uint8,
                                     True,
                                     positions_top_left,
                                     paths)
 def test_save_image(self):
     """Tests the function `save_image`.
     
     An image is saved at "tools/pseudo_visualization/save_image.png".
     The test is successful if this image is
     identical to "tools/pseudo_data/rgb_web.png".
     
     """
     rgb_uint8 = tls.read_image_mode('tools/pseudo_data/rgb_web.jpg',
                                     'RGB')
     tls.save_image('tools/pseudo_visualization/save_image.png',
                    rgb_uint8)
    def test_evaluate_hevc(self):
        """Tests the function `evaluate_hevc`.
        
        The test is successful if, the rate for the
        1st quantization parameter is much larger
        than the rate for the 2nd quantization parameter.
        Besides, the PSNR for the 1st quantization parameter
        must be much larger than the PSNR for the 2nd
        quantization parameter.
        
        """
        path_to_before_hevc = 'hevc/temp/luminance_before_hevc.yuv'
        path_to_after_hevc = 'hevc/temp/luminance_after_hevc.yuv'
        path_to_cfg = 'hevc/configuration/intra.cfg'
        path_to_bitstream = 'hevc/temp/bitstream.bin'
        qps = numpy.array([22, 42], dtype=numpy.int32)
        path_to_hevc_vis = 'hevc/pseudo_visualization/evaluate_hevc/'
        list_rotation = [0, 11, 4]
        positions_top_left = numpy.array([[300], [200]], dtype=numpy.int32)

        rgb_uint8 = tls.read_image_mode('hevc/pseudo_data/rgb_nightshot.jpg',
                                        'RGB')
        (height_initial, width_initial, _) = rgb_uint8.shape
        height_surplus = height_initial % 8
        width_surplus = width_initial % 8
        luminances_uint8 = numpy.expand_dims(
            tls.rgb_to_ycbcr(rgb_uint8)[0:height_initial - height_surplus,
                                        0:width_initial - width_surplus, 0],
            axis=0)
        (rate,
         psnr) = hevc.hevc.evaluate_hevc(luminances_uint8, path_to_before_hevc,
                                         path_to_after_hevc, path_to_cfg,
                                         path_to_bitstream, qps,
                                         path_to_hevc_vis, list_rotation,
                                         positions_top_left)
        print('1st quantization parameter: {}'.format(qps[0]))
        print('Rate for the 1st quantization parameter: {}'.format(rate[0, 0]))
        print('PSNR for the 1st quantization parameter: {}'.format(psnr[0, 0]))
        print('2nd quantization parameter: {}'.format(qps[1]))
        print('Rate for the 2nd quantization parameter: {}'.format(rate[1, 0]))
        print('PSNR for the 2nd quantization parameter: {}'.format(psnr[1, 0]))
    def test_compute_rate_psnr(self):
        """Tests the function `compute_rate_psnr`.
        
        An image is saved at
        "hevc/pseudo_visualization/compute_rate_psnr/reconstruction_0.png".
        A crop of this image is saved at
        "hevc/pseudo_visualization/compute_rate_psnr/reconstruction_0_crop_0.png".
        The test is successful if the image and its
        crop are rotated compared to the image at
        "hevc/pseudo_data/rgb_nightshot.jpg".
        
        """
        path_to_before_hevc = 'hevc/temp/luminance_before_hevc.yuv'
        path_to_after_hevc = 'hevc/temp/luminance_after_hevc.yuv'
        path_to_cfg = 'hevc/configuration/intra.cfg'
        path_to_bitstream = 'hevc/temp/bitstream.bin'
        qp = 42
        path_to_storage = 'hevc/pseudo_visualization/compute_rate_psnr/'
        list_rotation = [0, 11, 4]
        positions_top_left = numpy.array([[300], [200]], dtype=numpy.int32)

        rgb_uint8 = tls.read_image_mode('hevc/pseudo_data/rgb_nightshot.jpg',
                                        'RGB')
        (height_initial, width_initial, _) = rgb_uint8.shape
        height_surplus = height_initial % 8
        width_surplus = width_initial % 8

        # The 2nd and the 3rd dimension of `luminance_uint8`
        # must be divisible by 8 as the height and the width
        # of the images inserted into HEVC must be divisible
        # by the minimum CU size.
        luminances_uint8 = numpy.expand_dims(
            tls.rgb_to_ycbcr(rgb_uint8)[0:height_initial - height_surplus,
                                        0:width_initial - width_surplus, 0],
            axis=0)
        (rate, psnr) = hevc.hevc.compute_rate_psnr(
            luminances_uint8, path_to_before_hevc, path_to_after_hevc,
            path_to_cfg, path_to_bitstream, qp, path_to_storage, list_rotation,
            positions_top_left)
        print('Rate: {}'.format(rate[0]))
        print('PSNR: {}'.format(psnr[0]))
 def test_write_400(self):
     """Tests the function `write_400`.
     
     An image is saved at
     "hevc/pseudo_visualization/write_400.png".
     The test is successful if this image
     is identical to the image at
     "hevc/pseudo_visualization/read_400.png".
     
     """
     path_to_yuv = 'hevc/pseudo_data/luminance_nightshot.yuv'
     rgb_uint8 = tls.read_image_mode('hevc/pseudo_data/rgb_nightshot.jpg',
                                     'RGB')
     luminance_uint8 = tls.rgb_to_ycbcr(rgb_uint8)[:, :, 0]
     tls.save_image('hevc/pseudo_visualization/write_400.png',
                    luminance_uint8)
     if os.path.isfile(path_to_yuv):
         print('"{}" exists. Remove it manually and restart the same test.'.
               format(path_to_yuv))
     else:
         hevc.hevc.write_400(numpy.expand_dims(luminance_uint8, axis=2),
                             path_to_yuv)
    def test_compress_hevc(self):
        """Tests the function `compress_hevc`.
        
        A 1st image is saved at
        "hevc/pseudo_visualization/compress_hevc/luminance_before.png".
        A 2nd image is saved at
        "hevc/pseudo_visualization/compress_hevc/luminance_after.png".
        The test is successful if the 2nd
        image corresponds to the 1st image
        with HEVC compression artefacts.
        
        """
        path_to_before_hevc = 'hevc/temp/luminance_before_hevc.yuv'
        path_to_after_hevc = 'hevc/temp/luminance_after_hevc.yuv'
        path_to_cfg = 'hevc/configuration/intra.cfg'
        path_to_bitstream = 'hevc/temp/bitstream.bin'
        qp = 42

        rgb_uint8 = tls.read_image_mode('hevc/pseudo_data/rgb_nightshot.jpg',
                                        'RGB')
        (height_initial, width_initial, _) = rgb_uint8.shape
        height_surplus = height_initial % 8
        width_surplus = width_initial % 8
        luminance_uint8 = tls.rgb_to_ycbcr(rgb_uint8)[0:height_initial -
                                                      height_surplus,
                                                      0:width_initial -
                                                      width_surplus, 0]
        tls.save_image(
            'hevc/pseudo_visualization/compress_hevc/luminance_before.png',
            luminance_uint8)
        luminance_before_hevc_uint8 = numpy.expand_dims(luminance_uint8,
                                                        axis=2)
        luminance_after_hevc_uint8 = hevc.hevc.compress_hevc(
            luminance_before_hevc_uint8, path_to_before_hevc,
            path_to_after_hevc, path_to_cfg, path_to_bitstream, qp, True)
        tls.save_image(
            'hevc/pseudo_visualization/compress_hevc/luminance_after.png',
            numpy.squeeze(luminance_after_hevc_uint8, axis=2))
Beispiel #10
0
def create_imagenet(path_to_folder_rgbs, width_crop, nb_training, nb_validation, path_to_training, path_to_validation, path_to_tar=''):
    """Creates the ImageNet training and validation sets.
    
    The ImageNet RGB images are converted into
    luminance images. Then, the luminance images
    are cropped. Finally, the ImageNet training and
    validation sets are filled with the luminance
    crops and they are saved.
    
    Parameters
    ----------
    path_to_folder_rgbs : str
        Path to the folder storing ImageNet RGB images.
    width_crop : int
        Width of the crop.
    nb_training : int
        Number of luminance crops in
        the ImageNet training set.
    nb_validation : int
        Number of luminance crops in
        the ImageNet validation set.
    path_to_training : str
        Path to the file in which the
        ImageNet training set is saved.
        The path ends with ".npy".
    path_to_validation : str
        Path to the file in which the
        ImageNet validation set is saved.
        The path ends with ".npy".
    path_to_tar : str, optional
        Path to an archive containing ImageNet
        RGB images. The default value is ''. If
        the path is not the default path, the
        archive is extracted to `path_to_folder_rgbs`
        before the function starts creating the
        ImageNet training and validation sets.
    
    Raises
    ------
    RuntimeError
        If there are not enough ImageNet
        RGB images to create the ImageNet
        training and validation sets.
    
    """
    if os.path.isfile(path_to_training) and os.path.isfile(path_to_validation):
        print('"{0}" and "{1}" already exist.'.format(path_to_training, path_to_validation))
        print('Delete them manually to recreate the ImageNet training and validation sets.')
    else:
        if path_to_tar:
            tls.untar_archive(path_to_folder_rgbs,
                              path_to_tar)
        nb_total = nb_training + nb_validation
        
        # `width_crop` has to be divisible by 16.
        luminances_uint8 = numpy.zeros((nb_total, width_crop, width_crop, 1), dtype=numpy.uint8)
        
        # `os.listdir` returns a list whose order depends on the OS.
        # To make `create_bsds` independent of the OS, the output of
        # `os.listdir` is sorted.
        list_names = tls.clean_sort_list_strings(os.listdir(path_to_folder_rgbs),
                                                 ('jpg', 'JPEG', 'png'))
        i = 0
        for name in list_names:
            path_to_rgb = os.path.join(path_to_folder_rgbs,
                                       name)
            
            # If the condition below is met, the result of
            # the processing of `rgb_uint8` is added to the
            # ImageNet training set. Otherwise, the result
            # the processing of `rgb_uint8` is added to the
            # ImageNet validation set.
            if i < nb_training:
                is_random = True
            else:
                is_random = False
            try:
                rgb_uint8 = tls.read_image_mode(path_to_rgb,
                                                'RGB')
                crop_uint8 = tls.crop_option_2d(tls.rgb_to_ycbcr(rgb_uint8)[:, :, 0],
                                                width_crop,
                                                is_random)
            except (TypeError, ValueError) as err:
                print(err)
                print('"{}" is skipped.\n'.format(path_to_rgb))
                continue
            luminances_uint8[i, :, :, 0] = crop_uint8
            i += 1
            if i == nb_total:
                break
        
        # If the previous loop was not broken,
        # `luminances_uint8` is not full. In this
        # case, the program crashes as the ImageNet
        # training and validation sets should not
        # contain any "zero" luminance crop.
        if i != nb_total:
            raise RuntimeError('There are not enough ImageNet RGB images at "{}" to create the ImageNet training and validation sets.'.format(path_to_folder_rgbs))
        training_data = luminances_uint8[0:nb_training, :, :, :]
        validation_data = luminances_uint8[nb_training:nb_total, :, :, :]
        numpy.save(path_to_training,
                   training_data)
        numpy.save(path_to_validation,
                   validation_data)
def create_bsds(source_url, path_to_folder_rgbs, path_to_bsds, path_to_list_rotation, path_to_tar=''):
    """Creates the BSDS test set.
    
    100 BSDS RGB images are converted into luminance. The
    1st row and the 1st column of each luminance image are
    removed. Then, sideways luminance images are rotated.
    Finally, the BSDS test set is filled with the luminance
    images and it is saved.
    
    Parameters
    ----------
    source_url : str
        URL of the original BSDS dataset.
    path_to_folder_rgbs : str
        Path to the folder to which the original BSDS dataset
        (training RGB images and test RGB images) is extracted.
    path_to_bsds : str
        Path to the file in which the BSDS test
        set is saved. The path ends with ".npy".
    path_to_list_rotation : str
        Path to the file in which the list
        storing the indices of the rotated
        luminance images is saved. The path
        ends with ".pkl".
    path_to_tar : str, optional
        Path to the downloaded archive containing the original
        BSDS dataset. The default value is ''. If the path
        is not the default path, the archive is extracted
        to `path_to_folder_rgbs` before the function starts
        creating the BSDS test set.
    
    Raises
    ------
    RuntimeError
        If the number of BSDS RGB images to be
        read is not 100.
    ValueError
        If a RGB image is neither 481x321x3
        nor 321x481x3.
    
    """
    if os.path.isfile(path_to_bsds) and os.path.isfile(path_to_list_rotation):
        print('"{0}" and "{1}" already exist.'.format(path_to_bsds, path_to_list_rotation))
        print('Delete them manually to recreate the BSDS test set.')
    else:
        if path_to_tar:
            is_downloaded = tls.download_untar_archive(source_url,
                                                       path_to_folder_rgbs,
                                                       path_to_tar)
            if is_downloaded:
                print('Successfully downloaded "{}".'.format(path_to_tar))
            else:
                print('"{}" already exists.'.format(path_to_tar))
                print('Delete it manually to re-download it.')
        
        # The height and width of the luminance images we
        # feed into the autoencoders has to be divisible by 16.
        height_bsds = 321
        width_bsds = 481
        reference_uint8 = numpy.zeros((100, height_bsds - 1, width_bsds - 1), dtype=numpy.uint8)
        list_rotation = []
        
        # `os.listdir` returns a list whose order depends on the OS.
        # To make `create_bsds` independent of the OS, the output of
        # `os.listdir` is sorted.
        path_to_folder_test = os.path.join(path_to_folder_rgbs,
                                           'BSDS300/images/test/')
        list_names = tls.clean_sort_list_strings(os.listdir(path_to_folder_test),
                                                 'jpg')
        if len(list_names) != 100:
            raise RuntimeError('The number of BSDS RGB images to be read is not 100.')
        for i in range(100):
            path_to_file = os.path.join(path_to_folder_test,
                                        list_names[i])
            
            # `tls.read_image_mode` is not put into a `try` `except` clause
            # as each BSDS300 RGB image has to be read.
            rgb_uint8 = tls.read_image_mode(path_to_file,
                                            'RGB')
            
            # `tls.rgb_to_ycbcr` checks that the data-type of
            # its input array is equal to `numpy.uint8`. `tls.rgb_to_ycbcr`
            # also checks that its input array has 3 dimensions
            # and its 3rd dimension is equal to 3.
            luminance_uint8 = tls.rgb_to_ycbcr(rgb_uint8)[:, :, 0]
            (height_image, width_image) = luminance_uint8.shape
            if height_image == height_bsds and width_image == width_bsds:
                reference_uint8[i, :, :] = luminance_uint8[1:height_bsds, 1:width_bsds]
            elif width_image == height_bsds and height_image == width_bsds:
                reference_uint8[i, :, :] = numpy.rot90(luminance_uint8[1:width_bsds, 1:height_bsds])
                list_rotation.append(i)
            else:
                raise ValueError('"{0}" is neither {1}x{2}x3 nor {2}x{1}x3.'.format(path_to_file, height_bsds, width_bsds))
        
        numpy.save(path_to_bsds,
                   reference_uint8)
        with open(path_to_list_rotation, 'wb') as file:
            pickle.dump(list_rotation, file, protocol=2)
def compute_rate_psnr(quality, list_rotation, index, path_to_before_jpeg2000, path_to_after_jpeg2000, positions_top_left):
    """Computes the rate and the PSNR associated to the compression of the luminance image via JPEG2000.
    
    The compression of a single luminance image
    via JPEG2000 at a single compression quality
    is considered.
    
    Parameters
    ----------
    quality : int
        Compression quality.
    list_rotation : list
        Each integer in this list is the index
        of a rotated luminance image.
    index : int
        Luminance image index.
    path_to_before_jpeg2000 : str
        Path to the folder containing
        the luminance images before
        being compressed via JPEG2000.
    path_to_after_jpeg2000 : str
        Path to the folder containing
        the luminance images after being
        compressed via JPEG2000.
    positions_top_left : numpy.ndarray
        2D array with data-type `numpy.int32`.
        This array is dedicated to visualization.
        `positions_top_left[:, i]` contains the
        row and the column of the image pixel at
        the top-left of the ith crop of the single
        luminance image after being compressed
        via JPEG2000.
    
    Returns
    -------
    tuple
        float
            Rate associated to the compression
            of the luminance image via JPEG2000.
        numpy.float64
            PSNR associated to the compression
            of the luminance image via JPEG2000.
    
    """
    path_to_reference = os.path.join(path_to_before_jpeg2000,
                                     'reference_{}.png'.format(index))
    path_to_reconstruction = os.path.join(path_to_after_jpeg2000,
                                          'quality_{}'.format(quality),
                                          'reconstruction_{}.jp2'.format(index))
    reference_uint8 = tls.read_image_mode(path_to_reference,
                                          'L')
    
    # `Glymur` is needed to read JPEG2000 images.
    file = glymur.Jp2k(path_to_reconstruction)
    reconstruction_uint8 = file[:]
    psnr = tls.psnr_2d(reference_uint8, reconstruction_uint8)
    nb_bytes = os.stat(path_to_reconstruction).st_size
    rate = float(8*nb_bytes)/numpy.prod(reference_uint8.shape)
    
    # In Python 2.x, the loop control variable of
    # list comprehensions leak into the surrounding
    # scope. It is no longer the case in Python 3.x.
    paths = [os.path.join(path_to_after_jpeg2000, 'quality_{}'.format(quality), 'reconstruction_{}.png'.format(index))]
    paths += [os.path.join(path_to_after_jpeg2000, 'quality_{}'.format(quality), 'reconstruction_{0}_crop_{1}.png'.format(index, index_crop)) for index_crop in range(positions_top_left.shape[1])]
    tls.visualize_rotated_luminance(reconstruction_uint8,
                                    index in list_rotation,
                                    positions_top_left,
                                    paths)
    return (rate, psnr)
Beispiel #13
0
def create_kodak(source_url, path_to_folder_rgbs, path_to_kodak,
                 path_to_list_rotation):
    """Creates the Kodak test set.
    
    The 24 Kodak RGB images are downloaded and
    converted into luminance images. Then, the
    sideways luminance images are rotated. Finally,
    the Kodak test set is filled with the luminance
    images and it is saved.
    
    Parameters
    ----------
    source_url : str
        URL of the folder that contains the
        24 Kodak RGB images.
    path_to_folder_rgbs : str
        Path to the folder in which the downloaded
        24 Kodak RGB images are saved.
    path_to_kodak : str
        Path to the file in which the Kodak test
        set is saved. The path ends with ".npy".
    path_to_list_rotation : str
        Path to the file in which the list
        storing the indices of the rotated
        luminance images is saved. The path
        ends with ".pkl".
    
    Raises
    ------
    ValueError
        If a RGB image is neither
        512x768x3 nor 768x512x3.
    
    """
    if os.path.isfile(path_to_kodak) and os.path.isfile(path_to_list_rotation):
        print('"{0}" and "{1}" already exist.'.format(path_to_kodak,
                                                      path_to_list_rotation))
        print('Delete them manually to recreate the Kodak test set.')
    else:
        download_option(source_url, path_to_folder_rgbs)

        # The height and width of the luminance images we
        # feed into the autoencoders has to be divisible by 16.
        height_kodak = 512
        width_kodak = 768
        reference_uint8 = numpy.zeros((24, height_kodak, width_kodak),
                                      dtype=numpy.uint8)
        list_rotation = []
        for i in range(24):
            path_to_file = os.path.join(
                path_to_folder_rgbs,
                'kodim' + str(i + 1).rjust(2, '0') + '.png')

            # `tls.read_image_mode` is not put into a `try`
            # `except` clause as each Kodak RGB image has
            # to be read.
            rgb_uint8 = tls.read_image_mode(path_to_file, 'RGB')

            # `tls.rgb_to_ycbcr` checks that the data-type of
            # its input array is equal to `numpy.uint8`. `tls.rgb_to_ycbcr`
            # also checks that its input array has 3 dimensions
            # and its 3rd dimension is equal to 3.
            luminance_uint8 = tls.rgb_to_ycbcr(rgb_uint8)[:, :, 0]
            (height_image, width_image) = luminance_uint8.shape
            if height_image == height_kodak and width_image == width_kodak:
                reference_uint8[i, :, :] = luminance_uint8
            elif width_image == height_kodak and height_image == width_kodak:
                reference_uint8[i, :, :] = numpy.rot90(luminance_uint8)
                list_rotation.append(i)
            else:
                raise ValueError(
                    '"{0}" is neither {1}x{2}x3 nor {2}x{1}x3.'.format(
                        path_to_file, height_kodak, width_kodak))

        numpy.save(path_to_kodak, reference_uint8)
        with open(path_to_list_rotation, 'wb') as file:
            pickle.dump(list_rotation, file, protocol=2)
def create_extra(source_url_inria_holidays_0,
                 source_url_inria_holidays_1,
                 path_to_folder_rgbs_ilsvrc2012,
                 path_to_folder_rgbs_inria_holidays,
                 width_crop,
                 nb_extra,
                 path_to_extra,
                 path_to_tar_ilsvrc2012='',
                 path_to_tar_inria_holidays_0='',
                 path_to_tar_inria_holidays_1=''):
    """Creates the extra set.
    
    Parameters
    ----------
    source_url_inria_holidays_0 : str
        URL of the first part of the original INRIA Holidays dataset.
    source_url_inria_holidays_1 : str
        URL of the second part of the original INRIA Holidays dataset.
    path_to_folder_rgbs_ilsvrc2012 : str
        Path to the folder storing ImageNet RGB images.
    path_to_folder_rgbs_inria_holidays : str
        Path to the folder to which the original INRIA Holidays
        dataset (RGB images from the two files ".tar") is extracted.
    width_crop : int
        Width of the crop.
    nb_extra : int
        Number of luminance crops in the extra set.
    path_to_extra : str
        Path to the file in which the extra set
        is saved. The path ends with ".npy".
    path_to_tar_ilsvrc2012 : str, optional
        Path to an archive containing ImageNet RGB images.
        The default value is ''. If the path is not the
        default path, the archive is extracted to `path_to_folder_rgbs_ilsvrc2012`
        before the function starts creating the extra set.
    path_to_tar_inria_holidays_0 : str, optional
        Path to the downloaded archive containing the first part
        of the original INRIA Holidays dataset. The default value
        is ''. If the path is not the default path, the archive is
        extracted to `path_to_folder_rgbs_inria_holidays` before the
        function starts creating the extra set.
    path_to_tar_inria_holidays_1 : str, optional
        Path to the downloaded archive containing the second part
        of the original INRIA Holidays dataset. The default value
        is ''. If the path is not the default path, the archive is
        extracted to `path_to_folder_rgbs_inria_holidays` before the
        function starts creating the extra set.
    
    Raises
    ------
    RuntimeError
        If there are not enough RGB images
        to create the extra set.
    
    """
    if os.path.isfile(path_to_extra):
        print('"{}" already exists.'.format(path_to_extra))
        print('Delete it manually to recreate the extra set.')
    else:
        if path_to_tar_ilsvrc2012:
            tls.untar_archive(path_to_folder_rgbs_ilsvrc2012,
                              path_to_tar_ilsvrc2012)
        if path_to_tar_inria_holidays_0:
            is_downloaded_0 = tls.download_untar_archive(
                source_url_inria_holidays_0,
                path_to_folder_rgbs_inria_holidays,
                path_to_tar_inria_holidays_0)
            if is_downloaded_0:
                print('Successfully downloaded "{}".'.format(
                    path_to_tar_inria_holidays_0))
            else:
                print('"{}" already exists.'.format(
                    path_to_tar_inria_holidays_0))
                print('Delete it manually to re-download it.')
        if path_to_tar_inria_holidays_1:
            is_downloaded_1 = tls.download_untar_archive(
                source_url_inria_holidays_1,
                path_to_folder_rgbs_inria_holidays,
                path_to_tar_inria_holidays_1)
            if is_downloaded_1:
                print('Successfully downloaded "{}".'.format(
                    path_to_tar_inria_holidays_1))
            else:
                print('"{}" already exists.'.format(
                    path_to_tar_inria_holidays_1))
                print('Delete it manually to re-download it.')

        # `width_crop` has to be divisible by 16.
        luminances_uint8 = numpy.zeros((nb_extra, width_crop, width_crop, 1),
                                       dtype=numpy.uint8)
        paths_to_rgbs = group_shuffle_paths_to_rgbs(
            path_to_folder_rgbs_ilsvrc2012, path_to_folder_rgbs_inria_holidays)
        i = 0
        for path_to_rgb in paths_to_rgbs:
            try:
                rgb_uint8 = tls.read_image_mode(path_to_rgb, 'RGB')
                crop_uint8 = tls.crop_option_2d(
                    tls.rgb_to_ycbcr(rgb_uint8)[:, :, 0], width_crop, False)
            except (TypeError, ValueError) as err:
                print(err)
                print('"{}" is skipped.\n'.format(path_to_rgb))
                continue
            luminances_uint8[i, :, :, 0] = crop_uint8
            i += 1
            if i == nb_extra:
                break

    # If the previous loop was not broken,
    # `luminances_uint8` is not full. In
    # this case, the program crashes as the
    # extra set should not contain any "zero"
    # luminance crop.
    if i != nb_extra:
        raise RuntimeError(
            'There are not enough RGB images at "{0}" and "{1}" to create the extra set.'
            .format(paths_to_folders_rgbs[0],
                    path_to_folder_inria_holidays_jpg))
    numpy.save(path_to_extra, luminances_uint8)