def profile_line(img, src=None, dst=None, linewidth=1, order=1, mode="constant", cval=0.0, constrain=True, **kargs): """Wrapper for sckit-image method of the same name to get a line_profile. Parameters: img(ImageArray): Image data to take line section of src, dst (2-tuple of int or float): start and end of line profile. If the co-ordinates are given as intergers then they are assumed to be pxiel co-ordinates, floats are assumed to be real-space co-ordinates using the embedded metadata. linewidth (int): the wideth of the profile to be taken. order (int 1-3): Order of interpolation used to find image data when not aligned to a point mode (str): How to handle data outside of the image. cval (float): The constant value to assume for data outside of the image is mode is "constant" constrain (bool): Ensure the src and dst are within the image (default True). Returns: A :py:class:`Stoner.Data` object containing the line profile data and the metadata from the image. """ scale = img.get("MicronsPerPixel", 1.0) r, c = img.shape if src is None and dst is None: if "x" in kargs: src = (kargs["x"], 0) dst = (kargs["x"], r) if "y" in kargs: src = (0, kargs["y"]) dst = (c, kargs["y"]) if isinstance(src, float): src = (src, src) if isinstance(dst, float): dst = (dst, dst) dst = _scale(dst, scale) src = _scale(src, scale) if not istuple(src, int, int): raise ValueError("src co-ordinates are not a 2-tuple of ints.") if not istuple(dst, int, int): raise ValueError("dst co-ordinates are not a 2-tuple of ints.") if constrain: fix = lambda x, mx: int(round(sorted([0, x, mx])[1])) r, c = img.shape src = list(src) src = (fix(src[0], r), fix(src[1], c)) dst = (fix(dst[0], r), fix(dst[1], c)) result = measure.profile_line(img, src, dst, linewidth, order, mode, cval) points = measure.profile._line_profile_coordinates(src, dst, linewidth)[:, :, 0] ret = Data() ret.data = points.T ret.setas = "xy" ret &= np.sqrt(ret.x ** 2 + ret.y ** 2) * scale ret &= result ret.column_headers = ["X", "Y", "Distance", "Intensity"] ret.setas = "..xy" ret.metadata = img.metadata.copy() return ret
def normalise(im, scale=None, sample=None, limits=(0.0, 1.0)): """Norm alise the data to a fixed scale. Keyword Arguements: scale (2-tuple): The range to scale the image to, defaults to -1 to 1. saple (box): Only use a section of the input image to calculate the new scale over. limits (low,high): Take the input range from the *high* and *low* fraction of the input when sorted. Returns: A scaled version of the data. The ndarray min and max methods are used to allow masked images to be operated on only on the unmasked areas. Notes: The *sample* keyword controls the area in which the range of input values is calculated, the actual scaling is done on the whole image. The *limits* parameter is used to set the input scale being normalised from - if an image has a few outliers then this setting can be used to clip the input range before normalising. The parameters in the limit are the values at the *low* and *high* fractions of the cumulative distribution functions. """ mask = im.mask cls = im.__class__ im = im.astype(float) if scale is None: scale = (-1.0, 1.0) if sample is not None: section = im[im._box(sample)] else: section = im if limits != (0.0, 1.0): low, high = limits low = np.sort(section.ravel())[int(low * section.size)] high = np.sort(section.ravel())[int(high * section.size)] im.clip_intensity(limits=(low, high)) else: high = section.max() low = section.min() if not istuple(scale, float, float, strict=False): raise ValueError("scale should be a 2-tuple of floats.") scaled = (im.data - low) / (high - low) delta = scale[1] - scale[0] offset = scale[0] im = scaled * delta + offset im = im.view(cls) im.mask = mask return im