diff --git a/.gitignore b/.gitignore index 82f1b04..585b19b 100644 --- a/.gitignore +++ b/.gitignore @@ -2,3 +2,6 @@ ParticleSpy/__pycache__/ ParticleSpy/Parameters/ particlespy.egg-info/ ParticleSpy/__pycache__/*.pyc +*.pyc +ParticleSpy/Parameters/parameters_previous.hdf5 +ParticleSpy/__pycache__/ptcl_class.cpython-37.pyc diff --git a/ParticleSpy/Parameters/parameters_current.hdf5 b/ParticleSpy/Parameters/parameters_current.hdf5 index ebb9f72..41d78b7 100644 Binary files a/ParticleSpy/Parameters/parameters_current.hdf5 and b/ParticleSpy/Parameters/parameters_current.hdf5 differ diff --git a/ParticleSpy/Parameters/parameters_previous.hdf5 b/ParticleSpy/Parameters/parameters_previous.hdf5 index ddb527b..9d8fb9f 100644 Binary files a/ParticleSpy/Parameters/parameters_previous.hdf5 and b/ParticleSpy/Parameters/parameters_previous.hdf5 differ diff --git a/ParticleSpy/ParticleAnalysis.py b/ParticleSpy/ParticleAnalysis.py index 2cf8102..da7f08d 100644 --- a/ParticleSpy/ParticleAnalysis.py +++ b/ParticleSpy/ParticleAnalysis.py @@ -65,19 +65,21 @@ def ParticleAnalysis(acquisition,parameters,particles=None,mask=np.zeros((1))): for region in regionprops(labeled, coordinates='rc'): #'count' start with 1, 0 is background p = Particle() - - p_im = np.zeros_like(image.data) - p_im[labeled==region.label] = image.data[labeled==region.label] - np.min(image.data[labeled==region.label]) - + maskp = np.zeros_like(image.data) maskp[labeled==region.label] = 1 - #Calculate average background around image - dilated_mask = morphology.binary_dilation(maskp).astype(int) - dilated_mask2 = morphology.binary_dilation(dilated_mask).astype(int) - boundary_mask = dilated_mask2 - dilated_mask - p.background = np.sum(boundary_mask*image.data)/np.count_nonzero(boundary_mask) + p_im = np.ma.masked_array(image.data, mask=1-maskp) + #Calculate average background around image + if parameters.store['bkg_sub']==True: + dilated_mask = morphology.binary_dilation(maskp).astype(int) + dilated_mask2 = morphology.binary_dilation(dilated_mask).astype(int) + boundary_mask = dilated_mask2 - dilated_mask + background = np.sum(boundary_mask*image.data)/np.count_nonzero(boundary_mask) + p.set_background(background) + else: + p.set_background(0.0) #origin = ac_number #p.set_origin(origin) @@ -108,10 +110,11 @@ def ParticleAnalysis(acquisition,parameters,particles=None,mask=np.zeros((1))): p.set_property("solidity",region.solidity,None) #Set total image intensity - intensity = ((image.data - p.background)*maskp).sum() - p.set_intensity(intensity) - p.set_property("intensity_max",((image.data - p.background)*maskp).max(),None) - p.set_property("intensity_std",((image.data - p.background)*maskp).std()/p.properties['intensity_max']['value'],None) + p_im_bkgsub = np.ma.masked_array(p_im.data - p.properties['background']['value'], + mask=1-maskp) + p.set_intensity(p_im_bkgsub.sum()) + p.set_property("intensity_max",p_im_bkgsub.max(),None) + p.set_property("intensity_std",p_im_bkgsub.std(),None) #Set zoneaxis '''im_smooth = filters.gaussian(np.uint16(p_im),1) @@ -232,18 +235,24 @@ def store_image(particle,image,params): ii = np.where(particle.mask) box_x_min = np.min(ii[0]) - box_x_max = np.max(ii[0]) - box_y_max = np.max(ii[1]) + box_x_max = np.max(ii[0])+1 box_y_min = np.min(ii[1]) + box_y_max = np.max(ii[1])+1 pad = params.store['pad'] + if params.store['bkg_sub']==True: + image.data = image.data - particle.properties['background']['value'] + if params.store['p_only']==True: - image = image*particle.mask + image.data = image.data*particle.mask - if box_y_min-pad > 0 and box_x_min-pad > 0 and box_x_max+pad < particle.mask.shape[0] and box_y_max+pad < particle.mask.shape[1]: - p_boxed = image.isig[(box_y_min-pad):(box_y_max+pad),(box_x_min-pad):(box_x_max+pad)] + if pad!=None: + if box_y_min-pad > 0 and box_x_min-pad > 0 and box_x_max+pad < particle.mask.shape[0] and box_y_max+pad < particle.mask.shape[1]: + p_boxed = image.isig[(box_y_min-pad):(box_y_max+pad),(box_x_min-pad):(box_x_max+pad)] + else: + p_boxed = image.isig[(box_y_min):(box_y_max),(box_x_min):(box_x_max)] else: - p_boxed = image.isig[(box_y_min):(box_y_max),(box_x_min):(box_x_max)] + p_boxed = image particle.store_im(p_boxed) def store_maps(particle,ac,params): @@ -299,6 +308,7 @@ def generate(self,threshold='otsu',watershed=False,watershed_size=50, self.segment['local_size'] = local_size self.store = {} + self.store['bkg_sub'] = True self.store['store_im'] = store_im self.store['pad'] = pad self.store['p_only'] = False @@ -330,6 +340,7 @@ def save(self,filename=os.path.dirname(inspect.getfile(process))+'/Parameters/pa segment.attrs["rb_kernel"] = self.segment['rb_kernel'] segment.attrs["gaussian"] = self.segment['gaussian'] segment.attrs["local_size"] = self.segment['local_size'] + store.attrs['bkg_sub'] = self.store['bkg_sub'] store.attrs['store_im'] = self.store['store_im'] store.attrs['pad'] = self.store['pad'] store.attrs['store_maps'] = self.store['store_maps'] @@ -360,6 +371,7 @@ def load(self,filename=os.path.dirname(inspect.getfile(process))+'/Parameters/pa self.segment['rb_kernel'] = segment.attrs["rb_kernel"] self.segment['gaussian'] = segment.attrs["gaussian"] self.segment['local_size'] = segment.attrs["local_size"] + self.store['bkg_sub'] = store.attrs['bkg_sub'] self.store['store_im'] = store.attrs['store_im'] self.store['pad'] = store.attrs['pad'] self.store['store_maps'] = store.attrs['store_maps'] diff --git a/ParticleSpy/__pycache__/ParticleAnalysis.cpython-37.pyc b/ParticleSpy/__pycache__/ParticleAnalysis.cpython-37.pyc index 13e52ec..08c551d 100644 Binary files a/ParticleSpy/__pycache__/ParticleAnalysis.cpython-37.pyc and b/ParticleSpy/__pycache__/ParticleAnalysis.cpython-37.pyc differ diff --git a/ParticleSpy/__pycache__/SegUI.cpython-37.pyc b/ParticleSpy/__pycache__/SegUI.cpython-37.pyc index 1ec992c..084745d 100644 Binary files a/ParticleSpy/__pycache__/SegUI.cpython-37.pyc and b/ParticleSpy/__pycache__/SegUI.cpython-37.pyc differ diff --git a/ParticleSpy/__pycache__/__init__.cpython-37.pyc b/ParticleSpy/__pycache__/__init__.cpython-37.pyc index 3344dda..e08b2a7 100644 Binary files a/ParticleSpy/__pycache__/__init__.cpython-37.pyc and b/ParticleSpy/__pycache__/__init__.cpython-37.pyc differ diff --git a/ParticleSpy/__pycache__/api.cpython-37.pyc b/ParticleSpy/__pycache__/api.cpython-37.pyc index 7a5a848..7551fa0 100644 Binary files a/ParticleSpy/__pycache__/api.cpython-37.pyc and b/ParticleSpy/__pycache__/api.cpython-37.pyc differ diff --git a/ParticleSpy/__pycache__/find_zoneaxis.cpython-37.pyc b/ParticleSpy/__pycache__/find_zoneaxis.cpython-37.pyc index 1e0a836..a3563bd 100644 Binary files a/ParticleSpy/__pycache__/find_zoneaxis.cpython-37.pyc and b/ParticleSpy/__pycache__/find_zoneaxis.cpython-37.pyc differ diff --git a/ParticleSpy/__pycache__/particle_load.cpython-37.pyc b/ParticleSpy/__pycache__/particle_load.cpython-37.pyc index fd205db..6551d95 100644 Binary files a/ParticleSpy/__pycache__/particle_load.cpython-37.pyc and b/ParticleSpy/__pycache__/particle_load.cpython-37.pyc differ diff --git a/ParticleSpy/__pycache__/particle_save.cpython-37.pyc b/ParticleSpy/__pycache__/particle_save.cpython-37.pyc index 75e2803..7ace432 100644 Binary files a/ParticleSpy/__pycache__/particle_save.cpython-37.pyc and b/ParticleSpy/__pycache__/particle_save.cpython-37.pyc differ diff --git a/ParticleSpy/__pycache__/ptcl_class.cpython-37.pyc b/ParticleSpy/__pycache__/ptcl_class.cpython-37.pyc index a6a8454..23ebc6d 100644 Binary files a/ParticleSpy/__pycache__/ptcl_class.cpython-37.pyc and b/ParticleSpy/__pycache__/ptcl_class.cpython-37.pyc differ diff --git a/ParticleSpy/__pycache__/radial_profile.cpython-37.pyc b/ParticleSpy/__pycache__/radial_profile.cpython-37.pyc index 3e8d7ac..1fa57ba 100644 Binary files a/ParticleSpy/__pycache__/radial_profile.cpython-37.pyc and b/ParticleSpy/__pycache__/radial_profile.cpython-37.pyc differ diff --git a/ParticleSpy/__pycache__/segptcls.cpython-37.pyc b/ParticleSpy/__pycache__/segptcls.cpython-37.pyc index 84d0a5b..7fccec8 100644 Binary files a/ParticleSpy/__pycache__/segptcls.cpython-37.pyc and b/ParticleSpy/__pycache__/segptcls.cpython-37.pyc differ diff --git a/ParticleSpy/ptcl_class.py b/ParticleSpy/ptcl_class.py index 5951961..4e9a20a 100644 --- a/ParticleSpy/ptcl_class.py +++ b/ParticleSpy/ptcl_class.py @@ -62,6 +62,9 @@ def set_eccentricity(self,eccentricity): def set_intensity(self,intensity): self.properties['intensity'] = {'value':intensity,'units':None} + def set_background(self,background): + self.properties['background'] = {'value':background,'units':None} + def set_property(self,propname,value,units): """ Give a Particle() object an arbitrary property. @@ -101,7 +104,8 @@ def store_spectrum(self,spectrum,stype): def store_composition(self,composition): self.composition = {el.metadata.Sample.elements[0]:el.data for el in composition} - + + class Particle_list(object): """A particle list object.""" @@ -113,7 +117,7 @@ def append(self,particle): def save(self,filename): save_plist(self,filename) - + def plot_area(self,bins=20): """ Displays a plot of particle areas for analysed particles. @@ -254,6 +258,66 @@ def normalize_boxing(self,even=False): particle.image.axes_manager[0].size = particle.image.data.shape[0] particle.image.axes_manager[1].size = particle.image.data.shape[1] + def show(self, param='Image', cols=None, output=False): + """ + display all particle images or other parameters + + Parameters + ---------- + param : str, optional + DESCRIPTION. The default is ['Image']. + 'Image' + 'maps' + 'area' + 'circularity' + """ + self.normalize_boxing() + + num = len(self.list) + if cols==None: + cols = int(np.ceil(np.sqrt(num))) + data_ls = [] + for index in range(num): + if param == 'Image': + data_ls.append(self.list[index].image.data) + elif param == 'mask': + data_ls.append(self.list[index].mask) + self._show_images(data_ls, param, cols, np.arange(num)) + if output: + return data_ls + + def _show_images(self, images, main_title, cols=1, titles=None): + """ + Display a list of images in a single figure with matplotlib. + + Parameters + --------- + images: List of np.arrays compatible with plt.imshow. + + cols (Default = 1): Number of columns in figure (number of rows is + set to np.ceil(n_images/float(cols))). + + titles: List of titles corresponding to each image. Must have + the same length as titles. + --------- + Origin https://gist.github.com/soply/f3eec2e79c165e39c9d540e916142ae1 + """ + assert((titles is None) or (len(images) == len(titles))) + n_images = len(images) + if titles is None: titles = ['Image (%d)' % i for i in range(1, n_images+1)] + fig = plt.figure() + for n, (image, title) in enumerate(zip(images, titles)): + a = fig.add_subplot(cols, np.ceil(n_images/float(cols)), n+1) + if image.ndim == 2: + plt.gray() + plt.axis('off') + plt.imshow(image) + a.set_title(title, fontsize=30) + fig.set_size_inches(np.array([1,1]) * n_images) + fig.suptitle(main_title, fontsize=30, y=0.95) + plt.show() + + def cluster_particles(self,algorithm='Kmeans',properties=None,n_clusters=2,eps=0.2,min_samples=5): """ Cluster particles in to different populations based on specified properties.