Example #1
0
    def test_get_dask_array(self):
        s = EBSD((255 * np.random.rand(10, 10, 120, 120)).astype(np.uint8))
        dask_array = _get_dask_array(s)
        assert dask_array.chunksize == (8, 8, 120, 120)

        # Make data lazy
        s.data = dask_array.rechunk((5, 5, 120, 120))
        dask_array = _get_dask_array(s)
        assert dask_array.chunksize == (5, 5, 120, 120)
Example #2
0
    def test_get_dynamic_background_frequency(self, dummy_signal, std, answer):

        dtype_out = answer.dtype

        dask_array = _get_dask_array(dummy_signal, dtype=np.float32)

        kwargs = {}
        (
            kwargs["fft_shape"],
            kwargs["window_shape"],
            kwargs["transfer_function"],
            kwargs["offset_before_fft"],
            kwargs["offset_after_ifft"],
        ) = _dynamic_background_frequency_space_setup(
            pattern_shape=dummy_signal.axes_manager.signal_shape[::-1],
            std=std,
            truncate=4.0,
        )

        background = dask_array.map_blocks(
            func=chunk.get_dynamic_background,
            filter_func=_fft_filter,
            dtype_out=dtype_out,
            dtype=dtype_out,
            **kwargs,
        )

        # Check for correct data type and gives expected output intensities
        assert background.dtype == dtype_out
        assert np.allclose(background[0, 0].compute(), answer, atol=1e-4)
Example #3
0
    def test_rescale_intensity(self, dummy_signal, dtype_out, answer):
        dask_array = _get_dask_array(dummy_signal, dtype=np.float32)

        rescaled_patterns = dask_array.map_blocks(
            func=chunk.rescale_intensity, dtype_out=dtype_out, dtype=dtype_out,
        )

        assert isinstance(rescaled_patterns, da.Array)
        assert rescaled_patterns.dtype == dtype_out
        assert np.allclose(rescaled_patterns[0, 0].compute(), answer, atol=1e-4)
Example #4
0
    def test_adaptive_histogram_equalization_chunk(self, dummy_signal):
        dask_array = _get_dask_array(dummy_signal)
        dtype_out = dask_array.dtype
        kernel_size = (10, 10)
        nbins = 128
        equalized_patterns = dask_array.map_blocks(
            func=chunk.adaptive_histogram_equalization,
            kernel_size=kernel_size,
            nbins=nbins,
        )

        # Check for correct data type and gives expected output intensities
        assert equalized_patterns.dtype == dtype_out
        assert np.allclose(equalized_patterns[0, 0].compute(), ADAPT_EQ_UINT8)
Example #5
0
    def test_get_dynamic_background_spatial(self, dummy_signal, std, answer):
        filter_func = gaussian_filter
        kwargs = {"sigma": std}

        dtype_out = np.uint8
        dask_array = _get_dask_array(dummy_signal, dtype=np.float32)

        background = dask_array.map_blocks(
            func=chunk.get_dynamic_background,
            filter_func=filter_func,
            dtype_out=dtype_out,
            dtype=dtype_out,
            **kwargs,
        )
        assert background.dtype == dtype_out
        assert np.allclose(background[0, 0].compute(), answer)
Example #6
0
    def test_remove_dynamic_background_spatial_uint16(self, dummy_signal):
        dtype_out = np.uint16

        dask_array = _get_dask_array(dummy_signal, dtype=np.float32)

        corrected_patterns = dask_array.map_blocks(
            func=chunk.remove_dynamic_background,
            filter_func=gaussian_filter,
            operation_func=np.subtract,
            dtype_out=dtype_out,
            dtype=dtype_out,
            sigma=2,
        )

        # Check for correct data type and gives expected output intensities
        assert corrected_patterns.dtype == dtype_out
        assert np.allclose(
            corrected_patterns[0, 0].compute(), DYN_CORR_UINT16_SPATIAL_STD2
        )
Example #7
0
    def test_remove_dynamic_background_spatial(self, dummy_signal, std, answer):
        dtype_out = dummy_signal.data.dtype.type

        dask_array = _get_dask_array(dummy_signal, dtype=np.float32)

        kwargs = {"sigma": std}

        corrected_patterns = dask_array.map_blocks(
            func=chunk.remove_dynamic_background,
            filter_func=gaussian_filter,
            operation_func=np.subtract,
            dtype_out=dtype_out,
            dtype=dtype_out,
            **kwargs,
        )

        # Check for correct data type and gives expected output intensities
        assert corrected_patterns.dtype == dtype_out
        assert np.allclose(corrected_patterns[0, 0].compute(), answer)
Example #8
0
    def test_remove_static_background_chunk(
        self, dummy_signal, dummy_background, operation_func, answer
    ):
        dtype_out = dummy_signal.data.dtype.type
        dtype_proc = np.float32

        dask_array = _get_dask_array(dummy_signal, dtype=dtype_proc)
        corrected_patterns = dask_array.map_blocks(
            func=chunk.remove_static_background,
            static_bg=dummy_background.astype(dtype_proc),
            operation_func=operation_func,
            dtype_out=dtype_out,
            dtype=dtype_out,
        )

        # Check for correct data type and gives expected output intensities
        assert corrected_patterns.dtype == dtype_out
        assert isinstance(corrected_patterns, da.Array)
        assert np.allclose(corrected_patterns[0, 0].compute(), answer)
Example #9
0
    def test_rescale_intensity_percentiles(
        self, dummy_signal, percentiles, answer
    ):
        dtype_out = dummy_signal.data.dtype
        dask_array = _get_dask_array(dummy_signal, dtype=np.float32)

        rescaled_patterns = dask_array.map_blocks(
            func=chunk.rescale_intensity,
            percentiles=percentiles,
            dtype_out=dtype_out,
            dtype=dtype_out,
        )

        p1 = rescaled_patterns[0, 0].compute()
        p2 = rescaled_patterns[0, 1].compute()

        assert isinstance(rescaled_patterns, da.Array)
        assert rescaled_patterns.dtype == dtype_out
        assert np.allclose(p1, answer)
        assert not np.allclose(p1, p2, atol=1)
Example #10
0
    def test_average_neighbour_patterns_chunk(self, dummy_signal, dtype_in):
        w = Window()

        # Get array to operate on
        dask_array = _get_dask_array(dummy_signal)
        dtype_out = dask_array.dtype

        # Get sum of window data for each image
        nav_shape = dummy_signal.axes_manager.navigation_shape
        w_sums = convolve(
            input=np.ones(nav_shape[::-1]),
            weights=w.data,
            mode="constant",
            cval=0,
        )

        for i in range(dummy_signal.axes_manager.signal_dimension):
            w_sums = np.expand_dims(w_sums, axis=w_sums.ndim)
        w_sums = da.from_array(w_sums, chunks=dask_array.chunksize)

        # Add signal dimensions to window array to enable its use with Dask's
        # map_blocks()
        w = w.reshape(
            w.shape + (1,) * dummy_signal.axes_manager.signal_dimension
        )

        averaged_patterns = dask_array.map_blocks(
            func=chunk.average_neighbour_patterns,
            window_sums=w_sums,
            window=w,
            dtype_out=dtype_in,
            dtype=dtype_out,
        )

        answer = np.array([7, 4, 6, 6, 3, 7, 7, 3, 2], dtype=np.uint8).reshape(
            (3, 3)
        )

        # Check for correct data type and gives expected output intensities
        assert averaged_patterns.dtype == dtype_out
        assert np.allclose(averaged_patterns[0, 0].compute(), answer)
Example #11
0
    def test_remove_static_background_chunk_scalebg(
        self, dummy_signal, dummy_background
    ):
        dtype_out = dummy_signal.data.dtype.type
        dtype_proc = np.float32

        dask_array = _get_dask_array(dummy_signal, dtype=dtype_proc)

        corrected_patterns = dask_array.map_blocks(
            func=chunk.remove_static_background,
            static_bg=dummy_background.astype(dtype_proc),
            operation_func=np.subtract,
            dtype_out=dtype_out,
            scale_bg=True,
            dtype=dtype_out,
        )

        assert corrected_patterns.dtype == dtype_out
        assert np.allclose(
            corrected_patterns[0, 0].compute(), STATIC_SUB_SCALEBG_UINT8
        )
Example #12
0
    def test_remove_dynamic_background_out_range(
        self, dummy_signal, omax, answer
    ):
        dtype_out = dummy_signal.data.dtype.type

        out_range = (0, omax)

        dask_array = _get_dask_array(dummy_signal, dtype=np.float32)

        corrected_patterns = dask_array.map_blocks(
            func=chunk.remove_dynamic_background,
            filter_func=gaussian_filter,
            operation_func=np.subtract,
            sigma=2,
            out_range=out_range,
            dtype_out=dtype_out,
            dtype=dtype_out,
        )

        assert corrected_patterns.dtype == dtype_out
        assert corrected_patterns.max().compute() == omax
        assert np.allclose(corrected_patterns[0, 0].compute(), answer)
Example #13
0
    def rescale_intensity(
        self,
        relative: bool = False,
        in_range: Union[None, Tuple[int, int], Tuple[float, float]] = None,
        out_range: Union[None, Tuple[int, int], Tuple[float, float]] = None,
        dtype_out: Union[None, np.dtype, Tuple[int, int], Tuple[float,
                                                                float]] = None,
        percentiles: Union[None, Tuple[int, int], Tuple[float, float]] = None,
    ):
        """Rescale image intensities inplace.

        Output min./max. intensity is determined from `out_range` or the
        data type range of the :class:`numpy.dtype` passed to
        `dtype_out` if `out_range` is None.

        This method is based on
        :func:`skimage.exposure.rescale_intensity`.

        Parameters
        ----------
        relative
            Whether to keep relative intensities between images (default
            is False). If True, `in_range` must be None, because
            `in_range` is in this case set to the global min./max.
            intensity.
        in_range
            Min./max. intensity of input images. If None (default),
            stretching is performed when `in_range` is set to a narrower
            `in_range` is set to pattern min./max intensity. Contrast
            intensity range than the input patterns. Must be None if
            `relative` is True or `percentiles` are passed.
        out_range
            Min./max. intensity of output images. If None (default),
            `out_range` is set to `dtype_out` min./max according to
            `skimage.util.dtype.dtype_range`.
        dtype_out
            Data type of rescaled images, default is input images' data
            type.
        percentiles
            Disregard intensities outside these percentiles. Calculated
            per image. Must be None if `in_range` or `relative` is
            passed. Default is None.

        See Also
        --------
        kikuchipy.pattern.rescale_intensity,
        :func:`skimage.exposure.rescale_intensity`

        Examples
        --------
        Image intensities are stretched to fill the available grey
        levels in the input images' data type range or any
        :class:`numpy.dtype` range passed to `dtype_out`, either
        keeping relative intensities between images or not:

        >>> print(s.data.dtype_out, s.data.min(), s.data.max(),
        ...       s.inav[0, 0].data.min(), s.inav[0, 0].data.max())
        uint8 20 254 24 233
        >>> s2 = s.deepcopy()
        >>> s.rescale_intensity(dtype_out=np.uint16)
        >>> print(s.data.dtype_out, s.data.min(), s.data.max(),
        ...       s.inav[0, 0].data.min(), s.inav[0, 0].data.max())
        uint16 0 65535 0 65535
        >>> s2.rescale_intensity(relative=True)
        >>> print(s2.data.dtype_out, s2.data.min(), s2.data.max(),
        ...       s2.inav[0, 0].data.min(), s2.inav[0, 0].data.max())
        uint8 0 255 4 232

        Contrast stretching can be performed by passing percentiles:

        >>> s.rescale_intensity(percentiles=(1, 99))

        Here, the darkest and brightest pixels within the 1% percentile
        are set to the ends of the data type range, e.g. 0 and 255
        respectively for images of ``uint8`` data type.

        Notes
        -----
        Rescaling RGB images is not possible. Use RGB channel
        normalization when creating the image instead.
        """
        if self.data.dtype in rgb_dtypes.values():
            raise NotImplementedError(
                "Use RGB channel normalization when creating the image instead."
            )

        # Determine min./max. intensity of input image to rescale to
        if in_range is not None and percentiles is not None:
            raise ValueError(
                "'percentiles' must be None if 'in_range' is not None.")
        elif relative is True and in_range is not None:
            raise ValueError("'in_range' must be None if 'relative' is True.")
        elif relative:  # Scale relative to min./max. intensity in images
            in_range = (self.data.min(), self.data.max())

        if dtype_out is None:
            dtype_out = self.data.dtype.type

        if out_range is None:
            dtype_out_pass = dtype_out
            if isinstance(dtype_out, np.dtype):
                dtype_out_pass = dtype_out.type
            out_range = dtype_range[dtype_out_pass]

        # Create dask array of signal images and do processing on this
        dask_array = _get_dask_array(signal=self)

        # Rescale images
        rescaled_images = dask_array.map_blocks(
            func=chunk.rescale_intensity,
            in_range=in_range,
            out_range=out_range,
            dtype_out=dtype_out,
            percentiles=percentiles,
            dtype=dtype_out,
        )

        # Overwrite signal images
        if not self._lazy:
            with ProgressBar():
                if self.data.dtype != rescaled_images.dtype:
                    self.change_dtype(dtype_out)
                print("Rescaling the image intensities:", file=sys.stdout)
                rescaled_images.store(self.data, compute=True)
        else:
            self.data = rescaled_images
Example #14
0
    def normalize_intensity(
        self,
        num_std: int = 1,
        divide_by_square_root: bool = False,
        dtype_out: Optional[np.dtype] = None,
    ):
        """Normalize image intensities in inplace to a mean of zero with
        a given standard deviation.

        Parameters
        ----------
        num_std
            Number of standard deviations of the output intensities.
            Default is 1.
        divide_by_square_root
            Whether to divide output intensities by the square root of
            the signal dimension size. Default is False.
        dtype_out
            Data type of normalized images. If None (default), the input
            images' data type is used.

        Notes
        -----
        Data type should always be changed to floating point, e.g.
        ``np.float32`` with
        :meth:`~hyperspy.signal.BaseSignal.change_dtype`, before
        normalizing the intensities.

        Examples
        --------
        >>> np.mean(s.data)
        146.0670987654321
        >>> s.change_dtype(np.float32)  # Or passing dtype_out=np.float32
        >>> s.normalize_intensity()
        >>> np.mean(s.data)
        2.6373216e-08

        Notes
        -----
        Rescaling RGB images is not possible. Use RGB channel
        normalization when creating the image instead.
        """
        if self.data.dtype in rgb_dtypes.values():
            raise NotImplementedError(
                "Use RGB channel normalization when creating the image instead."
            )

        if dtype_out is None:
            dtype_out = self.data.dtype

        dask_array = _get_dask_array(self, dtype=np.float32)

        normalized_images = dask_array.map_blocks(
            func=chunk.normalize_intensity,
            num_std=num_std,
            divide_by_square_root=divide_by_square_root,
            dtype_out=dtype_out,
            dtype=dtype_out,
        )

        # Change data type if requested
        if dtype_out != self.data.dtype:
            self.change_dtype(dtype_out)

        # Overwrite signal patterns
        if not self._lazy:
            with ProgressBar():
                print("Normalizing the image intensities:", file=sys.stdout)
                normalized_images.store(self.data, compute=True)
        else:
            self.data = normalized_images