def test_ellipse_model_estimate_from_data(): data = np.array([ [264, 854], [265, 875], [268, 863], [270, 857], [275, 905], [285, 915], [305, 925], [324, 934], [335, 764], [336, 915], [345, 925], [345, 945], [354, 933], [355, 745], [364, 936], [365, 754], [375, 745], [375, 735], [385, 736], [395, 735], [394, 935], [405, 727], [415, 736], [415, 727], [425, 727], [426, 929], [435, 735], [444, 933], [445, 735], [455, 724], [465, 934], [465, 735], [475, 908], [475, 726], [485, 753], [485, 728], [492, 762], [495, 745], [491, 910], [493, 909], [499, 904], [505, 905], [504, 747], [515, 743], [516, 752], [524, 855], [525, 844], [525, 885], [533, 845], [533, 873], [535, 883], [545, 874], [543, 864], [553, 865], [553, 845], [554, 825], [554, 835], [563, 845], [565, 826], [563, 855], [563, 795], [565, 735], [573, 778], [572, 815], [574, 804], [575, 665], [575, 685], [574, 705], [574, 745], [575, 875], [572, 732], [582, 795], [579, 709], [583, 805], [583, 854], [586, 755], [584, 824], [585, 655], [581, 718], [586, 844], [585, 915], [587, 905], [594, 824], [593, 855], [590, 891], [594, 776], [596, 767], [593, 763], [603, 785], [604, 775], [603, 885], [605, 753], [605, 655], [606, 935], [603, 761], [613, 802], [613, 945], [613, 965], [615, 693], [617, 665], [623, 962], [624, 972], [625, 995], [633, 673], [633, 965], [633, 683], [633, 692], [633, 954], [634, 1016], [635, 664], [641, 804], [637, 999], [641, 956], [643, 946], [643, 926], [644, 975], [643, 655], [646, 705], [651, 664], [651, 984], [647, 665], [651, 715], [651, 725], [651, 734], [647, 809], [651, 825], [651, 873], [647, 900], [652, 917], [651, 944], [652, 742], [648, 811], [651, 994], [652, 783], [650, 911], [654, 879]]) # estimate parameters of real data model = EllipseModel() model.estimate(data) # test whether estimated parameters are smaller then 1000, so means stable assert_array_less(np.abs(model.params[:4]), np.array([2e3] * 4))
def test_ellipse_model_predict(): model = EllipseModel() model.params = (0, 0, 5, 10, 0) t = np.arange(0, 2 * np.pi, np.pi / 2) xy = np.array(((5, 0), (0, 10), (-5, 0), (0, -10))) assert_almost_equal(xy, model.predict_xy(t))
def test_ellipse_model_residuals(): model = EllipseModel() # vertical line through origin model.params = (0, 0, 10, 5, 0) assert_almost_equal(abs(model.residuals(np.array([[10, 0]]))), 0) assert_almost_equal(abs(model.residuals(np.array([[0, 5]]))), 0) assert_almost_equal(abs(model.residuals(np.array([[0, 10]]))), 5)
def bounding_ellipses(ellipses_nuclei, n_neighbour_nuclei=1, radial_slack=0.0): '''Bla bla ''' ellipses_bounding = {} for k_label, ellipse_n in ellipses_nuclei.items(): x0, y0, a0, b0, theta0 = ellipse_n.params dists = [] for l_label, ellipse_n_test in ellipses_nuclei.items(): xt, yt, at, bt, thetat = ellipse_n_test.params dist = (((xt - x0) * np.cos(theta0) + (yt - y0) * np.sin(theta0)) / a0) ** 2 + \ (((xt - x0) * np.sin(theta0) - (yt - y0) * np.cos(theta0)) / b0) ** 2 dists.append((l_label, dist)) sort_dist = sorted(dists, key=lambda x: x[1]) scale = np.sqrt( sort_dist[n_neighbour_nuclei][1]) * (1.0 + radial_slack) ellipse_bounder = EllipseModel() ellipse_bounder.params = (round(x0), round(y0), round(a0 * scale), round(b0 * scale), -theta0) ellipses_bounding[k_label] = ellipse_bounder return ellipses_bounding
def _fit_ellipse(self, p): # UNTESTED """ Fit ellipse to points parameter; then determine the xy coordinates along the ellipse that are at most half a pixel apart. We use EllipseModel.predict_xy() to estimate the xy coordinates along the ellipse. As the parameter to predict_xy() is the set of angles along the ellipse, we must first determine the radian interval that results in a distance (arc length) of maximum 0.5 pixels apart between xy points. (This arc length starts at pi/4 or 0, depending on which of the width or height of the ellipse is longer). """ def get_arc_length_func(_a, _b): return lambda _t:np.sqrt(_a**2*np.sin(_t)**2 + _b**2*np.cos(_t)**2) el = EllipseModel() assert(el.estimate(p)) a, b = el.params[2], el.params[3] # width and height of ellipse self._center = np.array([el.params[0], el.params[1]]) if a < b: stop = np.pi/4 # whether maximum arc length is around np.pi/4 or 0 else: stop = 0. t = np.pi/8 # radians along the ellipse arc_length = 1. arc_length_func = get_arc_length_func(a, b) while arc_length > 0.5: t = t*0.75 # ellipse arc length # https://math.stackexchange.com/questions/433094/how-to-determine-the-arc-length-of-ellipse arc_length = quad(arc_length_func, stop - t, stop)[0] circumfrence = quad(arc_length_func, 0, 2*np.pi)[0] n = circumfrence // t + 1 intervals = np.linspace(0, 2*np.pi, n, endpoint=False) return el.predict_xy(intervals)
def get_ellipse_fit_cost(region): pts = np.where(region.image) pts = np.array([pts[1], pts[0]]).T e = EllipseModel() e.estimate(pts) cost = np.mean(e.residuals(pts)**2) return (cost)
def define_bowl_mask(self): # Similar routine to that above. Single pass for 1 chamber ####################################################################### self._load_video_frame() # Resize total frame so all points on perimeter can be reached self.display_frame = cv2.resize(self.frame, None, fx=0.5, fy=0.5) cv2.namedWindow('image') cv2.setMouseCallback('image', self.draw_dot) # While the number of defined points < 5*n_patches, # click, draw and log the coordinates of points while (len(self.points) < 5): cv2.imshow('image', self.display_frame) cv2.moveWindow('image', 10, 10) k = cv2.waitKey(1) & 0xFF if k == ord('m'): break elif k == 27: break # Create ellipse model from 5 click-selected points point_array = np.asarray(self.points) xy = EllipseModel() xy.estimate(point_array) xc, yc, a, b, theta = int(xy.params[0]), int(xy.params[1]), int( xy.params[2]), int(xy.params[3]), int(np.rad2deg(xy.params[4])) display_bowl_mask = np.zeros(self.display_frame.shape, dtype=np.uint8) bowl_mask = np.zeros(self.frame.shape, dtype=np.uint8) # Create binary mask by drawing ellipse and filling in with white on black background display_bowl_mask = cv2.ellipse(display_bowl_mask, (xc, yc), (a, b), theta, 0, 360, (255, 255, 255), -1) self.bowl_mask = cv2.ellipse(bowl_mask, (2 * xc, 2 * yc), (2 * a, 2 * b), theta, 0, 360, (255, 255, 255), -1) self.mask_centroid = (2 * xc, 2 * yc) # Mask a video frame using generated mask display_masked = cv2.bitwise_and(self.display_frame, display_bowl_mask) masked = cv2.bitwise_and(self.frame, bowl_mask) # On the masked frame, draw the click-selected ellipse points and contour for i in range(5): x, y = self.points[i][0], self.points[i][1] cv2.circle(display_masked, (x, y), 7, (0, 0, 255), -1) cv2.putText(display_masked, "{}/5".format(i + 1), (x + 10, y + 10), cv2.FONT_HERSHEY_PLAIN, 1, (0, 0, 255)) # Display masked and overlaid frame cv2.imshow('image', display_masked) cv2.moveWindow('image', 10, 10) cv2.waitKey(0) cv2.destroyAllWindows()
def plotscatterwithellipse(data, xmin, xmax, ymin, ymax): ell = EllipseModel() ell.estimate(data) xc, yc, a, b, theta = ell.params ell_patch = Ellipse((xc, yc), 2 * a, 2 * b, theta * 180 / np.pi, edgecolor='red', facecolor='none') sns.set_style("whitegrid") ax = sns.scatterplot(x=data[:, 0], y=data[:, 1], legend=False) ax.set(xlim=(xmin, xmax)) ax.set(ylim=(ymin, ymax)) ax.set(xlabel='$x_1$') ax.set(ylabel='$x_2$') ax.add_patch(ell_patch) ax.scatter(xc, yc, color='red', s=20) #ax.scatter(xc-a*np.sin(theta),yc+a*np.sin(theta),color='red',s=20) #ax.scatter(xc+b*np.sin(theta),yc-b*np.cos(theta),color='green',s=20) #a and b scaled a little bit for better visuals scalefactor = 1.2 delta_endarrow1 = (scalefactor * b * np.sin(theta), scalefactor * (-b) * np.cos(theta)) delta_endarrow2 = (scalefactor * (-a) * np.sin(theta), scalefactor * a * np.sin(theta)) ax.arrow(xc, yc, delta_endarrow1[0], delta_endarrow1[1], width=0.02, color='red') ax.arrow(xc, yc, delta_endarrow2[0], delta_endarrow2[1], width=0.02, color='green') style1 = dict(size=20, color='red') style2 = dict(size=20, color='green') ax.text(xc + delta_endarrow1[0] + 0.2, yc + delta_endarrow1[1], "$z_1$", ha='left', **style1) ax.text(xc + delta_endarrow2[0], yc + delta_endarrow2[1] + 0.2, "$z_2$", ha='left', **style2) plt.show()
def fit_ellipse(contour, use_convex_hull): if use_convex_hull: contour = cv2.convexHull(contour) cnt = contour.reshape(-1, 2) * 1. model = EllipseModel() try: assert model.estimate(cnt) return model.params except AssertionError: warnings.warn('ellipse model estimation failed') cx, cy = contour_centre(contour) angle = contour_angle(contour) a = b = np.linalg.norm(cnt.max(0) - cnt.min(0)) return cx, cy, a, b, angle
def FindEllipse(points, number=100): """ this method applies the ellipse model to the input points points --- (N,2) inputs array number --- number of points in the estimated ellipse ----- out --- return points on the ellipse """ if type(points) is not np.ndarray: raise TypeError("the input must be a nd-array") if points.shape[1] != 2: print "the input array must be (N,2)" return model = EllipseModel() # create an object model.estimate(points) out = model.predict_xy(np.linspace(0, 2 * math.pi, number)) return out
def fit_model(self, cut_percent, gauss_sigma): '''Fit an ellipse model to a contour of a certain value in the filtered DFT.''' #Fit ellipse model al_dft = self.abs_log_dft gauss_dft = gaussian(al_dft, gauss_sigma) contour_value = gauss_dft.min() + ( (gauss_dft.max() - gauss_dft.min()) * cut_percent / 100) contours = find_contours(gauss_dft, contour_value) assert len(contours) == 1 self.contour = contours[0] self.ellipse = EllipseModel() self.ellipse.estimate(self.contour[:, ::-1]) center = tuple([x / 2 for x in self.dft.shape]) offset = euclidean(center, (self.ellipse.params[1], self.ellipse.params[0])) half_diagonal = sqrt(sum((x**2 for x in self.dft.shape))) / 2 assert (offset / half_diagonal) <= 0.03 #derive wavelength and texture parameters xy_points = self.ellipse.predict_xy( np.linspace(0, 2 * np.pi, 4 * self.ellipse.params[0])) max_x = round(xy_points[:, 0].max()) min_y = round(xy_points[:, 1].min()) wavelength_x = self.dft.shape[1] / (max_x - center[1]) wavelength_y = self.dft.shape[0] / (center[0] - min_y) self.wavelength = round((wavelength_x + wavelength_y) / 2)
def ellipse_fits(img_labelled, exclusion_list=[0]): '''Bla bla ''' ellipses_by_label = {} for k_label in np.unique(img_labelled): if k_label in exclusion_list: continue rows, cols = np.where(img_labelled == k_label) coords = np.stack([rows, cols]).T ellipse = EllipseModel() estimate_success = ellipse.estimate(coords) if not estimate_success: xc, yc = tuple([int(x) for x in np.median(coords, axis=0)]) ellipse.params = xc, yc, 10, 10, 0.0 ellipses_by_label[k_label] = ellipse return ellipses_by_label
def test_ellipse_model_estimate(): # generate original data without noise model0 = EllipseModel() model0.params = (10, 20, 15, 25, 0) t = np.linspace(0, 2 * np.pi, 100) data0 = model0.predict_xy(t) # add gaussian noise to data np.random.seed(1234) data = data0 + np.random.normal(size=data0.shape) # estimate parameters of noisy data model_est = EllipseModel() model_est.estimate(data) # test whether estimated parameters almost equal original parameters assert_almost_equal(model0.params, model_est.params, 0)
def test_ellipse_model_estimate(): for angle in range(0, 180, 15): rad = np.deg2rad(angle) # generate original data without noise model0 = EllipseModel() model0.params = (10, 20, 15, 25, rad) t = np.linspace(0, 2 * np.pi, 100) data0 = model0.predict_xy(t) # add gaussian noise to data random_state = np.random.RandomState(1234) data = data0 + random_state.normal(size=data0.shape) # estimate parameters of noisy data model_est = EllipseModel() model_est.estimate(data) # test whether estimated parameters almost equal original parameters assert_almost_equal(model0.params[:2], model_est.params[:2], 0) res = model_est.residuals(data0) assert_array_less(res, np.ones(res.shape))
def make_ellipse_data_points(x, y, a, b, r, nt=20, use_focus=True): """Get an ellipse position list. Parameters ---------- x, y : scalars Centre position of the ellipse. a, b : scalars Semi lengths r : scalar Rotation, in theta nt : int, optional Number of data positions, default 20 use_focus : bool If True, (x, y) will be the focus. If False, (x, y) will be centre of the ellipse. Returns ------- data : NumPy array [[x0, y0], [x1, y1], ...] Examples -------- >>> import pyxem.utils.ransac_ellipse_tools as ret >>> data = ret.make_ellipse_data_points(5, 9, 8, 4, np.pi/3) Using all the arguments >>> data = ret.make_ellipse_data_points(5, 9, 8, 4, 0, nt=40, ... use_focus=False) """ if use_focus: params = _make_ellipse_model_params_focus(x, y, a, b, r) else: params = (x, y, a, b, r) theta_array = np.arange(0, 2 * np.pi, 2 * np.pi / nt) data = EllipseModel().predict_xy(theta_array, params=params) return data
def test_ellipse_model_estimate(): # generate original data without noise model0 = EllipseModel() model0._params = (10, 20, 15, 25, 0) t = np.linspace(0, 2 * np.pi, 100) data0 = model0.predict_xy(t) # add gaussian noise to data np.random.seed(1234) data = data0 + np.random.normal(size=data0.shape) # estimate parameters of noisy data model_est = EllipseModel() model_est.estimate(data) # test whether estimated parameters almost equal original parameters assert_almost_equal(model0._params, model_est._params, 0)
max_ = np.argmax(vals) first = (i[:c][max_], j[:c][max_], vals[max_]) vals = line_values[c:] max_ = np.argmax(vals) second = (i[c:][max_], j[c:][max_], vals[max_]) return first, second # -------------------------------------------------------------------- if __name__ == '__main__': from skimage.measure import EllipseModel, CircleModel ellipse, circle = EllipseModel(), CircleModel() from filters import normalize import matplotlib #matplotlib.use('AGG') import matplotlib.pyplot as plt import skimage.io as io rpath = '/home/mirok/Downloads/MIRO_TSeries-01302019-0918-028_cycle_001_ch02_short_video-1.tif' red_seq = io.imread(rpath) red_nseq = normalize(red_seq) gpath = '/home/mirok/Downloads/MIRO_TSeries-01302019-0918-028_cycle_001_ch01_short_video-1.tif' green_seq = io.imread(gpath)
def determine_ellipse( signal, mask=None, num_points=1000, use_ransac=False, guess_starting_params=True, return_params=False, **kwargs, ): """ This method starts by taking some number of points which are the most intense in the signal. It then takes those points and guesses some starting parameters for the `get_ellipse_model_ransac_single_frame` function. From there it will try to determine the ellipse parameters. Parameters ----------- signal : Signal2D The signal of interest. mask : Array-like The mask to be applied to the data. The True values are ignored. num_points : int The number of points to consider. use_ransac : bool If Ransac should be used to determine the ellipse. False is faster but less. robust with respect to noise. guess_starting_params : bool If True then the starting parameters will be guessed based on the points determined. return_params : bool If the ellipse parameters should be returned as well. **kwargs: Any other keywords for `get_ellipse_model_ransac_single_frame`. Returns ------- center : (x,y) The center of the diffraction pattern. affine : The affine transformation to make the diffraction pattern circular. Examples -------- >>> import pyxem.utils.ransac_ellipse_tools as ret >>> import pyxem.dummy_data.make_diffraction_test_data as mdtd >>> test_data = mdtd.MakeTestData(200, 200, default=False) >>> test_data.add_disk(x0=100, y0=100, r=5, intensity=30) >>> test_data.add_ring_ellipse(x0=100, y0=100, semi_len0=63, semi_len1=70, rotation=45) >>> s = test_data.signal >>> s.set_signal_type("electron_diffraction") >>> import numpy as np >>> mask = np.zeros_like(s.data, dtype=bool) >>> mask[100 - 20:100 + 20, 100 - 20:100 + 20] = True # mask beamstop >>> center, affine = ret.determine_ellipse(s, mask=mask, use_ransac=False) >>> s_corr = s.apply_affine_transformation(affine, inplace=False) """ pos = _get_max_positions(signal, mask=mask, num_points=num_points) if use_ransac: if guess_starting_params: el, _ = get_ellipse_model_ransac_single_frame( pos, xf=np.mean(pos[:, 0]), yf=np.mean(pos[:, 1]), rf_lim=np.shape(signal.data)[0] / 5, semi_len_min=np.std(pos[:, 1]), semi_len_max=np.std(pos[:, 1]) * 2, semi_len_ratio_lim=1.2, min_samples=6, residual_threshold=20, max_trails=1000) else: el, _ = get_ellipse_model_ransac_single_frame(pos, **kwargs) else: e = EllipseModel() converge = e.estimate(data=pos) el = e if el is not None: affine = _ellipse_to_affine(el.params[3], el.params[2], el.params[4]) center = (el.params[0], el.params[1]) if return_params: return center, affine, el.params else: return center, affine else: warnings.warn("Ransac Ellipse detection did not converge") return None
def test_ellipse_model_invalid_input(): with testing.raises(ValueError): EllipseModel().estimate(np.empty((5, 3)))
def solve(filename, lat, lon, day, month, year, plot=False): # TODO Find Index of SHASUM from above table origName = "" with open(filename, 'rb') as f: data = f.read() h = sha1() h.update(data) chksum = h.digest() origName = lookup[chksum.hex()] vn = np.array([0, -1]) idx = inputs.index(origName) eidx = [ 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 2, 2, 2, 2, 2, 3, 3, 3, 3, 3, 4, 4, 4, 4, 4, 5, 5, 5, 5, 5, 6, 6, 6, 6, 6, 7, 7, 7, 7, 7, 8, 8, 8, 8, 8, 9, 9, 9, 9, 9, ][idx] # Each set start with North Tower, go clockwise ellipse_points = [ np.array([(587, 900), (615, 832), (1147, 601), (1215, 626), (1467, 1151), (1444, 1219), (893, 1472), (832, 1447)]), np.array([(1395, 1303), (1347, 1359), (739, 1392), (684, 1341), (665, 755), (714, 704), (1295, 673), (1349, 720)]), np.array([ (1445, 859), (1468, 925), (1198, 1456), (1127, 1478), (592, 1193), (573, 1122), (858, 616), (926, 596), ]), np.array([ (611, 848), (645, 789), (1200, 628), (1264, 659), (1450, 1207), (1419, 1270), (835, 1451), ]), np.array([ (834, 627), (901, 604), (1432, 835), (1461, 900), (1225, 1444), (1155, 1471), (602, 1217), (579, 1148), ]), np.array([ (956, 1485), (883, 1468), (571, 960), (590, 890), (1087, 589), (1155, 605), (1479, 1086), (1465, 1159), ]), np.array([ (668, 1324), (624, 1262), (733, 692), (791, 651), (1363, 738), (1407, 793), (1271, 1417), ]), np.array([ (710, 713), (766, 669), (1342, 718), (1389, 769), (1352, 1352), (1297, 1401), (689, 1347), (643, 1291), ]), np.array([ (1287, 671), (1342, 716), (1399, 1297), (1354, 1351), (744, 1396), (689, 1347), (661, 763), (710, 711), ]), np.array([ (1432, 1247), (1391, 1310), (790, 1428), (729, 1385), (631, 806), (674, 749), (1241, 645), (1302, 681), ]) ] x = ellipse_points[eidx][:, 0] y = ellipse_points[eidx][:, 1] xs = [ (x[0], 1112), (x[1], 1279), (x[1], 1148), (x[0], 786), (x[1], 833), (x[0], 661), (x[0], 631), (x[0], 893), (x[0], 1153), (x[1], 1485), (x[0], 837), (x[0], 1160), (x[0], 1329), (x[1], 948), (x[0], 789), (x[0], 1118), (x[0], 1467), (x[1], 400), (x[1], 669), (x[1], 925), (x[1], 785), (x[0], 1507), (x[1], 789), (x[0], 1135), (x[0], 1430), (x[0], 544), (x[1], 1323), (x[1], 1034), (x[1], 1397), (x[0], 525), (x[1], 1159), (x[0], 667), (x[1], 1316), (x[1], 1050), (x[1], 1280), (x[0], 1499), (x[0], 1001), (x[0], 1331), (x[0], 1200), (x[0], 1473), (x[1], 460), (x[1], 932), (x[1], 765), (x[0], 1097), (x[0], 1079), (x[0], 956), (x[1], 1269), (x[0], 1057), (x[1], 1508), (x[1], 1162), ][idx] ys = [ (y[0], 345), (y[1], 1334), (y[1], 1454), (y[0], 625), (y[1], 1363), (y[0], 1681), (y[0], 1039), (y[0], 1255), (y[0], 1303), (y[1], 662), (y[0], 1367), (y[0], 1250), (y[0], 1054), (y[1], 458), (y[0], 1441), (y[0], 1236), (y[0], 901), (y[1], 1473), (y[1], 1558), (y[1], 1190), (y[1], 1090), (y[0], 560), (y[1], 1361), (y[0], 898), (y[0], 839), (y[0], 1234), (y[1], 938), (y[1], 1208), (y[1], 1153), (y[0], 952), (y[1], 611), (y[0], 611), (y[1], 1003), (y[1], 1268), (y[1], 1408), (y[0], 480), (y[0], 821), (y[0], 828), (y[0], 861), (y[0], 1024), (y[1], 1055), (y[1], 815), (y[1], 620), (y[0], 1036), (y[0], 1009), (y[0], 1160), (y[1], 751), (y[0], 1620), (y[1], 753), (y[1], 626), ][idx] vs_c = np.array([xs[1] - xs[0], ys[1] - ys[0]]) vs_c = vs_c / np.linalg.norm(vs_c) vnx_0, vny_0 = x[5], y[5] vnx_1, vny_1 = x[0], y[0] vn_c = np.array([x[0] - x[5], y[0] - y[5]]) vn_c = vn_c / np.linalg.norm(vn_c) ell = EllipseModel() if not ell.estimate(ellipse_points[eidx]): print("Estimate Failed") xc, yc, a, b, theta = ell.params camera_a = np.arccos(np.dot(vn, vn_c)) if vn[0] * vn_c[1] - vn[1] * vn_c[0] < 0: camera_a = -camera_a if a > b: camera_e = np.arcsin(b / a) else: camera_e = np.arcsin(a / b) light_a = np.arccos(np.dot(vs_c, vn_c)) if vs_c[1] * vn_c[0] - vs_c[0] * vn_c[1] < 0: light_a = -light_a hMin = 0 mMin = 0 minE = 0 deltMin = 1000 target_a = np.cos(light_a) for h in range(0, 24): for m in range(0, 60, 5): a, e = sun.findSun(lat, lon, h, tmin=m, td=day, tm=month) #,ty=year) a_c = np.cos(np.radians(a)) #print(target_a, a_c, e, h, m) if abs(target_a - a_c) < deltMin: deltMin = abs(target_a - a_c) minE = e hMin = h mMin = m light_e = np.radians(minE) if (plot): img = plt.imread(filename) fig, ax = plt.subplots(figsize=(15, 10)) ax.imshow(img, aspect=1) # Plot the ellipse that matches the launch platform ell_patch = Ellipse((xc, yc), 2 * a, 2 * b, theta * 180 / np.pi, edgecolor='red', facecolor='none') ax.add_patch(ell_patch) ax.plot(xc, yc, "C1+") xc, yc = linear_extrapolate(np.array([vnx_0, vnx_1]), np.array([vny_0, vny_1]), np.array([0, 1.3])) ax.plot(xc, yc, "C0") xn, yn = linear_extrapolate(np.array([vnx_0, vnx_0]), np.array([vny_0, -100 + vny_0]), np.array([0, 4])) ax.plot(xn, yn, "C0") # Plot the shadow of the North tower and extrapolate #ax.plot(x_north_shadow, y_north_shadow, "C1o") xs, ys = linear_extrapolate(np.array([xs[0], xs[1]]), np.array([ys[0], ys[1]]), np.array([0, 1.2])) ax.plot(xs, ys, "C1") xsn, ysn = linear_extrapolate(np.array([xs[0], 300 * vn_c[0] + xs[0]]), np.array([ys[0], 300 * vn_c[1] + ys[0]]), np.array([0, 2])) ax.plot(xsn, ysn, "C1") ax.set_title("Estimating camera viewpoint azimuth and elevation") ax.set_xlabel("x (pixel)") ax.set_xlabel("y (pixel)") plt.tight_layout() plt.savefig("image_analysis.png", bbox_inches="tight") return (np.degrees(camera_a), np.degrees(camera_e), np.degrees(light_a), np.degrees(light_e), hMin, mMin)
gamma=0.1)), ("Isolation Forest", IsolationForest(contamination=outliers_fraction, random_state=42)), ("Local Outlier Factor", LocalOutlierFactor(n_neighbors=4, contamination=outliers_fraction)) ] gif = [np.array(g[:, :, 0]) for g in imageio.mimread('data/red.gif')] theta = np.linspace(0, 2 * np.pi, 100) ellipses = [] for step, img in enumerate(gif[:]): ellipse = EllipseModel() d = 10 shape = img.shape img[:, tuple(range(d))] = 0 img[:, tuple(range(shape[0] - d, shape[0]))] = 0 img[tuple(range(d)), :] = 0 img[tuple(range(shape[0] - d, shape[0])), :] = 0 X = np.array(np.where(img > 0)).T preds = {} for name, algorithm in anomaly_algorithms: if name == "Local Outlier Factor": y_pred = algorithm.fit_predict(X) else:
def test_ellipse_model_estimate_failers(): # estimate parameters of real data model = EllipseModel() assert not model.estimate(np.ones((5, 2))) assert not model.estimate(np.array([[50, 80], [51, 81], [52, 80]]))
import matplotlib.pyplot as plt import numpy as np from skimage.measure import EllipseModel import os fname = 'ray_db_pupil.hdf' df = pd.read_hdf(fname, 'df') grouped = df.groupby(['hx_deg', 'hy_deg']) if not os.path.exists('ellipticity'): os.mkdir('ellipticity') fits = [] for name, group in grouped: ellipse = EllipseModel() data = np.vstack((group.x_pos.values, group.y_pos.values)) ellipse.estimate(data.T) fits.append(ellipse) t = np.linspace(0, 2 * np.pi, 1000) for j, name_group in enumerate(grouped): name, group = name_group plt.scatter(group.x_pos, group.y_pos, marker='x', color='C%i' % j) p = fits[j].params label = 'fld: %1.1f %1.1f, a/b=%1.3f' % (name[0], name[1], p[2] / p[3]) predicted = fits[j].predict_xy(t) plt.plot(predicted[:, 0], predicted[:, 1], label=label) plt.grid() plt.title('Ellipticity') plt.xlabel('x[mm]')
def fit_objects(image, fit_obj='circle'): """Fits objects in each region of the input image, returning the parameters of each object. Parameters ---------- image : (N, M) ndarray Binary input image. fit_obj : string, optional (default : 'circle') Object to be fitted on the regions. Accepts the strings 'circle' and 'ellipse'. Returns ------- image_fit : (N, M, 3) ndarray An image with objects in green representing the fitted objects labeling each region. data_fit : array The parameters for each object fitted. Each row corresponds to a region present on the input image. Each column represents one parameter of the fitted object. For fit_obj='circle', they are the coordinates for the center of the circle, and the radius (x_center, y_center, radius); for fit_obj='ellipse', they are the coordinates for the center of the ellipse, the major and minor axis and the orientation (x_center, y_center, minor_axis, major_axis, theta). Examples -------- >>> from skcv.draw import draw_synthetic_circles >>> from skimage import img_as_bool >>> image = draw_synthetic_circles((512, 512), quant=20, shades=1, seed=0) >>> image_fit, data_fit = fit_objects(img_as_bool(image), fit_obj='circle') >>> from skcv.draw import draw_synthetic_ellipses >>> from skimage import img_as_bool >>> image = draw_synthetic_ellipses((512, 512), quant=20, shades=1, seed=0) >>> image_fit, data_fit = fit_objects(img_as_bool(image), fit_obj='ellipse') """ image_fit = gray2rgb(image) # checking labels. img_label, num_objects = label(image, return_num=True) if fit_obj == 'circle': obj = CircleModel() data_fit = np.zeros((num_objects, 3)) elif fit_obj == 'ellipse': obj = EllipseModel() data_fit = np.zeros((num_objects, 5)) for num in range(num_objects): # finding the contour. obj_contour = find_contours(img_label == num+1, fully_connected='high', level=0) try: # modelling image using obtained points. obj.estimate(obj_contour[0]) data_fit[num] = obj.params aux_fit = data_fit[num].astype(int) if fit_obj == 'circle': # drawing circle. rows, cols = circle(aux_fit[0], aux_fit[1], aux_fit[2], shape=image_fit.shape) image_fit[rows, cols] = [False, True, False] elif fit_obj == 'ellipse': # drawing ellipse. rows, cols = ellipse_perimeter(aux_fit[0], aux_fit[1], aux_fit[2], aux_fit[3], aux_fit[4], shape=image_fit.shape) image_fit[rows, cols] = [False, True, False] except TypeError: print('No sufficient points on region #', num) return image_fit, data_fit
def grid_field_props( A, maxima='centroid', allProps=True, **kwargs): """ Extracts various measures from a spatial autocorrelogram Parameters ---------- A : array_like The spatial autocorrelogram (SAC) maxima : str, optional The method used to detect the peaks in the SAC. Legal values are 'single' and 'centroid'. Default 'centroid' allProps : bool, optional Whether to return a dictionary that contains the attempt to fit an ellipse around the edges of the central size peaks. See below Default True Returns ------- props : dict A dictionary containing measures of the SAC. Keys include: * gridness score * scale * orientation * coordinates of the peaks (nominally 6) closest to SAC centre * a binary mask around the extent of the 6 central fields * values of the rotation procedure used to calculate gridness * ellipse axes and angle (if allProps is True and the it worked) Notes ----- The output from this method can be used as input to the show() method of this class. When it is the plot produced will display a lot more informative. See Also -------- ephysiopy.common.binning.autoCorr2D() """ A_tmp = A.copy() A_tmp[~np.isfinite(A)] = -1 A_tmp[A_tmp <= 0] = -1 A_sz = np.array(np.shape(A)) # [STAGE 1] find peaks & identify 7 closest to centre if 'min_distance' in kwargs: min_distance = kwargs.pop('min_distance') else: min_distance = np.ceil(np.min(A_sz / 2) / 8.).astype(int) peak_idx, field_labels = _get_field_labels( A_tmp, neighbours=7, **kwargs) # a fcn for the labeled_comprehension function that returns # linear indices in A where the values in A for each label are # greater than half the max in that labeled region def fn(val, pos): return pos[val > (np.max(val)/2)] nLbls = np.max(field_labels) indices = ndimage.labeled_comprehension( A_tmp, field_labels, np.arange(0, nLbls), fn, np.ndarray, 0, True) # turn linear indices into coordinates coords = [np.unravel_index(i, np.shape(A)) for i in indices] half_peak_labels = np.zeros_like(A) for peak_id, coord in enumerate(coords): xc, yc = coord half_peak_labels[xc, yc] = peak_id # Get some statistics about the labeled regions # fieldPerim = bwperim(half_peak_labels) lbl_range = np.arange(0, nLbls) # meanRInLabel = ndimage.mean(A, half_peak_labels, lbl_range) # nPixelsInLabel = np.bincount(np.ravel(half_peak_labels.astype(int))) # sumRInLabel = ndimage.sum_labels(A, half_peak_labels, lbl_range) # maxRInLabel = ndimage.maximum(A, half_peak_labels, lbl_range) peak_coords = ndimage.maximum_position( A, half_peak_labels, lbl_range) # Get some distance and morphology measures centre = np.floor(np.array(np.shape(A))/2) centred_peak_coords = peak_coords - centre peak_dist_to_centre = np.hypot( centred_peak_coords.T[0], centred_peak_coords.T[1] ) closest_peak_idx = np.argsort(peak_dist_to_centre) central_peak_label = closest_peak_idx[0] closest_peak_idx = closest_peak_idx[1:np.min((7, len(closest_peak_idx)-1))] # closest_peak_idx should now the indices of the labeled 6 peaks # surrounding the central peak at the image centre scale = np.median(peak_dist_to_centre[closest_peak_idx]) orientation = np.nan orientation = grid_orientation( centred_peak_coords, closest_peak_idx) central_pt = peak_coords[central_peak_label] x = np.linspace(-central_pt[0], central_pt[0], A_sz[0]) y = np.linspace(-central_pt[1], central_pt[1], A_sz[1]) xv, yv = np.meshgrid(x, y, indexing='ij') dist_to_centre = np.hypot(xv, yv) # get the max distance of the half-peak width labeled fields # from the centre of the image max_dist_from_centre = 0 for peak_id, _coords in enumerate(coords): if peak_id in closest_peak_idx: xc, yc = _coords if np.any(xc) and np.any(yc): xc = xc - np.floor(A_sz[0]/2) yc = yc - np.floor(A_sz[1]/2) d = np.max(np.hypot(xc, yc)) if d > max_dist_from_centre: max_dist_from_centre = d # Set the outer bits and the central region of the SAC to nans # getting ready for the correlation procedure dist_to_centre[np.abs(dist_to_centre) > max_dist_from_centre] = 0 dist_to_centre[half_peak_labels == central_peak_label] = 0 dist_to_centre[dist_to_centre != 0] = 1 dist_to_centre = dist_to_centre.astype(bool) sac_middle = A.copy() sac_middle[~dist_to_centre] = np.nan if 'step' in kwargs.keys(): step = kwargs.pop('step') else: step = 30 try: gridscore, rotationCorrVals, rotationArr = gridness( sac_middle, step=step) except Exception: gridscore, rotationCorrVals, rotationArr = np.nan, np.nan, np.nan im_centre = central_pt if allProps: # attempt to fit an ellipse around the outer edges of the nearest # peaks to the centre of the SAC. First find the outer edges for # the closest peaks using a ndimages labeled_comprehension try: def fn2(val, pos): xc, yc = np.unravel_index(pos, A_sz) xc = xc - np.floor(A_sz[0]/2) yc = yc - np.floor(A_sz[1]/2) idx = np.argmax(np.hypot(xc, yc)) return xc[idx], yc[idx] ellipse_coords = ndimage.labeled_comprehension( A, half_peak_labels, closest_peak_idx, fn2, tuple, 0, True) ellipse_fit_coords = np.array([(x, y) for x, y in ellipse_coords]) from skimage.measure import EllipseModel E = EllipseModel() E.estimate(ellipse_fit_coords) im_centre = E.params[0:2] ellipse_axes = E.params[2:4] ellipse_angle = E.params[-1] ellipseXY = E.predict_xy(np.linspace(0, 2*np.pi, 50), E.params) # get the min containing circle given the eliipse minor axis from skimage.measure import CircleModel _params = im_centre _params.append(np.min(ellipse_axes)) circleXY = CircleModel().predict_xy( np.linspace(0, 2*np.pi, 50), params=_params) except (TypeError, ValueError): # non-iterable x and y i.e. ellipse coords fail ellipse_axes = None ellipse_angle = (None, None) ellipseXY = None circleXY = None # collect all the following keywords into a dict for output closest_peak_coords = np.array(peak_coords)[closest_peak_idx] dictKeys = ( 'gridscore', 'scale', 'orientation', 'closest_peak_coords', 'dist_to_centre', 'ellipse_axes', 'ellipse_angle', 'ellipseXY', 'circleXY', 'im_centre', 'rotationArr', 'rotationCorrVals') outDict = dict.fromkeys(dictKeys, np.nan) for thiskey in outDict.keys(): outDict[thiskey] = locals()[thiskey] # neat trick: locals is a dict holding all locally scoped variables return outDict
def field_props( A, min_dist=5, neighbours=2, prc=50, plot=False, ax=None, tri=False, verbose=True, **kwargs): """ Returns a dictionary of properties of the field(s) in a ratemap A Parameters ---------- A : array_like a ratemap (but could be any image) min_dist : float the separation (in bins) between fields for measures such as field distance to make sense. Used to partition the image into separate fields in the call to feature.peak_local_max neighbours : int the number of fields to consider as neighbours to any given field. Defaults to 2 prc : float percent of fields to consider ax : matplotlib.Axes user supplied axis. If None a new figure window is created tri : bool whether to do Delaunay triangulation between fields and add to plot verbose : bool dumps the properties to the console plot : bool whether to plot some output - currently consists of the ratemap A, the fields of which are outline in a black contour. Default False Returns ------- result : dict The properties of the field(s) in the input ratemap A """ from skimage.measure import find_contours from sklearn.neighbors import NearestNeighbors nan_idx = np.isnan(A) Ac = A.copy() Ac[np.isnan(A)] = 0 # smooth Ac more to remove local irregularities n = ny = 5 x, y = np.mgrid[-n:n+1, -ny:ny+1] g = np.exp(-(x**2/float(n) + y**2/float(ny))) g = g / g.sum() Ac = signal.convolve(Ac, g, mode='same') peak_idx, field_labels = _get_field_labels(Ac, **kwargs) nFields = np.max(field_labels) if neighbours > nFields: print('neighbours value of {0} > the {1} peaks found'.format( neighbours, nFields)) print('Reducing neighbours to number of peaks found') neighbours = nFields sub_field_mask = np.zeros((nFields, Ac.shape[0], Ac.shape[1])) sub_field_props = skimage.measure.regionprops( field_labels, intensity_image=Ac) sub_field_centroids = [] sub_field_size = [] for sub_field in sub_field_props: tmp = np.zeros(Ac.shape).astype(bool) tmp[sub_field.coords[:, 0], sub_field.coords[:, 1]] = True tmp2 = Ac > sub_field.max_intensity * (prc/float(100)) sub_field_mask[sub_field.label - 1, :, :] = np.logical_and( tmp2, tmp) sub_field_centroids.append(sub_field.centroid) sub_field_size.append(sub_field.area) # in bins sub_field_mask = np.sum(sub_field_mask, 0) contours = skimage.measure.find_contours(sub_field_mask, 0.5) # find the nearest neighbors to the peaks of each sub-field nbrs = NearestNeighbors(n_neighbors=neighbours, algorithm='ball_tree').fit(peak_idx) distances, _ = nbrs.kneighbors(peak_idx) mean_field_distance = np.mean(distances[:, 1:neighbours]) nValid_bins = np.sum(~nan_idx) # calculate the amount of out of field firing A_non_field = np.zeros_like(A) * np.nan A_non_field[~sub_field_mask.astype(bool)] = A[ ~sub_field_mask.astype(bool)] A_non_field[nan_idx] = np.nan out_of_field_firing_prc = (np.count_nonzero( A_non_field > 0) / float(nValid_bins)) * 100 Ac[np.isnan(A)] = np.nan """ get some stats about the field ellipticity """ ellipse_ratio = np.nan _, central_field, _ = limit_to_one(A, prc=50) contour_coords = find_contours(central_field, 0.5) from skimage.measure import EllipseModel E = EllipseModel() E.estimate(contour_coords[0]) ellipse_axes = E.params[2:4] ellipse_ratio = np.min(ellipse_axes) / np.max(ellipse_axes) """ using the peak_idx values calculate the angles of the triangles that make up a delaunay tesselation of the space if the calc_angles arg is in kwargs """ if 'calc_angs' in kwargs.keys(): angs = calc_angs(peak_idx) else: angs = None props = { 'Ac': Ac, 'Peak_rate': np.nanmax(A), 'Mean_rate': np.nanmean(A), 'Field_size': np.mean(sub_field_size), 'Pct_bins_with_firing': (np.sum( sub_field_mask) / nValid_bins) * 100, 'Out_of_field_firing_prc': out_of_field_firing_prc, 'Dist_between_fields': mean_field_distance, 'Num_fields': float(nFields), 'Sub_field_mask': sub_field_mask, 'Smoothed_map': Ac, 'field_labels': field_labels, 'Peak_idx': peak_idx, 'angles': angs, 'contours': contours, 'ellipse_ratio': ellipse_ratio} if verbose: print('\nPercentage of bins with firing: {:.2%}'.format( np.sum(sub_field_mask) / nValid_bins)) print('Percentage out of field firing: {:.2%}'.format( np.count_nonzero(A_non_field > 0) / float(nValid_bins))) print('Peak firing rate: {:.3} Hz'.format(np.nanmax(A))) print('Mean firing rate: {:.3} Hz'.format(np.nanmean(A))) print('Number of fields: {0}'.format(nFields)) print('Mean field size: {:.5} cm'.format(np.mean(sub_field_size))) print('Mean inter-peak distance between \ fields: {:.4} cm'.format(mean_field_distance)) return props
class DFTanalyzer: '''Class to provide the 2D-DFT (shifted) of an image and a derived ellipse model representing the the frequencies of interest. Based on that model, several parameters for image analysis are provided.''' def __init__(self, img): self.dft = fft.fftshift(fft.fft2(img)) self.contour = None self.ellipse = None self.wavelength = None self.low_pass = None self.filtered_img = None @property def abs_log_dft(self): '''Return log-transformed DFT.''' return np.abs(np.log(self.dft)) def fit_model(self, cut_percent, gauss_sigma): '''Fit an ellipse model to a contour of a certain value in the filtered DFT.''' #Fit ellipse model al_dft = self.abs_log_dft gauss_dft = gaussian(al_dft, gauss_sigma) contour_value = gauss_dft.min() + ( (gauss_dft.max() - gauss_dft.min()) * cut_percent / 100) contours = find_contours(gauss_dft, contour_value) assert len(contours) == 1 self.contour = contours[0] self.ellipse = EllipseModel() self.ellipse.estimate(self.contour[:, ::-1]) center = tuple([x / 2 for x in self.dft.shape]) offset = euclidean(center, (self.ellipse.params[1], self.ellipse.params[0])) half_diagonal = sqrt(sum((x**2 for x in self.dft.shape))) / 2 assert (offset / half_diagonal) <= 0.03 #derive wavelength and texture parameters xy_points = self.ellipse.predict_xy( np.linspace(0, 2 * np.pi, 4 * self.ellipse.params[0])) max_x = round(xy_points[:, 0].max()) min_y = round(xy_points[:, 1].min()) wavelength_x = self.dft.shape[1] / (max_x - center[1]) wavelength_y = self.dft.shape[0] / (center[0] - min_y) self.wavelength = round((wavelength_x + wavelength_y) / 2) @property def texture_radius(self): if self.wavelength is not None: return round(self.wavelength / 2) else: return None @property def min_patch_size(self): if self.wavelength is not None: return round(self.texture_radius**2 * pi) else: return None def apply_lowpass(self, upper, lower, gauss_sigma=1): '''Filter unwanted high frequencies based on the ellipse model.''' cx, cy, a, b, theta = self.ellipse.params self.low_pass = np.zeros_like(self.dft, dtype=np.float64) + lower rr, cc = draw.ellipse(cy, cx, b, a, self.low_pass.shape, (theta * -1)) self.low_pass[rr, cc] = upper self.low_pass = gaussian(self.low_pass, gauss_sigma) filtered_dft = self.dft * self.low_pass self.filtered_img = np.abs(fft.ifft2(fft.ifftshift(filtered_dft)))
def test_ellipse_model_invalid_input(): assert_raises(ValueError, EllipseModel().estimate, np.empty((5, 3)))
tmp_y = 0 - np.sin(theta) * radiuses[axis_count][l] points_x.append(tmp_x) points_y.append(tmp_y) points.append([tmp_x, tmp_y]) #ell_patch = Ellipse((xc, yc), 2*a, 2*b, theta*180/np.pi, edgecolor='red', facecolor='none') #axs[i][j].add_patch(ell_patch) polygons_points.append([points_x, points_y]) poligon_patch = mPolygon(np.array([points_x, points_y]).T, color='tab:red', alpha=0.5) axs[i][j].add_patch(poligon_patch) ellipse_model = EllipseModel() ellipse_model.estimate(np.array(points)) xc, yc, a, b, theta = ellipse_model.params z_centers_curve.append(xc) y_centers_curve.append(yc) x_centers_curve.append(tmp_counter) tmp_counter += 1 radiuses_axes_ellipse.append([a, b]) angles_axes_ellipse.append(theta) print("center = ", (xc, yc)) print("angle of rotation = ", theta) print("axes = ", (a, b)) ellipse1 = create_ellipse( (y_centers_curve[axis_count], z_centers_curve[axis_count]), (a, b), theta)
model = model.to(device) model.eval() counter = 0 # os.makedirs('vedb_test/labels/',exist_ok=True) # os.makedirs('vedb_test/output/',exist_ok=True) # os.makedirs('vedb_test/mask/',exist_ok=True) labels = [] # out_video_file = ("{}/{}_{}_{}_{}_test.mp4").format(save_directory, session_id,method,gamma, eye_id) # print('output video file: {}'.format(out_video_file)) # fourcc = 'mp4v' # out = cv2.VideoWriter(out_video_file,cv2.VideoWriter_fourcc(*fourcc), 30, (1200,400)) ellipse_model = EllipseModel() with torch.no_grad(): #for i, batchdata in tqdm(enumerate(testloader),total=len(testloader)): for i in range(start_index, end_index, 4): # Read the next frame from the video. raw_image = vid.get_data(i) # Switch the color channels since opencv reads the frames under BGR and the imageio uses RGB format raw_image[:, :, [0, 2]] = raw_image[:, :, [2, 0]] # Convert the image into grayscale gray = cv2.cvtColor(raw_image, cv2.COLOR_BGR2GRAY) pilimg = Image.fromarray(raw_image).convert("L") if "eye0" in video_file: pilimg = pilimg.transpose(PIL.Image.FLIP_TOP_BOTTOM)
def define_food_patches(self, n_patches): # Function for defining foodpatches, 0, 1 or 2 are valid args for n_patches # Grab a frame to draw on & display it ####################################################################### self._load_video_frame() self.display_frame = self.frame cv2.namedWindow('image') # Define callback to draw index dots around patches cv2.setMouseCallback('image', self.draw_dot) if n_patches == 0: # Skip routine if no food patches self.no_patch = True pass else: # While the number of defined points < 5*n_patches, # click, draw and log the coordinates of points while (len(self.points) < 5 * n_patches): if len(self.points) == 5: self.draw_color = (255, 0, 0) self.index = 1 #Update frame with index-labelled dot and re-display cv2.imshow('image', self.display_frame) cv2.moveWindow('image', 10, 10) k = cv2.waitKey(1) & 0xFF if k == ord('m'): break elif k == 27: break # Return click-selected points grouped by unique food patch if len(self.points) == 5: self.segmented_points = self.points elif len(self.points) == 10: self.segmented_points = [[e for e in self.points[:5]], [e for e in self.points[5:]]] point_array = np.asarray(self.segmented_points) if n_patches == 1: point_array = np.expand_dims(point_array, axis=0) # After points have been selected, draw ellipse for verification # If bad ellipse, should be re-selected colors = [(0, 0, 255), (255, 0, 0)] # Simultaneously create a logical 1/0 mask for later determination of food patch pixels self.food_patch_mask = np.zeros(self.display_frame.shape, dtype=np.uint8) # Init empty list for food patch centroids self.food_patch_centroids = [] for i in range(n_patches): xy = EllipseModel() xy.estimate(point_array[i]) xc, yc, a, b, theta = int(xy.params[0]), int( xy.params[1]), int(xy.params[2]), int(xy.params[3]), int( np.rad2deg(xy.params[4])) self.frame = cv2.ellipse(self.display_frame, (xc, yc), (a, b), theta, 0, 360, colors[i], 1) # Mask is same food patch drawing with filled in ellipses (note -1 argument below) in white # This creates a logical mask the size of frame, non-patch pixels = 0, else patch pixels = 1 (black/white) self.food_patch_mask = cv2.ellipse(self.food_patch_mask, (xc, yc), (a, b), theta, 0, 360, (255, 255, 255), -1) # Cast the centroids into arrays and append them to centroid list self.food_patch_centroids.append(np.asarray([int(cx), int(cy)])) # Draw display frame with new ellipses cv2.imshow('image', self.display_frame) cv2.moveWindow('image', 10, 10) cv2.waitKey(0) # Clean up cv2.destroyAllWindows()