Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
28 commits
Select commit Hold shift + click to select a range
6ec6344
test
YichiWang Jul 3, 2020
2929e6d
Revert "test"
YichiWang Jul 3, 2020
ac91654
store segmented particles
YichiWang Jul 4, 2020
0b9c048
add function to show all segmented particle images
YichiWang Jul 4, 2020
c01d4be
pycache
YichiWang Jul 8, 2020
c84517f
Set store_im to False
YichiWang Jul 8, 2020
67ddc5b
pycache ignored
YichiWang Jul 8, 2020
2f676f0
Revert "pycache ignored"
YichiWang Jul 8, 2020
9cfb81e
Output particle image as a list of arrays
YichiWang Jul 8, 2020
1924709
typo
YichiWang Jul 9, 2020
ed2a093
pycache ignore
YichiWang Jul 10, 2020
935cdb0
Revert "pycache ignore"
YichiWang Jul 10, 2020
25fbbb3
Revert "typo"
YichiWang Jul 10, 2020
6befaeb
pycache and parameter.h5 ignored
YichiWang Jul 10, 2020
7575748
ignore
YichiWang Jul 10, 2020
44d9d19
Allow show particle masks in a single frame
YichiWang Jul 10, 2020
f59395d
adjust particle_list.show
YichiWang Jul 11, 2020
cbff6f9
Correct particle intensity_std calculation
YichiWang Jul 11, 2020
f33e4d9
Allow user to select whether perform background subtraction before ca…
YichiWang Jul 11, 2020
e0b7666
create a new parameter "bkg_sub" and set default to True
YichiWang Jul 11, 2020
9ce452e
store background intensity into particle.properties
YichiWang Jul 11, 2020
df9217b
Allow save no-paded particle image
YichiWang Jul 11, 2020
01e1290
correction
YichiWang Jul 11, 2020
5243334
Correct image intensity calculation
YichiWang Jul 15, 2020
1436108
Create boundary_analysis.py
YichiWang Jul 31, 2020
e19dbd8
Add reference for boundary following algorithm
YichiWang Jul 31, 2020
7ddf2f0
Revert "Add reference for boundary following algorithm"
YichiWang Jul 31, 2020
bf264fa
Revert "Create boundary_analysis.py"
YichiWang Jul 31, 2020
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -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
Binary file modified ParticleSpy/Parameters/parameters_current.hdf5
Binary file not shown.
Binary file modified ParticleSpy/Parameters/parameters_previous.hdf5
Binary file not shown.
50 changes: 31 additions & 19 deletions ParticleSpy/ParticleAnalysis.py
Original file line number Diff line number Diff line change
Expand Up @@ -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)

Expand Down Expand Up @@ -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)
Expand Down Expand Up @@ -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']
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This will change the image out of the function and so will subtract the value every loop.


if params.store['p_only']==True:
image = image*particle.mask
image.data = image.data*particle.mask
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This will change the image outside of the function and so results in everything other than the first particle being zero.


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
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm not sure why you've changed this. This will store the full image and not just the particle.

particle.store_im(p_boxed)

def store_maps(particle,ac,params):
Expand Down Expand Up @@ -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
Expand Down Expand Up @@ -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']
Expand Down Expand Up @@ -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']
Expand Down
Binary file modified ParticleSpy/__pycache__/ParticleAnalysis.cpython-37.pyc
Binary file not shown.
Binary file modified ParticleSpy/__pycache__/SegUI.cpython-37.pyc
Binary file not shown.
Binary file modified ParticleSpy/__pycache__/__init__.cpython-37.pyc
Binary file not shown.
Binary file modified ParticleSpy/__pycache__/api.cpython-37.pyc
Binary file not shown.
Binary file modified ParticleSpy/__pycache__/find_zoneaxis.cpython-37.pyc
Binary file not shown.
Binary file modified ParticleSpy/__pycache__/particle_load.cpython-37.pyc
Binary file not shown.
Binary file modified ParticleSpy/__pycache__/particle_save.cpython-37.pyc
Binary file not shown.
Binary file modified ParticleSpy/__pycache__/ptcl_class.cpython-37.pyc
Binary file not shown.
Binary file modified ParticleSpy/__pycache__/radial_profile.cpython-37.pyc
Binary file not shown.
Binary file modified ParticleSpy/__pycache__/segptcls.cpython-37.pyc
Binary file not shown.
68 changes: 66 additions & 2 deletions ParticleSpy/ptcl_class.py
Original file line number Diff line number Diff line change
Expand Up @@ -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.
Expand Down Expand Up @@ -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."""

Expand All @@ -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.
Expand Down Expand Up @@ -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.
Expand Down