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_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 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(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 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_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_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
fig, ax = plt.subplots(1, 2) ax = ax.ravel() red_ = foo[idx] results = np.zeros_like(red_) x_, y_ = m.collect(red_) 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] results[x_, y_] = 1 circle = CircleModel() circle.estimate(np.c_[x_, y_]) thetas = np.linspace(0, 2 * np.pi, 200) XC, YC, R = circle.params x = XC + R * np.sin(thetas) y = YC + R * np.cos(thetas) ax[0].imshow(red_) ax[1].imshow(results) ax[0].plot(y, x, color='magenta') ax[1].plot(y, x, color='magenta') plt.show() exit() import tqdm
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()