Ejemplo n.º 1
0
 def test_linear_ramp(self):
     s0, s1 = hs.signals.Signal2D(np.meshgrid(range(100), range(110)))
     s0.change_dtype("float64")
     s1.change_dtype("float64")
     s0_plane = pst._get_linear_plane_from_signal2d(s0)
     s1_plane = pst._get_linear_plane_from_signal2d(s1)
     np.testing.assert_almost_equal(s0_plane.data, s0.data)
     np.testing.assert_almost_equal(s1_plane.data, s1.data)
Ejemplo n.º 2
0
    def make_linear_plane(self, mask=None):
        """Fit linear planes to the beam shifts, which replaces the original data.

        In many scanning transmission electron microscopes, the center position of the
        diffraction pattern will change as a function of the scan position. This is most
        apparent when scanning over large regions (100+ nanometers). Thus, when working
        with datasets, it is typically necessary to correct for this.
        However, other effects can also affect the apparent center point, like
        diffraction contrast. So while it is possible to correct for the beam shift
        by finding the center position in each diffraction pattern, this can lead to
        features such as interfaces or grain boundaries affecting the centering of the
        diffraction pattern. As the shift caused by the scan system is a slow and
        monotonic, it can often be approximated by fitting linear planes to
        the x- and y- beam shifts.

        In addition, for regions within the scan where the center point of the direct
        beam is hard to ascertain precisely, for example in very thick or heavily
        diffracting regions, a mask can be used to ignore fitting the plane to
        these regions.

        This method does this, and replaces the original beam shift data with these
        fitted planes. The beam shift signal can then be directly used in the
        Diffraction2D.center_direct_beam method.

        Note that for very large regions, this linear plane will probably not
        approximate the beam shift very well. In those cases a higher order plane
        will likely be necessary. Alternatively, a vacuum scan with exactly the same
        scanning parameters should be used.

        Parameters
        ----------
        mask : HyperSpy signal, optional
            Must be the same shape as the navigation dimensions of the beam
            shift signal. The True values will be masked.

        Examples
        --------
        >>> s = pxm.signals.BeamShift(np.random.randint(0, 99, (100, 120, 2)))
        >>> s_mask = hs.signals.Signal2D(np.zeros((100, 120), dtype=bool))
        >>> s_mask.data[20:-20, 20:-20] = True
        >>> s.make_linear_plane(mask=s_mask)

        """
        if self._lazy:
            raise ValueError(
                "make_linear_plane is not implemented for lazy signals, "
                "run compute() first")
        s_shift_x = self.isig[0].T
        s_shift_y = self.isig[1].T
        if mask is not None:
            mask = mask.__array__()
        plane_image_x = pst._get_linear_plane_from_signal2d(s_shift_x,
                                                            mask=mask)
        plane_image_y = pst._get_linear_plane_from_signal2d(s_shift_y,
                                                            mask=mask)
        plane_image = np.stack((plane_image_x, plane_image_y), -1)
        self.data = plane_image
        self.events.data_changed.trigger(None)
Ejemplo n.º 3
0
 def test_mask(self):
     data = np.ones((110, 200), dtype=np.float32)
     mask = np.zeros_like(data, dtype=bool)
     data[50, 51] = 10000
     mask[50, 51] = True
     s = hs.signals.Signal2D(data)
     plane_no_mask = pst._get_linear_plane_from_signal2d(s)
     plane_mask = pst._get_linear_plane_from_signal2d(s, mask=mask)
     assert plane_no_mask != approx(1.0)
     assert plane_mask == approx(1.0)
Ejemplo n.º 4
0
    def correct_ramp(self, corner_size=0.05, only_offset=False, out=None):
        """Subtract a plane from the signal by fitting a plane to the corners.

        Useful for removing the effects of the center of the diffraction
        pattern shifting as a function of scan position.

        The plane is calculated by fitting a plane to the corner values
        of the signal. This will only work well when the property one
        wants to measure is zero in these corners.

        Parameters
        ----------
        corner_size : number, optional
            The size of the corners, as a percentage of the image's axis.
            If corner_size is 0.05 (5%), and the image is 500 x 1000,
            the size of the corners will be (500*0.05) x (1000*0.05) = 25 x 50.
            Default 0.05
        only_offset : bool, optional
            If True, will subtract a "flat" plane, i.e. it will subtract the
            mean value of the corners. Default False
        out : optional, DPCSignal2D signal

        Returns
        -------
        corrected_signal : Signal2D

        Examples
        --------
        >>> s = pxm.dummy_data.get_square_dpc_signal(add_ramp=True)
        >>> s_corr = s.correct_ramp()
        >>> s_corr.plot()

        Only correct offset

        >>> s_corr = s.correct_ramp(only_offset=True)
        >>> s_corr.plot()

        """
        if out is None:
            output = self.deepcopy()
        else:
            output = out

        corner_slice_list = pst._get_corner_slices(self.inav[0],
                                                   corner_size=corner_size)
        mask = np.ones_like(self.inav[0].data, dtype=np.bool)
        for corner_slice in corner_slice_list:
            mask[corner_slice] = False
        for i, s in enumerate(self):
            if only_offset:
                plane = s.data[np.invert(mask)].mean()
            else:
                plane = pst._get_linear_plane_from_signal2d(s, mask=mask)
            output.data[i, :, :] -= plane
        if out is None:
            return output
Ejemplo n.º 5
0
 def test_offest_and_scale(self):
     s, _ = hs.signals.Signal2D(np.meshgrid(range(100), range(110)))
     s.axes_manager[0].offset = -40
     s.axes_manager[1].offset = 50
     s.axes_manager[0].scale = -0.22
     s.axes_manager[1].scale = 5.2
     s_orig = s.deepcopy()
     mask = np.zeros_like(s.data, dtype=bool)
     s.data[50, 51] = 10000
     mask[50, 51] = True
     plane_mask = pst._get_linear_plane_from_signal2d(s, mask=mask)
     np.testing.assert_almost_equal(plane_mask, s_orig.data)
Ejemplo n.º 6
0
 def test_crop_signal(self):
     s, _ = hs.signals.Signal2D(np.meshgrid(range(100), range(110)))
     s.change_dtype("float32")
     s.axes_manager[0].offset = -40
     s.axes_manager[1].offset = 50
     s.axes_manager[0].scale = -0.22
     s.axes_manager[1].scale = 5.2
     s_crop = s.isig[10:-20, 21:-11]
     s_crop_orig = s_crop.deepcopy()
     s_crop.data[50, 51] = 10000
     mask = np.zeros_like(s_crop.data, dtype=bool)
     mask[50, 51] = True
     plane = pst._get_linear_plane_from_signal2d(s_crop, mask=mask)
     np.testing.assert_almost_equal(plane, s_crop_orig.data, decimal=6)
Ejemplo n.º 7
0
 def test_wrong_input_dimensions(self):
     s = hs.signals.Signal2D(np.ones((2, 10, 10)))
     with pytest.raises(ValueError):
         pst._get_linear_plane_from_signal2d(s)
     s = hs.signals.Signal2D(np.ones((2, 2, 10, 10)))
     with pytest.raises(ValueError):
         pst._get_linear_plane_from_signal2d(s)
     s = hs.signals.Signal1D(np.ones(10))
     with pytest.raises(ValueError):
         pst._get_linear_plane_from_signal2d(s)
Ejemplo n.º 8
0
 def test_wrong_mask_dimensions(self):
     s = hs.signals.Signal2D(np.ones((10, 10)))
     mask = np.zeros((11, 9), dtype=bool)
     with pytest.raises(ValueError):
         pst._get_linear_plane_from_signal2d(s, mask=mask)
Ejemplo n.º 9
0
 def test_negative_values(self):
     data = np.ones((110, 100)) * -10
     s = hs.signals.Signal2D(data)
     s_plane = pst._get_linear_plane_from_signal2d(s)
     np.testing.assert_almost_equal(s_plane.data, s.data)
Ejemplo n.º 10
0
 def test_ones_values(self):
     s = hs.signals.Signal2D(np.ones((100, 200), dtype=np.float32))
     s_plane = pst._get_linear_plane_from_signal2d(s)
     np.testing.assert_almost_equal(s_plane.data, s.data)