Skip to content

Commit ddaf9a1

Browse files
committed
[bugfix] adjust calculatemoments code to properly use labels
1 parent 7bfb390 commit ddaf9a1

1 file changed

Lines changed: 40 additions & 43 deletions

File tree

active_plugins/calculatemoments.py

100644100755
Lines changed: 40 additions & 43 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,6 @@
55
#################################
66

77
import numpy as np
8-
import scipy.ndimage as scind
98

109
#################################
1110
#
@@ -14,27 +13,27 @@
1413
##################################
1514

1615
import cellprofiler_core.module as cpm
17-
import cellprofiler_core.measurement as cpmeas
18-
import cellprofiler_core.object as cpo
1916
import cellprofiler_core.setting as cps
2017
from cellprofiler_core.constants.measurement import COLTYPE_FLOAT
2118
from cellprofiler_core.setting.do_something import DoSomething
2219
from cellprofiler_core.setting.multichoice import MultiChoice
2320
from cellprofiler_core.setting.subscriber import ImageSubscriber, LabelSubscriber
2421
from 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)
@@ -50,14 +49,14 @@
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

6362
def 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

Comments
 (0)