diff --git a/defdap/base.py b/defdap/base.py index 5d54710..7681c59 100755 --- a/defdap/base.py +++ b/defdap/base.py @@ -1,4 +1,4 @@ -# Copyright 2023 Mechanics of Microstructures Group +# Copyright 2024 Mechanics of Microstructures Group # at The University of Manchester # # Licensed under the Apache License, Version 2.0 (the "License"); @@ -921,6 +921,7 @@ def grain_data(self, map_data): return grain_data + def grain_map_data(self, map_data=None, grain_data=None, bg=np.nan): """Extract a single grain map from the given map data. diff --git a/defdap/crystal.py b/defdap/crystal.py index e6e4fa7..eb5ac99 100755 --- a/defdap/crystal.py +++ b/defdap/crystal.py @@ -1,4 +1,4 @@ -# Copyright 2023 Mechanics of Microstructures Group +# Copyright 2024 Mechanics of Microstructures Group # at The University of Manchester # # Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/defdap/ebsd.py b/defdap/ebsd.py index 3a6a8fa..ac91212 100755 --- a/defdap/ebsd.py +++ b/defdap/ebsd.py @@ -1,4 +1,4 @@ -# Copyright 2023 Mechanics of Microstructures Group +# Copyright 2024 Mechanics of Microstructures Group # at The University of Manchester # # Licensed under the Apache License, Version 2.0 (the "License"); @@ -242,21 +242,34 @@ def scale(self): return self.step_size @report_progress("rotating EBSD data") - def rotate_data(self): - """Rotate map by 180 degrees and transform quats accordingly. + def rotate_data(self, angle=180): + """Rotate map counter-clockwise by the specified angle (90, 180, 270 degrees) + and transform quats accordingly. - """ - - self.data.euler_angle = self.data.euler_angle[:, ::-1, ::-1] - self.data.band_contrast = self.data.band_contrast[::-1, ::-1] - self.data.band_slope = self.data.band_slope[::-1, ::-1] - self.data.phase = self.data.phase[::-1, ::-1] - self.calc_quat_array() - - # Rotation from old coord system to new - transform_quat = Quat.from_axis_angle(np.array([0, 0, 1]), np.pi).conjugate + Parameters + ---------- + angle : int + The angle to rotate the map. Must be one of [90, 180, 270]. - # Perform vectorised multiplication + """ + if angle not in [90, 180, 270]: + raise ValueError("Angle must be one of [90, 180, 270]") + + # Rotate the data arrays by the specified angle + k = angle // 90 # Number of 90 degree rotations + + # Change the shape of the EBSD data to match + if k % 2 == 1: + self.shape = self.shape[::-1] + + self.data.euler_angle = np.rot90(self.data.euler_angle, k=k, axes=(1, 2)) + self.data.band_contrast = np.rot90(self.data.band_contrast, k=k) + self.data.mean_angular_deviation = np.rot90(self.data.mean_angular_deviation, k=k) + self.data.band_slope = np.rot90(self.data.band_slope, k=k) + self.data.phase = np.rot90(self.data.phase, k=k) + + # Rotation quaterions from old coord system to new + transform_quat = Quat.from_axis_angle(np.array([0, 0, 1]), np.deg2rad(-angle)).conjugate quats = Quat.multiply_many_quats(self.data.orientation.flatten(), transform_quat) self.data.orientation = np.array(quats).reshape(self.shape) diff --git a/defdap/file_readers.py b/defdap/file_readers.py index 0b90cb6..0ff0c28 100644 --- a/defdap/file_readers.py +++ b/defdap/file_readers.py @@ -1,4 +1,4 @@ -# Copyright 2023 Mechanics of Microstructures Group +# Copyright 2024 Mechanics of Microstructures Group # at The University of Manchester # # Licensed under the Apache License, Version 2.0 (the "License"); @@ -19,6 +19,7 @@ from abc import ABC, abstractmethod import pathlib import re +from skimage.io import imread from typing import TextIO, Dict, List, Callable, Any, Type, Optional @@ -205,7 +206,6 @@ def parse_phase() -> Phase: 'cmap': 'gray', 'clabel': 'Band contrast', } - ) self.loaded_data.add( 'band_slope', data['BS'].reshape(shape), @@ -791,6 +791,22 @@ def load(self, file_name: pathlib.Path) -> None: self.check_data() +def load_image(file_name: pathlib.Path) -> Datastore: + image = imread(file_name, as_gray=True) + loaded_metadata = { + 'shape': image.shape, + } + laoded_data = Datastore() + laoded_data.add( + 'image', image, unit='', type='map', order=0, + plot_params={ + 'plot_colour_bar': False, + 'cmap': 'gray', + } + ) + return loaded_metadata, laoded_data + + def read_until_string( file: TextIO, term_string: str, @@ -798,6 +814,8 @@ def read_until_string( line_process: Optional[Callable[[str], Any]] = None, exact: bool = False ) -> List[Any]: + + """Read lines in a file until a line starting with the `termString` is encountered. The file position is returned before the line starting with the `termString` when found. Comment and empty lines are ignored. diff --git a/defdap/file_writers.py b/defdap/file_writers.py index 00ffeb7..9d38a9b 100644 --- a/defdap/file_writers.py +++ b/defdap/file_writers.py @@ -1,4 +1,4 @@ -# Copyright 2023 Mechanics of Microstructures Group +# Copyright 2024 Mechanics of Microstructures Group # at The University of Manchester # # Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/defdap/hrdic.py b/defdap/hrdic.py index a409d59..a1078a8 100755 --- a/defdap/hrdic.py +++ b/defdap/hrdic.py @@ -1,4 +1,4 @@ -# Copyright 2023 Mechanics of Microstructures Group +# Copyright 2024 Mechanics of Microstructures Group # at The University of Manchester # # Licensed under the Apache License, Version 2.0 (the "License"); @@ -28,17 +28,16 @@ import peakutils from defdap._accelerated import flood_fill_dic -from defdap.utils import Datastore +from defdap.utils import Datastore, report_progress from defdap.file_readers import DICDataLoader, DavisLoader -from defdap import base +from defdap import base, mixin from defdap import defaults -from defdap.plotting import MapPlot, GrainPlot +from defdap.plotting import MapPlot from defdap.inspector import GrainInspector -from defdap.utils import report_progress -class Map(base.Map): +class Map(base.Map, mixin.Map): """ Class to encapsulate DIC map data and useful analysis and plotting methods. @@ -115,7 +114,6 @@ def __init__(self, *args, **kwargs): self.ebsd_map = None # EBSD map linked to DIC map self.highlight_alpha = 0.6 self.bse_scale = None # size of pixels in pattern images - self.bse_scale = None # size of pixels in pattern images self.crop_dists = np.array(((0, 0), (0, 0)), dtype=int) ## TODO: cropping, have metadata to state if saved data is cropped, if @@ -213,7 +211,7 @@ def load_data(self, file_name, data_type=None): # write final status yield (f"Loaded {self.format} {self.version} data " - f"(dimensions: {self.xdim} x {self.xdim} pixels, " + f"(dimensions: {self.xdim} x {self.ydim} pixels, " f"sub-window size: {self.binning} x {self.binning} pixels)") def load_corr_val_data(self, file_name, data_type=None): @@ -311,139 +309,6 @@ def print_stats_table(self, percentiles, components): per = [np.nanpercentile(self.data[c][i], p) for p in percentiles] print(str_format.format(c+''.join([str(t+1) for t in i]), *per)) - def set_crop(self, *, left=None, right=None, top=None, bottom=None, - update_homog_points=False): - """Set a crop for the DIC map. - - Parameters - ---------- - left : int - Distance to crop from left in pixels (formally `xMin`) - right : int - Distance to crop from right in pixels (formally `xMax`) - top : int - Distance to crop from top in pixels (formally `yMin`) - bottom : int - Distance to crop from bottom in pixels (formally `yMax`) - update_homog_points : bool, optional - If true, change homologous points to reflect crop. - - """ - # changes in homog points - dx = 0 - dy = 0 - - # update crop distances - if left is not None: - left = int(left) - dx = self.crop_dists[0, 0] - left - self.crop_dists[0, 0] = left - if right is not None: - self.crop_dists[0, 1] = int(right) - if top is not None: - top = int(top) - dy = self.crop_dists[1, 0] - top - self.crop_dists[1, 0] = top - if bottom is not None: - self.crop_dists[1, 1] = int(bottom) - - # update homogo points if required - if update_homog_points and (dx != 0 or dy != 0): - self.frame.update_homog_points(homog_idx=-1, delta=(dx, dy)) - - # set new cropped dimensions - x_dim = self.xdim - self.crop_dists[0, 0] - self.crop_dists[0, 1] - y_dim = self.ydim - self.crop_dists[1, 0] - self.crop_dists[1, 1] - self.shape = (y_dim, x_dim) - - def crop(self, map_data, binning=None): - """ Crop given data using crop parameters stored in map - i.e. cropped_data = DicMap.crop(DicMap.data_to_crop). - - Parameters - ---------- - map_data : numpy.ndarray - Bap data to crop. - binning : int - True if mapData is binned i.e. binned BSE pattern. - """ - binning = 1 if binning is None else binning - - min_y = int(self.crop_dists[1, 0] * binning) - max_y = int((self.ydim - self.crop_dists[1, 1]) * binning) - - min_x = int(self.crop_dists[0, 0] * binning) - max_x = int((self.xdim - self.crop_dists[0, 1]) * binning) - - return map_data[..., min_y:max_y, min_x:max_x] - - def link_ebsd_map(self, ebsd_map, transform_type="affine", **kwargs): - """Calculates the transformation required to align EBSD dataset to DIC. - - Parameters - ---------- - ebsd_map : defdap.ebsd.Map - EBSD map object to link. - transform_type : str, optional - affine, piecewiseAffine or polynomial. - kwargs - All arguments are passed to `estimate` method of the transform. - - """ - self.ebsd_map = ebsd_map - kwargs.update({'type': transform_type.lower()}) - self.experiment.link_frames(self.frame, ebsd_map.frame, kwargs) - self.data.add_derivative( - self.ebsd_map.data, - lambda boundaries: BoundarySet.from_ebsd_boundaries( - self, boundaries - ), - in_props={ - 'type': 'boundaries' - } - ) - - def check_ebsd_linked(self): - """Check if an EBSD map has been linked. - - Returns - ---------- - bool - Returns True if EBSD map linked. - - Raises - ---------- - Exception - If EBSD map not linked. - - """ - if self.ebsd_map is None: - raise Exception("No EBSD map linked.") - return True - - def warp_to_dic_frame(self, map_data, **kwargs): - """Warps a map to the DIC frame. - - Parameters - ---------- - map_data : numpy.ndarray - Data to warp. - kwargs - All other arguments passed to :func:`defdap.experiment.Experiment.warp_map`. - - Returns - ---------- - numpy.ndarray - Map (i.e. EBSD map data) warped to the DIC frame. - - """ - # Check a EBSD map is linked - self.check_ebsd_linked() - return self.experiment.warp_image( - map_data, self.ebsd_map.frame, self.frame, output_shape=self.shape, - **kwargs - ) - # TODO: fix component stuff def generate_threshold_mask(self, mask, dilation=0, preview=True): """ @@ -488,10 +353,10 @@ def generate_threshold_mask(self, mask, dilation=0, preview=True): num_removed_crop = np.sum(self.crop(self.mask)) num_total_crop = self.x_dim * self.y_dim - print('Filtering will remove {0} \ {1} ({2:.3f} %) datapoints in map' + print('Filtering will remove {0} / {1} ({2:.3f} %) datapoints in map' .format(num_removed, num_total, (num_removed / num_total) * 100)) print( - 'Filtering will remove {0} \ {1} ({2:.3f} %) datapoints in cropped map' + 'Filtering will remove {0} / {1} ({2:.3f} %) datapoints in cropped map' .format(num_removed_crop, num_total_crop, (num_removed_crop / num_total_crop * 100))) @@ -727,7 +592,7 @@ def grain_inspector(self, vmax=0.1, correction_angle=0, rdr_line_length=3): Length of lines perpendicular to slip trace used to calculate RDR. """ - GrainInspector(selected_dic_map=self, vmax=vmax, correction_angle=correction_angle, + GrainInspector(selected_map=self, vmax=vmax, correction_angle=correction_angle, rdr_line_length=rdr_line_length) @@ -804,38 +669,6 @@ def plot_max_shear(self, **kwargs): return plot - @property - def ref_ori(self): - """Returns average grain orientation. - - Returns - ------- - defdap.quat.Quat - - """ - return self.ebsd_grain.ref_ori - - @property - def slip_traces(self): - """Returns list of slip trace angles based on EBSD grain orientation. - - Returns - ------- - list - - """ - return self.ebsd_grain.slip_traces - - def calc_slip_traces(self, slip_systems=None): - """Calculates list of slip trace angles based on EBSD grain orientation. - - Parameters - ------- - slip_systems : defdap.crystal.SlipSystem, optional - - """ - self.ebsd_grain.calc_slip_traces(slip_systems=slip_systems) - def calc_slip_bands(self, grain_map_data, thres=None, min_dist=None): """Use Radon transform to detect slip band angles. @@ -896,33 +729,3 @@ def calc_slip_bands(self, grain_map_data, thres=None, min_dist=None): slip_band_angles = slip_band_angles * np.pi / 180 return slip_band_angles - -class BoundarySet(object): - def __init__(self, dic_map, points, lines): - self.dic_map = dic_map - self.points = set(points) - self.lines = lines - - @classmethod - def from_ebsd_boundaries(cls, dic_map, ebsd_boundaries): - if len(ebsd_boundaries.points) == 0: - return cls(dic_map, [], []) - - points = dic_map.experiment.warp_points( - ebsd_boundaries.image.astype(float), - dic_map.ebsd_map.frame, dic_map.frame, - output_shape=dic_map.shape - ) - lines = dic_map.experiment.warp_lines( - ebsd_boundaries.lines, dic_map.ebsd_map.frame, dic_map.frame - ) - return cls(dic_map, points, lines) - - def _image(self, points): - image = np.zeros(self.dic_map.shape, dtype=bool) - image[tuple(zip(*points))[::-1]] = True - return image - - @property - def image(self): - return self._image(self.points) diff --git a/defdap/inspector.py b/defdap/inspector.py index 84191e2..e6aa10a 100644 --- a/defdap/inspector.py +++ b/defdap/inspector.py @@ -1,4 +1,4 @@ -# Copyright 2023 Mechanics of Microstructures Group +# Copyright 2024 Mechanics of Microstructures Group # at The University of Manchester # # Licensed under the Apache License, Version 2.0 (the "License"); @@ -19,9 +19,8 @@ import ast from defdap.plotting import Plot, GrainPlot -from defdap import hrdic -from typing import List +from typing import List, Union class GrainInspector: @@ -32,15 +31,15 @@ class GrainInspector: """ def __init__(self, - selected_dic_map: 'hrdic.Map', - vmax: float, + selected_map: Union['hrdic.Map', 'optical.Map'], + vmax: float = 0.1, correction_angle: float = 0, rdr_line_length: int = 3): """ Parameters ---------- - selected_dic_map + selected_map DIC map to run grain inspector on. vmax Maximum effective shear strain in colour scale. @@ -51,14 +50,16 @@ def __init__(self, """ # Initialise some values self.grain_id = 0 - self.selected_dic_map = selected_dic_map - self.selected_ebsd_map = self.selected_dic_map.ebsd_map - self.selected_dic_grain = self.selected_dic_map[self.grain_id] - self.selected_ebsd_grain = self.selected_dic_grain.ebsd_grain - self.vmax = vmax + self.selected_map = selected_map + self.selected_ebsd_map = self.selected_map.ebsd_map + self.selected_grain = self.selected_map[self.grain_id] + self.selected_ebsd_grain = self.selected_grain.ebsd_grain self.correction_angle = correction_angle - self.rdr_line_length = rdr_line_length - self.filename = str(self.selected_dic_map.retrieve_name()) + '_RDR.txt' + + if self.selected_map.MAPNAME == 'hrdic': + self.vmax = vmax + self.rdr_line_length = rdr_line_length + self.filename = str(self.selected_map.retrieve_name()) + '_RDR.txt' # Plot window self.plot = Plot(ax=None, make_interactive=True, figsize=(13, 8), title='Grain Inspector') @@ -75,24 +76,27 @@ def __init__(self, self.plot.add_button( 'Next\nGrain', lambda e, p: self.goto_grain(self.grain_id + 1, p), (div_frac + 0.06, 0.94, 0.05, 0.04)) self.plot.add_button( - 'Run All STA', self.batch_run_sta, (0.85, 0.07, 0.11, 0.04)) + 'Print STA table', self.batch_run_sta, (0.85, 0.07, 0.11, 0.04)) self.plot.add_button( 'Clear\nAll Lines', self.clear_all_lines, (div_frac + 0.2, 0.48, 0.05, 0.04)) - self.plot.add_button( - 'Load\nFile', self.load_file, (0.85, 0.02, 0.05, 0.04)) - self.plot.add_button( - 'Save\nFile', self.save_file, (0.91, 0.02, 0.05, 0.04)) + if self.selected_map.MAPNAME == 'hrdic': + self.plot.add_button( + 'Load\nFile', self.load_file, (0.85, 0.02, 0.05, 0.04)) + self.plot.add_button( + 'Save\nFile', self.save_file, (0.91, 0.02, 0.05, 0.04)) # Text boxes - self.plot.add_text_box(label='', loc=(0.7, 0.02, 0.13, 0.04), + if self.selected_map.MAPNAME == 'hrdic': + self.plot.add_text_box(label='', loc=(0.7, 0.02, 0.13, 0.04), change_handler=self.update_filename, initial=self.filename) + self.rdr_group_text_box = self.plot.add_text_box(label='Run RDR only\non group:', loc=(0.78, 0.07, 0.05, 0.04), + submit_handler=self.run_rdr_group) + self.plot.add_text_box(label='Go to \ngrain ID:', loc=(div_frac + 0.17, 0.94, 0.05, 0.04), submit_handler=self.goto_grain) self.plot.add_text_box(label='Remove\nID:', loc=(div_frac + 0.1, 0.48, 0.05, 0.04), submit_handler=self.remove_line) - self.rdr_group_text_box = self.plot.add_text_box(label='Run RDR only\non group:', loc=(0.78, 0.07, 0.05, 0.04), - submit_handler=self.run_rdr_group) - + # Axes self.max_shear_axis = self.plot.add_axes((0.05, 0.4, 0.65, 0.55)) self.slip_trace_axis = self.plot.add_axes((0.25, 0.05, 0.5, 0.3)) @@ -100,7 +104,8 @@ def __init__(self, self.grain_info_axis = self.plot.add_axes((div_frac, 0.86, 0.25, 0.06)) self.line_info_axis = self.plot.add_axes((div_frac, 0.55, 0.25, 0.3)) self.groups_info_axis = self.plot.add_axes((div_frac, 0.15, 0.25, 0.3)) - self.grain_plot = self.selected_dic_map[self.grain_id].plot_max_shear(fig=self.plot.fig, + if self.selected_map.MAPNAME == 'hrdic': + self.grain_plot = self.selected_map[self.grain_id].plot_max_shear(fig=self.plot.fig, ax=self.max_shear_axis, vmax=self.vmax, plot_scale_bar=True, @@ -124,8 +129,8 @@ def goto_grain(self, # Go to grain ID specified in event self.grain_id = int(event) self.grain_plot.arrow = None - self.selected_dic_grain = self.selected_dic_map[self.grain_id] - self.selected_ebsd_grain = self.selected_dic_grain.ebsd_grain + self.selected_grain = self.selected_map[self.grain_id] + self.selected_ebsd_grain = self.selected_grain.ebsd_grain self.redraw() def save_line(self, @@ -155,7 +160,7 @@ def save_line(self, line_angle = float("{:.2f}".format(line_angle)) # Save drawn line to the DIC grain - self.selected_dic_grain.points_list.append([points, line_angle, -1]) + self.selected_grain.points_list.append([points, line_angle, -1]) # Group lines and redraw self.group_lines() @@ -177,7 +182,7 @@ def group_lines(self, """ if grain is None: - grain = self.selected_dic_grain + grain = self.selected_grain if grain.points_list == []: grain.groups_list = [] @@ -221,8 +226,8 @@ def clear_all_lines(self, """ - self.selected_dic_grain.points_list = [] - self.selected_dic_grain.groups_list = [] + self.selected_grain.points_list = [] + self.selected_grain.groups_list = [] self.redraw() def remove_line(self, @@ -237,7 +242,7 @@ def remove_line(self, """ # Remove single line - del self.selected_dic_grain.points_list[int(event)] + del self.selected_grain.points_list[int(event)] self.group_lines() self.redraw() @@ -248,21 +253,35 @@ def redraw(self): # Plot max shear for grain self.max_shear_axis.clear() - self.grain_plot = self.selected_dic_map[self.grain_id].plot_max_shear( - fig=self.plot.fig, ax=self.max_shear_axis, vmax=self.vmax, plot_colour_bar=False, plot_scale_bar=True) + if self.selected_map.MAPNAME == 'hrdic': + self.grain_plot = self.selected_grain.plot_max_shear(fig=self.plot.fig, + ax=self.max_shear_axis, + vmax=self.vmax, + plot_colour_bar=False, + plot_scale_bar=True) + + elif self.selected_map.MAPNAME == 'optical': + self.grain_plot = self.selected_grain.plot_grain_data(grain_data=self.selected_grain.data.image, + fig=self.plot.fig, + ax=self.max_shear_axis, + cmap='grey') # Draw unit cell self.unit_cell_axis.clear() - self.selected_ebsd_grain.plot_unit_cell(fig=self.plot.fig, ax=self.unit_cell_axis) + try: + self.selected_ebsd_grain.plot_unit_cell(fig=self.plot.fig, ax=self.unit_cell_axis) + except: + print('An error occured plotting the unit cell. Try running calc_average_grain_schmid_factors on the EBSD map.') # Write grain info text self.grain_info_axis.clear() self.grain_info_axis.axis('off') - grain_info_text = 'Grain ID: {0} / {1}\n'.format(self.grain_id, len(self.selected_dic_map.grains) - 1) - grain_info_text += 'Min: {0:.2f} % Mean:{1:.2f} % Max: {2:.2f} %'.format( - np.min(self.selected_dic_grain.data.max_shear) * 100, - np.mean(self.selected_dic_grain.data.max_shear) * 100, - np.max(self.selected_dic_grain.data.max_shear) * 100) + grain_info_text = 'Grain ID: {0} / {1}\n'.format(self.grain_id, len(self.selected_map.grains) - 1) + if self.selected_map.MAPNAME == 'hrdic': + grain_info_text += 'Min: {0:.2f} % Mean:{1:.2f} % Max: {2:.2f} %'.format( + np.min(self.selected_grain.data.max_shear) * 100, + np.mean(self.selected_grain.data.max_shear) * 100, + np.max(self.selected_grain.data.max_shear) * 100) self.plot.add_text(self.grain_info_axis, 0, 1, grain_info_text, va='top', ha='left', fontsize=10, fontfamily='monospace') @@ -281,8 +300,8 @@ def redraw_line(self): title_text = 'List of lines' lines_text = 'ID x0 y0 x1 y1 Angle Group\n' \ '-----------------------------------------\n' - if self.selected_dic_grain.points_list: - for idx, points in enumerate(self.selected_dic_grain.points_list): + if self.selected_grain.points_list: + for idx, points in enumerate(self.selected_grain.points_list): lines_text += '{0:<3} {1:<5.0f} {2:<5.0f} {3:<5.0f} {4:<5.0f} {5:<7.1f} {6:<5}\n'.format( idx, *points[0], points[1], points[2]) self.grain_plot.add_arrow(start_end=points[0], clear_previous=False, persistent=True, label=idx) @@ -297,16 +316,28 @@ def redraw_line(self): # Write groups info text title_text = 'List of groups' - groupsTxt = 'ID Av. Angle System Dev RDR\n' \ + if self.selected_map.MAPNAME == 'hrdic': + groupsTxt = 'ID Av. Angle System Dev RDR\n' \ '----------------------------------------\n' - if self.selected_dic_grain.groups_list: - for idx, group in enumerate(self.selected_dic_grain.groups_list): - groupsTxt += '{0:<3} {1:<10.1f} {2:<7} {3:<12} {4:.2f}\n'.format( - idx, - group[1], - ','.join([str(np.round(i, 1)) for i in group[2]]), - ','.join([str(np.round(i, 1)) for i in group[3]]), - group[4]) + elif self.selected_map.MAPNAME == 'optical': + groupsTxt = 'ID Av. Angle System Dev\n' \ + '--------------------------\n' + if self.selected_grain.groups_list: + for idx, group in enumerate(self.selected_grain.groups_list): + if self.selected_map.MAPNAME == 'hrdic': + groupsTxt += '{0:<3} {1:<10.1f} {2:<7} {3:<12} {4:.2f}\n'.format( + idx, + group[1], + ','.join([str(np.round(i, 1)) for i in group[2]]), + ','.join([str(np.round(i, 1)) for i in group[3]]), + group[4]) + elif self.selected_map.MAPNAME == 'optical': + groupsTxt += '{0:<3} {1:<10.1f} {2:<7} {3:<12}\n'.format( + idx, + group[1], + ','.join([str(np.round(i, 1)) for i in group[2]]), + ','.join([str(np.round(i, 1)) for i in group[3]])) + self.groups_info_axis.clear() self.groups_info_axis.axis('off') @@ -318,30 +349,15 @@ def redraw_line(self): self.slip_trace_axis.clear() self.slip_trace_axis.set_aspect('equal', 'box') slipPlot = GrainPlot(fig=self.plot.fig, - calling_grain=self.selected_dic_map[self.grain_id], ax=self.slip_trace_axis) + calling_grain=self.selected_map[self.grain_id].ebsd_grain, ax=self.slip_trace_axis) traces = slipPlot.add_slip_traces(top_only=True) self.slip_trace_axis.axis('off') # Draw slip bands - bands = [elem[1] for elem in self.selected_dic_grain.groups_list] - if self.selected_dic_grain.groups_list != None: + bands = [elem[1] for elem in self.selected_grain.groups_list] + if self.selected_grain.groups_list != None: slipPlot.add_slip_bands(top_only=True, angles=list(np.deg2rad(bands))) - def run_rdr_group(self, - event: int, - plot): - """ Run RDR on a specified group, upon submitting a text box. - - Parameters - ---------- - event - Group ID specified from text box. - - """ - # Run RDR for group of lines - if event != '': - self.calc_rdr(grain=self.selected_dic_grain, group=int(event)) - self.rdr_group_text_box.set_val('') def batch_run_sta(self, event, @@ -351,24 +367,48 @@ def batch_run_sta(self, """ # Print header - print("Grain\tEul1\tEul2\tEul3\tMaxSF\tGroup\tAngle\tSystem\tDev\tRDR") + if self.selected_map.MAPNAME == 'hrdic': + print("Grain\tEul1\tEul2\tEul3\tMaxSF\tGroup\tAngle\tSystem\tDev\tRDR") + elif self.selected_map.MAPNAME == 'optical': + print("Grain\tEul1\tEul2\tEul3\tMaxSF\tGroup\tAngle\tSystem\tDev") # Print information for each grain - for idx, grain in enumerate(self.selected_dic_map): + for idx, grain in enumerate(self.selected_map): if grain.points_list != []: for group in grain.groups_list: maxSF = np.max([item for sublist in grain.ebsd_grain.average_schmid_factors for item in sublist]) eulers = self.selected_ebsd_grain.ref_ori.euler_angles() * 180 / np.pi text = '{0}\t{1:.1f}\t{2:.1f}\t{3:.1f}\t{4:.3f}\t'.format( idx, eulers[0], eulers[1], eulers[2], maxSF) - text += '{0}\t{1:.1f}\t{2}\t{3}\t{4:.2f}'.format( - group[0], group[1], group[2], np.round(group[3], 3), group[4]) + if self.selected_map.MAPNAME == 'hrdic': + text += '{0}\t{1:.1f}\t{2}\t{3}\t{4:.2f}'.format( + group[0], group[1], group[2], np.round(group[3], 3), group[4]) + elif self.selected_map.MAPNAME == 'optical': + text += '{0}\t{1:.1f}\t{2}\t{3}'.format( + group[0], group[1], group[2], np.round(group[3], 3)) + print(text) + + def run_rdr_group(self, + event: int, + plot): + """ Run RDR on a specified group, upon submitting a text box. + + Parameters + ---------- + event + Group ID specified from text box. + + """ + # Run RDR for group of lines + if event != '': + self.calc_rdr(grain=self.selected_grain, group=int(event)) + self.rdr_group_text_box.set_val('') def calc_rdr(self, - grain, - group: int, - show_plot: bool = True): + grain, + group: int, + show_plot: bool = True): """ Calculates the relative displacement ratio for a given grain and group. Parameters @@ -406,15 +446,15 @@ def calc_rdr(self, x, y = skimage_line(int(x0), int(y0), int(x1), int(y1)) # Get x and y coordinates for points to be samples for RDR - xmap = np.array(x).T[:, None] + coordinateOffsets[:,0] + self.selected_dic_grain.extreme_coords[0] - ymap = np.array(y).T[:, None] + coordinateOffsets[:,1] + self.selected_dic_grain.extreme_coords[1] + xmap = np.array(x).T[:, None] + coordinateOffsets[:,0] + self.selected_grain.extreme_coords[0] + ymap = np.array(y).T[:, None] + coordinateOffsets[:,1] + self.selected_grain.extreme_coords[1] - x_list.extend(xmap - self.selected_dic_grain.extreme_coords[0]) - y_list.extend(ymap - self.selected_dic_grain.extreme_coords[1]) + x_list.extend(xmap - self.selected_grain.extreme_coords[0]) + y_list.extend(ymap - self.selected_grain.extreme_coords[1]) # Get u and v values at each coordinate - u = self.selected_dic_map.crop(self.selected_dic_map.data.displacement[0])[ymap, xmap] - v = self.selected_dic_map.crop(self.selected_dic_map.data.displacement[1])[ymap, xmap] + u = self.selected_map.crop(self.selected_map.data.displacement[0])[ymap, xmap] + v = self.selected_map.crop(self.selected_map.data.displacement[1])[ymap, xmap] # Subtract mean u and v value for each row u_list.extend(u - np.mean(u, axis=1)[:, None]) @@ -430,13 +470,13 @@ def calc_rdr(self, self.plot_rdr(grain, group, u_list, v_list, x_list, y_list, lin_reg_result) def plot_rdr(self, - grain, - group: int, - u_list: List[float], - v_list: List[float], - x_list: List[List[int]], - y_list: List[List[int]], - lin_reg_result: List): + grain, + group: int, + u_list: List[float], + v_list: List[float], + x_list: List[List[int]], + y_list: List[List[int]], + lin_reg_result: List): """ Plot rdr figure, including location of perpendicular lines and scatter plot of ucentered vs vcentered. @@ -471,8 +511,8 @@ def plot_rdr(self, self.rdr_plot.plot_axis = self.rdr_plot.add_axes((0.05, 0.1, 0.3, 0.35)) # Draw grain plot - self.rdr_plot.grainPlot = self.selected_dic_grain.plot_grain_data( - grain_data=self.selected_dic_grain.data.max_shear, + self.rdr_plot.grainPlot = self.selected_grain.plot_grain_data( + grain_data=self.selected_grain.data.max_shear, fig=self.rdr_plot.fig, ax=self.rdr_plot.grain_axis, plot_colour_bar=False, @@ -498,10 +538,10 @@ def plot_rdr(self, self.rdr_plot.plot_axis.set_xlabel('v-centered') self.rdr_plot.plot_axis.set_ylabel('u-centered') self.rdr_plot.add_text(self.rdr_plot.plot_axis, 0.95, 0.01, - 'Slope = {0:.3f} ± {1:.3f}\nR-squared = {2:.3f}\nn={3}' - .format(slope, std_err, r_value ** 2, len(u_list)), - va='bottom', ha='right', - transform=self.rdr_plot.plot_axis.transAxes, fontsize=10, fontfamily='monospace'); + 'Slope = {0:.3f} ± {1:.3f}\nR-squared = {2:.3f}\nn={3}' + .format(slope, std_err, r_value ** 2, len(u_list)), + va='bottom', ha='right', + transform=self.rdr_plot.plot_axis.transAxes, fontsize=10, fontfamily='monospace'); self.selected_ebsd_grain.calc_slip_traces() self.selected_ebsd_grain.calc_rdr() @@ -523,7 +563,7 @@ def plot_rdr(self, for i, slip_system_group in enumerate(self.selected_ebsd_grain.phase.slip_systems): slip_trace_angle = np.rad2deg(self.selected_ebsd_grain.slip_trace_angles[i]) text = "Plane: {0:s} Angle: {1:.1f}\n".format(slip_system_group[0].slip_plane_label, - slip_trace_angle) + slip_trace_angle) # Then loop over individual slip systems for j, slip_system in enumerate(slip_system_group): @@ -534,10 +574,10 @@ def plot_rdr(self, if i in grain.groups_list[group][2]: self.rdr_plot.add_text(self.rdr_plot.text_axis, 0.15, 0.9 - offset, text, va='top', - weight='bold', fontsize=10) + weight='bold', fontsize=10) else: self.rdr_plot.add_text(self.rdr_plot.text_axis, 0.15, 0.9 - offset, text, va='top', - fontsize=10) + fontsize=10) offset += 0.0275 * text.count('\n') @@ -554,7 +594,7 @@ def plot_rdr(self, # Measured values as red points self.rdr_plot.number_line_axis.plot([0], slope, 'ro', label='Measured RDR value') self.rdr_plot.add_text(self.rdr_plot.number_line_axis, -0.002, slope, '{0:.3f}'.format(float(slope)), - fontfamily='monospace', horizontalalignment='right', verticalalignment='center') + fontfamily='monospace', horizontalalignment='right', verticalalignment='center') self.rdr_plot.number_line_axis.legend(bbox_to_anchor=(1.15, 1.05)) @@ -563,8 +603,8 @@ def plot_rdr(self, if (unique_rdr > slope - 1.5) & (unique_rdr < slope + 1.5): # Add number to the left of point self.rdr_plot.add_text(self.rdr_plot.number_line_axis, -0.002, unique_rdr, - '{0:.3f}'.format(float(unique_rdr)), - fontfamily='monospace', horizontalalignment='right', verticalalignment='center') + '{0:.3f}'.format(float(unique_rdr)), + fontfamily='monospace', horizontalalignment='right', verticalalignment='center') # Go through all planes and directions and add to string if they have the rdr from above loop txt = '' @@ -576,7 +616,7 @@ def plot_rdr(self, txt += str('{0} {1} '.format(slip_system.slip_plane_label, slip_system.slip_dir_label)) self.rdr_plot.add_text(self.rdr_plot.number_line_axis, 0.002, unique_rdr - 0.01, - txt) + txt) self.rdr_plot.number_line_axis.set_ylim(slope - 1.5, slope + 1.5) self.rdr_plot.number_line_axis.set_xlim(-0.01, 0.05) @@ -594,8 +634,8 @@ def update_filename(self, self.filename = event def save_file(self, - event, - plot): + event, + plot): """ Save a file which contains definitions of slip lines drawn in grains [(x0, y0, x1, y1), angle, groupID] and groups of lines, defined by an average angle and identified sip plane @@ -603,14 +643,14 @@ def save_file(self, """ - with open(self.selected_dic_map.path + str(self.filename), 'w') as file: + with open(self.selected_map.path + str(self.filename), 'w') as file: file.write('# This is a file generated by defdap which contains ') file.write('definitions of slip lines drawn in grains by grainInspector\n') file.write('# [(x0, y0, x1, y1), angle, groupID]\n') file.write('# and groups of lines, defined by an average angle and identified sip plane\n') file.write('# [groupID, angle, [slip plane id], [angular deviation]\n\n') - for i, grain in enumerate(self.selected_dic_map): + for i, grain in enumerate(self.selected_map): if grain.points_list != []: file.write('Grain {0}\n'.format(i)) file.write('{0} Lines\n'.format(len(grain.points_list))) @@ -622,8 +662,8 @@ def save_file(self, file.write('\n') def load_file(self, - event, - plot): + event, + plot): """ Load a file which contains definitions of slip lines drawn in grains [(x0, y0, x1, y1), angle, groupID] and groups of lines, defined by an average angle and identified sip plane @@ -631,7 +671,7 @@ def load_file(self, """ - with open(self.selected_dic_map.path + str(self.filename), 'r') as file: + with open(self.selected_map.path + str(self.filename), 'r') as file: lines = file.readlines() # Parse file and make list of @@ -653,11 +693,11 @@ def load_file(self, start_index_lines = start_index + 2 grain_points = lines[start_index_lines:start_index_lines + num_lines] for point in grain_points: - self.selected_dic_map[grain_id].points_list.append(ast.literal_eval(point.split('\\')[0])) + self.selected_map[grain_id].points_list.append(ast.literal_eval(point.split('\\')[0])) start_index_groups = start_index + 3 + num_lines grain_groups = lines[start_index_groups:start_index_groups + num_groups] for group in grain_groups: - self.selected_dic_map[grain_id].groups_list.append(ast.literal_eval(group.split('\\')[0])) + self.selected_map[grain_id].groups_list.append(ast.literal_eval(group.split('\\')[0])) - self.redraw() + self.redraw() \ No newline at end of file diff --git a/defdap/mixin.py b/defdap/mixin.py new file mode 100644 index 0000000..0b37642 --- /dev/null +++ b/defdap/mixin.py @@ -0,0 +1,216 @@ +# Copyright 2024 Mechanics of Microstructures Group +# at The University of Manchester +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +import numpy as np + +class Map(): + + def set_crop(self, *, left=None, right=None, top=None, bottom=None, + update_homog_points=False): + """Set a crop for the map. + + Parameters + ---------- + left : int + Distance to crop from left in pixels (formally `xMin`) + right : int + Distance to crop from right in pixels (formally `xMax`) + top : int + Distance to crop from top in pixels (formally `yMin`) + bottom : int + Distance to crop from bottom in pixels (formally `yMax`) + update_homog_points : bool, optional + If true, change homologous points to reflect crop. + + """ + # changes in homog points + dx = 0 + dy = 0 + + # update crop distances + if left is not None: + left = int(left) + dx = self.crop_dists[0, 0] - left + self.crop_dists[0, 0] = left + if right is not None: + self.crop_dists[0, 1] = int(right) + if top is not None: + top = int(top) + dy = self.crop_dists[1, 0] - top + self.crop_dists[1, 0] = top + if bottom is not None: + self.crop_dists[1, 1] = int(bottom) + + # update homogo points if required + if update_homog_points and (dx != 0 or dy != 0): + self.frame.update_homog_points(homog_idx=-1, delta=(dx, dy)) + + # set new cropped dimensions + x_dim = self.xdim - self.crop_dists[0, 0] - self.crop_dists[0, 1] + y_dim = self.ydim - self.crop_dists[1, 0] - self.crop_dists[1, 1] + self.shape = (y_dim, x_dim) + + def crop(self, map_data, binning=None): + """ Crop given data using crop parameters stored in map + i.e. cropped_data = Map.crop(Map.data_to_crop). + + Parameters + ---------- + map_data : numpy.ndarray + Bap data to crop. + binning : int + True if mapData is binned i.e. binned BSE pattern. + """ + binning = 1 if binning is None else binning + + min_y = int(self.crop_dists[1, 0] * binning) + max_y = int((self.ydim - self.crop_dists[1, 1]) * binning) + + min_x = int(self.crop_dists[0, 0] * binning) + max_x = int((self.xdim - self.crop_dists[0, 1]) * binning) + + return map_data[..., min_y:max_y, min_x:max_x] + + def link_ebsd_map(self, ebsd_map, transform_type="affine", **kwargs): + """Calculates the transformation required to align EBSD map to this map. + + Parameters + ---------- + ebsd_map : defdap.ebsd.Map + EBSD map object to link. + transform_type : str, optional + affine, piecewiseAffine or polynomial. + kwargs + All arguments are passed to `estimate` method of the transform. + + """ + self.ebsd_map = ebsd_map + kwargs.update({'type': transform_type.lower()}) + self.experiment.link_frames(self.frame, ebsd_map.frame, kwargs) + self.data.add_derivative( + self.ebsd_map.data, + lambda boundaries: BoundarySet.from_ebsd_boundaries( + self, boundaries + ), + in_props={ + 'type': 'boundaries' + } + ) + + def check_ebsd_linked(self): + """Check if an EBSD map has been linked. + + Returns + ---------- + bool + Returns True if EBSD map linked. + + Raises + ---------- + Exception + If EBSD map not linked. + + """ + if self.ebsd_map is None: + raise Exception("No EBSD map linked.") + return True + + def warp_to_dic_frame(self, map_data, **kwargs): + """Warps a map to the this frame. + + Parameters + ---------- + map_data : numpy.ndarray + Data to warp. + kwargs + All other arguments passed to :func:`defdap.experiment.Experiment.warp_map`. + + Returns + ---------- + numpy.ndarray + Map (i.e. EBSD map data) warped to the this frame. + + """ + # Check a EBSD map is linked + self.check_ebsd_linked() + return self.experiment.warp_image( + map_data, self.ebsd_map.frame, self.frame, output_shape=self.shape, + **kwargs + ) + + +class Grain(): + + @property + def ref_ori(self): + """Returns average grain orientation. + + Returns + ------- + defdap.quat.Quat + + """ + return self.ebsd_grain.ref_ori + + @property + def slip_traces(self): + """Returns list of slip trace angles based on EBSD grain orientation. + + Returns + ------- + list + + """ + return self.ebsd_grain.slip_traces + + def calc_slip_traces(self, slip_systems=None): + """Calculates list of slip trace angles based on EBSD grain orientation. + + Parameters + ------- + slip_systems : defdap.crystal.SlipSystem, optional + + """ + self.ebsd_grain.calc_slip_traces(slip_systems=slip_systems) + +class BoundarySet(object): + def __init__(self, dic_map, points, lines): + self.dic_map = dic_map + self.points = set(points) + self.lines = lines + + @classmethod + def from_ebsd_boundaries(cls, dic_map, ebsd_boundaries): + if len(ebsd_boundaries.points) == 0: + return cls(dic_map, [], []) + + points = dic_map.experiment.warp_points( + ebsd_boundaries.image.astype(float), + dic_map.ebsd_map.frame, dic_map.frame, + output_shape=dic_map.shape + ) + lines = dic_map.experiment.warp_lines( + ebsd_boundaries.lines, dic_map.ebsd_map.frame, dic_map.frame + ) + return cls(dic_map, points, lines) + + def _image(self, points): + image = np.zeros(self.dic_map.shape, dtype=bool) + image[tuple(zip(*points))[::-1]] = True + return image + + @property + def image(self): + return self._image(self.points) \ No newline at end of file diff --git a/defdap/optical.py b/defdap/optical.py new file mode 100644 index 0000000..be25f99 --- /dev/null +++ b/defdap/optical.py @@ -0,0 +1,297 @@ +# Copyright 2024 Mechanics of Microstructures Group +# at The University of Manchester +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +import numpy as np + +from skimage import measure + +from defdap.file_readers import load_image +from defdap import base, mixin +from defdap.utils import Datastore, report_progress +from defdap import defaults +from defdap.inspector import GrainInspector + +class Map(base.Map, mixin.Map): + ''' + This class is for import and analysing optical image data + such as polarised light images and darkfield images to link + to EBSD data for slip trace analysis. (No RDR) + + Attributes + ---------------------------- + xdim : int + Size of map along x (from header). + ydim : int + Size of map along y (from header). + shape : tuple + Size of map (after cropping, like *Dim). + corrVal : numpy.ndarray + Correlation value. + ebsd_map : defdap.ebsd.Map + EBSD map linked to optical map. + highlight_alpha : float + Alpha (transparency) of grain highlight. + path : str + File path. + fname : str + File name. + crop_dists : numpy.ndarray + Crop distances (default all zeros). + + data : defdap.utils.Datastore + Must contain after loading data (maps): + image : numpy.ndarray + 2D image data + Derived data: + Grain list data to map data from all grains + ''' + + MAPNAME = 'optical' + + def __init__(self, *args, **kwargs): + self.xdim = None # size of map along x (from header) + self.ydim = None # size of map along y (from header) + + # Call base class constructor + super(Map, self).__init__(*args, **kwargs) + + self.ebsd_map = None # EBSD map linked to optical map + self.highlight_alpha = 0.6 + self.crop_dists = np.array(((0, 0), (0, 0)), dtype=int) + + self.plot_default = lambda *args, **kwargs: self.plot_map( + map_name='image', plot_gbs=True, *args, **kwargs) + + self.homog_map_name = 'image' + + self.data.add_generator( + 'grains', self.find_grains, unit='', type='map', order=0, + cropped=True + ) + + self.plot_default = lambda *args, **kwargs: self.plot_map(map_name='image', + plot_gbs=True, *args, **kwargs + ) + + @report_progress("loading optical data") + def load_data(self, file_name, data_type=None): + """Load optical data from file. + + Parameters + ---------- + file_name : pathlib.Path + Name of file including extension. + + """ + metadata_dict, loaded_data = load_image(file_name) + self.data.update(loaded_data) + + self.shape = metadata_dict['shape'] + # *dim are full size of data. shape (old *Dim) are size after cropping + ## TODO needs updating for all maps. cropped shape is stored as a + # tuple, why are this seperate values + self.xdim = self.shape[1] + self.ydim = self.shape[0] + + # write final status + yield f"(dimensions: {self.xdim} x {self.ydim} pixels)" + + # def load_metadata_from_excel(self, file_path): + # """Load metadata from an Excel file and convert it into a list of dictionaries.""" + # # Read the Excel file into a DataFrame + # df = pd.read_excel(file_path) + + # # Convert each row in the DataFrame to a dictionary and store in a list + # self.metadata = df.to_dict(orient='records') + + + def set_scale(self, scale): + """Sets the scale of the map. + + Parameters + ---------- + scale : float + Length of pixel in original BSE image in micrometres. + + """ + self.optical_scale = scale + + @property + def scale(self): + """Returns the number of micrometers per pixel in the optical map. + + """ + if self.optical_scale is None: + # raise ValueError("Map scale not set. Set with setScale()") + return None + + return self.optical_scale + + @report_progress("finding grains") + def find_grains(self, algorithm=None, min_grain_size=10): + """Finds grains in the optical map. + + Parameters + ---------- + algorithm : str {'warp', 'floodfill'} + Use floodfill or warp algorithm. + min_grain_size : int + Minimum grain area in pixels for floodfill algorithm. + """ + # Check a EBSD map is linked + self.check_ebsd_linked() + + if algorithm is None: + algorithm = defaults['hrdic_grain_finding_method'] + algorithm = algorithm.lower() + + grain_list = [] + group_id = Datastore.generate_id() + + if algorithm == 'warp': + # Warp EBSD grain map to optical frame + grains = self.warp_to_dic_frame( + self.ebsd_map.data.grains, order=0, preserve_range=True + ) + + # Find all unique values (these are the EBSD grain IDs in the optical area, sorted) + ebsd_grain_ids = np.unique(grains) + neg_vals = ebsd_grain_ids[ebsd_grain_ids <= 0] + ebsd_grain_ids = ebsd_grain_ids[ebsd_grain_ids > 0] + + # Map the EBSD IDs to the optical IDs (keep the same mapping for values <= 0) + old = np.concatenate((neg_vals, ebsd_grain_ids)) + new = np.concatenate((neg_vals, np.arange(1, len(ebsd_grain_ids) + 1))) + index = np.digitize(grains.ravel(), old, right=True) + grains = new[index].reshape(self.shape) + grainprops = measure.regionprops(grains) + props_dict = {prop.label: prop for prop in grainprops} + + for dic_grain_id, ebsd_grain_id in enumerate(ebsd_grain_ids): + yield dic_grain_id / len(ebsd_grain_ids) + + # Make grain object + grain = Grain(dic_grain_id, self, group_id) + + # Find (x,y) coordinates and corresponding max shears of grain + coords = props_dict[dic_grain_id + 1].coords # (y, x) + grain.data.point = np.flip(coords, axis=1) # (x, y) + + # Assign EBSD grain ID to optical grain and increment grain list + grain.ebsd_grain = self.ebsd_map[ebsd_grain_id - 1] + grain.ebsd_map = self.ebsd_map + grain_list.append(grain) + + elif algorithm == 'floodfill': + raise NotImplementedError() + + else: + raise ValueError(f"Unknown grain finding algorithm '{algorithm}'.") + + ## TODO: this will get duplicated if find grains called again + self.data.add_derivative( + grain_list[0].data, self.grain_data_to_map, pass_ref=True, + in_props={ + 'type': 'list' + }, + out_props={ + 'type': 'map' + } + ) + + self._grains = grain_list + return grains + + def grain_inspector(self, correction_angle=0): + """Run the grain inspector interactive tool. + Parameters + ---------- + correction_angle: float + Correction angle in degrees to subtract from measured angles to account + for small rotation between optical and EBSD frames. Approximately the rotation + component of affine transform. + """ + GrainInspector(selected_map=self, correction_angle=correction_angle) + + +class Grain(base.Grain): + """ + Class to encapsulate optical grain data and useful analysis and plotting + methods. + + Attributes + ---------- + dicMap : defdap.optical.Map + Optical map this grain is a member of + ownerMap : defdap.hrdic.Map + Optical map this grain is a member of + maxShearList : list + List of maximum shear values for grain. + ebsd_grain : defdap.ebsd.Grain + EBSD grain ID that this optical grain corresponds to. + ebsd_map : defdap.ebsd.Map + EBSD map that this optical grain belongs to. + points_list : numpy.ndarray + Start and end points for lines drawn using defdap.inspector.GrainInspector. + groups_list : + Groups, angles and slip systems detected for + lines drawn using defdap.inspector.GrainInspector. + + data : defdap.utils.Datastore + Must contain after creating: + point : list of tuples + (x, y) in cropped map + Generated data: + + Derived data: + Map data to list data from the map the grain is part of + + """ + def __init__(self, grain_id, optical_map, group_id): + # Call base class constructor + super(Grain, self).__init__(grain_id, optical_map, group_id) + + self.optical_map = self.owner_map # Optical map this grain is a member of + self.ebsd_grain = None + self.ebsd_map = None + + self.points_list = [] # Lines drawn for STA + self.groups_list = [] # Unique angles drawn for STA + + self.plot_default = lambda *args, **kwargs: self.plot_map( + plot_colour_bar=True, plot_scale_bar=True, *args, **kwargs + ) + + def plot_map(self, **kwargs): + """Plot the image for an individual grain. + + Parameters + ---------- + kwargs + All arguments are passed to :func:`defdap.base.plot_grain_data`. + + Returns + ------- + defdap.plotting.GrainPlot + + """ + # Set default plot parameters then update with any input + plot_params = { + } + plot_params.update(kwargs) + + plot = self.plot_grain_data(grain_data=self.data.image, **plot_params) + + return plot \ No newline at end of file diff --git a/defdap/plotting.py b/defdap/plotting.py index c32730b..7ad2220 100644 --- a/defdap/plotting.py +++ b/defdap/plotting.py @@ -1,4 +1,4 @@ -# Copyright 2023 Mechanics of Microstructures Group +# Copyright 2024 Mechanics of Microstructures Group # at The University of Manchester # # Licensed under the Apache License, Version 2.0 (the "License"); @@ -103,7 +103,9 @@ def add_axes(self, loc, proj='2d'): if proj == '2d': return self.fig.add_axes(loc) if proj == '3d': - return Axes3D(self.fig, rect=loc, proj_type='ortho', azim=270, elev=90) + return self.fig.add_axes(loc, projection='3d', proj_type='ortho', azim=270, elev=90) + + def add_button(self, label, click_handler, loc=(0.8, 0.0, 0.1, 0.07), **kwargs): """Add a button to the plot. @@ -683,12 +685,14 @@ def create( defdap.plotting.MapPlot """ + if plot is None: plot = cls(calling_map, fig=fig, ax=ax, ax_params=ax_params, make_interactive=make_interactive, **fig_params) if map_data is not None: plot.add_map(map_data, cmap=cmap, vmin=vmin, vmax=vmax, **kwargs) + if plot_colour_bar: plot.add_colour_bar(clabel) @@ -849,7 +853,8 @@ def add_slip_traces(self, top_only=False, colours=None, pos=None, **kwargs): """ if colours is None: - colours = self.calling_grain.ebsd_grain.phase.slip_trace_colours + #colours = self.calling_grain.ebsd_grain.phase.slip_trace_colours #----------------------------------------- + colours = self.calling_grain.phase.slip_trace_colours slip_trace_angles = self.calling_grain.slip_traces self.add_traces(slip_trace_angles, colours, top_only, pos=pos, **kwargs) diff --git a/defdap/quat.py b/defdap/quat.py index 9fda81d..4e83438 100755 --- a/defdap/quat.py +++ b/defdap/quat.py @@ -1,4 +1,4 @@ -# Copyright 2023 Mechanics of Microstructures Group +# Copyright 2024 Mechanics of Microstructures Group # at The University of Manchester # # Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/defdap/utils.py b/defdap/utils.py index d1a3036..bf56452 100644 --- a/defdap/utils.py +++ b/defdap/utils.py @@ -1,4 +1,4 @@ -# Copyright 2023 Mechanics of Microstructures Group +# Copyright 2024 Mechanics of Microstructures Group # at The University of Manchester # # Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/notebooks/example_notebook.ipynb b/notebooks/example_notebook.ipynb index 5c75499..134889d 100644 --- a/notebooks/example_notebook.ipynb +++ b/notebooks/example_notebook.ipynb @@ -1442,9 +1442,9 @@ ], "metadata": { "kernelspec": { - "display_name": "Python [conda env:defdap]", + "display_name": "Python 3 (ipykernel)", "language": "python", - "name": "conda-env-defdap-py" + "name": "python3" }, "language_info": { "codemirror_mode": { @@ -1456,7 +1456,7 @@ "name": "python", "nbconvert_exporter": "python", "pygments_lexer": "ipython3", - "version": "3.11.0" + "version": "3.12.6" } }, "nbformat": 4, diff --git a/notebooks/optical.ipynb b/notebooks/optical.ipynb new file mode 100644 index 0000000..35583d8 --- /dev/null +++ b/notebooks/optical.ipynb @@ -0,0 +1,937 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "id": "57b4960f-e126-4439-a53c-a58f1bfdcdfd", + "metadata": { + "pycharm": { + "name": "#%% md\n" + } + }, + "source": [ + "# Optical Example notebook\n", + "\n", + "This notebook will outline basic usage of DefDAP, including loading an image and EBSD map, linking them with homologous points and producing maps" + ] + }, + { + "cell_type": "markdown", + "id": "28930750-ec9b-4f73-876c-639afe7531cd", + "metadata": { + "pycharm": { + "name": "#%% md\n" + } + }, + "source": [ + "## Load in packages" + ] + }, + { + "cell_type": "markdown", + "id": "e518d33b-73cc-4208-a1ee-354943464a3c", + "metadata": { + "pycharm": { + "name": "#%% md\n" + } + }, + "source": [ + "DefDAP is split into modules for processing EBSD (`defdap.ebsd`) and image (`defdap.optical`) data. There are also modules for manpulating orientations (`defdap.quat`) and creating custom figures (`defdap.plotting`) which is introduced later. We also import some of the usual suspects of the python scientific stack: `numpy` and `matplotlib`." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "fcd0edc9-7d79-412b-84b7-1f3091cb090c", + "metadata": { + "pycharm": { + "name": "#%%\n" + }, + "tags": [] + }, + "outputs": [], + "source": [ + "import numpy as np\n", + "import matplotlib.pyplot as plt\n", + "\n", + "import defdap.optical as optical\n", + "import defdap.ebsd as ebsd\n", + "import defdap.plotting as plotting\n", + "from defdap.quat import Quat\n", + "\n", + "# try tk, qt, osx (if using mac) or notebook for interactive plots. If none work, use inline\n", + "%matplotlib tk" + ] + }, + { + "cell_type": "markdown", + "id": "93366c53-2e3e-454d-b3a6-6eea264b4efd", + "metadata": { + "pycharm": { + "name": "#%% md\n" + } + }, + "source": [ + "## Load in a optical/SEM image" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "1ea4e773-0af0-4748-b0e9-f2b2daca0745", + "metadata": { + "pycharm": { + "name": "#%%\n" + } + }, + "outputs": [], + "source": [ + "optical_filepath = \"../tests/data/testOptical.png\"\n", + "optical_map = optical.Map(file_name = optical_filepath)" + ] + }, + { + "cell_type": "markdown", + "id": "fa1ca733-53ad-499b-af61-1eeb1e047217", + "metadata": { + "pycharm": { + "name": "#%% md\n" + } + }, + "source": [ + "### Set the scale of the map\n", + "This is defined as the pixel size in the images, measured in microns per pixel." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "6e1489dc-78e1-4d00-98d1-243546fa3308", + "metadata": { + "pycharm": { + "name": "#%%\n" + } + }, + "outputs": [], + "source": [ + "optical_map.set_scale(2.105) # um/pixel" + ] + }, + { + "cell_type": "markdown", + "id": "29d890a1-71a6-4f9d-855f-e891e8ac0d76", + "metadata": { + "pycharm": { + "name": "#%% md\n" + } + }, + "source": [ + "### Plot the map with a scale bar" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "bb82e614-bb95-4e40-9309-e7bfc5df2e0c", + "metadata": { + "pycharm": { + "name": "#%%\n" + } + }, + "outputs": [], + "source": [ + "optical_map.plot_map('image', vmin=0, vmax=1, plot_scale_bar=True)" + ] + }, + { + "cell_type": "markdown", + "id": "2331ad9a-35e4-4ee3-ae61-f3c532dcd52d", + "metadata": { + "pycharm": { + "name": "#%% md\n" + } + }, + "source": [ + "### Crop the map\n", + "Optical maps can contain spurious data at the edges which should be removed before performing any analysis. The crop is defined by the number of points to remove from each edge of the map, where `xMin`, `xMax`, `yMin` and `yMax` are the left, right, top and bottom edges respectively. Note that the test data doesn not require cropping as it is a subset of a larger dataset." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "546c6f28-3982-4401-8ce1-81176f144181", + "metadata": { + "pycharm": { + "name": "#%%\n" + } + }, + "outputs": [], + "source": [ + "optical_map.set_crop(left=10, right=10, top=10, bottom=10)" + ] + }, + { + "cell_type": "markdown", + "id": "d27e69a0-4f2d-4a22-a78c-056d10092627", + "metadata": { + "pycharm": { + "name": "#%% md\n" + } + }, + "source": [ + "## Load in an EBSD map\n", + "Currently, OxfordBinary (a .crc and .cpr file pair), OxfordText (.ctf file), EdaxAng (.ang file) or PythonDict (Python dictionary) filetypes are supported. The crystal structure and slip systems are automatically loaded for each phase in the map. The orientation in the EBSD are converted to a quaternion representation so calculations can be applied later." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "8da89bf7-685b-4bda-97ac-84def01b93c2", + "metadata": { + "pycharm": { + "name": "#%%\n" + } + }, + "outputs": [], + "source": [ + "ebsd_map = ebsd.Map(\"../tests/data/testOpticalEBSD\")" + ] + }, + { + "cell_type": "markdown", + "id": "5c7c1683-a93e-4a92-ae15-939e8837b758", + "metadata": { + "pycharm": { + "name": "#%% md\n" + } + }, + "source": [ + "A list of detected phases and crystal structures can be printed" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "40afadd4-0f21-46d9-976e-c0efe52d0f34", + "metadata": { + "pycharm": { + "name": "#%%\n" + } + }, + "outputs": [], + "source": [ + "for i, phase in enumerate(ebsd_map.phases):\n", + " print(i+1)\n", + " print(phase)" + ] + }, + { + "cell_type": "markdown", + "id": "f813cee6-fcba-4916-9bff-85fb8f08219a", + "metadata": { + "pycharm": { + "name": "#%% md\n" + } + }, + "source": [ + "A list of the slip planes, colours and slip directions can be printed" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "f4698cd1-3211-4c58-a197-0ac17103f1db", + "metadata": { + "pycharm": { + "name": "#%%\n" + } + }, + "outputs": [], + "source": [ + "ebsd_map.phases[0].print_slip_systems()" + ] + }, + { + "cell_type": "markdown", + "id": "7ed8a89a-e756-443e-b20d-7b629aa56ef7", + "metadata": { + "pycharm": { + "name": "#%% md\n" + } + }, + "source": [ + "### Plot the EBSD map\n", + "Using an Euler colour mapping or inverse pole figure colouring with the sample reference direction passed as a vector." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "321c2a28-5c5c-4ab4-a63a-de8f60693a42", + "metadata": { + "pycharm": { + "name": "#%%\n" + } + }, + "outputs": [], + "source": [ + "ebsd_map.plot_map('euler_angle', 'all_euler', plot_scale_bar=True)" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "2d996f21-6d1d-4e59-b187-e9a38e0e1b36", + "metadata": { + "pycharm": { + "name": "#%%\n" + } + }, + "outputs": [], + "source": [ + "ebsd_map.plot_map('orientation', 'IPF_x', plot_scale_bar=True)" + ] + }, + { + "cell_type": "markdown", + "id": "3f7a242d-41b2-4c2c-83f2-db8c65036b3c", + "metadata": { + "pycharm": { + "name": "#%% md\n" + } + }, + "source": [ + "A KAM map can also be plotted as follows" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "af64b232-f523-4cc2-9692-6e680b69881a", + "metadata": { + "pycharm": { + "name": "#%%\n" + } + }, + "outputs": [], + "source": [ + "ebsd_map.plot_map('KAM', vmin=0, vmax=2*np.pi/180)" + ] + }, + { + "cell_type": "markdown", + "id": "7dd951a3-3c33-4d0d-acb9-7bb6cb44518d", + "metadata": { + "pycharm": { + "name": "#%% md\n" + } + }, + "source": [ + "### Detect grains in the EBSD\n", + "This is done in two stages: first bounaries are detected in the map as any point with a misorientation to a neighbouring point greater than a critical value (`boundDef` in degrees). A flood fill type algorithm is then applied to segment the map into grains, with any grains containining fewer than a critical number of pixels removed (`minGrainSize` in pixels). The data e.g. orientations associated with each grain are then stored (referenced strictly, the data isn't stored twice) in a grain object and a list of the grains is stored in the EBSD map (named `grainList`). This allows analysis routines to be applied to each grain in a map in turn." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "88510a8e-a612-4705-bd9e-86b992ced80f", + "metadata": { + "pycharm": { + "name": "#%%\n" + } + }, + "outputs": [], + "source": [ + "ebsd_map.data.generate('grain_boundaries', misori_tol=8)\n", + "ebsd_map.data.generate('grains', min_grain_size=200)" + ] + }, + { + "cell_type": "markdown", + "id": "3630d208-2904-42ac-be21-a4dae5b9491d", + "metadata": { + "pycharm": { + "name": "#%% md\n" + } + }, + "source": [ + "The Schmid factors for each grain can be calculated and plotted. The `slipSystems` argument can be specified, to only calculate the Schmid factor for certain planes, otherwise the maximum for all slip systems is calculated." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "5cd4c838-c45f-443f-ba99-85903b63d6ec", + "metadata": { + "pycharm": { + "name": "#%%\n" + } + }, + "outputs": [], + "source": [ + "ebsd_map.calc_average_grain_schmid_factors(load_vector=np.array([1,0,0]), slip_systems=None)" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "14e99911-5664-4ca9-b652-77510576a929", + "metadata": { + "pycharm": { + "name": "#%%\n" + } + }, + "outputs": [], + "source": [ + "ebsd_map.plot_average_grain_schmid_factors_map()" + ] + }, + { + "cell_type": "markdown", + "id": "cb38b166-bcc1-42d2-95cf-80725bdb9843", + "metadata": { + "pycharm": { + "name": "#%% md\n" + } + }, + "source": [ + "### Single grain analysis\n", + "The `locate_grain` method allows interactive selection of a grain of intereset to apply any analysis to. Clicking on grains in the map will highlight the grain and print out the grain ID (position in the grain list) of the grain." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "1815f9c2-4271-4c42-ae8c-78faab5506b2", + "metadata": {}, + "outputs": [], + "source": [ + "ebsd_map.locate_grain()" + ] + }, + { + "cell_type": "markdown", + "id": "dcf101f3-41fb-4282-b3d9-d503e5215d77", + "metadata": { + "pycharm": { + "name": "#%% md\n" + } + }, + "source": [ + "A built-in example is to calculate the average orientation of the grain and plot this orientation in a IPF" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "f38acf82-dc55-4ca5-86a1-5eae2b1d73da", + "metadata": { + "pycharm": { + "name": "#%%\n" + } + }, + "outputs": [], + "source": [ + "grain_id = 48\n", + "grain = ebsd_map[grain_id]\n", + "grain.calc_average_ori() # stored as a quaternion named grain.refOri\n", + "print(grain.ref_ori)\n", + "grain.plot_ref_ori(direction=[0, 0, 1])" + ] + }, + { + "cell_type": "markdown", + "id": "b59d8a8d-0da3-4252-a1e9-8fe8948ff33d", + "metadata": { + "pycharm": { + "name": "#%% md\n" + } + }, + "source": [ + "The spread of orientations in a given grain can also be plotted on an IPF" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "ecf0d23e-1566-4cdd-a37e-82587d1f3207", + "metadata": { + "pycharm": { + "name": "#%%\n" + } + }, + "outputs": [], + "source": [ + "plot = grain.plot_ori_spread(direction=np.array([0, 0, 1]), c='b', s=1, alpha=0.2)\n", + "grain.plot_ref_ori(direction=[0, 0, 1], c='k', plot=plot)" + ] + }, + { + "cell_type": "markdown", + "id": "74f31034-9034-488d-9c63-dd20f7242a97", + "metadata": { + "pycharm": { + "name": "#%% md\n" + } + }, + "source": [ + "The unit cell for the average grain orientation can also be ploted" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "c8abdc41-199d-4a83-8896-c174916b5796", + "metadata": { + "pycharm": { + "name": "#%%\n" + } + }, + "outputs": [], + "source": [ + "grain.plot_unit_cell()" + ] + }, + { + "cell_type": "markdown", + "id": "883f6a7c-c7b1-4489-8b5f-9d156cafc374", + "metadata": { + "pycharm": { + "name": "#%% md\n" + } + }, + "source": [ + "Printing a list of the slip plane indices, angle of slip plane intersection with the screen (defined as counter-clockwise from upwards), colour defined for the slip plane and also the slip directions and corresponding Schmid factors, is also built in" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "a7e9ef68-e2f4-493e-b331-4c85176e5af6", + "metadata": { + "pycharm": { + "name": "#%%\n" + } + }, + "outputs": [], + "source": [ + "grain.print_slip_traces()" + ] + }, + { + "cell_type": "markdown", + "id": "3fb6ca64-3e97-4dd3-90b4-9393e89e0746", + "metadata": { + "pycharm": { + "name": "#%% md\n" + } + }, + "source": [ + "A second built-in example is to calcuate the grain misorientation, specifically the grain reference orientation deviation (GROD). This shows another feature of the `locate_grain` method, which stores the last selected grain in a variable called `sel_grain` in the EBSD map." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "0c28f0b3-0b94-4fbe-b3ba-c3333dc20e2d", + "metadata": { + "pycharm": { + "name": "#%%\n" + } + }, + "outputs": [], + "source": [ + "if ebsd_map.sel_grain == None: \n", + " ebsd_map.sel_grain = ebsd_map[57]\n", + " \n", + "ebsd_map.sel_grain.build_mis_ori_list()\n", + "ebsd_map.sel_grain.plot_mis_ori(plot_scale_bar=True, vmin=0, vmax=5)" + ] + }, + { + "cell_type": "markdown", + "id": "f9b73c12-60f2-4f47-af7e-ebdbe07b5979", + "metadata": { + "pycharm": { + "name": "#%% md\n" + } + }, + "source": [ + "### Multi grain analysis\n", + "Once an analysis routine has been prototyped for a single grain it can be applied to all the grains in a map using a loop over the grains and any results added to a list for use later. Of couse you could also apply to a smaller subset of grains as well." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "0e9ce3da-a3bb-4e09-9b89-fe475b292f70", + "metadata": { + "pycharm": { + "name": "#%%\n" + } + }, + "outputs": [], + "source": [ + "grain_av_oris = []\n", + "for grain in ebsd_map:\n", + " grain.calc_average_ori()\n", + " grain_av_oris.append(grain.ref_ori)\n", + "\n", + "# Plot all the grain orientations in the map\n", + "Quat.plot_ipf(grain_av_oris, [0, 0, 1], ebsd_map.crystal_sym, marker='o', s=10)\n", + "plt.tight_layout()" + ] + }, + { + "cell_type": "markdown", + "id": "3ff0c852-be44-4088-a5de-669b0fa229fd", + "metadata": { + "pycharm": { + "name": "#%% md\n" + } + }, + "source": [ + "Some common grain analysis routines are built into the EBSD map object, including:" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "66aa6bd5-1f88-4a4f-8294-d88ff61c659d", + "metadata": { + "pycharm": { + "name": "#%%\n" + } + }, + "outputs": [], + "source": [ + "ebsd_map.calc_grain_av_oris()" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "5be22991-2cc8-4e7d-9b45-ab2ca1378632", + "metadata": { + "pycharm": { + "name": "#%%\n" + } + }, + "outputs": [], + "source": [ + "ebsd_map.calc_grain_mis_ori()\n", + "ebsd_map.plot_mis_ori_map(vmin=0, vmax=5, plot_gbs=True, plot_scale_bar=True)" + ] + }, + { + "cell_type": "markdown", + "id": "a4a94c7e-03c6-40c3-b17e-cac3c282d636", + "metadata": { + "pycharm": { + "name": "#%% md\n" + } + }, + "source": [ + "There are also methods for plotting GND density, phases and boundaries. All of the plotting functions in DefDAP use the same parameters to modify the plot, examples seen so far are `plot_gbs`, `plotScaleBar`, `vmin`, `vmax`." + ] + }, + { + "cell_type": "markdown", + "id": "713e6f8b-a1d4-491d-96d5-9cf12a2956f0", + "metadata": { + "pycharm": { + "name": "#%% md\n" + } + }, + "source": [ + "## Linking the optical and EBSD maps\n", + "### Define homologous points\n", + "To register the two datasets, homologous points (points at the same material location) within each map are used to estimate a transformation between the two frames the data are defined in. The homologous points are selected manually using an interactive tool within DefDAP. To select homologous call the method `setHomogPoint` on each of the data maps, which will open a plot window with a button labelled 'save point' in the bottom right. You select a point by right clicking on the map, adjust the position with the arrow and accept the point by with the save point button. Then select the same location in the other map." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "c6fcdb04-369b-4101-9478-9f3c765fc7ad", + "metadata": { + "pycharm": { + "name": "#%%\n" + } + }, + "outputs": [], + "source": [ + "optical_map.set_homog_point()" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "ecefe035-a5c9-40e9-bf0b-a46319df3fd9", + "metadata": { + "pycharm": { + "name": "#%%\n" + } + }, + "outputs": [], + "source": [ + "ebsd_map.set_homog_point()" + ] + }, + { + "cell_type": "markdown", + "id": "98e0aae0-1526-43e1-b6f9-c87eb2a5054e", + "metadata": { + "pycharm": { + "name": "#%% md\n" + } + }, + "source": [ + "The points are stored as a list of tuples `(x, y)` in each of the maps. This means the points can be set from previous values." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "f86b6dee-453a-4545-b752-57dabd7c16e9", + "metadata": { + "pycharm": { + "name": "#%%\n" + } + }, + "outputs": [], + "source": [ + "optical_map.frame.homog_points" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "b73e8887-aa39-4759-8fee-984c0e2b3786", + "metadata": { + "pycharm": { + "name": "#%%\n" + } + }, + "outputs": [], + "source": [ + "ebsd_map.frame.homog_points" + ] + }, + { + "cell_type": "markdown", + "id": "7e06cda2-1ccb-4b38-9c60-534ab8254deb", + "metadata": { + "pycharm": { + "name": "#%% md\n" + } + }, + "source": [ + "Here are some example homologous points for this data, after setting these by running the cells below you can view the locations in the maps by running the `setHomogPoint` methods (above) again" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "5db8cb21-0612-4900-9af5-7c69e059c73a", + "metadata": { + "pycharm": { + "name": "#%%\n" + } + }, + "outputs": [], + "source": [ + "optical_map.frame.homog_points = [\n", + " (467, 653), \n", + " (806, 239), \n", + " (180, 94)\n", + "]" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "e9c2b077-67b3-4eea-865f-39aacba48246", + "metadata": { + "pycharm": { + "name": "#%%\n" + } + }, + "outputs": [], + "source": [ + "ebsd_map.frame.homog_points = [\n", + " (314, 533), \n", + " (543, 242), \n", + " (97, 143)\n", + "]" + ] + }, + { + "cell_type": "markdown", + "id": "aca05b18-d4d0-4015-ac3e-dc28ebc6065f", + "metadata": { + "pycharm": { + "name": "#%% md\n" + } + }, + "source": [ + "### Link the maps\n", + "Finally the two data maps are linked. The type of transform between the two frames can be affine, projective, polynomial." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "223a0c85-4204-4803-984b-b026252b2152", + "metadata": { + "pycharm": { + "name": "#%%\n" + } + }, + "outputs": [], + "source": [ + "optical_map.link_ebsd_map(ebsd_map, transform_type=\"affine\")\n", + "# optical_map.link_ebsd_map(ebsd_map, transform_type=\"projective\")\n", + "# optical_map.link_ebsd_map(ebsd_map, transform_type=\"polynomial\", order=2)" + ] + }, + { + "cell_type": "markdown", + "id": "e6784cf6-8dcd-4134-990d-b6dba399243b", + "metadata": { + "pycharm": { + "name": "#%% md\n" + } + }, + "source": [ + "### Show the transformation" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "5aa0d397-4c57-42c0-b9cf-b571ea0c979b", + "metadata": { + "pycharm": { + "name": "#%%\n" + } + }, + "outputs": [], + "source": [ + "from skimage import transform as tf\n", + "\n", + "data = np.zeros((2000, 2000), dtype=float)\n", + "data[500:1200, 500:1200] = 1.\n", + "transform = optical_map.experiment.get_frame_transform(optical_map.frame, ebsd_map.frame)\n", + "dataWarped = tf.warp(data, transform)\n", + "\n", + "fig, (ax1, ax2) = plt.subplots(1, 2, figsize=(8,4))\n", + "ax1.set_title('Reference')\n", + "ax1.imshow(data)\n", + "ax2.set_title('Transformed')\n", + "ax2.imshow(dataWarped)" + ] + }, + { + "cell_type": "markdown", + "id": "36579474-98fd-46bc-bba1-1cd59ecc482c", + "metadata": { + "pycharm": { + "name": "#%% md\n" + } + }, + "source": [ + "### Segment into grains\n", + "The optical map can now be segmented into grains using the grain boundaries detected in the EBSD map. Analysis rountines can then be applied to individual grain, as with the EBSD grains. The grain finding process will also attempt to link the grains between the EBSD and optical maps and each grain in the optical image has a reference (`ebsdGrain`) to the corrosponding grain in the EBSD map." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "bb95be4e-5bca-43ec-a9c6-09243c000d8a", + "metadata": { + "pycharm": { + "name": "#%%\n" + } + }, + "outputs": [], + "source": [ + "optical_map.data.generate('grains', algorithm='warp', min_grain_size=10)" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "2ef9e5ee-3ada-4bc6-ac23-8ea1ce4e0f5d", + "metadata": {}, + "outputs": [], + "source": [ + "optical_map.plot_map('image', vmin=0, vmax=1, plot_scale_bar=True, plot_gbs='line')" + ] + }, + { + "cell_type": "markdown", + "id": "ac310178-33b2-46a2-9f5a-7a94878cade6", + "metadata": { + "pycharm": { + "name": "#%% md\n" + } + }, + "source": [ + "Now, a grain can also be selected interactively in the optical map, in the same way a grain can be selected from an EBSD map. If `displaySelected` is set to true, then a pop-out window shows the map segmented for the grain" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "fa2a0497-3fd7-4dff-bf71-797b601c75f8", + "metadata": { + "pycharm": { + "name": "#%%\n" + } + }, + "outputs": [], + "source": [ + "optical_map.locate_grain(display_grain=True)" + ] + }, + { + "cell_type": "markdown", + "id": "908017fb-24e1-4963-aa09-03c52567dcc8", + "metadata": {}, + "source": [ + "### Grain inspector\n", + "This is an interactive tool used to perform slip trace analysis" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "b6d7a470-7bcf-4b7f-8902-de3d53c0febc", + "metadata": {}, + "outputs": [], + "source": [ + "optical_map.grain_inspector()" + ] + } + ], + "metadata": { + "kernelspec": { + "display_name": "Python 3 (ipykernel)", + "language": "python", + "name": "python3" + }, + "language_info": { + "codemirror_mode": { + "name": "ipython", + "version": 3 + }, + "file_extension": ".py", + "mimetype": "text/x-python", + "name": "python", + "nbconvert_exporter": "python", + "pygments_lexer": "ipython3", + "version": "3.12.2" + } + }, + "nbformat": 4, + "nbformat_minor": 5 +} diff --git a/tests/data/test-meta-data.xlsx b/tests/data/test-meta-data.xlsx new file mode 100644 index 0000000..d565f9a Binary files /dev/null and b/tests/data/test-meta-data.xlsx differ diff --git a/tests/data/testOptical.png b/tests/data/testOptical.png new file mode 100644 index 0000000..2fe9047 Binary files /dev/null and b/tests/data/testOptical.png differ diff --git a/tests/data/testOpticalEBSD.cpr b/tests/data/testOpticalEBSD.cpr new file mode 100644 index 0000000..60c5cf8 --- /dev/null +++ b/tests/data/testOpticalEBSD.cpr @@ -0,0 +1,100 @@ +[General] +Version=5.0 +Date=2024-09-20 +Time=14:30:42 +Description=f-5 +Author=[Author] +JobMode=RegularGrid +SampleSymmetry=0 +ScanningRotationAngle=180 +ProjectFile=C:\Users\mbgm5pc3\The University of Manchester Dropbox\Patrick Curran\PhD Patrick Curran\4) Experiments folder\year 2 4-point bending\EBSD_data\f-5\f-5\f-5.oipx +Notes= +ProjectNotes= +Duration=1.05596531042309 +PerCycle=1.68855027827309E-06 + +[Job] +Magnification=246 +kV=20 +TiltAngle=70 +TiltAxis=0 +Coverage=100 +Device=None +Automatic=True +NoOfPoints=625368 +GridDistX=3 +GridDistY=3 +GridDist=3 +xCells=852 +yCells=734 + +[SEMFields] +DOEuler1=0.2441 +DOEuler2=87.7736 +DOEuler3=0.2303 + +[SampleAxisLanbels] +LabelX0=X0 +LabelY0=Y0 +LabelZ0=Z0 +LabelX1=X1 +LabelY1=Y1 +LabelZ1=Z1 + +[Acquisition Surface] +Euler1=0 +Euler2=0 +Euler3=0 + +[Fields] +Count=8 +Field1=3 +Field2=4 +Field3=5 +Field4=6 +Field5=7 +Field6=8 +Field7=10 +Field8=11 + +[Phases] +Count=2 + +[Phase1] +StructureName=Titanium cubic +Reference=technique de l'ingenieur +Enabled=True +a=3.192 +b=3.192 +c=3.192 +alpha=90 +beta=90 +gamma=90 +LaueGroup=11 +SpaceGroup=229 +ID1= +ID2= +NumberOfReflectors=190 +Color=16711680 + +[Phase2] +StructureName=Ti-Hex +Reference=[Titanhex v3.cry] +Enabled=True +a=2.954 +b=2.954 +c=4.729 +alpha=90 +beta=90 +gamma=120 +LaueGroup=9 +SpaceGroup=0 +ID1= +ID2= +NumberOfReflectors=199 +Color=255 + +[Settings] +Thumbnail=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 +Settings=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 + diff --git a/tests/data/testOpticalEBSD.crc b/tests/data/testOpticalEBSD.crc new file mode 100644 index 0000000..cafa267 Binary files /dev/null and b/tests/data/testOpticalEBSD.crc differ diff --git a/tests/test_ebsd.py b/tests/test_ebsd.py index 583ac67..483d7c6 100644 --- a/tests/test_ebsd.py +++ b/tests/test_ebsd.py @@ -174,7 +174,7 @@ def test_calc(mock_map, min_grain_size): f'{EXPECTED_RESULTS_DIR}/ebsd_grains_5deg_{min_grain_size}.npz' )['grains'] - assert np.alltrue(result == expected) + assert np.all(result == expected) @staticmethod def test_add_derivative(mock_map): diff --git a/tests/test_hrdic.py b/tests/test_hrdic.py index 29a0464..267646c 100644 --- a/tests/test_hrdic.py +++ b/tests/test_hrdic.py @@ -114,7 +114,7 @@ def test_calc_warp(mock_map, algorithm, min_grain_size): f'{EXPECTED_RESULTS_DIR}/hrdic_grains_{algorithm}{min_grain_size}.npz' )['grains'] - assert np.alltrue(result == expected) + assert np.all(result == expected) @staticmethod def test_add_derivative(mock_map):