def _check_master_pattern_and_get_data( master_pattern, energy: Union[int, float]) -> Tuple[np.ndarray, np.ndarray, int, int, float]: """Check whether the master pattern is suitable for projection, and return the northern and southern hemispheres along with their shape. Parameters ---------- master_pattern : kikuchipy.signals.EBSDMasterPattern Master pattern in the square Lambert projection. energy Accelerating voltage of the electron beam in kV specifying which master pattern energy to use during projection of simulated patterns. Returns ------- master_north, master_south Northern and southern hemispheres of master pattern of data type 32-bit float. npx, npy Number of columns and rows of the master pattern. scale Factor to scale up from the square Lambert projection to the master pattern. """ master_pattern._is_suitable_for_projection(raise_if_not=True) ( master_north, master_south, ) = master_pattern._get_master_pattern_arrays_from_energy(energy=energy) npx, npy = master_pattern.axes_manager.signal_shape scale = (npx - 1) / 2 dtype_desired = np.float32 if master_north.dtype != dtype_desired: master_north = rescale_intensity(master_north, dtype_out=dtype_desired) master_south = rescale_intensity(master_south, dtype_out=dtype_desired) return master_north, master_south, npx, npy, scale
def get_rgb_image( channels: List[np.ndarray], percentiles: Optional[Tuple] = None, normalize: bool = True, alpha: Optional[np.ndarray] = None, dtype_out: Union[np.uint8, np.uint16] = np.uint8, **kwargs, ) -> np.ndarray: """Return an RGB image from three numpy arrays, with a potential alpha channel. Parameters ---------- channels A list of np.ndarray for the red, green and blue channel, respectively. normalize Whether to normalize the individual `channels` before RGB image creation. alpha Potential alpha channel. If None (default), no alpha channel is added to the image. percentiles Whether to apply contrast stretching with a given percentile tuple with percentages, e.g. (0.5, 99.5), after creating the RGB image. If None (default), no contrast stretching is performed. dtype_out Output data type, either np.uint16 or np.uint8 (default). kwargs : Keyword arguments passed to :func:`~kikuchipy.generators.virtual_bse_generator.normalize_image`. Returns ------- rgb_image : np.ndarray RGB image. """ n_channels = 3 rgb_image = np.zeros(channels[0].shape + (n_channels, ), np.float32) for i, channel in enumerate(channels): if normalize: channel = normalize_image(channel.astype(np.float32), dtype_out=dtype_out, **kwargs) rgb_image[..., i] = channel # Apply alpha channel if desired if alpha is not None: alpha_min = np.nanmin(alpha) rescaled_alpha = (alpha - alpha_min) / (np.nanmax(alpha) - alpha_min) for i in range(n_channels): rgb_image[..., i] *= rescaled_alpha # Rescale to fit data type range if percentiles is not None: in_range = tuple(np.percentile(rgb_image, q=percentiles)) else: in_range = None rgb_image = rescale_intensity(rgb_image, in_range=in_range, dtype_out=dtype_out) return rgb_image.astype(dtype_out)
def _get_patterns_chunk( rotations_array: np.ndarray, dc: Vector3d, master_north: np.ndarray, master_south: np.ndarray, npx: int, npy: int, scale: Union[int, float], rescale: bool, dtype_out: Optional[type] = np.float32, ) -> np.ndarray: """Get the EBSD patterns on the detector for each rotation in the chunk. Each pattern is found by a bi-quadratic interpolation of the master pattern as described in EMsoft. Parameters ---------- rotations_array Array of rotations of shape (..., 4) for a given chunk in quaternions. dc Direction cosines unit vector between detector and sample. master_north Northern hemisphere of the master pattern. master_south Southern hemisphere of the master pattern. npx Number of pixels in the x-direction on the master pattern. npy Number of pixels in the y-direction on the master pattern. scale Factor to scale up from square Lambert projection to the master pattern. rescale Whether to call rescale_intensities() or not. dtype_out Data type of the returned patterns, by default np.float32. Returns ------- numpy.ndarray 3D or 4D array with simulated patterns. """ rotations = Rotation(rotations_array) rotations_shape = rotations_array.shape[:-1] simulated = np.empty(shape=rotations_shape + dc.shape, dtype=dtype_out) for i in np.ndindex(rotations_shape): rotated_dc = rotations[i] * dc ( nii, nij, niip, nijp, di, dj, dim, djm, ) = _get_lambert_interpolation_parameters( rotated_direction_cosines=rotated_dc, npx=npx, npy=npy, scale=scale, ) pattern = np.where( rotated_dc.z >= 0, ( master_north[nii, nij] * dim * djm + master_north[niip, nij] * di * djm + master_north[nii, nijp] * dim * dj + master_north[niip, nijp] * di * dj ), ( master_south[nii, nij] * dim * djm + master_south[niip, nij] * di * djm + master_south[nii, nijp] * dim * dj + master_south[niip, nijp] * di * dj ), ) if rescale: pattern = rescale_intensity(pattern, dtype_out=dtype_out) simulated[i] = pattern return simulated