def setUpClass(cls): cls.size = validate_tuple(cls.size, cls.ndim) if not hasattr(cls, 'diameter'): cls.diameter = tuple([int(s * 4) for s in cls.size]) else: cls.diameter = validate_tuple(cls.diameter, cls.ndim) cls.separation = tuple([d * 2 for d in cls.diameter]) cls.radius = tuple([int(d // 2) for d in cls.diameter]) cls.isotropic = np.all([cls.diameter[1:] == cls.diameter[:-1]]) cls.pos_columns = ['z', 'y', 'x'][-cls.ndim:] cls.pos_columns_err = [col + '_std' for col in cls.pos_columns] if cls.isotropic: cls.size_columns = ['size'] else: cls.size_columns = ['size_z', 'size_y', 'size_x'][-cls.ndim:] cls.names = cls.pos_columns + ['signal'] + cls.size_columns # cls.rtol = [None] * len(cls.im.pos_columns) # cls.atol = [0.1] * len(cls.im.pos_columns) cls.bounds = dict() if not hasattr(cls, 'param_mode'): cls.param_mode = dict(signal='var', size='const') if not hasattr(cls, 'feat_kwargs'): cls.feat_kwargs = dict() if not hasattr(cls, 'param_val'): cls.param_val = dict()
def __init__(self, shape, size, dtype=np.uint8, saturation=None, hard_radius=None, signal=None, noise=0, feat_func=feat_gauss, **feat_kwargs): self.ndim = len(shape) self.shape = shape self.dtype = dtype self.image = Frame(np.zeros(shape, dtype=dtype)) self.size = validate_tuple(size, self.ndim) self.isotropic = np.all([self.size[1:] == self.size[:-1]]) self.feat_func = feat_func self.feat_kwargs = feat_kwargs self.noise = noise if saturation is None and np.issubdtype(dtype, np.integer): self.saturation = np.iinfo(dtype).max elif saturation is None and np.issubdtype(dtype, np.float): self.saturation = 1 else: self.saturation = saturation if signal is None: self.signal = self.saturation else: self.signal = signal self.center = tuple([s // 2 for s in shape]) self.hard_radius = hard_radius self._coords = [] self.pos_columns = ['z', 'y', 'x'][-self.ndim:] if self.isotropic: self.size_columns = ['size'] else: self.size_columns = ['size_z', 'size_y', 'size_x'][-self.ndim:]
def draw_array(N, size, separation=None, ndim=2, **kwargs): """ Generates an image with an array of features. Each feature has a random offset of +- 0.5 pixel. Parameters ---------- N : int the number of features size : number the size of the feature (meaning depends on feature, for feat_gauss, it is the radius of gyration) separation : number or tuple the desired separation between features kwargs : keyword arguments are passed to draw_spots See also -------- draw_spots draw_feature """ size = validate_tuple(size, ndim) if separation is None: separation = tuple([sz * 8 for sz in size]) margin = separation Nsqrt = int(N**(1 / ndim) + 0.9999) pos = np.meshgrid(*[np.arange(0, s * Nsqrt, s) for s in separation], indexing='ij') pos = np.array([p.ravel() for p in pos], dtype=float).T[:N] + margin pos += (np.random.random(pos.shape) - 0.5) #randomize subpixel location shape = tuple(np.max(pos, axis=0).astype(int) + margin) return pos, draw_spots(shape, pos, size, **kwargs)
def draw_array(N, diameter, separation=None, ndim=2, **kwargs): """ Generates an image with an array of features. Each feature has a random offset of +- 0.5 pixel. Parameters ---------- N : int the number of features diameter : number or tuple the sizes of the box that will be used per feature. The actual feature 'size' is determined by feat_func and kwargs given to feat_func. separation : number or tuple the desired separation between features kwargs : see draw_spots See also -------- draw_spots """ diameter = validate_tuple(diameter, ndim) if separation is None: separation = tuple([d * 2 for d in diameter]) margin = separation Nsqrt = int(N**(1/ndim) + 0.9999) pos = np.meshgrid(*[np.arange(0, s * Nsqrt, s) for s in separation], indexing='ij') pos = np.array([p.ravel() for p in pos], dtype=np.float).T[:N] + margin pos += (np.random.random(pos.shape) - 0.5) #randomize subpixel location shape = tuple(np.max(pos, axis=0).astype(np.int) + margin) return pos, draw_spots(shape, pos, diameter, **kwargs)
def draw_array(N, size, separation=None, ndim=2, **kwargs): """ Generates an image with an array of features. Each feature has a random offset of +- 0.5 pixel. Parameters ---------- N : int the number of features size : number the size of the feature (meaning depends on feature, for feat_gauss, it is the radius of gyration) separation : number or tuple the desired separation between features kwargs : keyword arguments are passed to draw_spots See also -------- draw_spots draw_feature """ size = validate_tuple(size, ndim) if separation is None: separation = tuple([sz * 8 for sz in size]) margin = separation Nsqrt = int(N**(1/ndim) + 0.9999) pos = np.meshgrid(*[np.arange(0, s * Nsqrt, s) for s in separation], indexing='ij') pos = np.array([p.ravel() for p in pos], dtype=np.float).T[:N] + margin pos += (np.random.random(pos.shape) - 0.5) #randomize subpixel location shape = tuple(np.max(pos, axis=0).astype(np.int) + margin) return pos, draw_spots(shape, pos, size, **kwargs)
def gen_random_locations(shape, count, margin=0): """ Generates `count` number of positions within `shape`. If a `margin` is given, positions will be inside this margin. Margin may be tuple-valued. """ margin = validate_tuple(margin, len(shape)) np.random.seed(0) pos = [np.random.uniform(round(m), round(s - m), count) for (s, m) in zip(shape, margin)] return np.array(pos).T
def draw_feature(image, position, diameter, max_value=None, feat_func=feat_gauss, ecc=None, **kwargs): """ Draws a radial symmetric feature and adds it to the image at given position. The given function will be evaluated at each pixel coordinate, no averaging or convolution is done. Parameters ---------- image : ndarray image to draw features on position : iterable coordinates of feature position diameter : number defines the box that will be drawn on max_value : number maximum feature value. should be much less than the max value of the image dtype, to avoid pixel wrapping at overlapping features feat_func : function. Default: feat_gauss function f(r) that takes an ndarray of radius values and returns intensity values <= 1 ecc : positive number, optional eccentricity of feature, defined only in 2D. Identical to setting diameter to (diameter / (1 - ecc), diameter * (1 - ecc)) kwargs : keyword arguments are passed to feat_func """ if len(position) != image.ndim: raise ValueError("Number of position coordinates should match image" " dimensionality.") diameter = validate_tuple(diameter, image.ndim) if ecc is not None: if len(diameter) != 2: raise ValueError("Eccentricity is only defined in 2 dimensions") if diameter[0] != diameter[1]: raise ValueError("Diameter is already anisotropic; eccentricity is" " not defined.") diameter = (diameter[0] / (1 - ecc), diameter[1] * (1 - ecc)) radius = tuple([d / 2 for d in diameter]) if max_value is None: max_value = np.iinfo(image.dtype).max - 3 rect = [] vectors = [] for (c, r, lim) in zip(position, radius, image.shape): if (c >= lim) or (c < 0): raise ValueError("Position outside of image.") lower_bound = max(int(np.floor(c - r)), 0) upper_bound = min(int(np.ceil(c + r + 1)), lim) rect.append(slice(lower_bound, upper_bound)) vectors.append(np.arange(lower_bound - c, upper_bound - c) / r) coords = np.meshgrid(*vectors, indexing='ij', sparse=True) r = np.sqrt(np.sum(np.array(coords)**2, axis=0)) spot = max_value * feat_func(r, **kwargs) image[rect] += spot.astype(image.dtype)
def gen_random_locations(shape, count, margin=0): """ Generates `count` number of positions within `shape`. If a `margin` is given, positions will be inside this margin. Margin may be tuple-valued. """ margin = validate_tuple(margin, len(shape)) np.random.seed(0) pos = [np.random.randint(round(m), round(s - m), count) for (s, m) in zip(shape, margin)] return np.array(pos).T
def gen_connected_locations(shape, count, separation, margin=0): """ Generates `count` number of positions within `shape` that are touching. If a `margin` is given, positions will be inside this margin. Margin may be tuple-valued. """ margin = validate_tuple(margin, len(shape)) center_pos = margin + np.round(np.subtract(shape, margin) / 2.0) indices = np.arange(0, count, 1) - np.round(count / 2.0) pos = np.array( [np.add(center_pos, np.multiply(i, separation)) for i in indices]) return pos
def setUpClass(cls): super(RefineTsts, cls).setUpClass() cls.size = validate_tuple(cls.size, cls.ndim) if not hasattr(cls, 'diameter'): cls.diameter = tuple([int(s * 4) for s in cls.size]) else: cls.diameter = validate_tuple(cls.diameter, cls.ndim) cls.separation = tuple([d * 2 for d in cls.diameter]) cls.radius = tuple([int(d // 2) for d in cls.diameter]) cls.isotropic = np.all([cls.diameter[1:] == cls.diameter[:-1]]) cls.pos_columns = ['z', 'y', 'x'][-cls.ndim:] cls.pos_columns_err = [col + '_std' for col in cls.pos_columns] if cls.isotropic: cls.size_columns = ['size'] else: cls.size_columns = ['size_z', 'size_y', 'size_x'][-cls.ndim:] cls.names = cls.pos_columns + ['signal'] + cls.size_columns cls.bounds = dict() if not hasattr(cls, 'param_mode'): cls.param_mode = dict(signal='var', size='const') if not hasattr(cls, 'feat_kwargs'): cls.feat_kwargs = dict() if not hasattr(cls, 'param_val'): cls.param_val = dict()
def eliminate_overlapping_locations(f, separation): """ Makes sure that no position is within `separation` from each other, by deleting one of the that are to close to each other. """ separation = validate_tuple(separation, f.shape[1]) assert np.greater(separation, 0).all() # Rescale positions, so that pairs are identified below a distance of 1. f = f / separation while True: duplicates = cKDTree(f, 30).query_pairs(1) if len(duplicates) == 0: break to_drop = [] for pair in duplicates: to_drop.append(pair[1]) f = np.delete(f, to_drop, 0) return f * separation
def __init__(self, shape, size, dtype=np.uint8, saturation=None, hard_radius=None, signal=None, noise=0, feat_func=feat_gauss, **feat_kwargs): self.ndim = len(shape) self.shape = shape self.dtype = dtype self.image = np.zeros(shape, dtype=dtype) if _Frame is not None: self.image = _Frame(self.image) self.size = validate_tuple(size, self.ndim) self.isotropic = np.all([self.size[1:] == self.size[:-1]]) self.feat_func = feat_func self.feat_kwargs = feat_kwargs self.noise = noise if saturation is None and np.issubdtype(dtype, np.integer): self.saturation = np.iinfo(dtype).max elif saturation is None and np.issubdtype(dtype, np.floating): self.saturation = 1 else: self.saturation = saturation if signal is None: self.signal = self.saturation else: self.signal = signal self.center = tuple([s // 2 for s in shape]) self.hard_radius = hard_radius self._coords = [] self.pos_columns = ['z', 'y', 'x'][-self.ndim:] if self.isotropic: self.size_columns = ['size'] else: self.size_columns = ['size_z', 'size_y', 'size_x'][-self.ndim:]
def draw_feature(image, position, size, max_value=None, feat_func='gauss', ecc=None, mask_diameter=None, **kwargs): """ Draws a radial symmetric feature and adds it to the image at given position. The given function will be evaluated at each pixel coordinate, no averaging or convolution is done. Parameters ---------- image : ndarray image to draw features on position : iterable coordinates of feature position size : number the size of the feature (meaning depends on feature, for feat_gauss, it is the radius of gyration) max_value : number maximum feature value. should be much less than the max value of the image dtype, to avoid pixel wrapping at overlapping features feat_func : {'gauss', 'disc', 'ring'} or callable Default: 'gauss' When callable is given, it should take an ndarray of radius values and it should return intensity values <= 1 ecc : positive number, optional eccentricity of feature, defined only in 2D. Identical to setting diameter to (diameter / (1 - ecc), diameter * (1 - ecc)) mask_diameter : defines the box that will be drawn on. Default 4 * size. kwargs : keyword arguments are passed to feat_func See also -------- draw_spots """ if len(position) != image.ndim: raise ValueError("Number of position coordinates should match image" " dimensionality.") if not hasattr(feat_func, '__call__'): feat_func = feat_dict[feat_func] size = validate_tuple(size, image.ndim) if ecc is not None: if len(size) != 2: raise ValueError("Eccentricity is only defined in 2 dimensions") if size[0] != size[1]: raise ValueError("Diameter is already anisotropic; eccentricity is" " not defined.") size = (size[0] / (1 - ecc), size[1] * (1 - ecc)) if mask_diameter is None: mask_diameter = tuple([s * 4 for s in size]) else: mask_diameter = validate_tuple(mask_diameter, image.ndim) if max_value is None: max_value = np.iinfo(image.dtype).max - 3 rect = [] vectors = [] for (c, s, m, lim) in zip(position, size, mask_diameter, image.shape): if (c >= lim) or (c < 0): raise ValueError("Position outside of image.") lower_bound = max(int(np.floor(c - m / 2)), 0) upper_bound = min(int(np.ceil(c + m / 2 + 1)), lim) rect.append(slice(lower_bound, upper_bound)) vectors.append(np.arange(lower_bound - c, upper_bound - c) / s) coords = np.meshgrid(*vectors, indexing='ij') r = np.sqrt(np.sum(np.array(coords)**2, axis=0)) spot = max_value * feat_func(r, ndim=image.ndim, **kwargs) image[tuple(rect)] += spot.astype(image.dtype)
def link(self, *args, **kwargs): kwargs.update(self.linker_opts) return link(args[0], validate_tuple(args[1], 2), *args[2:], **kwargs)
def draw_feature(image, position, size, max_value=None, feat_func='gauss', ecc=None, mask_diameter=None, **kwargs): """ Draws a radial symmetric feature and adds it to the image at given position. The given function will be evaluated at each pixel coordinate, no averaging or convolution is done. Parameters ---------- image : ndarray image to draw features on position : iterable coordinates of feature position size : number the size of the feature (meaning depends on feature, for feat_gauss, it is the radius of gyration) max_value : number maximum feature value. should be much less than the max value of the image dtype, to avoid pixel wrapping at overlapping features feat_func : {'gauss', 'disc', 'ring'} or callable Default: 'gauss' When callable is given, it should take an ndarray of radius values and it should return intensity values <= 1 ecc : positive number, optional eccentricity of feature, defined only in 2D. Identical to setting diameter to (diameter / (1 - ecc), diameter * (1 - ecc)) mask_diameter : defines the box that will be drawn on. Default 8 * size. kwargs : keyword arguments are passed to feat_func """ if len(position) != image.ndim: raise ValueError("Number of position coordinates should match image" " dimensionality.") if not hasattr(feat_func, '__call__'): feat_func = feat_dict[feat_func] size = validate_tuple(size, image.ndim) if ecc is not None: if len(size) != 2: raise ValueError("Eccentricity is only defined in 2 dimensions") if size[0] != size[1]: raise ValueError("Diameter is already anisotropic; eccentricity is" " not defined.") size = (size[0] / (1 - ecc), size[1] * (1 - ecc)) if mask_diameter is None: mask_diameter = tuple([s * 8 for s in size]) else: mask_diameter = validate_tuple(mask_diameter, image.ndim) if max_value is None: max_value = np.iinfo(image.dtype).max - 3 rect = [] vectors = [] for (c, s, m, lim) in zip(position, size, mask_diameter, image.shape): if (c >= lim) or (c < 0): raise ValueError("Position outside of image.") lower_bound = max(int(np.floor(c - m / 2)), 0) upper_bound = min(int(np.ceil(c + m / 2 + 1)), lim) rect.append(slice(lower_bound, upper_bound)) vectors.append(np.arange(lower_bound - c, upper_bound - c) / s) coords = np.meshgrid(*vectors, indexing='ij', sparse=True) r = np.sqrt(np.sum(np.array(coords)**2, axis=0)) spot = max_value * feat_func(r, ndim=image.ndim, **kwargs) image[rect] += spot.astype(image.dtype)