def test_get_virtual_electron_diffraction_no_intensities( self, vdf_segments: VDFSegment, signal_data ): vdf_segments.intensities = None with pytest.raises( ValueError, match="VDFSegment does not have the attribute intensities, required for this method", ): vdf_segments.get_virtual_electron_diffraction( calibration=1, sigma=1, shape=signal_data.axes_manager.signal_shape )
def test_get_virtual_electron_diffraction_for_single_vectors( self, vdf_segments: VDFSegment, signal_data ): vs = vdf_segments.get_virtual_electron_diffraction( calibration=1, sigma=1, shape=signal_data.axes_manager.signal_shape ) assert isinstance(vs, ElectronDiffraction2D)
def test_get_virtual_electron_diffraction( self, vdf_segments: VDFSegment, signal_data ): corrsegs = vdf_segments.correlate_vdf_segments(0.1, 1, 1) vs = corrsegs.get_virtual_electron_diffraction( calibration=1, sigma=1, shape=signal_data.axes_manager.signal_shape ) assert isinstance(vs, ElectronDiffraction2D)
def test_correlate_segments_bad_thresholds(self, vdf_segments: VDFSegment): with pytest.raises( ValueError, match="segment_threshold must be smaller than or equal to vector_threshold", ): _ = vdf_segments.correlate_vdf_segments( vector_threshold=4, segment_threshold=5 )
def test_correlate_segments( self, vdf_segments: VDFSegment, corr_threshold, vector_threshold, segment_threshold, ): corrsegs = vdf_segments.correlate_vdf_segments( corr_threshold, vector_threshold, segment_threshold ) assert isinstance(corrsegs.segments, Signal2D) assert isinstance(corrsegs.vectors_of_segments, DiffractionVectors) assert isinstance(corrsegs.intensities, np.ndarray)
def get_vdf_segments( self, min_distance=1, min_size=1, max_size=np.inf, max_number_of_grains=np.inf, marker_radius=1, threshold=False, exclude_border=False, ): """Separate segments from each of the virtual dark field (VDF) images using edge-detection by the Sobel transform and the watershed segmentation method implemented in scikit-image [1,2]. Obtain a VDFSegment, similar to VDFImage, but where each image is a segment of a VDF and the vectors correspond to each segment and are not necessarily unique. Parameters ---------- min_distance: int Minimum distance (in pixels) between grains required for them to be considered as separate grains. min_size : float Grains with size (i.e. total number of pixels) below min_size are discarded. max_size : float Grains with size (i.e. total number of pixels) above max_size are discarded. max_number_of_grains : int Maximum number of grains included in the returned separated grains. If it is exceeded, those with highest peak intensities will be returned. marker_radius : float If 1 or larger, each marker for watershed is expanded to a disk of radius marker_radius. marker_radius should not exceed 2*min_distance. threshold: bool If True, a mask is calculated by thresholding the VDF image by the Li threshold method in scikit-image. If False (default), the mask is the boolean VDF image. exclude_border : int or True, optional If non-zero integer, peaks within a distance of exclude_border from the boarder will be discarded. If True, peaks at or closer than min_distance of the boarder, will be discarded. References ---------- [1] http://scikit-image.org/docs/dev/auto_examples/segmentation/ plot_watershed.html [2] http://scikit-image.org/docs/dev/auto_examples/xx_applications/ plot_coins_segmentation.html#sphx-glr-auto-examples-xx- applications-plot-coins-segmentation-py Returns ------- vdfsegs : VDFSegment VDFSegment object containing segments (i.e. grains) of single virtual dark field images with corresponding vectors. """ vdfs = self.copy() vectors = self.vectors.data # TODO : Add aperture radius as an attribute of VDFImage? # Create an array of length equal to the number of vectors where each # element is a np.object with shape (n: number of segments for this # VDFImage, VDFImage size x, VDFImage size y). vdfsegs = np.array( vdfs.map( separate_watershed, show_progressbar=True, inplace=False, min_distance=min_distance, min_size=min_size, max_size=max_size, max_number_of_grains=max_number_of_grains, marker_radius=marker_radius, threshold=threshold, exclude_border=exclude_border, ), dtype=np.object, ) segments, vectors_of_segments = [], [] for i, vector in zip(np.arange(vectors.size), vectors): segments = np.append(segments, vdfsegs[i]) num_segs = np.shape(vdfsegs[i])[0] vectors_of_segments = np.append( vectors_of_segments, np.broadcast_to(vector, (num_segs, 2))) vectors_of_segments = vectors_of_segments.reshape((-1, 2)) segments = segments.reshape(( np.shape(vectors_of_segments)[0], vdfs.axes_manager.signal_shape[0], vdfs.axes_manager.signal_shape[1], )) # Calculate the total intensities of each segment segment_intensities = np.array([[np.sum(x, axis=(0, 1))] for x in segments], dtype="object") # if TraitError is raised, it is likely no segments were found segments = Signal2D(segments).transpose(navigation_axes=[0], signal_axes=[2, 1]) # Create VDFSegment and transfer axes calibrations vdfsegs = VDFSegment(segments, DiffractionVectors(vectors_of_segments), segment_intensities) vdfsegs.segments = transfer_signal_axes(vdfsegs.segments, vdfs) n = vdfsegs.segments.axes_manager.navigation_axes[0] n.name = "n" n.units = "number" vdfsegs.vectors_of_segments.axes_manager.set_signal_dimension(1) vdfsegs.vectors_of_segments = transfer_signal_axes( vdfsegs.vectors_of_segments, self.vectors) n = vdfsegs.vectors_of_segments.axes_manager.navigation_axes[0] n.name = "n" n.units = "number" return vdfsegs
def test_correlate_segments_small_vector_threshold(self, vdf_segments: VDFSegment): _ = vdf_segments.correlate_vdf_segments( corr_threshold=0.7, vector_threshold=0, segment_threshold=-1 )
def test_correlate_segments_cropped(self, vdf_segments_cropped: VDFSegment): corrsegs = vdf_segments_cropped.correlate_vdf_segments(0.9, 1, 0) assert isinstance(corrsegs.segments, Signal2D) assert isinstance(corrsegs.vectors_of_segments, DiffractionVectors) assert isinstance(corrsegs.intensities, np.ndarray)
def vdf_segments_cropped(vdf_segments): return VDFSegment( vdf_segments.segments.inav[:4], vdf_segments.vectors_of_segments.inav[:4] )