from turtle import left import matplotlib.pyplot as plt import numpy as np from IPython import embed def crop_frame(frame, marker_positions): # load the four marker positions bottom_left = marker_positions[0]['bottom left corner'] bottom_right = marker_positions[0]['bottom right corner'] top_left = marker_positions[0]['top left corner'] top_right = marker_positions[0]['top right corner'] # define boundaries of frame, taken by average of points on same line but slightly different pixel values left_bound = int(np.mean([bottom_left[0], top_left[0]])) right_bound = int(np.mean([bottom_right[0], top_right[0]])) top_bound = int(np.mean([top_left[1], top_right[1]])) bottom_bound = int(np.mean([bottom_left[1], bottom_right[1]])) # crop the frame by boundary values crop_frame = frame[top_bound:bottom_bound, left_bound:right_bound] crop_frame = np.mean(crop_frame, axis=2) # mean over 3rd dimension (RGB/color values) # mean over short or long side of the frame corresponding to x or y axis of picture frame_width = np.mean(crop_frame,axis=0) frame_height = np.mean(crop_frame,axis=1) # differences of color values lying next to each other --> derivation diff_width = np.diff(frame_width) diff_height = np.diff(frame_height) # two x vectors for better plotting x_width = np.arange(0, len(diff_width), 1) x_height = np.arange(0, len(diff_height), 1) return frame_width, frame_height, diff_width, diff_height, x_width, x_height def rotation_angle(): pass def threshold_crossings(data, threshold_factor): # upper and lower threshold median_data = np.median(data) median_lower = median_data + np.min(data) median_upper = np.max(data) - median_data lower_threshold = median_lower / threshold_factor upper_threshold = median_upper / threshold_factor # array with values if data >/< than threshold = True or not lower_crossings = np.diff(data < lower_threshold, prepend=False) # prepend: point after crossing upper_crossings = np.diff(data > upper_threshold, append=False) # append: point before crossing # indices where crossings are lower_crossings_indices = np.argwhere(lower_crossings) upper_crossings_indices = np.argwhere(upper_crossings) # sort out several crossings of same edge of checkerboard (due to noise) half_window_size = 10 lower_peaks = [] upper_peaks = [] for lower_idx in lower_crossings_indices: # for every lower crossing.. if lower_idx < half_window_size: # ..if indice smaller than window size near indice 0 half_window_size = lower_idx lower_window = data[lower_idx[0] - int(half_window_size):lower_idx[0] + int(half_window_size)] # create data window from -window_size to +window_size min_window = np.min(lower_window) # take minimum of window min_idx = np.where(data == min_window) # find indice where minimum is lower_peaks.append(min_idx) # append to list for upper_idx in upper_crossings_indices: # same for upper crossings with max of window if upper_idx < half_window_size: half_window_size = upper_idx upper_window = data[upper_idx[0] - int(half_window_size) : upper_idx[0] + int(half_window_size)] max_window = np.max(upper_window) max_idx = np.where(data == max_window) upper_peaks.append(max_idx) # if several crossings create same peaks due to overlapping windows, only one (unique) will be taken lower_peaks = np.unique(lower_peaks) upper_peaks = np.unique(upper_peaks) return lower_peaks, upper_peaks def checkerboard_position(lower_crossings_indices, upper_crossings_indices): """Take crossing positions to generate a characteristic sequence for a corresponding position of the checkerboard inside the frame. Positional description has to be interpreted depending on the input data. Args: lower_crossings_indices: Indices where lower threshold was crossed by derivation data. upper_crossings_indices: Indices where upper threshold was crossed by derivation data Returns: checkerboard_position: General position where the checkerboard lays inside the frame along the axis of the input data. """ # create zipped list with both indices zip_list = [] for zl in lower_crossings_indices: zip_list.append(zl) for zu in upper_crossings_indices: zip_list.append(zu) zip_list = np.sort(zip_list) # order by indice # compare and assign zipped list to original indices lists and corresponding direction (to upper or lower threshold) sequence = [] for z in zip_list: if z in lower_crossings_indices: sequence.append('down') else: sequence.append('up') print('sequence:', sequence) # depending on order of crossings through upper or lower treshold, we get a characteristic sequence for a position of the checkerboard in the frame if sequence == ['up', 'down', 'up', 'down']: # first down, second up are edges of checkerboard print('in middle') checkerboard_position = 'middle' left_checkerboard_edge = zip_list[1] right_checkerboard_edge = zip_list[2] elif sequence == ['up', 'up', 'down']: # first and second up are edges of checkerboard print('at left') checkerboard_position = 'left' left_checkerboard_edge = zip_list[0] right_checkerboard_edge = zip_list[1] else: # first and second down are edges of checkerboard print('at right') checkerboard_position = 'right' left_checkerboard_edge = zip_list[1] right_checkerboard_edge = zip_list[2] return checkerboard_position, left_checkerboard_edge, right_checkerboard_edge # position of checkerboard then will be returned def filter_data(data, n): """Filter/smooth data with kernel of length n. Args: data: Raw data. n: Number of datapoints the mean gets computed over. Returns: filtered_data: Filtered data. """ new_data = np.zeros(len(data)) # empty vector where data will be put in in the following steps for k in np.arange(0, len(data) - n): kk = int(k) f = np.mean(data[kk:kk+n]) # mean over data over window from kk to kk+n kkk = int(kk+n / 2) # position where mean datapoint will be placed (so to say) if k == 0: new_data[:kkk] = f new_data[kkk] = f # assignment of value to datapoint new_data[kkk:] = f for nd in new_data[0:n-1]: # correction of left boundary effects (boundaries up to length of n were same number) nd_idx = np.argwhere(nd) new_data[nd_idx] = data[nd_idx] for nd in new_data[-1 - (n-1):-1]: # same as above, correction of right boundary effect nd_idx = np.argwhere(nd) new_data[nd_idx] = data[nd_idx] return new_data