def as_tuple( self ): """ Return indices as tuple. """ return cube.xyzarr_to_tuple(self.indices, coordaxis=1)
def clumpfind( self, levels=None, corners=False, seeded=False, allow_new_peaks=True, timer=True ): """ Generate a clumpfind assignment mask. """ # ................................................... # Check user options # ................................................... if self.linked_data == None: print "Clumpfind assignment requires data." return if seeded == True: if self.linked_lmax == None: print "Seeded clumpfind assignment requires local maxima." return if seeded == False and allow_new_peaks == False: print "Cannot run an unseeded (classic) clumpfind without being able to add seeds." return # ................................................... # Get data to use # ................................................... # Get the data and set the values we will not use to a low # number that will be ignored by the algorithm. data = copy.deepcopy(self.linked_data.data) if self.linked_mask != None: use = self.linked_mask.data*self.linked_data.valid else: use = self.linked_data.valid min_use = np.min(self.linked_data.data[use]) max_use = np.max(self.linked_data.data[use]) low_value = min_use-1. data[(use==False)] = low_value # ................................................... # Calculate contour levels # ................................................... if levels == None: if self.linked_data.noise != None: print "Defaulting to 2 sigma spacing." levels = contour_values( linspace = True, maxval = max_use, minval = min_use, spacing = 2.0*self.linked_data.noise.scale ) else: print "Need a noise estimate." return self.levels = levels # ................................................... # Build the structuring element # ................................................... structure = (Struct( "simple", ndim=self.linked_data.data.ndim, corners=corners)).struct # ................................................... # Initialize the output # ................................................... # ... data self.data = np.zeros_like(data, dtype=np.int) # ... local maxima if seeded == False: print "Initializing a new set of local maxima" self.linked_lmax = \ lmax.Lmax(self.linked_data, self.linked_mask) # ................................................... # Loop over levels (from high to low) # ................................................... nlev = len(levels) count = 0 for level in levels: # ........................ # Print a counter # ........................ perc = count*1./nlev sys.stdout.write('\r') sys.stdout.write("Clumpfind level %d out of %d" % (count, nlev)) sys.stdout.flush() count += 1 # ............................ # Label regions for this level # ............................ thresh = (data >= level) labels, ncolors = ndimage.label( thresh, structure=structure) # ........................... # Vectorize the labeled data # ........................... # This gives a big speedup for sparse data. ind = np.where(thresh) val = self.linked_data.data[ind] ind_arr = cube.xyztup_to_array(ind, coordaxis=1) label_vec = labels[ind] # Get the assignments for the current seeds if self.linked_lmax.num > 0: seed_labels = labels[self.linked_lmax.as_tuple()] # ........................................ # Loop over discrete regions at this level # ........................................ for label in range(1,ncolors+1): # ........................................ # Get the indices for this region # ........................................ this_color = np.where(label_vec == label) this_val = val[this_color] this_ind_arr = ind_arr[this_color[0],:] this_ind = cube.xyzarr_to_tuple(this_ind_arr,coordaxis=1) # ........................................ # Check if we should add a new peak # ........................................ # If there are no peaks or if there are no peaks in # this region, we want to add a new one --- but only # if that's allowed! # A future extension is to add additional criteria # that must be met to add a peak (volume, area, etc.) if self.linked_lmax.num == 0: if allow_new_peaks: add_a_new_peak = True else: continue elif np.sum(seed_labels == label) == 0: if allow_new_peaks: add_a_new_peak = True else: continue else: add_a_new_peak = False # ........................................ # Add a new peak # ........................................ if add_a_new_peak: # Find the location of the maximum value maxind = np.argmax(this_val) # Get the corresponding coordinates peak_index = this_ind_arr[maxind,:] # Add a local maximum new_name = self.linked_lmax.add_local_max(peak_index) # Label these data in the assignment cube self.data[this_ind] = new_name continue # ........................................ # Deal with the case of a signle seed # ........................................ if np.sum(seed_labels == label) == 1: maxind = np.where((seed_labels == label)) self.data[this_ind] = self.linked_lmax.name[maxind] continue # ........................................ # Deal with the case of competing seeds # ........................................ # Several matching labels if np.sum(seed_labels == label) > 1: # Initialize an assignment vector this_assign = np.zeros_like(this_val) best_dist = np.zeros_like(this_val) # Identify the competing seeds maxind = np.where((seed_labels == label)) n_max = len(maxind[0]) for i in range(n_max): this_max_name = self.linked_lmax.name[maxind[0][i]] this_max_coord = self.linked_lmax.indices[this_max_name-1] dist_to_this_max = \ np.sum((this_ind_arr - this_max_coord)**2,axis=1) if i == 0: # ... all true for the first test is_closest = (dist_to_this_max == dist_to_this_max) else: is_closest = (dist_to_this_max < best_dist) this_assign[is_closest] = this_max_name best_dist[is_closest] = dist_to_this_max[is_closest] self.data[this_ind] = this_assign
def as_tuple(self): """ Return indices as tuple. """ return cube.xyzarr_to_tuple(self.indices, coordaxis=1)