def test_circle_model_residuals(): model = CircleModel() model.params = (0, 0, 5) assert_almost_equal(abs(model.residuals(np.array([[5, 0]]))), 0) assert_almost_equal(abs(model.residuals(np.array([[6, 6]]))), np.sqrt(2 * 6**2) - 5) assert_almost_equal(abs(model.residuals(np.array([[10, 0]]))), 5)
class RadiusEstimator(RadialFinder): '''Estimate vessel radius by fitting a circle''' def __init__(self, img, threshold=0.2): # The main idea of the algo is based on assumed radiual "symmetry" # of the result. So when we fit the circle we don't want to work with # all the pixels by just the "rim" ones for each angle super(RadiusEstimator, self).__init__( f=lambda x: x, # For each ray, how do you find a rim? reduction=lambda x: reduce_last(x, threshold * np.max(x)), img=img) # And we will be fitting a circle self.model = CircleModel() def __call__(self, img): '''Estimate for the given image''' x_, y_ = self.collect(img) ii, = np.where( np.logical_and(np.logical_and(x_ > 10, x_ < 80), np.logical_and(y_ > 10, y_ < 80))) x_, y_ = x_[ii], y_[ii] self.model.estimate(np.c_[x_, y_]) # Give back the circle parameters return self.model.params
def test_circle_model_predict(): model = CircleModel() r = 5 model.params = (0, 0, r) t = np.arange(0, 2 * np.pi, np.pi / 2) xy = np.array(((5, 0), (0, 5), (-5, 0), (0, -5))) assert_almost_equal(xy, model.predict_xy(t))
def test_circle_model_int_overflow(): xy = np.array([[1, 0], [0, 1], [-1, 0], [0, -1]], dtype=np.int32) xy += 500 model = CircleModel() model.estimate(xy) assert_almost_equal(model.params, [500, 500, 1])
def __init__(self, img, threshold=0.2): # The main idea of the algo is based on assumed radiual "symmetry" # of the result. So when we fit the circle we don't want to work with # all the pixels by just the "rim" ones for each angle super(RadiusEstimator, self).__init__( f=lambda x: x, # For each ray, how do you find a rim? reduction=lambda x: reduce_last(x, threshold * np.max(x)), img=img) # And we will be fitting a circle self.model = CircleModel()
def test_circle_model_insufficient_data(): model = CircleModel() with expected_warnings(["Input data does not contain enough significant"]): model.estimate(np.array([[1, 2], [3, 4]])) with expected_warnings(["Input data does not contain enough significant"]): model.estimate(np.ones((6, 2))) with expected_warnings(["Input data does not contain enough significant"]): model.estimate(np.array([[0, 0], [1, 1], [2, 2]]))
def fit(self, image): B = image > 0.5 * np.max(image) #+3*np.std(image) circle = CircleModel() # Need a better model here hull = array_convex_hull(B) x_, y_ = hull.T x_ = np.r_[x_, x_[0]] y_ = np.r_[y_, y_[0]] circle.estimate(np.c_[x_, y_]) # Plot ellipse XC, YC, R = circle.params x = XC + R * np.sin(self.thetas) y = YC + R * np.cos(self.thetas) self.params = (XC, YC, R) return B, np.c_[x, y]
def test_ransac_shape(): # generate original data without noise model0 = CircleModel() model0.params = (10, 12, 3) t = np.linspace(0, 2 * np.pi, 1000) data0 = model0.predict_xy(t) # add some faulty data outliers = (10, 30, 200) data0[outliers[0], :] = (1000, 1000) data0[outliers[1], :] = (-50, 50) data0[outliers[2], :] = (-100, -10) # estimate parameters of corrupted data model_est, inliers = ransac(data0, CircleModel, 3, 5, random_state=1) # test whether estimated parameters equal original parameters assert_almost_equal(model0.params, model_est.params) for outlier in outliers: assert outlier not in inliers
def test_ransac_shape(): # generate original data without noise model0 = CircleModel() model0.params = (10, 12, 3) t = np.linspace(0, 2 * np.pi, 1000) data0 = model0.predict_xy(t) # add some faulty data outliers = (10, 30, 200) data0[outliers[0], :] = (1000, 1000) data0[outliers[1], :] = (-50, 50) data0[outliers[2], :] = (-100, -10) # estimate parameters of corrupted data model_est, inliers = ransac(data0, CircleModel, 3, 5, random_state=1) # test whether estimated parameters equal original parameters assert_equal(model0.params, model_est.params) for outlier in outliers: assert outlier not in inliers
def fit(self, image): B = np.zeros_like(image) # Radial sample for maximum x_, y_ = self.m.collect(image) # We are only after points that are not too far ii, = np.where( np.logical_and(np.logical_and(x_ > 10, x_ < 80), np.logical_and(y_ > 10, y_ < 80))) x_ = x_[ii] y_ = y_[ii] B[x_, y_] = 1 circle = CircleModel() circle.estimate(np.c_[x_, y_]) XC, YC, R = circle.params x = XC + R * np.sin(self.thetas) y = YC + R * np.cos(self.thetas) self.params = (XC, YC, R) return B, np.c_[x, y]
def test_circle_model_estimate(): # generate original data without noise model0 = CircleModel() model0.params = (10, 12, 3) t = np.linspace(0, 2 * np.pi, 1000) 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 = CircleModel() model_est.estimate(data) # test whether estimated parameters almost equal original parameters assert_almost_equal(model0.params, model_est.params, 0)
def test_circle_model_estimate(): # generate original data without noise model0 = CircleModel() model0.params = (10, 12, 3) t = np.linspace(0, 2 * np.pi, 1000) 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 = CircleModel() model_est.estimate(data) # test whether estimated parameters almost equal original parameters assert_almost_equal(model0.params, model_est.params, 1)
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
hsv = rgb2hsv(small) deviations = [] for color in (0, 1, 2): masked = ma.array(hsv[:, :, color], mask=~canvas.astype(np.bool)) deviations.append(masked.std()) mole.h = deviations[0] mole.s = deviations[1] mole.v = deviations[2] # In[104]: from skimage.measure import CircleModel circle_model = CircleModel() circle_model.estimate(contours[0]) symmetry = circle_model.residuals(contours[0]).mean() mole.symmetry = symmetry # In[125]: diameter = (19.05 / coin_radius) * (circle_model.params[2]) mole.diameter = diameter mole.status = 100 db.session.merge(mole) db.session.commit()
def test_circle_model_invalid_input(): with testing.raises(ValueError): CircleModel().estimate(np.empty((5, 3)))
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 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 test_circle_model_invalid_input(): assert_raises(ValueError, CircleModel().estimate, np.empty((5, 3)))
time_idx = np.arange(len(time)) my_times = split_jobs(comm, time_idx) results = [] fig, ax = plt.subplots(1, 3, figsize=(20, 14)) for i in tqdm.tqdm(my_times): ax[1].set_title('Time {} s'.format(i * 0.33)) image = red_nseq[i] #hist, hist_centers = histogram(image, nbins=10) #plt.figure() #plt.plot(hist_centers, hist) B = image > 0.5 * np.max(image) #+3*np.std(image) ellipse, circle = EllipseModel(), CircleModel() hull = array_convex_hull(B) x_, y_ = hull.T x_ = np.r_[x_, x_[0]] y_ = np.r_[y_, y_[0]] ellipse.estimate(np.c_[x_, y_]) circle.estimate(np.c_[x_, y_]) # Plot original ax[0].imshow(red_nseq_bk[i]) # Auxiliary ax[1].imshow(B) blue = np.zeros_like(image) ax[2].imshow(np.stack([red_nseq_bk[i], green_nseq[i], blue], axis=2))