def feature_filter(arr, feature_id, threshold, knn): """ Filters a point cloud based on a given feature threshold. Only points with selected feature values higher than threshold are kept as valid. Parameters ---------- arr : array Three-dimensional (m x n) array of a point cloud, where the coordinates are represented in the columns (n) and the points are represented in the rows (m). feature_id : int Column index of feature selected as criteria to filter. Column indices follow Python notation [0 - (n_columns - 1)]. threshold : float Minimum feature value for valid points. knn : int Number of neighbors to select around each point. Used to describe local point arrangement. Returns ------- mask_feature : numpy.ndarray Boolean mask with valid points entries set as True. """ # Running NearestNeighborhood search and calculating geometric features # for each point's neighborhood. nbrs_idx = set_nbrs_knn(arr, arr, knn, False) features = knn_features(arr, nbrs_idx) # Masking valid points. return features[:, feature_id] >= threshold
def apply_nn_value(base, arr, attr): """ Upscales a set of attributes from a base array to another denser array. Args: base (array): Base array to which the attributes to upscale were originaly matched. arr (array): Target array to which the attributes will be upscaled. attr (array): Attributes to upscale. Returns: new_attr (array): Upscales attributes. Raises: AssertionError: length (number of samples) of "base" and "attr" must be equal. """ assert base.shape[0] == attr.shape[0], '"base" and "attr" must have the\ same number of samples.' # Obtaining the closest in base for each point in arr. idx = set_nbrs_knn(base, arr, 1, return_dist=False) # Making sure idx has the right type, int, for indexing. idx = idx.astype(int) # Applying base's attribute (attr) to points in arr. newattr = attr[idx] return np.reshape(newattr, newattr.shape[0])
def upper_quantile_min_cc(point_cloud): mask = point_cloud[:, 2] >= np.quantile(point_cloud[:, 2], 0.95) lower_points = point_cloud[mask] dist, ids = set_nbrs_knn(lower_points, lower_points, 2) return np.median(dist[:, 1:])
def lower_quantile_max_cc(point_cloud): mask = point_cloud[:, 2] <= np.quantile(point_cloud[:, 2], 0.1) lower_points = point_cloud[mask] dist, ids = set_nbrs_knn(lower_points, lower_points, 3) return np.max(dist[:, 1:])
def detect_nn_dist(arr, knn, sigma=1): """ Calcuates the optimum distance among neighboring points. Args: arr (array): N-dimensional array (m x n) containing a set of parameters (n) over a set of observations (m). knn (int): Number of nearest neighbors to search to constitue the local subset of points around each point in 'arr'. Returns: dist (float): Optimal distance among neighboring points. """ dist, indices = set_nbrs_knn(arr, arr, knn) return np.mean(dist[:, 1:]) + (np.std(dist[:, 1:]) * sigma)
def dist_majority(arr_1, arr_2, **kwargs): """ Applies majority filter on two arrays. Args: arr_1 (array): n-dimensional array of points to filter. arr_2 (array): n-dimensional array of points to filter. **kwargs: knn, rad. knn (int or float): Number neighbors to select around each point in arr in order to apply the majority criteria. rad (int or float): Search radius arount each point in arr to select neighbors in order to apply the majority criteria. Returns: c_maj_1 (array): Boolean mask of filtered entries of same class as input 'arr_1'. c_maj_2 (array): Boolean mask of filtered entries of same class as input 'arr_2'. Raises: AssertionError: Raised if neither 'knn' or 'rad' arguments are passed with valid values (int or float). """ # Asserting input arguments are valid. assert ('knn' in kwargs.keys()) or ('rad' in kwargs.keys()), 'Please\ input a value for either "knn" or "rad".' if 'knn' in kwargs.keys(): assert (type(kwargs['knn']) == int) or (type(kwargs['knn']) == float), \ '"knn" variable must be of type int or float.' elif 'rad' in kwargs.keys(): assert (type(kwargs['rad']) == int) or (type(kwargs['rad']) == float), \ '"rad" variable must be of type int or float.' # Stacking the arrays from both classes to generate a combined array. arr = np.vstack((arr_1, arr_2)) # Generating the indices for the local subsets of points around all points # in the combined array. Function used is based upon the argument passed. if 'knn' in kwargs.keys(): dist, indices = set_nbrs_knn(arr, arr, kwargs['knn']) elif 'rad' in kwargs.keys(): dist, indices = set_nbrs_rad(arr, arr, kwargs['rad']) # Making sure indices has type int. indices = indices.astype(int) # Generating the class arrays from both classified arrays and combining # them into a single classes array (classes). class_1 = np.full(arr_1.shape[0], 1, dtype=np.int) class_2 = np.full(arr_2.shape[0], 2, dtype=np.int) classes = np.hstack((class_1, class_2)).T # Allocating output variable. c_maj = np.zeros(classes.shape) # Selecting subset of classes based on the neighborhood expressed by # indices. class_ = classes[indices] # Looping over all points in indices. for i in range(len(indices)): # Obtaining classe from indices i. c = class_[i, :] # Caculating accummulated distance for each class. d1 = np.sum(dist[i][c == 1]) d2 = np.sum(dist[i][c == 2]) # Checking which class has the highest distance and assigning it # to current index in c_maj. if d1 >= d2: c_maj[i] = 1 elif d1 < d2: c_maj[i] = 2 return c_maj == 1, c_maj == 2
def class_filter(arr_1, arr_2, target, **kwargs): """ Function to apply class filter on an array based on the combination of classed from both arrays (arr_1 and arr_2). Which array gets filtered is defined by ''target''. Args: arr_1 (array): n-dimensional array of points to filter. arr_2 (array): n-dimensional array of points to filter. target (int or float): number of the input array to filter. Valid values are 0 or 1. **kwargs: knn, rad. knn (int or float): Number neighbors to select around each point in arr in order to apply the majority criteria. rad (int or float): Search radius arount each point in arr to select neighbors in order to apply the majority criteria. Returns: c_maj_1 (array): Boolean mask of filtered entries of same class as input 'arr_1'. c_maj_2 (array): Boolean mask of filtered entries of same class as input 'arr_2'. Raises: AssertionError: Raised if neither 'knn' or 'rad' arguments are passed with valid values (int or float). AssertionError: Raised if 'target' variable is not an int or float with value 0 or 1. """ # Asserting input arguments are valid. assert ('knn' in kwargs.keys()) or ('rad' in kwargs.keys()), 'Please\ input a value for either "knn" or "rad".' if 'knn' in kwargs.keys(): assert (type(kwargs['knn']) == int) or (type(kwargs['knn']) == float), \ '"knn" variable must be of type int or float.' elif 'rad' in kwargs.keys(): assert (type(kwargs['rad']) == int) or (type(kwargs['rad']) == float), \ '"rad" variable must be of type int or float.' assert (type(target) == int) or (type(target) == float), '"target"\ variable must be of type int or float.' assert (target == 0) or (target == 1), '"target" variable must be either\ 0 or 1.' # Stacking the arrays from both classes to generate a combined array. arr = np.vstack((arr_1, arr_2)) # Generating the class arrays from both classified arrays and combining # them into a single classes array (classes). class_1 = np.full(arr_1.shape[0], 1, dtype=np.int) class_2 = np.full(arr_2.shape[0], 2, dtype=np.int) classes = np.hstack((class_1, class_2)).T # Generating the indices for the local subsets of points around all points # in the combined array. Function used is based upon the argument passed. if 'knn' in kwargs.keys(): indices = set_nbrs_knn(arr, arr, kwargs['knn'], return_dist=False) elif 'rad' in kwargs.keys(): indices = set_nbrs_rad(arr, arr, kwargs['rad'], return_dist=False) # Making sure indices has type int. indices = indices.astype(int) # Allocating output variable. c_maj = classes.copy() # Selecting subset of classes based on the neighborhood expressed by # indices. class_ = classes[indices] # Checking for the target class. target_idx = np.where(classes == target)[0] # Looping over the target points to filter. for i in target_idx: # Counting the number of occurrences of each value in the ith instance # of class_. count = np.bincount(class_[i, :]) # Appending the majority class into the output variable. c_maj[i] = count.argmax() return c_maj == 1, c_maj == 2
def array_majority(arr_1, arr_2, **kwargs): """ Applies majority filter on two arrays. Args: arr_1 (array): n-dimensional array of points to filter. arr_2 (array): n-dimensional array of points to filter. **kwargs: knn, rad. knn (int or float): Number neighbors to select around each point in arr in order to apply the majority criteria. rad (int or float): Search radius arount each point in arr to select neighbors in order to apply the majority criteria. Returns: c_maj_1 (array): Boolean mask of filtered entries of same class as input 'arr_1'. c_maj_2 (array): Boolean mask of filtered entries of same class as input 'arr_2'. Raises: AssertionError: Raised if neither 'knn' or 'rad' arguments are passed with valid values (int or float). """ # Asserting input arguments are valid. assert ('knn' in kwargs.keys()) or ('rad' in kwargs.keys()), 'Please\ input a value for either "knn" or "rad".' if 'knn' in kwargs.keys(): assert (type(kwargs['knn']) == int) or (type(kwargs['knn']) == float), \ '"knn" variable must be of type int or float.' elif 'rad' in kwargs.keys(): assert (type(kwargs['rad']) == int) or (type(kwargs['rad']) == float), \ '"rad" variable must be of type int or float.' # Stacking the arrays from both classes to generate a combined array. arr = np.vstack((arr_1, arr_2)) # Generating the indices for the local subsets of points around all points # in the combined array. Function used is based upon the argument passed. if 'knn' in kwargs.keys(): indices = set_nbrs_knn(arr, arr, kwargs['knn'], return_dist=False) elif 'rad' in kwargs.keys(): indices = set_nbrs_rad(arr, arr, kwargs['rad'], return_dist=False) # Making sure indices has type int. indices = indices.astype(int) # Generating the class arrays from both classified arrays and combining # them into a single classes array (classes). class_1 = np.full(arr_1.shape[0], 1, dtype=np.int) class_2 = np.full(arr_2.shape[0], 2, dtype=np.int) classes = np.hstack((class_1, class_2)).T # Allocating output variable. c_maj = np.zeros(classes.shape) # Selecting subset of classes based on the neighborhood expressed by # indices. class_ = classes[indices] # Looping over all points in indices. for i in range(len(indices)): # Counting the number of occurrences of each value in the ith instance # of class_. unique, count = np.unique(class_[i, :], return_counts=True) # Appending the majority class into the output variable. c_maj[i] = unique[np.argmax(count)] return c_maj == 1, c_maj == 2