def get_ncc_matrix(self): """Get the normalised correlation coefficient (NCC) matrix containing the NCC between each pair of segments. Returns ------- ncc_matrix : Signal2D Normalised correlation coefficient matrix for loadings and factors. """ # Set up empty matrices of correct size to store NCC values. num_comp = np.shape(self.loadings.data)[0] ncc_loadings = np.zeros((num_comp, num_comp)) ncc_factors = np.zeros((num_comp, num_comp)) factors = self.factors.map(np.nan_to_num, inplace=False).copy() loadings = self.loadings.map(np.nan_to_num, inplace=False).copy() # Iterate through loadings calculating NCC values. for i in np.arange(num_comp): ncc_loadings[i] = list( map( lambda x: norm_cross_corr(x, template=loadings.data[i]), loadings.data, )) # Iterate through factors calculating NCC values. for i in np.arange(num_comp): ncc_factors[i] = list( map(lambda x: norm_cross_corr(x, template=factors.data[i]), factors.data)) # Convert matrix to Signal2D and set axes ncc_sig = Signal2D(np.array((ncc_loadings, ncc_factors))) ncc_sig.axes_manager.signal_axes[0].name = "index" ncc_sig.axes_manager.signal_axes[1].name = "index" ncc_sig.metadata.General.title = "Normalised Correlation Coefficient" return ncc_sig
def get_ncc_matrix(self): """Get the normalised correlation coefficient (NCC) matrix containing the NCC between each pair of segments. Returns ------- ncc_matrix : Signal2D Normalised correlation coefficient matrix. """ # TODO: This code should be factored out for reuse in other ncc method. # Set up an empty matrix of correct size to store NCC values. num_comp = np.shape(self.segments.data)[0] ncc_matrix = np.zeros((num_comp, num_comp)) # Iterate through segments calculating NCC values. for i in np.arange(num_comp): ncc_matrix[i] = list( map( lambda x: norm_cross_corr(x, template=self.segments.data[i]), self.segments.data, )) # Convert matrix to Signal2D and set axes ncc_sig = Signal2D(ncc_matrix) ncc_sig.axes_manager.signal_axes[0].name = "segment index" ncc_sig.axes_manager.signal_axes[1].name = "segment index" ncc_sig.metadata.General.title = "Normalised Correlation Coefficient" return ncc_sig
def correlate_learning_segments(self, corr_th_factors=0.4, corr_th_loadings=0.4): """Iterates through the factors and loadings and calculates the normalized cross-correlation between all factors and all loadings. Factors and loadings are summed if the correlations of both factors and loadings exceed the given thresholds. Parameters ---------- corr_th_factors : float Correlation threshold for factors. Must be between -1 and 1. Factors and loadings are summed if both factors and loadings have normalized cross-correlations above corr_th_factors and corr_th_loadings, respectively. corr_th_loadings : int, optional Correlation threshold for loadings. Must be between -1 and 1. Returns ------- learning_segment : LearningSegment LearningSegment where possibly some factors and loadings have been summed. """ # If a mask was used during the decomposition, the factors and/or # loadings will contain nan, which must be converted to numbers prior # to the correlations calculations. factors = self.factors.map(np.nan_to_num, inplace=False) loadings = self.loadings.map(np.nan_to_num, inplace=False) factors = factors.copy().data loadings = loadings.copy().data correlated_loadings = np.zeros_like(loadings[:1]) correlated_factors = np.zeros_like(factors[:1]) # For each loading and factor, calculate the normalized # cross-correlation to all other loadings and factors, and define # add_indices for those with a value above corr_th_loadings and # corr_th_factors respectively. while np.shape(loadings)[0] > 0: corr_list_loadings = list( map(lambda x: norm_cross_corr(x, template=loadings[0]), loadings)) corr_list_factors = list( map(lambda x: norm_cross_corr(x, template=factors[0]), factors)) add_indices = np.where( list( map( lambda l, f: (l > corr_th_loadings and f > corr_th_factors), corr_list_loadings, corr_list_factors, ))) correlated_loadings = np.append( correlated_loadings, np.array([np.sum(loadings[add_indices], axis=0)]), axis=0, ) correlated_factors = np.append( correlated_factors, np.array([np.sum(factors[add_indices], axis=0)]), axis=0, ) loadings = np.delete(loadings, add_indices, axis=0) factors = np.delete(factors, add_indices, axis=0) correlated_loadings = Signal2D( np.delete(correlated_loadings, 0, axis=0)) correlated_factors = Signal2D(np.delete(correlated_factors, 0, axis=0)) learning_segment = LearningSegment(factors=correlated_factors, loadings=correlated_loadings) return learning_segment
def correlate_vdf_segments(self, corr_threshold=0.7, vector_threshold=4, segment_threshold=3): """Iterates through VDF segments and sums those that are associated with the same segment. Summation will be done for those segments that have a normalised cross correlation above corr_threshold. The vectors of each segment sum will be updated accordingly, so that the vectors of each resulting segment sum are all the vectors of the original individual segments. Each vector is assigned an intensity that is the integrated intensity of the segment it originates from. Parameters ---------- corr_threshold : float Segments will be summed if they have a normalized cross- correlation above corr_threshold. Must be between 0 and 1. vector_threshold : int, optional Correlated segments having a number of vectors less than vector_threshold will be discarded. segment_threshold : int, optional Correlated segment intensities that lie in a region where a number of segments less than segment_thresholdhave been found, are set to 0, i.e. the resulting segment will only have intensities above 0 where at least a number of segment_threshold segments have intensitives above 0. Returns ------- vdfseg : VDFSegment The VDFSegment instance updated according to the image correlation results. """ vectors = self.vectors_of_segments.data if segment_threshold > vector_threshold: raise ValueError("segment_threshold must be smaller than or " "equal to vector_threshold.") segments = self.segments.data.copy() num_vectors = np.shape(vectors)[0] gvectors = np.array(np.empty(num_vectors, dtype=object)) vector_indices = np.array(np.empty(num_vectors, dtype=object)) for i in np.arange(num_vectors): gvectors[i] = np.array(vectors[i].copy()) vector_indices[i] = np.array([i], dtype=int) correlated_segments = np.zeros_like(segments[:1]) correlated_vectors = np.array([0.0], dtype=object) correlated_vectors[0] = np.array(np.zeros_like(vectors[:1])) correlated_vector_indices = np.array([0], dtype=object) correlated_vector_indices[0] = np.array([0]) i = 0 pbar = tqdm(total=np.shape(segments)[0]) while np.shape(segments)[0] > i: # For each segment, calculate the normalized cross-correlation to # all other segments, and define add_indices for those with a value # above corr_threshold. corr_list = list( map(lambda x: norm_cross_corr(x, template=segments[i]), segments)) corr_add = list(map(lambda x: x > corr_threshold, corr_list)) add_indices = np.where(corr_add) # If there are more add_indices than vector_threshold, # sum segments and add their vectors. Otherwise, discard segment. if (np.shape(add_indices[0])[0] >= vector_threshold and np.shape(add_indices[0])[0] > 1): new_segment = np.array([np.sum(segments[add_indices], axis=0)]) if segment_threshold > 1: segment_check = np.zeros_like(segments[add_indices], dtype=int) segment_check[np.where(segments[add_indices])] = 1 segment_check = np.sum(segment_check, axis=0, dtype=int) segment_mask = np.zeros_like(segments[0], dtype=bool) segment_mask[np.where( segment_check >= segment_threshold)] = 1 new_segment = new_segment * segment_mask correlated_segments = np.append(correlated_segments, new_segment, axis=0) add_indices = add_indices[0] new_vectors = np.array([0], dtype=object) new_vectors[0] = np.concatenate(gvectors[add_indices], axis=0).reshape(-1, 2) correlated_vectors = np.append(correlated_vectors, new_vectors, axis=0) new_indices = np.array([0], dtype=object) new_indices[0] = np.concatenate(vector_indices[add_indices], axis=0).reshape(-1, 1) correlated_vector_indices = np.append( correlated_vector_indices, new_indices, axis=0) elif np.shape(add_indices[0])[0] >= vector_threshold: add_indices = add_indices[0] correlated_segments = np.append(correlated_segments, segments[add_indices], axis=0) correlated_vectors = np.append(correlated_vectors, gvectors[add_indices], axis=0) correlated_vector_indices = np.append( correlated_vector_indices, vector_indices[add_indices], axis=0) else: add_indices = i segments = np.delete(segments, add_indices, axis=0) gvectors = np.delete(gvectors, add_indices, axis=0) vector_indices = np.delete(vector_indices, add_indices, axis=0) pbar.close() correlated_segments = np.delete(correlated_segments, 0, axis=0) correlated_vectors = np.delete(correlated_vectors, 0, axis=0) correlated_vector_indices = np.delete(correlated_vector_indices, 0, axis=0) correlated_vector_intensities = np.array(np.empty( len(correlated_vectors)), dtype=object) # Sum the intensities in the original segments and assign those to the # correct vectors by referring to vector_indices. # If segment_mask has been used, use the segments as masks too. if segment_threshold > 1: for i in range(len(correlated_vectors)): correlated_vector_intensities[i] = np.zeros( len(correlated_vector_indices[i])) segment_mask = np.zeros_like(segment_mask) segment_mask[np.where(correlated_segments[i])] = 1 segment_intensities = np.sum(self.segments.data * segment_mask, axis=(1, 2)) for n, index in zip( range(len(correlated_vector_indices[i])), correlated_vector_indices[i], ): correlated_vector_intensities[i][n] = np.sum( segment_intensities[index]) else: segment_intensities = np.sum(self.segments.data, axis=(1, 2)) for i in range(len(correlated_vectors)): correlated_vector_intensities[i] = np.zeros( len(correlated_vector_indices[i])) for n, index in zip( range(len(correlated_vector_indices[i])), correlated_vector_indices[i], ): correlated_vector_intensities[i][n] = np.sum( segment_intensities[index]) vdfseg = VDFSegment( Signal2D(correlated_segments), DiffractionVectors(correlated_vectors), correlated_vector_intensities, ) # Transfer axes properties of segments vdfseg.segments = transfer_signal_axes(vdfseg.segments, self.segments) n = vdfseg.segments.axes_manager.navigation_axes[0] n.name = "n" n.units = "number" return vdfseg
def test_norm_cross_corr(img, template, corr_expt): c = norm_cross_corr(img, template) np.testing.assert_allclose(c, corr_expt)