55#################################
66
77import numpy as np
8- import scipy .ndimage as scind
98
109#################################
1110#
1413##################################
1514
1615import cellprofiler_core .module as cpm
17- import cellprofiler_core .measurement as cpmeas
18- import cellprofiler_core .object as cpo
1916import cellprofiler_core .setting as cps
2017from cellprofiler_core .constants .measurement import COLTYPE_FLOAT
2118from cellprofiler_core .setting .do_something import DoSomething
2219from cellprofiler_core .setting .multichoice import MultiChoice
2320from cellprofiler_core .setting .subscriber import ImageSubscriber , LabelSubscriber
2421from cellprofiler_core .utilities .core .object import size_similarly
22+ from centrosome .cpmorphology import fixup_scipy_ndimage_result as fix
23+
2524
2625__doc__ = """\
2726 CalculateMoments
2827================
2928
3029**CalculateMoments** extracts moments statistics from a given distribution of pixel values.
3130
32- This module extracts a collection of quantitative measures of the shape of a distribution of pixel values.
33- The user can use all pixels to compute the moments or can restrict to pixels within objects.
34- If the image has a mask, only unmasked pixels will be used.
31+ This module extracts a collection of quantitative measures of the shape of a distribution of
32+ pixel values. The user can use all pixels to compute the moments or can restrict to pixels
33+ within objects. If the image has a mask, only unmasked pixels will be used.
3534
36- Available measurements:
37- - Mean
35+ Available measurements:
36+ - Mean
3837- Standard deviation (computed using the unbiased estimator)
3938- Skewness (the third moment about the mean, scaled by the standard deviation to the third power)
4039- Kurtosis (the fourth moment about the mean, scaled by the standard deviation to the fourth power)
5049"""
5150
5251
53- def get_object_moment (pixels , func ):
54- labs = np .unique (pixels )
55- moms = np .zeros ([ np .max (labs ) + 1 , 1 ] )
56- for l in labs :
57- if l != 0 :
58- px = pixels [np .where (pixels == l )]
59- moms [l ] = func (px )
60- return moms
52+ def get_object_moment (pixels , labels , func ):
53+ labs = np .unique (labels )
54+ moms = np .zeros (np .max (labs ) + 1 )
55+ for lab in labs :
56+ if lab != 0 :
57+ px = pixels [np .where (labels == lab )]
58+ moms [lab ] = func (px )
59+ return moms [ 1 :] # ignore the 0th label
6160
6261
6362def mean (pixels ):
@@ -76,7 +75,6 @@ def skewness(pixels):
7675 mean = np .mean (pixels )
7776
7877 num = np .sum (np .power (pixels - mean , 3 ))
79- # num=num/(len(pixels)*len(pixels[0]))
8078 num = num / pixels .size
8179 denom = np .std (pixels )
8280
@@ -142,13 +140,17 @@ def create_settings(self):
142140 "Moments to compute" ,
143141 MOM_ALL ,
144142 MOM_ALL ,
145- doc = """Moments are statistics describing the distribution of values in the set of pixels of interest:
146-
147- - %(MOM_1)s - the first image moment, which corresponds to the central value of the collection of pixels of interest.
148- - %(MOM_2)s - the second image moment, which measures the amount of variation or dispersion of pixel values about its mean.
149- - %(MOM_3)s - a scaled version of the third moment, which measures the asymmetry of the pixel values distribution about its mean.
150- - %(MOM_4)s - a scaled version of the fourth moment, which measures the "peakedness" of the pixel values distribution.
151-
143+ doc = """Moments are statistics describing the distribution of values in the set
144+ of pixels of interest:
145+ - %(MOM_1)s - the first image moment, which corresponds to the central value
146+ of the collection of pixels of interest.
147+ - %(MOM_2)s - the second image moment, which measures the amount of variation
148+ or dispersion of pixel values about its mean.
149+ - %(MOM_3)s - a scaled version of the third moment, which measures the asymmetry
150+ of the pixel values distribution about its mean.
151+ - %(MOM_4)s - a scaled version of the fourth moment, which measures the
152+ "peakedness" of the pixel values distribution.
153+
152154 Choose one or more moments to measure."""
153155 % globals (),
154156 )
@@ -205,8 +207,8 @@ def add_image_cb(self, can_remove=True):
205207 ImageSubscriber (
206208 "Select an image to measure" ,
207209 "None" ,
208- doc = """
209- What did you call the grayscale images whose moments you want to calculate?""" ,
210+ doc = """What did you call the grayscale images whose moments you want
211+ to calculate?""" ,
210212 ),
211213 )
212214 if can_remove :
@@ -233,13 +235,13 @@ def add_object_cb(self, can_remove=True):
233235 "Select objects to measure" ,
234236 "None" ,
235237 doc = """
236- What did you call the objects from which you want to calculate moments?
237- If you only want to calculate moments of
238- the image overall, you can remove all objects using the "Remove this object" button.
239- Objects specified here will have moments computed against *all* images specified above, which
240- may lead to image-object combinations that are unnecessary. If you
241- do not want this behavior, use multiple CalculateMoments
242- modules to specify the particular image-object measures that you want.""" ,
238+ What did you call the objects from which you want to calculate moments?
239+ If you only want to calculate moments of
240+ the image overall, you can remove all objects using the "Remove this object"
241+ button. Objects specified here will have moments computed against *all* images
242+ specified above, which may lead to image-object combinations that are unnecessary.
243+ If you do not want this behavior, use multiple CalculateMoments
244+ modules to specify the particular image-object measures that you want.""" ,
243245 ),
244246 )
245247 if can_remove :
@@ -328,22 +330,18 @@ def run_object(self, image_name, object_name, workspace):
328330
329331 for name in self .moms .value .split ("," ):
330332 fn = MOM_TO_F [name ]
331- value = get_object_moment (pixels , fn )
333+ moments = get_object_moment (pixels , labels , fn )
332334 statistics += self .record_measurement (
333- workspace , image_name , object_name , name , value
335+ workspace , image_name , object_name , name , moments
334336 )
335337 return statistics
336338
337339 def is_interactive (self ):
338340 return False
339341
340- def display (self , workspace ):
342+ def display (self , workspace , figure ):
341343 statistics = workspace .display_data .statistics
342- figure = workspace .create_or_find_figure (
343- title = "CalculateMoments, image cycle #%d"
344- % (workspace .measurements .image_set_number ),
345- subplots = (1 , 1 ),
346- )
344+ figure .set_subplots ((1 , 1 ))
347345 figure .subplot_table (0 , 0 , statistics , ratio = (0.25 , 0.25 , 0.25 , 0.25 ))
348346
349347 def get_features (self ):
@@ -418,8 +416,7 @@ def record_measurement(
418416 ):
419417 """Record the result of a measurement in the workspace's
420418 measurements"""
421- # Todo: The line below previous referred to "fix", assumed this meant the numpy version
422- data = np .fix (result )
419+ data = fix (result )
423420 data [~ np .isfinite (data )] = 0
424421 workspace .add_measurement (
425422 object_name , "%s_%s_%s" % (MOMENTS , feature_name , image_name ), data
0 commit comments