From 9e1e49c9046109f81bbe3095f348c1ffc4903ed4 Mon Sep 17 00:00:00 2001 From: Olegs NIKISINS <onikisins@italix03.idiap.ch> Date: Fri, 29 Sep 2017 10:48:59 +0200 Subject: [PATCH] Moved histogram extraction to preprocessor VideoSparseCoding --- .../preprocessor/video_sparse_coding.py | 85 ++++++++++++++- .../face/preprocessor/VideoSparseCoding.py | 100 +++++++++++++++++- setup.py | 4 + 3 files changed, 185 insertions(+), 4 deletions(-) diff --git a/bob/pad/face/config/preprocessor/video_sparse_coding.py b/bob/pad/face/config/preprocessor/video_sparse_coding.py index 5de78ecf..905dd7b0 100644 --- a/bob/pad/face/config/preprocessor/video_sparse_coding.py +++ b/bob/pad/face/config/preprocessor/video_sparse_coding.py @@ -20,4 +20,87 @@ preprocessor = VideoSparseCoding(gblock_size = BLOCK_SIZE, min_face_size = MIN_FACE_SIZE, norm_face_size = NORM_FACE_SIZE, dictionary_file_names = DICTIONARY_FILE_NAMES, - frame_step = FRAME_STEP) \ No newline at end of file + frame_step = FRAME_STEP) + + +#======================================================================================= + + +BLOCK_SIZE = 5 +BLOCK_LENGTH = 10 +MIN_FACE_SIZE = 50 +NORM_FACE_SIZE = 64 +DICTIONARY_FILE_NAMES = ["/idiap/user/onikisins/Projects/ODIN/Python/scripts/test_scripts/data/dictionary_front_10_5_16.hdf5", + "/idiap/user/onikisins/Projects/ODIN/Python/scripts/test_scripts/data/dictionary_hor_10_5_16.hdf5", + "/idiap/user/onikisins/Projects/ODIN/Python/scripts/test_scripts/data/dictionary_vert_10_5_16.hdf5"] +FRAME_STEP = 2 +EXTRACT_HISTOGRAMS_FLAG = True + +preprocessor_10_5_16 = VideoSparseCoding(gblock_size = BLOCK_SIZE, + block_length = BLOCK_LENGTH, + min_face_size = MIN_FACE_SIZE, + norm_face_size = NORM_FACE_SIZE, + dictionary_file_names = DICTIONARY_FILE_NAMES, + frame_step = FRAME_STEP, + extract_histograms_flag = EXTRACT_HISTOGRAMS_FLAG) + +BLOCK_SIZE = 5 +BLOCK_LENGTH = 10 +MIN_FACE_SIZE = 50 +NORM_FACE_SIZE = 64 +DICTIONARY_FILE_NAMES = ["/idiap/user/onikisins/Projects/ODIN/Python/scripts/test_scripts/data/dictionary_front_10_5_32.hdf5", + "/idiap/user/onikisins/Projects/ODIN/Python/scripts/test_scripts/data/dictionary_hor_10_5_32.hdf5", + "/idiap/user/onikisins/Projects/ODIN/Python/scripts/test_scripts/data/dictionary_vert_10_5_32.hdf5"] +FRAME_STEP = 2 +EXTRACT_HISTOGRAMS_FLAG = True + +preprocessor_10_5_32 = VideoSparseCoding(gblock_size = BLOCK_SIZE, + block_length = BLOCK_LENGTH, + min_face_size = MIN_FACE_SIZE, + norm_face_size = NORM_FACE_SIZE, + dictionary_file_names = DICTIONARY_FILE_NAMES, + frame_step = FRAME_STEP, + extract_histograms_flag = EXTRACT_HISTOGRAMS_FLAG) + +BLOCK_SIZE = 5 +BLOCK_LENGTH = 10 +MIN_FACE_SIZE = 50 +NORM_FACE_SIZE = 64 +DICTIONARY_FILE_NAMES = ["/idiap/user/onikisins/Projects/ODIN/Python/scripts/test_scripts/data/dictionary_front_10_5_64.hdf5", + "/idiap/user/onikisins/Projects/ODIN/Python/scripts/test_scripts/data/dictionary_hor_10_5_64.hdf5", + "/idiap/user/onikisins/Projects/ODIN/Python/scripts/test_scripts/data/dictionary_vert_10_5_64.hdf5"] +FRAME_STEP = 2 +EXTRACT_HISTOGRAMS_FLAG = True + +preprocessor_10_5_64 = VideoSparseCoding(gblock_size = BLOCK_SIZE, + block_length = BLOCK_LENGTH, + min_face_size = MIN_FACE_SIZE, + norm_face_size = NORM_FACE_SIZE, + dictionary_file_names = DICTIONARY_FILE_NAMES, + frame_step = FRAME_STEP, + extract_histograms_flag = EXTRACT_HISTOGRAMS_FLAG) + + +BLOCK_SIZE = 5 +BLOCK_LENGTH = 10 +MIN_FACE_SIZE = 50 +NORM_FACE_SIZE = 64 +DICTIONARY_FILE_NAMES = ["/idiap/user/onikisins/Projects/ODIN/Python/scripts/test_scripts/data/dictionary_front_10_5_128.hdf5", + "/idiap/user/onikisins/Projects/ODIN/Python/scripts/test_scripts/data/dictionary_hor_10_5_128.hdf5", + "/idiap/user/onikisins/Projects/ODIN/Python/scripts/test_scripts/data/dictionary_vert_10_5_128.hdf5"] +FRAME_STEP = 2 +EXTRACT_HISTOGRAMS_FLAG = True + +preprocessor_10_5_128 = VideoSparseCoding(gblock_size = BLOCK_SIZE, + block_length = BLOCK_LENGTH, + min_face_size = MIN_FACE_SIZE, + norm_face_size = NORM_FACE_SIZE, + dictionary_file_names = DICTIONARY_FILE_NAMES, + frame_step = FRAME_STEP, + extract_histograms_flag = EXTRACT_HISTOGRAMS_FLAG) + + + + + + diff --git a/bob/pad/face/preprocessor/VideoSparseCoding.py b/bob/pad/face/preprocessor/VideoSparseCoding.py index 4168882b..63cade37 100644 --- a/bob/pad/face/preprocessor/VideoSparseCoding.py +++ b/bob/pad/face/preprocessor/VideoSparseCoding.py @@ -51,7 +51,7 @@ class VideoSparseCoding(Preprocessor, object): The size of the face after normalization. Default: 64 . ``dictionary_file_names`` : [:py:class:`str`] - A list of filenames containing the dictionary. The filenames must be + A list of filenames containing the dictionaries. The filenames must be listed in the following order: [file_name_pointing_to_frontal_dictionary, file_name_pointing_to_horizontal_dictionary, @@ -61,6 +61,22 @@ class VideoSparseCoding(Preprocessor, object): Selected frames for processing with this step. If set to 1, all frames will be processes. Used to speed up the experiments. Default: 1. + + ``extract_histograms_flag`` : :py:class:`bool` + If this flag is set to ``True`` the histograms of sparse codes will be + computed for all stacks of facial images / samples. In this case an + empty feature extractor must be used, because feature vectors (histograms) + are already extracted in the preprocessing step. + + NOTE: set this flag to``True`` if you want to reduce the amount of + memory required to store temporary files. + Default: ``False``. + + ``method`` : :py:class:`str` + A method to use in the histogram computation. Two options are available: + "mean" and "hist". This argument is valid only if ``extract_histograms_flag`` + is set to ``True``. + Default: "hist". """ #========================================================================== @@ -71,6 +87,8 @@ class VideoSparseCoding(Preprocessor, object): norm_face_size = 64, dictionary_file_names = [], frame_step = 1, + extract_histograms_flag = False, + method = "hist", **kwargs): super(VideoSparseCoding, self).__init__(block_size = block_size, @@ -78,7 +96,9 @@ class VideoSparseCoding(Preprocessor, object): min_face_size = min_face_size, norm_face_size = norm_face_size, dictionary_file_names = dictionary_file_names, - frame_step = frame_step) + frame_step = frame_step, + extract_histograms_flag = extract_histograms_flag, + method = method) self.block_size = block_size self.block_length = block_length @@ -86,6 +106,8 @@ class VideoSparseCoding(Preprocessor, object): self.norm_face_size = norm_face_size self.dictionary_file_names = dictionary_file_names self.frame_step = frame_step + self.extract_histograms_flag = extract_histograms_flag + self.method = method self.video_preprocessor = bob.bio.video.preprocessor.Wrapper() @@ -692,6 +714,62 @@ class VideoSparseCoding(Preprocessor, object): return frame_container + #========================================================================== + def comp_hist_of_sparse_codes(self, frames, method): + """ + Compute the histograms of sparse codes. + """ + + histograms = [] + + for frame_data in frames: + + frame = frame_data[1] + + if method == "mean": + + frame_codes = np.mean(frame, axis=1) + + if method == "hist": + + frame_codes = np.mean(frame!=0, axis=1) + + for idx, row in enumerate(frame_codes): + + frame_codes[idx,:] = row/np.sum(row) + + hist = frame_codes.flatten() + + histograms.append(hist) + + return histograms + + + #========================================================================== + def convert_arrays_to_frame_container(self, list_of_arrays): + """ + Convert an input list of arrays into Frame Container. + + **Parameters:** + + ``list_of_arrays`` : [:py:class:`numpy.ndarray`] + A list of arrays. + + **Returns:** + + ``frame_container`` : FrameContainer + FrameContainer containing the feature vectors. + """ + + frame_container = bob.bio.video.FrameContainer() # initialize the FrameContainer + + for idx, item in enumerate(list_of_arrays): + + frame_container.add(idx, item) # add frame to FrameContainer + + return frame_container + + #========================================================================== def __call__(self, frames, annotations): """ @@ -702,6 +780,10 @@ class VideoSparseCoding(Preprocessor, object): However, this number can be smaller, and is controlled by two arguments of this class: ``min_face_size`` and ``frame_step``. + If ``self.extract_histograms_flag`` flag is set to ``True`` the + histograms of sparse codes will be computed for all possible stacks of + facial images. + **Parameters:** ``frames`` : FrameContainer @@ -720,12 +802,18 @@ class VideoSparseCoding(Preprocessor, object): **Returns:** ``frame_container`` : FrameContainer + If ``self.extract_histograms_flag`` flag is set to ``False`: FrameContainer containing the frames with sparse codes for the frontal, horizontal and vertical patches. Each frame is a 3D array. - The dimensionality of array is: + The dimensionality of each array is: (``3`` x ``n_samples`` x ``n_words_in_the_dictionary``). The first slice in the 3D arrays corresponds to frontal sparse codes, second slice to horizontal, and third to vertical codes. + + If ``self.extract_histograms_flag`` flag is set to ``True`` the + histograms of sparse codes will be computed. In this case each + frame is a 1D array with dimensionality: + (3*``n_words_in_the_dictionary``, ) """ # Convert frame container to 3D array: @@ -749,6 +837,12 @@ class VideoSparseCoding(Preprocessor, object): frame_container = self.convert_sparse_codes_to_frame_container([frontal_video_codes, horizontal_video_codes, vertical_video_codes]) + if self.extract_histograms_flag: # in this case histograms will be extracted in the preprocessor , no feature extraction is needed then + + histograms = self.comp_hist_of_sparse_codes(frame_container, self.method) + + frame_container = self.convert_arrays_to_frame_container(histograms) + return frame_container diff --git a/setup.py b/setup.py index 552001a1..474dcb05 100644 --- a/setup.py +++ b/setup.py @@ -106,6 +106,10 @@ setup( # The sparse coding based preprocessors 'sparse-coding-preprocessor = bob.pad.face.config.preprocessor.video_sparse_coding:preprocessor', + 'sparse-coding-preprocessor-10-5-16 = bob.pad.face.config.preprocessor.video_sparse_coding:preprocessor_10_5_16', + 'sparse-coding-preprocessor-10-5-32 = bob.pad.face.config.preprocessor.video_sparse_coding:preprocessor_10_5_32', + 'sparse-coding-preprocessor-10-5-64 = bob.pad.face.config.preprocessor.video_sparse_coding:preprocessor_10_5_64', + 'sparse-coding-preprocessor-10-5-128 = bob.pad.face.config.preprocessor.video_sparse_coding:preprocessor_10_5_128', ], # registered extractors: -- GitLab