percept_simulator_2023/processing_chain/DiscardElements.py

163 lines
6.1 KiB
Python
Raw Normal View History

2023-07-31 15:23:13 +02:00
#%%
# DiscardElements.py
# ====================================
# removes elements from a sparse image representation
# such that a 'most uniform' coverage still exists
#
# Version V1.0, pre-07.03.2023:
# no actual changes, is David's last code version...
import numpy as np
# assume locations is array [n, 3]
# the three entries are [shape_index, pos_x, pos_y]
def discard_elements_simple(locations: np.ndarray, target_number_elements: list):
n_locations: int = locations.shape[0]
locations_remain: list = []
# Loop across all target number of elements
for target_elem in target_number_elements:
assert target_elem > 0, "Number of target elements must be larger than 0!"
assert (
target_elem <= n_locations
), "Number of target elements must be <= number of available locations!"
# Build distance matrix between positions in locations_highest_res.
# Its diagonal is defined as Inf because we don't want to consider these values in our
# search for the minimum distances.
distance_matrix = np.sqrt(
((locations[np.newaxis, :, 1:] - locations[:, np.newaxis, 1:]) ** 2).sum(
axis=-1
)
)
distance_matrix[np.arange(n_locations), np.arange(n_locations)] = np.inf
# Find the minimal distances in upper triangle of matrix.
idcs_remove: list = []
while (n_locations - len(idcs_remove)) != target_elem:
# Get index of matrix with minimal distance
row_idcs, col_idcs = np.where(
distance_matrix == distance_matrix[distance_matrix > 0].min()
)
# Get the max index.
# It correspond to the index of the element we will remove in the locations_highest_res list
sel_idx: int = max(row_idcs[0], col_idcs[0])
idcs_remove.append(sel_idx) # Save the index
# Set current distance as Inf because we don't want to consider it further in our search
distance_matrix[sel_idx, :] = np.inf
distance_matrix[:, sel_idx] = np.inf
idcs_remain: list = np.setdiff1d(np.arange(n_locations), idcs_remove)
locations_remain.append(locations[idcs_remain, :])
return locations_remain
# assume locations is array [n, 3]
# the three entries are [shape_index, pos_x, pos_y]
def discard_elements(
locations: np.ndarray, target_number_elements: list, prior: np.ndarray
):
n_locations: int = locations.shape[0]
locations_remain: list = []
disable_value: float = np.nan
# if type(prior) != np.ndarray:
# prior = np.ones((n_locations,))
assert prior.shape == (
n_locations,
), "Prior must have same number of entries as elements in locations!"
print(prior)
# Loop across all target number of elements
for target_elem in target_number_elements:
assert target_elem > 0, "Number of target elements must be larger than 0!"
assert (
target_elem <= n_locations
), "Number of target elements must be <= number of available locations!"
# Build distance matrix between positions in locations_highest_res.
# Its diagonal is defined as Inf because we don't want to consider these values in our
# search for the minimum distances.
distance_matrix = np.sqrt(
((locations[np.newaxis, :, 1:] - locations[:, np.newaxis, 1:]) ** 2).sum(
axis=-1
)
)
prior_matrix = prior[np.newaxis, :] * prior[:, np.newaxis]
distance_matrix *= prior_matrix
distance_matrix[np.arange(n_locations), np.arange(n_locations)] = disable_value
print(distance_matrix)
# Find the minimal distances in upper triangle of matrix.
idcs_remove: list = []
while (n_locations - len(idcs_remove)) != target_elem:
# Get index of matrix with minimal distance
row_idcs, col_idcs = np.where(
# distance_matrix == distance_matrix[distance_matrix > 0].min()
distance_matrix
== np.nanmin(distance_matrix)
)
# Get the max index.
# It correspond to the index of the element we will remove in the locations_highest_res list
print(row_idcs[0], col_idcs[0])
# if prior[row_idcs[0]] >= prior[col_idcs[0]]:
# sel_idx = row_idcs[0]
# else:
# sel_idx = col_idcs[0]
d_row = np.nansum(distance_matrix[row_idcs[0], :])
d_col = np.nansum(distance_matrix[:, col_idcs[0]])
if d_row > d_col:
sel_idx = col_idcs[0]
else:
sel_idx = row_idcs[0]
# sel_idx: int = max(row_idcs[0], col_idcs[0])
idcs_remove.append(sel_idx) # Save the index
# Set current distance as Inf because we don't want to consider it further in our search
distance_matrix[sel_idx, :] = disable_value
distance_matrix[:, sel_idx] = disable_value
idcs_remain: list = np.setdiff1d(np.arange(n_locations), idcs_remove)
locations_remain.append(locations[idcs_remain, :])
return locations_remain
if __name__ == "__main__":
import matplotlib.pyplot as plt
# generate a circle with n locations
n_locations: int = 20
phi = np.arange(n_locations) / n_locations * 2 * np.pi
locations = np.ones((n_locations, 3))
locations[:, 1] = np.cos(phi)
locations[:, 2] = np.sin(phi)
prior = np.ones((n_locations,))
prior[:10] = 0.1
locations_remain = discard_elements(locations, [n_locations // 5], prior=prior)
plt.plot(locations[:, 1], locations[:, 2], "ko")
plt.plot(locations_remain[0][:, 1], locations_remain[0][:, 2], "rx")
plt.show()
locations_remain_simple = discard_elements_simple(locations, [n_locations // 5])
plt.plot(locations[:, 1], locations[:, 2], "ko")
plt.plot(locations_remain_simple[0][:, 1], locations_remain_simple[0][:, 2], "rx")
plt.show()
# %%