Browse Source

Update of dataset generation

Jérôme BUISINE 3 years ago
parent
commit
3fcd2818bf

+ 3 - 0
.gitmodules

@@ -0,0 +1,3 @@
+[submodule "modules"]
+	path = modules
+	url = https://github.com/prise-3d/Thesis-DeepLearning-modules.git

+ 45 - 1
README.md

@@ -14,11 +14,55 @@ or other information...
 Output :
 - Reference image
 
+## Requirements
+
+```bash
+git clone --recursive https://github.com/prise-3d/Thesis-Denoising-autoencoder.git XXXXX
+```
+
+```bash
+pip install -r requirements.txt
+```
+
 ## How to use ?
 
 [Autoencoder keras documentation](https://blog.keras.io/building-autoencoders-in-keras.html)
 
-Detailed later...
+Generate reconstructed data from specific method of reconstruction (run only once time or clean data folder before):
+```
+python generate_reconstructed_data.py -h
+```
+
+Generate custom dataset from one reconstructed method or multiples (implemented later)
+```
+python generate_dataset.py -h
+```
+
+### Reconstruction parameter (--params)
+
+List of expected parameter by reconstruction method:
+- **svd_reconstruction:** Singular Values Decomposition
+  - Param definition: *interval data used for reconstruction (begin, end)*
+  - Example: *"100, 200"*
+- **ipca_reconstruction:** Iterative Principal Component Analysis
+  - Param definition: *number of components used for compression and batch size*
+  - Example: *"30, 35"*
+- **fast_ica_reconstruction:**  Fast Iterative Component Analysis
+  - Param definition: *number of components used for compression*
+  - Example: *"50"*
+- **static** Use static file to manage (such as z-buffer, normals card...)
+  - Param definition: *Name of image of scene need to be in {sceneName}/static/xxxx.png*
+  - Example: *"img.png"*
+
+**__Example:__**
+```bash
+python generate_dataset.py --output data/output_data_filename --metrics "svd_reconstruction, ipca_reconstruction, fast_ica_reconstruction" --renderer "maxwell" --scenes "A, D, G, H" --params "100, 200 :: 50, 10 :: 50" --nb_zones 10 --random 1 --only_noisy 1
+```
+
+Then, run the model:
+```bash
+python image_denoising --data data/my_dataset --output output_model_name
+```
 
 ## License
 

+ 71 - 15
generate_dataset.py

@@ -13,13 +13,12 @@ import time
 import json
 
 from PIL import Image
-from ipfml import processing, metrics, utils
+from ipfml.processing.segmentation import divide_in_blocks
 from skimage import color
 
 from modules.utils import config as cfg
 from modules.utils import data as dt
 
-from transformation_functions import svd_reconstruction
 from modules.classes.Transformation import Transformation
 
 # getting configuration information
@@ -95,7 +94,7 @@ def generate_data_model(_scenes_list, _filename, _transformations, _scenes, _nb_
             for i in learned_zones_indices:
                 f.write(str(i) + ';')
 
-        ref_image_blocks = processing.divide_in_blocks(Image.open(ref_image_path), cfg.keras_img_size)
+        ref_image_blocks = divide_in_blocks(Image.open(ref_image_path), cfg.keras_img_size)
 
         for id_zone, index_folder in enumerate(zones_indices):
 
@@ -107,21 +106,56 @@ def generate_data_model(_scenes_list, _filename, _transformations, _scenes, _nb_
             zone_path = os.path.join(scene_path, current_zone_folder)
 
             # path of zone of reference image
-            ref_image_block_path = os.path.join(zone_path, last_image_name)
+            # ref_image_block_path = os.path.join(zone_path, last_image_name)
 
-            if not os.path.exists(ref_image_block_path):
-                ref_image_blocks[id_zone].save(ref_image_block_path)
+            # compute augmented images for ref image
+            current_ref_zone_image = ref_image_blocks[id_zone]
+
+            ref_image_name_prefix = last_image_name.replace('.png', '')
+            dt.augmented_data_image(current_ref_zone_image, zone_path, ref_image_name_prefix)
+
+            # get list of all augmented ref images
+            ref_augmented_images = [os.path.join(zone_path, f) for f in os.listdir(zone_path) if ref_image_name_prefix in f]
 
             # custom path for interval of reconstruction and metric
             metrics_path = []
 
             for transformation in _transformations:
-                metric_interval_path = os.path.join(zone_path, transformation.getTransformationPath())
-                metrics_path.append(metric_interval_path)
+                
+                # check if it's a static content and create augmented images if necessary
+                if transformation.getName() == 'static':
+                    
+                    # {sceneName}/zoneXX/static
+                    static_metric_path = os.path.join(zone_path, transformation.getName())
+
+                    # img.png
+                    image_name = transformation.getParam().split('/')[-1]
+
+                    # {sceneName}/zoneXX/static/img
+                    image_prefix_name = image_name.replace('.png', '')
+                    image_folder_path = os.path.join(static_metric_path, image_prefix_name)
+                    
+                    if not os.path.exists(image_folder_path):
+                        os.makedirs(image_folder_path)
+
+                    metrics_path.append(image_folder_path)
+
+                    # get image path to manage
+                    # {sceneName}/static/img.png
+                    transform_image_path = os.path.join(scene_path, transformation.getName(), image_name) 
+                    static_transform_image = Image.open(transform_image_path)
+
+                    static_transform_image_block = divide_in_blocks(static_transform_image, cfg.keras_img_size)[id_zone]
+
+                    # generate augmented data
+                    dt.augmented_data_image(static_transform_image_block, image_folder_path, image_prefix_name)
+
+                else:
+                    metric_interval_path = os.path.join(zone_path, transformation.getTransformationPath())
+                    metrics_path.append(metric_interval_path)
 
             # as labels are same for each metric
             for label in os.listdir(metrics_path[0]):
-                
 
                 if (label == cfg.not_noisy_folder and _only_noisy == 0) or label == cfg.noisy_folder:
                     
@@ -134,22 +168,44 @@ def generate_data_model(_scenes_list, _filename, _transformations, _scenes, _nb_
                     # getting images list for each metric
                     metrics_images_list = []
                         
-                    for label_path in label_metrics_path:
-                        images = sorted(os.listdir(label_path))
-                        metrics_images_list.append(images)
+                    for index_metric, label_path in enumerate(label_metrics_path):
+
+                        if _transformations[index_metric].getName() == 'static':
+                            # by default append nothing..
+                            metrics_images_list.append([])
+                        else:
+                            images = sorted(os.listdir(label_path))
+                            metrics_images_list.append(images)
 
                     # construct each line using all images path of each
                     for index_image in range(0, len(metrics_images_list[0])):
                         
                         images_path = []
 
+                        # get information about rotation and flip from first transformation (need to be a not static transformation)
+                        current_post_fix =  metrics_images_list[0][index_image].split(cfg.post_image_name_separator)[-1]
 
                         # getting images with same index and hence name for each metric (transformation)
                         for index_metric in range(0, len(metrics_path)):
-                            img_path = metrics_images_list[index_metric][index_image]
-                            images_path.append(os.path.join(label_metrics_path[index_metric], img_path))
 
-                        line = ref_image_block_path + ';'
+                            # custom behavior for static transformation (need to check specific image)
+                            if _transformations[index_metric].getName() == 'static':
+                                # add static path with selecting correct data augmented image
+                                image_name = _transformations[index_metric].getParam().split('/')[-1].replace('.png', '')
+                                img_path = os.path.join(metrics_path[index_metric], image_name + cfg.post_image_name_separator + current_post_fix)
+                                images_path.append(img_path)
+                            else:
+                                img_path = metrics_images_list[index_metric][index_image]
+                                images_path.append(os.path.join(label_metrics_path[index_metric], img_path))
+
+                        # get information about rotation and flip
+                        current_post_fix = images_path[0].split(cfg.post_image_name_separator)[-1]
+
+                        # get ref block which matchs we same information about rotation and flip
+                        augmented_ref_image_block_path = next(img for img in ref_augmented_images 
+                                                              if img.split(cfg.post_image_name_separator)[-1] == current_post_fix)
+
+                        line = augmented_ref_image_block_path + ';'
 
                         # compute line information with all images paths
                         for id_path, img_path in enumerate(images_path):

+ 2 - 2
generate_reconstructed_data.py

@@ -158,8 +158,8 @@ def generate_data(transformation):
                     for rotation in rotations:
                         rotated_output_img = flip.rotate(rotation)
 
-                        output_reconstructed_filename = img_path.split('/')[-1].replace('.png', '') + '_' + zones_folder[id_block]
-                        output_reconstructed_filename = output_reconstructed_filename + '_' + img_flip_labels[id] + '_' + str(rotation) + '.png'
+                        output_reconstructed_filename = img_path.split('/')[-1].replace('.png', '') + '_' + zones_folder[id_block] + cfg.post_image_name_separator
+                        output_reconstructed_filename = output_reconstructed_filename + img_flip_labels[id] + '_' + str(rotation) + '.png'
                         output_reconstructed_path = os.path.join(label_path, output_reconstructed_filename)
 
                         rotated_output_img.save(output_reconstructed_path)

+ 33 - 17
image_denoising.py

@@ -3,35 +3,41 @@ from keras.models import Model
 from keras import backend as K
 from keras.callbacks import TensorBoard
 
+import os
+import json
 import pandas as pd
 import numpy as np
+import argparse
+
 from sklearn.utils import shuffle
+import cv2
 
 from modules.utils import config as cfg
-import cv2
 
-import argparse
+def generate_model(input_shape):
 
-def generate_model(input_shape=(3, 200, 200)):
-    print(input_shape)
     input_img = Input(shape=input_shape)  # adapt this if using `channels_first` image data format
 
     x = Conv3D(32, (1, 3, 3), activation='relu', padding='same')(input_img)
     x = MaxPooling3D((1, 2, 2), padding='same')(x)
     x = Conv3D(32, (1, 3, 3), activation='relu', padding='same')(x)
+    x = MaxPooling3D((1, 2, 2), padding='same')(x)
+    x = Conv3D(32, (1, 3, 3), activation='relu', padding='same')(x)
     encoded = MaxPooling3D((1, 2, 2), padding='same')(x)
 
+    print(encoded)
 
     x = Conv3D(32, (1, 3, 3), activation='relu', padding='same')(encoded)
     x = UpSampling3D((1, 2, 2))(x)
     x = Conv3D(32, (1, 3, 3), activation='relu', padding='same')(x)
     x = UpSampling3D((1, 2, 2))(x)
-    decoded = Conv3D(1, (1, 3, 3), activation='sigmoid', padding='same')(x)
+    x = Conv3D(32, (1, 3, 3), activation='relu', padding='same')(x)
+    x = UpSampling3D((1, 2, 2))(x)
+    decoded = Conv3D(3, (1, 3, 3), activation='sigmoid', padding='same')(x)
 
     autoencoder = Model(input_img, decoded)
 
-    # TODO : check if 
-    autoencoder.compile(optimizer='adadelta', loss='binary_crossentropy')
+    autoencoder.compile(optimizer='adadelta', loss='mse')
 
     return autoencoder
 
@@ -102,16 +108,12 @@ def main():
     y_dataset_train = dataset_train[0].apply(lambda x: cv2.imread(x).reshape(input_shape))
     y_dataset_test = dataset_test[0].apply(lambda x: cv2.imread(x).reshape(input_shape))
 
-    # format correct data
-    x_data_train = np.array([item for item in x_dataset_train.values])
-    #x_data_train = np.array(x_dataset_train.values)
-    x_data_test = np.array([item for item in x_dataset_test.values])
-    #x_data_test = np.array(x_dataset_test.values)
+    # format data correctly
+    x_data_train = np.array([item[0].reshape(input_shape) for item in x_dataset_train.values])
+    x_data_test = np.array([item[0].reshape(input_shape) for item in x_dataset_test.values])
 
-    y_data_train = np.array([item for item in y_dataset_train.values])
-    #y_data_train = np.array(y_dataset_train.values)
-    y_data_test = np.array([item for item in y_dataset_test.values])
-    #y_data_test = np.array(y_dataset_test.values)
+    y_data_train = np.array([item[0].reshape(input_shape) for item in y_dataset_train.values])
+    y_data_test = np.array([item[0].reshape(input_shape) for item in y_dataset_test.values])
 
     # load model
     autoencoder = generate_model(input_shape)
@@ -124,7 +126,21 @@ def main():
                     validation_data=(x_data_test, y_data_test),
                     callbacks=[TensorBoard(log_dir='/tmp/autoencoder', histogram_freq=0, write_graph=False)])
 
-    # save model
+    ##############
+    # save model #
+    ##############
+    if not os.path.exists(cfg.saved_models_folder):
+        os.makedirs(cfg.saved_models_folder)
+
+    # save the model into HDF5 file
+    model_output_path = os.path.join(cfg.saved_models_folder, p_output + '.json')
+    json_model_content = autoencoder.to_json()
+
+    with open(model_output_path, 'w') as f:
+        print("Model saved into ", model_output_path)
+        json.dump(json_model_content, f, indent=4)
+
+    autoencoder.save_weights(model_output_path.replace('.json', '.h5'))
     
 if __name__ == "__main__":
     main()

+ 1 - 0
modules

@@ -0,0 +1 @@
+Subproject commit 670ff4f4b984534d477ebee6616197427b4833f2

+ 0 - 0
modules/__init__.py


+ 0 - 53
modules/classes/Transformation.py

@@ -1,53 +0,0 @@
-import os
-
-from transformation_functions import svd_reconstruction, fast_ica_reconstruction, ipca_reconstruction
-
-# Transformation class to store transformation method of image and get usefull information
-class Transformation():
-
-    def __init__(self, _transformation, _param):
-        self.transformation = _transformation
-        self.param = _param
-
-    def getTransformedImage(self, img):
-
-        if self.transformation == 'svd_reconstruction':
-            begin, end = list(map(int, self.param.split(',')))
-            data = svd_reconstruction(img, [begin, end])
-
-        if self.transformation == 'ipca_reconstruction':
-            n_components, batch_size = list(map(int, self.param.split(',')))
-            data = ipca_reconstruction(img, n_components, batch_size)
-
-        if self.transformation == 'fast_ica_reconstruction':
-            n_components = self.param
-            data = fast_ica_reconstruction(img, n_components)
-
-        return data
-    
-    def getTransformationPath(self):
-
-        path = self.transformation
-
-        if self.transformation == 'svd_reconstruction':
-            begin, end = list(map(int, self.param.split(',')))
-            path = os.path.join(path, str(begin) + '_' + str(end))
-
-        if self.transformation == 'ipca_reconstruction':
-            n_components, batch_size = list(map(int, self.param.split(',')))
-            path = os.path.join(path, 'N' + str(n_components) + '_' + str(batch_size))
-
-        if self.transformation == 'fast_ica_reconstruction':
-            n_components = self.param
-            path = os.path.join(path, 'N' + str(n_components))
-
-        return path
-
-    def getName(self):
-        return self.transformation
-
-    def getParam(self):
-        return self.param
-
-    def __str__( self ):
-        return self.transformation + ' transformation with parameter : ' + self.param

+ 0 - 0
modules/classes/__init__.py


+ 0 - 0
modules/utils/__init__.py


+ 0 - 47
modules/utils/config.py

@@ -1,47 +0,0 @@
-import numpy as np
-
-zone_folder                     = "zone"
-output_data_folder              = 'data'
-dataset_path                    = 'dataset'
-threshold_map_folder            = 'threshold_map'
-models_information_folder       = 'models_info'
-saved_models_folder             = 'saved_models'
-min_max_custom_folder           = 'custom_norm'
-learned_zones_folder            = 'learned_zones'
-correlation_indices_folder      = 'corr_indices'
-
-csv_model_comparisons_filename  = "models_comparisons.csv"
-seuil_expe_filename             = 'seuilExpe'
-min_max_filename_extension      = "_min_max_values"
-config_filename                 = "config"
-
-noisy_folder                    = 'noisy'
-not_noisy_folder                = 'notNoisy'
-
-models_names_list               = ["svm_model","ensemble_model","ensemble_model_v2","deep_keras"]
-
-# define all scenes values
-renderer_choices                = ['all', 'maxwell', 'igloo', 'cycle']
-
-scenes_names                    = ['Appart1opt02', 'Bureau1', 'Cendrier', 'Cuisine01', 'EchecsBas', 'PNDVuePlongeante', 'SdbCentre', 'SdbDroite', 'Selles']
-scenes_indices                  = ['A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I']
-
-maxwell_scenes_names            = ['Appart1opt02', 'Cuisine01', 'SdbCentre', 'SdbDroite']
-maxwell_scenes_indices          = ['A', 'D', 'G', 'H']
-
-igloo_scenes_names              = ['Bureau1', 'PNDVuePlongeante']
-igloo_scenes_indices            = ['B', 'F']
-
-cycle_scenes_names              = ['EchecBas', 'Selles']
-cycle_scenes_indices            = ['E', 'I']
-
-normalization_choices           = ['svd', 'svdn', 'svdne']
-zones_indices                   = np.arange(16)
-
-metric_choices_labels           = ['all', 'svd_reconstruction', 'fast_ica_reconstruction', 'ipca_reconstruction']
-
-keras_epochs                    = 30
-keras_batch                     = 32
-val_dataset_size                = 0.2
-
-keras_img_size                  = (200, 200)

+ 0 - 44
modules/utils/data.py

@@ -1,44 +0,0 @@
-from ipfml import processing, metrics, utils
-from modules.utils.config import *
-from transformation_functions import svd_reconstruction
-
-from PIL import Image
-from skimage import color
-from sklearn.decomposition import FastICA
-from sklearn.decomposition import IncrementalPCA
-from sklearn.decomposition import TruncatedSVD
-from numpy.linalg import svd as lin_svd
-
-from scipy.signal import medfilt2d, wiener, cwt
-import pywt
-
-import numpy as np
-
-
-_scenes_names_prefix   = '_scenes_names'
-_scenes_indices_prefix = '_scenes_indices'
-
-# store all variables from current module context
-context_vars = vars()
-
-
-def get_renderer_scenes_indices(renderer_name):
-
-    if renderer_name not in renderer_choices:
-        raise ValueError("Unknown renderer name")
-
-    if renderer_name == 'all':
-        return scenes_indices
-    else:
-        return context_vars[renderer_name + _scenes_indices_prefix]
-
-def get_renderer_scenes_names(renderer_name):
-
-    if renderer_name not in renderer_choices:
-        raise ValueError("Unknown renderer name")
-
-    if renderer_name == 'all':
-        return scenes_names
-    else:
-        return context_vars[renderer_name + _scenes_names_prefix]
-

+ 8 - 0
requirements.txt

@@ -0,0 +1,8 @@
+Pillow
+keras
+tensorflow
+sklearn
+matplotlib
+path.py
+ipfml
+cv2