def test_axis(self): """ Test that iprod(axis = 0) yields 0d arrays """ source = [np.ones((16,), dtype=np.float) for _ in range(10)] with self.subTest("axis = 0"): summed = prod(source, axis=0) self.assertTrue(np.all(summed == 1)) with self.subTest("axis = None"): summed = prod(source, axis=None) self.assertTrue(np.allclose(summed, np.ones_like(summed)))
def combine_masks(*masks): """ Combine multiple pixel masks into one. This assumes that pixel masks evaluate to ``True`` on valid pixels and ``False`` on invalid pixels. Returns ------- combined : `~numpy.ndarray`, dtype bool """ # By multiplying boolean arrays, values of False propagate return prod(masks, dtype=bool)
def test_against_numpy(self): """ Test that iprod() returns the same as numpy.prod() for various axis inputs """ stream = [np.random.random((16, 16)) for _ in range(10)] stack = np.dstack(stream) for axis in (0, 1, 2, None): with self.subTest("axis = {}".format(axis)): from_numpy = np.prod(stack, axis=axis) from_stream = prod(stream, axis=axis) self.assertTrue(np.allclose(from_stream, from_numpy))
def test_dtype(self): """ Test that dtype argument is working """ source = [np.ones((16,), dtype=np.float) for _ in range(10)] product = prod(source, dtype=np.int) self.assertTrue(np.allclose(product, np.ones_like(product))) self.assertEqual(product.dtype, np.int)
def test_ignore_nans(self): """ Test that NaNs are ignored. """ source = [np.ones((16,), dtype=np.float) for _ in range(10)] source.append(np.full_like(source[0], np.nan)) product = prod(source, ignore_nan=True) self.assertTrue(np.allclose(product, np.ones_like(product)))
def test_trivial(self): """ Test a product of ones """ source = [np.ones((16,), dtype=np.float) for _ in range(10)] product = prod(source) self.assertTrue(np.allclose(product, np.ones_like(product)))
def nfold(im, mod, center=None, mask=None, fill_value=0.0): """ Returns an images averaged according to n-fold rotational symmetry. This can be used to boost the signal-to-noise ratio on an image with known symmetry, e.g. a diffraction pattern. Parameters ---------- im : array_like, ndim 2 Image to be azimuthally-symmetrized. center : array_like, shape (2,) or None, optional Coordinates of the center (in pixels) in the format ``center=[col, row]``. If ``center=None``, the image is rotated around the center of the array, i.e. ``center=(cols / 2 - 0.5, rows / 2 - 0.5)``. mod : int Fold symmetry number. Valid numbers must be a divisor of 360. mask : `~numpy.ndarray` or None, optional Mask of `image`. The mask should evaluate to `True` (or 1) on valid pixels. If None (default), no mask is used. fill_value : float, optional In the case of a mask that overlaps with itself when rotationally averaged, the overlapping regions will be filled with this value. Returns ------- out : `~numpy.ndarray`, dtype float Symmetrized image. Raises ------ ValueError : If `mod` is not a divisor of 360 deg. """ if 360 % mod: raise ValueError( f"{mod}-fold rotational symmetry is not valid (not a divisor of 360)." ) angles = range(0, 360, int(360 / mod)) im = np.array(im, copy=True) kwargs = { "center": center, "mode": "constant", "cval": 0, "preserve_range": True } if mask is None: return ns.average(rotate(im, angle, **kwargs) for angle in angles) # Use weights because edges of the pictures, which might be cropped by the rotation # should not count in the average wt = np.ones_like(mask, dtype=im.dtype) wt[np.logical_not(mask)] = 0 weights = (rotate(wt, angle, **kwargs) for angle in angles) imgs = (rotate(im, angle, **kwargs) for angle in angles) avg = ns.average(imgs, weights=weights) # Mask may overlap with itself during symmetrization. At those points, the average # will be zero (because the weights are 0 there) # However, because users may want to change that value to `fill_value != 0`, we need # to know where is the overlap if fill_value != 0.0: invalid_pixels = np.logical_not(mask) masks = (rotate(invalid_pixels, angle, **kwargs) for angle in angles) overlap = ns.prod(masks).astype(bool) # equivalent to logical_and avg[overlap] = fill_value return ns.nan_to_num(avg, fill_value=fill_value)