Source code for lightonml.encoding.utils

# -*- coding: utf8
"""This module contains all the functions that are used to implement the data formatting. Coordinates are (y, x).
"""
import warnings

import numpy as np

from .opu_formatting import to_opu_format_multiple


[docs]def compute_new_indices_greater_rectangle(indices, old_rectangle_shape, old_rectangle_position, new_rectangle_shape): """Computes new indices from an old rectangle to a new and larger one. It is useful in the case where the region of interest is smaller than the DMD area. Parameters ---------- indices: np.ndarray of uint64/uint32, indices in the old rectangle. old_rectangle_shape: tuple of 2 integer, shape of the old rectangle. old_rectangle_position: tuple of 2 integer, position of the origin of the old rectangle inside the new one (distance from top, distance from left margin) new_rectangle_shape: tuple of 2 integer, shape of the new rectangle. Returns ------- new_indices : np.ndarray of uint64/uint32, indices in the new rectangle. """ n_rows = indices // old_rectangle_shape[1] n_cols = indices % old_rectangle_shape[1] old_coordinates = np.vstack((n_rows, n_cols)) new_coordinates = np.array([[old_rectangle_position[0]], [old_rectangle_position[1]]]) + old_coordinates new_indices = new_coordinates[0] * new_rectangle_shape[1] + new_coordinates[1] return new_indices
[docs]def compute_indices_1d_macro_pixels(n_features, rectangle_shape, feature_shape='square'): """Computes indices of the macro pixels in a linear way. It means that it is using the whole width of the rectangle even if the quotient (rectangle_width / macro_pixel_width) is not an integer. Parameters ---------- n_features: int, number of features for. rectangle_shape: tuple of 2 integer, shape of the rectangle area. feature_shape: string, shape of the macropixels ('rectangle' or 'square') Returns ------- indices : np.ndarray of int64/int32, indices in the rectangle. factor: int, size of the macropixels. """ # compute the shape of a unit feature to maximize the used area max_size = 51 if feature_shape == 'rectangle': x = np.arange(max_size).reshape(-1, 1) y = np.arange(max_size).reshape(1, -1) area_feature = x * y condition = np.ceil(n_features / rectangle_shape[1] * x) * y <= rectangle_shape[0] area_feature = np.where(condition, area_feature, 0) # max of N-dimensional array rows_feature, cols_feature = np.unravel_index(np.argmax(area_feature), (max_size, max_size)) else: x = np.arange(max_size) condition = np.ceil(n_features / rectangle_shape[1] * x) * x <= rectangle_shape[0] rows_feature = np.argmax(x[condition]) cols_feature = rows_feature # computing indices of the upper pixel for each unit sub_indices = np.unravel_index(np.arange(n_features) * cols_feature, rectangle_shape) indices_starting_points = np.ravel_multi_index((sub_indices[0] * rows_feature, sub_indices[1]), rectangle_shape) # adding indices of the left pixel of each rows in the second dimension indices_plus_rows = indices_starting_points.reshape(-1, 1) + (np.arange(rows_feature).reshape(1, -1) * rectangle_shape[1]) # adding all the indices of each lines in the third dimension indices_plus_cols = np.expand_dims(indices_plus_rows, axis=2) + np.arange(cols_feature).reshape(1, 1, -1) # adjusting indices in case of line breaks search_line_breaks = indices_plus_cols[:, 0, :] % rectangle_shape[1] ind_row_min = np.argmin(search_line_breaks, axis=1) row_min = search_line_breaks[np.arange(n_features), ind_row_min] # looping over the line breaks and correcting the indices place for i_feat, (index, value) in enumerate(zip(ind_row_min, row_min)): if not ((value == 0) & (index != 0)): continue indices_plus_cols[i_feat, :, index:] += (rows_feature - 1) * rectangle_shape[1] # raveling and type casting for the C++ functions indices = indices_plus_cols.ravel().astype(np.int32) factor = int(rows_feature * cols_feature) return indices, factor
[docs]def compute_indices_2d_macro_pixels(n_features, rectangle_shape): """Computes indices of the macro pixels as a classical zoom in of the squared features. Parameters ---------- n_features: int, number of features for. rectangle_shape: tuple of 2 integer, shape of the rectangle area. Returns ------- indices : np.ndarray of int64/int32, indices in the rectangle. factor: int, size of the macropixels. """ small_dim = np.min(rectangle_shape) n_square = np.ceil(np.sqrt(n_features)) if n_square > small_dim: raise ValueError('Impossible to use 2d_macro_pixels formatting when sqrt(n_features) > {}. '.format(small_dim) + 'Change formatting function.') n_pixels_per_feature_per_dim = int(np.floor(small_dim / n_square)) coordinates_1d = np.arange(n_square) * n_pixels_per_feature_per_dim coordinate_grid = np.meshgrid(coordinates_1d, coordinates_1d) sub_indices = np.vstack((coordinate_grid[1].ravel(), coordinate_grid[0].ravel())) indices_starting_points = sub_indices[0] * rectangle_shape[1] + sub_indices[1] indices_starting_points = indices_starting_points[:n_features] indices_plus_rows = indices_starting_points.reshape(-1, 1) + (np.arange(n_pixels_per_feature_per_dim).reshape(1, -1) * rectangle_shape[1]) indices_plus_cols = indices_plus_rows.reshape(indices_plus_rows.size, 1) + np.arange(n_pixels_per_feature_per_dim).reshape(1, -1) indices = indices_plus_cols.ravel().astype(np.int32) factor = int(n_pixels_per_feature_per_dim ** 2) return indices, factor
[docs]def compute_indices_centered(n_features, rectangle_shape): """Computes indices in order to have the feature values in a square centered in the area. Parameters ---------- n_features: int, number of features for. rectangle_shape: tuple of 2 integer, shape of the rectangle area. Returns ------- indices : np.ndarray of int64/int32, indices in the rectangle. factor: int, size of the macropixels. """ n_square = int(np.ceil(np.sqrt(n_features))) indices = np.reshape(np.arange(n_square), (1, n_square)) indices = np.reshape(np.arange(n_square) * rectangle_shape[1], (n_square, 1)) + indices left_corner_row = int((rectangle_shape[0] - n_square) / 2) left_corner_col = int((rectangle_shape[1] - n_square) / 2) indices += left_corner_col + left_corner_row * rectangle_shape[1] indices = indices.ravel().astype(np.int32) factor = 1 return indices, factor
[docs]def compute_indices_lined(n_features, rectangle_shape): """Computes indices in order to have the feature values positioned in line. Parameters ---------- n_features: int, number of features for. rectangle_shape: tuple of 2 integer, shape of the rectangle area. Returns ------- indices : np.ndarray of int64/int32, indices in the rectangle. factor: int, size of the macropixels. """ rectangle_size = rectangle_shape[0] * rectangle_shape[1] factor = int(np.floor(rectangle_size / n_features)) indices = np.arange(n_features * factor, dtype=np.int32) return indices, factor
[docs]def get_formatting_function(n_features, position='2d_macro_pixels', roi_shape=(1140, 912), roi_position=(0, 0), dmd_shape=(1140, 912)): """Returns a formatting function that takes feature vectors and returns the dmd formatted vectors . Parameters ---------- n_features: int, number of features for. position: str, type of formatting. roi_shape: tuple of ints, shape of the ROI on the DMD. roi_position: tuple of ints, position of the ROI on the DMD. dmd_shape: tuple of ints, shape of the DMD. Returns ------- formatting_func: callable, callable to perform the formatting of the input arrays. factor: int, size of the macropixels. """ dmd_size = np.prod(dmd_shape) if n_features == dmd_size: # if the input is already of the same shape of the DMD, do nothing formatting_func = lambda x: x factor = 1 message = 'Samples already of DMD shape {}. Returning identity function for formatting'.format(dmd_shape) warnings.warn(message) else: if position == '1d_square_macro_pixels': indices_roi, factor = compute_indices_1d_macro_pixels(n_features, roi_shape) elif position == '1d_rectangle_macro_pixels': indices_roi, factor = compute_indices_1d_macro_pixels(n_features, roi_shape, feature_shape='rectangle') elif position == '2d_macro_pixels': indices_roi, factor = compute_indices_2d_macro_pixels(n_features, roi_shape) elif position == 'lined': indices_roi, factor = compute_indices_lined(n_features, roi_shape) elif position == 'centered': indices_roi, factor = compute_indices_centered(n_features, roi_shape) else: raise Exception("Unknown formatting style. You have five options :" + "['1d_rectangle_macro_pixels', '1d_square_macro_pixels'," + "'2d_macro_pixels', 'lined', 'centered']") indices_dmd = compute_new_indices_greater_rectangle(indices_roi, roi_shape, roi_position, dmd_shape) formatting_func = lambda x: to_opu_format_multiple(indices_dmd, x, dmd_size, factor) return formatting_func, factor