diff --git a/tools.py b/tools.py index b10883b74021f0eb01bbaeed77884cc2fccc4ada..73ba1c09de1d4a74c8e92449a42a36e0bd4f272c 100644 --- a/tools.py +++ b/tools.py @@ -52,7 +52,6 @@ class Main: # Define class attributes self.init_time = time.time() - self.num = 0 self.output = {} def start_thread(self): @@ -102,7 +101,6 @@ class Main: # Save variables in self.memory self._save_in_memory(output) - self.num += 1 # Delete unnecessary variables for html and put output in queue del output['num_ions'] @@ -143,11 +141,6 @@ class Main: num_dim_ions = np.sum(coord[:, 2] == 1).item() num_dark_ions = np.sum(coord[:, 2] == 2).item() - # Reset self.memory every NUM_ITERATIONS - if self.num > settings.NUM_ITERATIONS: - self.memory.reset_memory(coord) - self.num = 0 - return { 'image': image, 'coord': coord, @@ -206,6 +199,8 @@ class Memory: Stores values in memory and counts how many times each value was stored. """ def __init__(self): + self.i = 0 + self.max_idx = 0 self.memory = [] self.count = [] @@ -216,7 +211,8 @@ class Memory: # If memory is empty, append new value if len(self.memory) == 0: self.memory.append(value) - self.count.append(1) + self.count.append([0]) + self.i += 1 return # If value has the same ion types as any element in memory, append abs(value - element) @@ -232,14 +228,37 @@ class Memory: # If sum(abs(value - element)) is less than 10, consider as same distribution try: if 0 <= diff[:, 1].min() < 30: - self.memory[diff[np.argmin(diff[:, 1])][0]] = value - self.count[diff[np.argmin(diff[:, 1])][0]] += 1 + idx = diff[np.argmin(diff[:, 1])][0] + self.memory[idx] = value + self.count[idx].append(self.i) + self.i += 1 else: self.memory.append(value) - self.count.append(1) + self.count.append([self.i]) + self.i += 1 except IndexError: self.memory.append(value) - self.count.append(1) + self.count.append([self.i]) + self.i += 1 + + # When we reach NUM_ITERATIONS, we remove the 0 value and + # substract 1 for each value inside count list. + + if self.i == settings.NUM_ITERATIONS: + list_len = [] + count_copy = self.count.copy() + for i, val in enumerate(count_copy): + if 0 in val: + val.remove(0) + if len(val) == 0: + del self.memory[i] + del self.count[i] + else: + val = [val[i] - 1 for i in range(len(val))] + self.count[i] = val + list_len.append(len(val)) + self.i -= 1 + self.max_idx = np.argmax(list_len) def get_value(self): @@ -248,22 +267,11 @@ class Memory: where this value was stored. """ try: - max_idx = np.argmax(self.count) - max_value = self.memory[max_idx] - except ValueError: - max_idx = 0 + max_value = self.memory[self.max_idx] + except IndexError: max_value = None - return max_value, max_idx - - def reset_memory(self, value): - """ - Delete memory and add new value. - """ - del self.memory - del self.count - self.memory = [value] - self.count = [0] + return max_value, self.max_idx class MovingAverage: @@ -437,6 +445,7 @@ def ion_roundness(image, center): image_copy = image_copy[c_x - 25 : c_x + 25, c_y - 25 : c_y + 25] # crop the image # get coordinates of ion pixels + # TODO: fix this (sometimes the image_copy is empty) pca_input = np.swapaxes(np.stack(np.where(image_copy > image_copy.max()*0.5)), 0, 1) if len(pca_input) > 1: pca = PCA(n_components=2) # compute PCA @@ -538,54 +547,55 @@ def dark_ions(image, coord, dist_factor): mask_dist = (pd.read_csv("data/mask_dist.csv", index_col=0).to_numpy()* dist_factor)[low_idx : high_idx, :] - # Compute min error between every value of the mask and every value of the measured distances - comparison = np.full((3, mask.shape[0], mask.shape[1]), 100000, dtype=float) - for i in range(mask.shape[0]): - dist = x_dist.copy() - for j in range(mask.shape[1]): - val = mask[i, j] - val_dist = mask_dist[i, j] - if val >= 0: - comparison[:2, i, j] = np.min((x_pos - val)**2, axis=1) - if val_dist >= 0: - diff = (dist - val_dist)**2 - comparison[2, i, j] = np.min(diff) - dist[np.argmin(diff)] = 0 - - comp = np.sort(comparison, axis=2)[:, :, :len(x_pos[1])] - # Set to 0 the last column of the comparison of the distances (they have 1 value less) - # This way the last column won't affect the loss - comp[2, :, -1] = 0 - loss = np.sum(comp, axis=2)/len(x_pos) - - idx = np.where(loss == np.min(loss)) - - if idx[0][0] == 1: # if using "inverted positions", transform back - new_x_pos = np.abs(mask[idx[1][0], :][mask[idx[1][0], :] >= 0] - coord[-1, 1]) - else: - new_x_pos = mask[idx[1][0], :][mask[idx[1][0], :] >= 0] + coord[0, 1] - - diff_n = len(new_x_pos) - len(x_pos[0]) - for i in range(diff_n): - mask2 = comparison[idx[0][0], idx[1][0], :] < 100000 - idx2 = np.argsort(comparison[idx[0][0], idx[1][0], :][mask2])[-(diff_n - i)] - if idx2 != 0: - # If we are using the distances' loss, then we have to add 1 to the index - if idx[0][0] == 2: - idx2 += 1 - coord = np.append(coord, np.array([[np.mean(coord[:, 0]), - new_x_pos[idx2], 2]]), axis=0) - - elif idx2 == 0 and idx[0][0] == 2: - coord = np.append(coord, np.array([[np.mean(coord[:, 0]), new_x_pos[0] - - comparison[2, idx[1][0], 0], 2]]), axis=0) - - coord = coord[coord[:, 1].argsort()].astype(int) - coord = coord[coord[:, 1] < image.shape[1]] # remove points outside the image - - # if loss.min() > 20: - # warnings.warn("Loss is too high... " - # "Try calculating a new factor value using calibrate() function.") + if len(mask) > 0: + # Compute min error between every value of the mask and every value of the measured distances + comparison = np.full((3, mask.shape[0], mask.shape[1]), 100000, dtype=float) + for i in range(mask.shape[0]): + dist = x_dist.copy() + for j in range(mask.shape[1]): + val = mask[i, j] + val_dist = mask_dist[i, j] + if val >= 0: + comparison[:2, i, j] = np.min((x_pos - val)**2, axis=1) + if val_dist >= 0: + diff = (dist - val_dist)**2 + comparison[2, i, j] = np.min(diff) + dist[np.argmin(diff)] = 0 + + comp = np.sort(comparison, axis=2)[:, :, :len(x_pos[1])] + # Set to 0 the last column of the comparison of the distances (they have 1 value less) + # This way the last column won't affect the loss + comp[2, :, -1] = 0 + loss = np.sum(comp, axis=2)/len(x_pos) + + idx = np.where(loss == np.min(loss)) + + if idx[0][0] == 1: # if using "inverted positions", transform back + new_x_pos = np.abs(mask[idx[1][0], :][mask[idx[1][0], :] >= 0] - coord[-1, 1]) + else: + new_x_pos = mask[idx[1][0], :][mask[idx[1][0], :] >= 0] + coord[0, 1] + + diff_n = len(new_x_pos) - len(x_pos[0]) + for i in range(diff_n): + mask2 = comparison[idx[0][0], idx[1][0], :] < 100000 + idx2 = np.argsort(comparison[idx[0][0], idx[1][0], :][mask2])[-(diff_n - i)] + if idx2 != 0: + # If we are using the distances' loss, then we have to add 1 to the index + if idx[0][0] == 2: + idx2 += 1 + coord = np.append(coord, np.array([[np.mean(coord[:, 0]), + new_x_pos[idx2], 2]]), axis=0) + + elif idx2 == 0 and idx[0][0] == 2: + coord = np.append(coord, np.array([[np.mean(coord[:, 0]), new_x_pos[0] - + comparison[2, idx[1][0], 0], 2]]), axis=0) + + coord = coord[coord[:, 1].argsort()].astype(int) + coord = coord[coord[:, 1] < image.shape[1]] # remove points outside the image + # TODO: uncomment this! + # if loss.min() > 20: + # warnings.warn("Loss is too high... " + # "Try calculating a new factor value using calibrate() function.") return coord