Beispiel #1
0
            def __init__(self, index, operation):
                self.__index = index
                self.__operation = operation
                self.__operand_choice = cps.Choice(
                    self.operand_choice_text(),
                    MC_ALL,
                    doc="""Indicate whether the operand is an image or object measurement.""",
                )

                self.__operand_objects = cps.ObjectNameSubscriber(
                    self.operand_objects_text(),
                    "None",
                    doc="""Choose the objects you want to measure for this operation.""",
                )

                self.__operand_measurement = cps.Measurement(
                    self.operand_measurement_text(),
                    self.object_fn,
                    doc="""\
Enter the category that was used to create the measurement. You
will be prompted to add additional information depending on
the type of measurement that is requested.""",
                )

                self.__multiplicand = cps.Float(
                    "Multiply the above operand by",
                    1,
                    doc="""Enter the number by which you would like to multiply the above operand.""",
                )

                self.__exponent = cps.Float(
                    "Raise the power of above operand by",
                    1,
                    doc="""Enter the power by which you would like to raise the above operand.""",
                )
Beispiel #2
0
    def create_settings(self):
        """Create the settings for the module

        Create the settings for the module during initialization.
        """
        self.secondary_objects_name = cps.ObjectNameSubscriber(
            "Select the larger identified objects",
            "None",
            doc="""\
Select the larger identified objects. This will usually be an object
previously identified by an **IdentifySecondaryObjects** module.""",
        )

        self.primary_objects_name = cps.ObjectNameSubscriber(
            "Select the smaller identified objects",
            "None",
            doc="""\
Select the smaller identified objects. This will usually be an object
previously identified by an **IdentifyPrimaryObjects** module.""",
        )

        self.subregion_objects_name = cps.ObjectNameProvider(
            "Name the tertiary objects to be identified",
            "Cytoplasm",
            doc="""\
Enter a name for the new tertiary objects. The tertiary objects
will consist of the smaller object subtracted from the larger object.""",
        )

        self.shrink_primary = cps.Binary(
            "Shrink smaller object prior to subtraction?",
            True,
            doc="""\
Select *Yes* to shrink the smaller objects by 1 pixel before
subtracting them from the larger objects. this approach will ensure that
there is always a tertiary object produced, even if it is only 1 pixel wide.
If you need alternate amounts of shrinking, use the **ExpandOrShrink**
module prior to **IdentifyTertiaryObjects**.

Select *No* to subtract the objects directly, which will ensure that
no pixels are shared between the primary/secondary/tertiary objects and
hence measurements for all three sets of objects will not use the same
pixels multiple times. However, this may result in the creation of
objects with no area. Measurements can still be made on such objects,
but the results will be zero or not-a-number (NaN).
""" % globals(),
        )
    def add_image_measurement(self, can_remove=True):
        group = cps.SettingsGroup()
        if can_remove:
            group.append("divider", cps.Divider())

        group.append(
            "image_name",
            cps.ImageNameSubscriber(
                "Select the image to measure",
                "None",
                doc="""\
Choose an image name from the drop-down menu to calculate intensity for
that image. Use the *Add another image* button below to add additional
images to be measured. You can add the same image multiple times
if you want to measure the intensity within several different
objects.""",
            ),
        )

        group.append(
            "wants_objects",
            cps.Binary(
                "Measure the intensity only from areas enclosed by objects?",
                False,
                doc="""\
Select *Yes* to measure only those pixels within an object type you
choose, identified by a prior module. Note that this module will
aggregate intensities across all objects in the image: to measure each
object individually, see **MeasureObjectIntensity** instead.
""" % globals(),
            ),
        )

        group.append(
            "object_name",
            cps.ObjectNameSubscriber(
                "Select the input objects",
                "None",
                doc="""\
*(Used only when measuring intensity from area occupied by objects)*

Select the objects that the intensity will be aggregated within. The
intensity measurement will be restricted to the pixels within these
objects.""",
            ),
        )

        if can_remove:
            group.append(
                "remover",
                cps.RemoveSettingButton("", "Remove this image", self.images,
                                        group),
            )
        self.images.append(group)
    def add_objects(self):
        og = cps.SettingsGroup()
        og.append(
            "objects_name",
            cps.ObjectNameSubscriber(
                "Select objects to measure",
                "None",
                doc="""\
Select the objects whose granularity will be measured. You can select
objects from prior modules that identify objects, such as
**IdentifyPrimaryObjects**. If you only want to measure the granularity
for the image overall, you can remove all objects using the “Remove this
object” button.""",
            ),
        )
        og.append(
            "remover",
            cps.RemoveSettingButton("", "Remove this object", self.objects,
                                    og),
        )
        self.objects.append(og)
Beispiel #5
0
    def create_settings(self):
        """Create the settings here and set the module name (initialization)

        """
        self.source_choice = cps.Choice(
            "Use objects or an image as a mask?",
            [IO_OBJECTS, IO_IMAGE],
            doc="""\
You can mask an image in two ways:

-  *%(IO_OBJECTS)s*: Using objects created by another module (for
   instance **IdentifyPrimaryObjects**). The module will mask out all
   parts of the image that are not within one of the objects (unless you
   invert the mask).
-  *%(IO_IMAGE)s*: Using a binary image as the mask, where black
   portions of the image (false or zero-value pixels) will be masked
   out. If the image is not binary, the module will use all pixels whose
   intensity is greater than 0.5 as the mask’s foreground (white area).
   You can use **Threshold** instead to create a binary image with
   finer control over the intensity choice.
   """
            % globals(),
        )

        self.object_name = cps.ObjectNameSubscriber(
            "Select object for mask",
            "None",
            doc="""\
*(Used only if mask is to be made from objects)*

Select the objects you would like to use to mask the input image.
""",
        )

        self.masking_image_name = cps.ImageNameSubscriber(
            "Select image for mask",
            "None",
            doc="""\
*(Used only if mask is to be made from an image)*

Select the image that you like to use to mask the input image.
""",
        )

        self.image_name = cps.ImageNameSubscriber(
            "Select the input image",
            "None",
            doc="Select the image that you want to mask.",
        )

        self.masked_image_name = cps.ImageNameProvider(
            "Name the output image",
            "MaskBlue",
            doc="Enter the name for the output masked image.",
        )

        self.invert_mask = cps.Binary(
            "Invert the mask?",
            False,
            doc="""\
This option reverses the foreground/background relationship of the mask.

-  Select "*No*" to produce the mask from the foreground (white
   portion) of the masking image or the area within the masking objects.
-  Select "*Yes*" to instead produce the mask from the *background*
   (black portions) of the masking image or the area *outside* the
   masking objects.
       """
            % globals(),
        )
Beispiel #6
0
    def create_settings(self):
        """Create the settings for the module

        Create the settings for the module during initialization.
        """
        self.contrast_choice = cps.Choice(
            "Make each classification decision on how many measurements?",
            [BY_SINGLE_MEASUREMENT, BY_TWO_MEASUREMENTS],
            doc="""\
This setting controls how many measurements are used to make a
classifications decision for each object:

-  *%(BY_SINGLE_MEASUREMENT)s:* Classifies each object based on a
   single measurement.
-  *%(BY_TWO_MEASUREMENTS)s:* Classifies each object based on a pair
   of measurements taken together (that is, an object must meet two
   criteria to belong to a class).
""" % globals(),
        )

        ############### Single measurement settings ##################
        #
        # A list holding groupings for each of the single measurements
        # to be done
        #
        self.single_measurements = []
        #
        # A count of # of measurements
        #
        self.single_measurement_count = cps.HiddenCount(
            self.single_measurements)
        #
        # Add one single measurement to start off
        #
        self.add_single_measurement(False)
        #
        # A button to press to get another measurement
        #
        self.add_measurement_button = cps.DoSomething(
            "", "Add another classification", self.add_single_measurement)
        #
        ############### Two-measurement settings #####################
        #
        # The object for the contrasting method
        #
        self.object_name = cps.ObjectNameSubscriber(
            "Select the object name",
            "None",
            doc="""\
Choose the object that you want to measure from the list. This should be
an object created by a previous module such as
**IdentifyPrimaryObjects**, **IdentifySecondaryObjects**, **IdentifyTertiaryObjects**, or **Watershed**
""",
        )

        #
        # The two measurements for the contrasting method
        #
        def object_fn():
            return self.object_name.value

        self.first_measurement = cps.Measurement(
            "Select the first measurement",
            object_fn,
            doc="""\
*(Used only if using a pair of measurements)*

Choose a measurement made on the above object. This is the first of two
measurements that will be contrasted together. The measurement should be
one made on the object in a prior module.
""",
        )

        self.first_threshold_method = cps.Choice(
            "Method to select the cutoff",
            [TM_MEAN, TM_MEDIAN, TM_CUSTOM],
            doc="""\
*(Used only if using a pair of measurements)*

Objects are classified as being above or below a cutoff value for a
measurement. You can set this cutoff threshold in one of three ways:

-  *%(TM_MEAN)s*: At the mean of the measurement’s value for all
   objects in the image cycle.
-  *%(TM_MEDIAN)s*: At the median of the measurement’s value for all
   objects in the image set.
-  *%(TM_CUSTOM)s*: You specify a custom threshold value.
""" % globals(),
        )

        self.first_threshold = cps.Float(
            "Enter the cutoff value",
            0.5,
            doc="""\
*(Used only if using a pair of measurements)*

This is the cutoff value separating objects in the two classes.""",
        )

        self.second_measurement = cps.Measurement(
            "Select the second measurement",
            object_fn,
            doc="""\
*(Used only if using a pair of measurements)*

Select a measurement made on the above object. This is
the second of two measurements that will be contrasted together.
The measurement should be one made on the object in a prior
module.""",
        )

        self.second_threshold_method = cps.Choice(
            "Method to select the cutoff",
            [TM_MEAN, TM_MEDIAN, TM_CUSTOM],
            doc="""\
*(Used only if using a pair of measurements)*

Objects are classified as being above or below a cutoff value for a
measurement. You can set this cutoff threshold in one of three ways:

-  *%(TM_MEAN)s:* At the mean of the measurement’s value for all
   objects in the image cycle.
-  *%(TM_MEDIAN)s:* At the median of the measurement’s value for all
   objects in the image set.
-  *%(TM_CUSTOM)s:* You specify a custom threshold value.
""" % globals(),
        )

        self.second_threshold = cps.Float(
            "Enter the cutoff value",
            0.5,
            doc="""\
*(Used only if using a pair of measurements)*

This is the cutoff value separating objects in the two classes.""",
        )

        self.wants_custom_names = cps.Binary(
            "Use custom names for the bins?",
            False,
            doc="""\
*(Used only if using a pair of measurements)*

Select "*Yes*" if you want to specify the names of each bin
measurement.

Select "*No*" to create names based on the measurements. For instance,
for “Intensity_MeanIntensity_Green” and
“Intensity_TotalIntensity_Blue”, the module generates measurements
such as
“Classify_Intensity_MeanIntensity_Green_High_Intensity_TotalIntensity_Low”.
""" % globals(),
        )

        self.low_low_custom_name = cps.AlphanumericText(
            "Enter the low-low bin name",
            "low_low",
            doc="""\
*(Used only if using a pair of measurements)*

Name of the measurement for objects that fall below the threshold for
both measurements.
""",
        )

        self.low_high_custom_name = cps.AlphanumericText(
            "Enter the low-high bin name",
            "low_high",
            doc="""\
*(Used only if using a pair of measurements)*

Name of the measurement for objects whose
first measurement is below threshold and whose second measurement
is above threshold.
""",
        )

        self.high_low_custom_name = cps.AlphanumericText(
            "Enter the high-low bin name",
            "high_low",
            doc="""\
*(Used only if using a pair of measurements)*

Name of the measurement for objects whose
first measurement is above threshold and whose second measurement
is below threshold.""",
        )

        self.high_high_custom_name = cps.AlphanumericText(
            "Enter the high-high bin name",
            "high_high",
            doc="""\
*(Used only if using a pair of measurements)*

Name of the measurement for objects that
are above the threshold for both measurements.""",
        )

        self.wants_image = cps.Binary(
            "Retain an image of the classified objects?",
            False,
            doc="""\
Select "*Yes*" to retain the image of the objects color-coded
according to their classification, for use later in the pipeline (for
example, to be saved by a **SaveImages** module).
""" % globals(),
        )

        self.image_name = cps.ImageNameProvider(
            "Enter the image name",
            "None",
            doc="""\
*(Used only if the classified object image is to be retained for later use in the pipeline)*

Enter the name to be given to the classified object image.""",
        )
Beispiel #7
0
    def add_single_measurement(self, can_delete=True):
        """Add a single measurement to the group of single measurements

        can_delete - True to include a "remove" button, False if you're not
                     allowed to remove it.
        """
        group = cps.SettingsGroup()
        if can_delete:
            group.append("divider", cps.Divider(line=True))

        group.append(
            "object_name",
            cps.ObjectNameSubscriber(
                "Select the object to be classified",
                "None",
                doc="""\
The name of the objects to be classified. You can choose from objects
created by any previous module. See **IdentifyPrimaryObjects**,
**IdentifySecondaryObjects**, **IdentifyTertiaryObjects**, or **Watershed**
""",
            ),
        )

        def object_fn():
            return group.object_name.value

        group.append(
            "measurement",
            cps.Measurement(
                "Select the measurement to classify by",
                object_fn,
                doc="""\
*(Used only if using a single measurement)*

Select a measurement made by a previous module. The objects will be
classified according to their values for this measurement.
""",
            ),
        )

        group.append(
            "bin_choice",
            cps.Choice(
                "Select bin spacing",
                [BC_EVEN, BC_CUSTOM],
                doc="""\
*(Used only if using a single measurement)*

Select how you want to define the spacing of the bins. You have the
following options:

-  *%(BC_EVEN)s:* Choose this if you want to specify bins of equal
   size, bounded by upper and lower limits. If you want two bins, choose
   this option and then provide a single threshold when asked.
-  *%(BC_CUSTOM)s:* Choose this option to create the indicated number
   of bins at evenly spaced intervals between the low and high
   threshold. You also have the option to create bins for objects that
   fall below or above the low and high threshold.
""" % globals(),
            ),
        )

        group.append(
            "bin_count",
            cps.Integer(
                "Number of bins",
                3,
                minval=1,
                doc="""\
*(Used only if using a single measurement)*

This is the number of bins that will be created between
the low and high threshold""",
            ),
        )

        group.append(
            "low_threshold",
            cps.Float(
                "Lower threshold",
                0,
                doc="""\
*(Used only if using a single measurement and "%(BC_EVEN)s" selected)*

This is the threshold that separates the lowest bin from the others. The
lower threshold, upper threshold, and number of bins define the
thresholds of bins between the lowest and highest.
""" % globals(),
            ),
        )

        group.append(
            "wants_low_bin",
            cps.Binary(
                "Use a bin for objects below the threshold?",
                False,
                doc="""\
*(Used only if using a single measurement)*

Select "*Yes*" if you want to create a bin for objects whose values
fall below the low threshold. Select "*No*" if you do not want a bin
for these objects.
""" % globals(),
            ),
        )

        def min_upper_threshold():
            return group.low_threshold.value + np.finfo(float).eps

        group.append(
            "high_threshold",
            cps.Float(
                "Upper threshold",
                1,
                minval=cps.NumberConnector(min_upper_threshold),
                doc="""\
*(Used only if using a single measurement and "%(BC_EVEN)s" selected)*

This is the threshold that separates the last bin from the others. Note
that if you would like two bins, you should select "*%(BC_CUSTOM)s*".
""" % globals(),
            ),
        )

        group.append(
            "wants_high_bin",
            cps.Binary(
                "Use a bin for objects above the threshold?",
                False,
                doc="""\
*(Used only if using a single measurement)*

Select "*Yes*" if you want to create a bin for objects whose values
are above the high threshold.

Select "*No*" if you do not want a bin for these objects.
""" % globals(),
            ),
        )

        group.append(
            "custom_thresholds",
            cps.Text(
                "Enter the custom thresholds separating the values between bins",
                "0,1",
                doc="""\
*(Used only if using a single measurement and "%(BC_CUSTOM)s" selected)*

This setting establishes the threshold values for the bins. You should
enter one threshold between each bin, separating thresholds with commas
(for example, *0.3, 1.5, 2.1* for four bins). The module will create one
more bin than there are thresholds.
""" % globals(),
            ),
        )

        group.append(
            "wants_custom_names",
            cps.Binary(
                "Give each bin a name?",
                False,
                doc="""\
*(Used only if using a single measurement)*

Select "*Yes*" to assign custom names to bins you have specified.

Select "*No*" for the module to automatically assign names based on
the measurements and the bin number.
""" % globals(),
            ),
        )

        group.append(
            "bin_names",
            cps.Text(
                "Enter the bin names separated by commas",
                "None",
                doc="""\
*(Used only if "Give each bin a name?" is checked)*

Enter names for each of the bins, separated by commas.
An example including three bins might be *First,Second,Third*.""",
            ),
        )

        group.append(
            "wants_images",
            cps.Binary(
                "Retain an image of the classified objects?",
                False,
                doc="""\
Select "*Yes*" to keep an image of the objects which is color-coded
according to their classification, for use later in the pipeline (for
example, to be saved by a **SaveImages** module).
""" % globals(),
            ),
        )

        group.append(
            "image_name",
            cps.ImageNameProvider(
                "Name the output image",
                "ClassifiedNuclei",
                doc=
                """Enter the name to be given to the classified object image.""",
            ),
        )

        group.can_delete = can_delete

        def number_of_bins():
            """Return the # of bins in this classification"""
            if group.bin_choice == BC_EVEN:
                value = group.bin_count.value
            else:
                value = len(group.custom_thresholds.value.split(",")) - 1
            if group.wants_low_bin:
                value += 1
            if group.wants_high_bin:
                value += 1
            return value

        group.number_of_bins = number_of_bins

        def measurement_name():
            """Get the measurement name to use inside the bin name

            Account for conflicts with previous measurements
            """
            measurement_name = group.measurement.value
            other_same = 0
            for other in self.single_measurements:
                if id(other) == id(group):
                    break
                if other.measurement.value == measurement_name:
                    other_same += 1
            if other_same > 0:
                measurement_name += str(other_same)
            return measurement_name

        def bin_feature_names():
            """Return the feature names for each bin"""
            if group.wants_custom_names:
                return [
                    name.strip() for name in group.bin_names.value.split(",")
                ]
            return [
                "_".join((measurement_name(), "Bin_%d" % (i + 1)))
                for i in range(number_of_bins())
            ]

        group.bin_feature_names = bin_feature_names

        def validate_group():
            bin_name_count = len(bin_feature_names())
            bin_count = number_of_bins()
            if bin_count < 1:
                bad_setting = (group.bin_count if group.bin_choice == BC_EVEN
                               else group.custom_thresholds)
                raise cps.ValidationError(
                    "You must have at least one bin in order to take measurements. "
                    "Either add more bins or ask for bins for objects above or below threshold",
                    bad_setting,
                )
            if bin_name_count != number_of_bins():
                raise cps.ValidationError(
                    "The number of bin names (%d) does not match the number of bins (%d)."
                    % (bin_name_count, bin_count),
                    group.bin_names,
                )
            for bin_feature_name in bin_feature_names():
                cps.AlphanumericText.validate_alphanumeric_text(
                    bin_feature_name, group.bin_names, True)
            if group.bin_choice == BC_CUSTOM:
                try:
                    [
                        float(x.strip())
                        for x in group.custom_thresholds.value.split(",")
                    ]
                except ValueError:
                    raise cps.ValidationError(
                        "Custom thresholds must be a comma-separated list "
                        'of numbers (example: "1.0, 2.3, 4.5")',
                        group.custom_thresholds,
                    )

        group.validate_group = validate_group

        if can_delete:
            group.remove_settings_button = cps.RemoveSettingButton(
                "", "Remove this classification", self.single_measurements,
                group)
        self.single_measurements.append(group)
Beispiel #8
0
    def create_settings(self):
        self.objects_name = cps.ObjectNameSubscriber(
            "Select the input objects",
            "None",
            doc="""\
Select the objects you would like to split or merge (that is,
whose object numbers you want to reassign). You can
use any objects that were created in previous modules, such as
**IdentifyPrimaryObjects** or **IdentifySecondaryObjects**.""",
        )

        self.output_objects_name = cps.ObjectNameProvider(
            "Name the new objects",
            "RelabeledNuclei",
            doc="""\
Enter a name for the objects that have been split or merged (that is,
whose numbers have been reassigned).
You can use this name in subsequent modules that take objects as inputs.""",
        )

        self.relabel_option = cps.Choice(
            "Operation",
            [OPTION_MERGE, OPTION_SPLIT],
            doc="""\
You can choose one of the following options:

-  *%(OPTION_MERGE)s:* Assign adjacent or nearby objects the same label
   based on certain criteria. It can be useful, for example, to merge
   together touching objects that were incorrectly split into two pieces
   by an **Identify** module.
-  *%(OPTION_SPLIT)s:* Assign a unique number to separate objects that
   currently share the same label. This can occur if you applied certain
   operations in the **Morph** module to objects.""" % globals(),
        )

        self.merge_option = cps.Choice(
            "Merging method",
            [UNIFY_DISTANCE, UNIFY_PARENT],
            doc="""\
*(Used only with the "%(OPTION_MERGE)s" option)*

You can merge objects in one of two ways:

-  *%(UNIFY_DISTANCE)s:* All objects within a certain pixel radius from
   each other will be merged.
-  *%(UNIFY_PARENT)s:* All objects which share the same parent
   relationship to another object will be merged. This is not to be
   confused with using the **RelateObjects** module, in which the
   related objects remain as individual objects. See **RelateObjects**
   for more details.""" % globals(),
        )

        self.merging_method = cps.Choice(
            "Output object type",
            [UM_DISCONNECTED, UM_CONVEX_HULL],
            doc="""\
*(Used only with the "%(UNIFY_PARENT)s" merging method)*

**SplitOrMergeObjects** can either merge the child objects and keep them
disconnected or it can find the smallest convex polygon (the convex
hull) that encloses all of a parent’s child objects. The convex hull
will be truncated to include only those pixels in the parent - in that
case it may not truly be convex. Choose *%(UM_DISCONNECTED)s* to leave
the children as disconnected pieces. Choose *%(UM_CONVEX_HULL)s* to
create an output object that is the convex hull around them all.""" %
            globals(),
        )

        self.parent_object = cps.Choice(
            "Select the parent object",
            ["None"],
            choices_fn=self.get_parent_choices,
            doc="""\
Select the parent object that will be used to merge the child objects.
Please note the following:

-  You must have established a parent-child relationship between the
   objects using a prior **RelateObjects** module.
-  Primary objects and their associated secondary objects are already in
   a one-to-one parent-child relationship, so it makes no sense to merge
   them here.""",
        )

        self.distance_threshold = cps.Integer(
            "Maximum distance within which to merge objects",
            0,
            minval=0,
            doc="""\
*(Used only with the "%(OPTION_MERGE)s" option and the "%(UNIFY_DISTANCE)s"
method)*

Objects that are less than or equal to the distance you enter here, in
pixels, will be merged. If you choose zero (the default), only objects
that are touching will be merged. Note that *%(OPTION_MERGE)s* will
not actually connect or bridge the two objects by adding any new pixels;
it simply assigns the same object number to the portions of the object.
The new, merged object may therefore consist of two or more unconnected
components. If you want to add pixels around objects, see
**ExpandOrShrink** or **Morph**.""" % globals(),
        )

        self.wants_image = cps.Binary(
            "Merge using a grayscale image?",
            False,
            doc="""\
*(Used only with the "%(OPTION_MERGE)s" option)*

Select *Yes* to use the objects’ intensity features to determine
whether two objects should be merged. If you choose to use a grayscale
image, *%(OPTION_MERGE)s* will merge two objects only if they are
within the distance you have specified *and* certain criteria about the
objects within the grayscale image are met.""" % globals(),
        )

        self.image_name = cps.ImageNameSubscriber(
            "Select the grayscale image to guide merging",
            "None",
            doc="""\
*(Used only if a grayscale image is to be used as a guide for
merging)*

Select the name of an image loaded or created by a previous module.""",
        )

        self.minimum_intensity_fraction = cps.Float(
            "Minimum intensity fraction",
            0.9,
            minval=0,
            maxval=1,
            doc="""\
*(Used only if a grayscale image is to be used as a guide for
merging)*

Select the minimum acceptable intensity fraction. This will be used as
described for the method you choose in the next setting.""",
        )

        self.where_algorithm = cps.Choice(
            "Method to find object intensity",
            [CA_CLOSEST_POINT, CA_CENTROIDS],
            doc="""\
*(Used only if a grayscale image is to be used as a guide for
merging)*

You can use one of two methods to determine whether two objects should
merged, assuming they meet the distance criteria (as specified
above):

-  *%(CA_CENTROIDS)s:* When the module considers merging two objects,
   this method identifies the centroid of each object, records the
   intensity value of the dimmer of the two centroids, multiplies this
   value by the *minimum intensity fraction* to generate a threshold,
   and draws a line between the centroids. The method will merge the two
   objects only if the intensity of every point along the line is above
   the threshold. For instance, if the intensity of one centroid is 0.75
   and the other is 0.50 and the *minimum intensity fraction* has been
   chosen to be 0.9, all points along the line would need to have an
   intensity of min(0.75, 0.50) \* 0.9 = 0.50 \* 0.9 = 0.45.
   This method works well for round cells whose maximum intensity is in
   the center of the cell: a single cell that was incorrectly segmented
   into two objects will typically not have a dim line between the
   centroids of the two halves and will be correctly merged.
-  *%(CA_CLOSEST_POINT)s:* This method is useful for unifying
   irregularly shaped cells that are connected. It starts by assigning
   background pixels in the vicinity of the objects to the nearest
   object. Objects are then merged if each object has background pixels
   that are:

   -  Within a distance threshold from each object;
   -  Above the minimum intensity fraction of the nearest object pixel;
   -  Adjacent to background pixels assigned to a neighboring object.

   An example of a feature that satisfies the above constraints is a
   line of pixels that connects two neighboring objects and is roughly
   the same intensity as the boundary pixels of both (such as an axon
   connecting two neurons' soma).""" % globals(),
        )
    def create_settings(self):
        self.x_source = cps.Choice(
            "Type of measurement to plot on X-axis",
            SOURCE_CHOICE,
            doc="""\
You can plot two types of measurements:

-  *%(SOURCE_IM)s:* For a per-image measurement, one numerical value is
   recorded for each image analyzed. Per-image measurements are produced
   by many modules. Many have **MeasureImage** in the name but others do
   not (e.g., the number of objects in each image is a per-image
   measurement made by the **Identify** modules).
-  *%(SOURCE_OBJ)s:* For a per-object measurement, each identified
   object is measured, so there may be none or many numerical values
   recorded for each image analyzed. These are usually produced by
   modules with **MeasureObject** in the name.
"""
            % globals(),
        )

        self.x_object = cps.ObjectNameSubscriber(
            "Select the object to plot on the X-axis",
            "None",
            doc="""\
*(Used only when plotting objects)*

Choose the name of objects identified by some previous module (such as
**IdentifyPrimaryObjects** or **IdentifySecondaryObjects**) whose
measurements are to be displayed on the X-axis.
""",
        )

        self.x_axis = cps.Measurement(
            "Select the measurement to plot on the X-axis",
            self.get_x_object,
            "None",
            doc="""Choose the measurement (made by a previous module) to plot on the X-axis.""",
        )

        self.y_source = cps.Choice(
            "Type of measurement to plot on Y-axis",
            SOURCE_CHOICE,
            doc="""\
You can plot two types of measurements:

-  *%(SOURCE_IM)s:* For a per-image measurement, one numerical value is
   recorded for each image analyzed. Per-image measurements are produced
   by many modules. Many have **MeasureImage** in the name but others do
   not (e.g., the number of objects in each image is a per-image
   measurement made by **Identify** modules).
-  *%(SOURCE_OBJ)s:* For a per-object measurement, each identified
   object is measured, so there may be none or many numerical values
   recorded for each image analyzed. These are usually produced by
   modules with **MeasureObject** in the name.
"""
            % globals(),
        )

        self.y_object = cps.ObjectNameSubscriber(
            "Select the object to plot on the Y-axis",
            "None",
            doc="""\
*(Used only when plotting objects)*

Choose the name of objects identified by some previous module (such as
**IdentifyPrimaryObjects** or **IdentifySecondaryObjects**) whose
measurements are to be displayed on the Y-axis.
""",
        )

        self.y_axis = cps.Measurement(
            "Select the measurement to plot on the Y-axis",
            self.get_y_object,
            "None",
            doc="""Choose the measurement (made by a previous module) to plot on the Y-axis.""",
        )

        self.xscale = cps.Choice(
            "How should the X-axis be scaled?",
            SCALE_CHOICE,
            None,
            doc="""\
The X-axis can be scaled with either a *linear* scale or a *log* (base
10) scaling.

Log scaling is useful when one of the measurements being plotted covers
a large range of values; a log scale can bring out features in the
measurements that would not easily be seen if the measurement is plotted
linearly.
""",
        )

        self.yscale = cps.Choice(
            "How should the Y-axis be scaled?",
            SCALE_CHOICE,
            None,
            doc="""\
The Y-axis can be scaled with either a *linear* scale or with a *log*
(base 10) scaling.

Log scaling is useful when one of the measurements being plotted covers
a large range of values; a log scale can bring out features in the
measurements that would not easily be seen if the measurement is plotted
linearly.
""",
        )

        self.title = cps.Text(
            "Enter a title for the plot, if desired",
            "",
            doc="""\
Enter a title for the plot. If you leave this blank, the title will
default to *(cycle N)* where *N* is the current image cycle being
executed.
""",
        )
    def create_settings(self):
        self.object_name = cps.ObjectNameSubscriber(
            "Select objects to measure",
            "None",
            doc="""\
Select the objects whose neighbors you want to measure.""",
        )

        self.neighbors_name = cps.ObjectNameSubscriber(
            "Select neighboring objects to measure",
            "None",
            doc="""\
This is the name of the objects that are potential
neighbors of the above objects. You can find the neighbors
within the same set of objects by selecting the same objects
as above.""",
        )

        self.distance_method = cps.Choice(
            "Method to determine neighbors",
            D_ALL,
            D_EXPAND,
            doc="""\
There are several methods by which to determine whether objects are
neighbors:

-  *%(D_ADJACENT)s:* In this mode, two objects must have adjacent
   boundary pixels to be neighbors.
-  *%(D_EXPAND)s:* The objects are expanded until all pixels on the
   object boundaries are touching another. Two objects are neighbors if
   any of their boundary pixels are adjacent after expansion.
-  *%(D_WITHIN)s:* Each object is expanded by the number of pixels you
   specify. Two objects are neighbors if they have adjacent pixels after
   expansion.

For *%(D_ADJACENT)s* and *%(D_EXPAND)s*, the
*%(M_PERCENT_TOUCHING)s* measurement is the percentage of pixels on
the boundary of an object that touch adjacent objects. For
*%(D_WITHIN)s*, two objects are touching if any of their boundary
pixels are adjacent after expansion and *%(M_PERCENT_TOUCHING)s*
measures the percentage of boundary pixels of an *expanded* object that
touch adjacent objects.
""" % globals(),
        )

        self.distance = cps.Integer(
            "Neighbor distance",
            5,
            1,
            doc="""\
*(Used only when “%(D_WITHIN)s” is selected)*

The Neighbor distance is the number of pixels that each object is
expanded for the neighbor calculation. Expanded objects that touch are
considered neighbors.
""" % globals(),
        )

        self.wants_count_image = cps.Binary(
            "Retain the image of objects colored by numbers of neighbors?",
            False,
            doc="""\
An output image showing the input objects colored by numbers of
neighbors may be retained. A colormap of your choice shows how many
neighbors each object has. The background is set to -1. Objects are
colored with an increasing color value corresponding to the number of
neighbors, such that objects with no neighbors are given a color
corresponding to 0. Use the **SaveImages** module to save this image to
a file.""",
        )

        self.count_image_name = cps.ImageNameProvider(
            "Name the output image",
            "ObjectNeighborCount",
            doc="""\
*(Used only if the image of objects colored by numbers of neighbors is
to be retained for later use in the pipeline)*

Specify a name that will allow the image of objects colored by numbers
of neighbors to be selected later in the pipeline.""",
        )

        self.count_colormap = cps.Colormap(
            "Select colormap",
            doc="""\
*(Used only if the image of objects colored by numbers of neighbors is
to be retained for later use in the pipeline)*

Select the colormap to use to color the neighbor number image. All
available colormaps can be seen `here`_.

.. _here: http://matplotlib.org/examples/color/colormaps_reference.html""",
        )

        self.wants_percent_touching_image = cps.Binary(
            "Retain the image of objects colored by percent of touching pixels?",
            False,
            doc="""\
Select *Yes* to keep an image of the input objects colored by the
percentage of the boundary touching their neighbors. A colormap of your
choice is used to show the touching percentage of each object. Use the
**SaveImages** module to save this image to a file.
""" % globals(),
        )

        self.touching_image_name = cps.ImageNameProvider(
            "Name the output image",
            "PercentTouching",
            doc="""\
*(Used only if the image of objects colored by percent touching is to be
retained for later use in the pipeline)*

Specify a name that will allow the image of objects colored by percent
of touching pixels to be selected later in the pipeline.""",
        )

        self.touching_colormap = cps.Colormap(
            "Select colormap",
            doc="""\
*(Used only if the image of objects colored by percent touching is to be
retained for later use in the pipeline)*

Select the colormap to use to color the percent touching image. All
available colormaps can be seen `here`_.

.. _here: http://matplotlib.org/examples/color/colormaps_reference.html""",
        )

        self.wants_excluded_objects = cps.Binary(
            "Consider objects discarded for touching image border?",
            True,
            doc="""\
When set to *{YES}*, objects which were previously discarded for touching
the image borders will be considered as potential object neighbours in this
analysis. You may want to disable this if using object sets which were
further filtered, since those filters won't have been applied to the
previously discarded objects.""".format(**{"YES": "Yes"}),
        )
Beispiel #11
0
    def create_settings(self):
        self.objects_or_image = cps.Choice(
            "Display object or image measurements?",
            [OI_OBJECTS, OI_IMAGE],
            doc="""\
-  *%(OI_IMAGE)s* allows you to select an image measurement to display
   for each well.
-  *%(OI_OBJECTS)s* allows you to select an object measurement to
   display for each well.
""" % globals(),
        )

        self.object = cps.ObjectNameSubscriber(
            "Select the object whose measurements will be displayed",
            "None",
            doc="""\
Choose the name of objects identified by some previous module (such as
**IdentifyPrimaryObjects** or **IdentifySecondaryObjects**)
whose measurements are to be displayed.
""",
        )

        self.plot_measurement = cps.Measurement(
            "Select the measurement to plot",
            self.get_object,
            "None",
            doc=
            """Choose the image or object measurement made by a previous module to plot.""",
        )

        self.plate_name = cps.Measurement(
            "Select your plate metadata",
            lambda: cpmeas.IMAGE,
            "Metadata_Plate",
            doc="""\
Choose the metadata tag that corresponds to the plate identifier. That
is, each plate should have a metadata tag containing a specifier
corresponding uniquely to that plate.

%(USING_METADATA_HELP_REF)s
""" % globals(),
        )

        self.plate_type = cps.Choice(
            "Multiwell plate format",
            ["96", "384"],
            doc="""\
The module assumes that your data is laid out in a multi-well plate
format common to high-throughput biological screens. Supported formats
are:

-  *96:* A 96-well plate with 8 rows × 12 columns
-  *384:* A 384-well plate with 16 rows × 24 columns
""",
        )

        self.well_format = cps.Choice(
            "Well metadata format",
            [WF_NAME, WF_ROWCOL],
            doc="""\
-  *%(WF_NAME)s* allows you to select an image measurement to display
   for each well.
-  *%(WF_ROWCOL)s* allows you to select an object measurement to
   display for each well.
""" % globals(),
        )

        self.well_name = cps.Measurement(
            "Select your well metadata",
            lambda: cpmeas.IMAGE,
            "Metadata_Well",
            doc="""\
Choose the metadata tag that corresponds to the well identifier. The
row-column format of these entries should be an alphabetical character
(specifying the plate row), followed by two integer characters
(specifying the plate column). For example, a standard format 96-well
plate would span from “A1” to “H12”, whereas a 384-well plate (16 rows
and 24 columns) would span from well “A01” to well “P24”."

%(USING_METADATA_HELP_REF)s
""" % globals(),
        )

        self.well_row = cps.Measurement(
            "Select your well row metadata",
            lambda: cpmeas.IMAGE,
            "Metadata_WellRow",
            doc="""\
Choose the metadata tag that corresponds to the well row identifier,
typically specified as an alphabetical character. For example, a
standard format 96-well plate would span from row “A” to “H”, whereas a
384-well plate (16 rows and 24 columns) would span from row “A” to “P”.

%(USING_METADATA_HELP_REF)s
""" % globals(),
        )

        self.well_col = cps.Measurement(
            "Select your well column metadata",
            lambda: cpmeas.IMAGE,
            "Metadata_WellCol",
            doc="""\
Choose the metadata tag that corresponds to the well column identifier,
typically specified with two integer characters. For example, a standard
format 96-well plate would span from column “01” to “12”, whereas a
384-well plate (16 rows and 24 columns) would span from column “01” to
“24”.

%(USING_METADATA_HELP_REF)s
""" % globals(),
        )

        self.agg_method = cps.Choice(
            "How should the values be aggregated?",
            AGG_NAMES,
            AGG_NAMES[0],
            doc="""\
Measurements must be aggregated to a single number for each well so that
they can be represented by a color. Options are:

-  *%(AGG_AVG)s:* Average
-  *%(AGG_STDEV)s:* Standard deviation
-  *%(AGG_MEDIAN)s*
-  *%(AGG_CV)s:* Coefficient of variation, defined as the ratio of the
   standard deviation to the mean. This is useful for comparing between
   data sets with different units or widely different means.
""" % globals(),
        )

        self.title = cps.Text(
            "Enter a title for the plot, if desired",
            "",
            doc="""\
Enter a title for the plot. If you leave this blank, the title will
default to *(cycle N)* where *N* is the current image cycle being
executed.
""",
        )
Beispiel #12
0
    def create_settings(self):
        """Create the settings that control this module"""
        self.object_name = cps.ObjectNameSubscriber(
            "Select objects to be masked",
            "None",
            doc="""\
Select the objects that will be masked (that is, excluded in whole or in
part based on the other settings in the module). You can choose from any
objects created by a previous object processing module, such as
**IdentifyPrimaryObjects**, **IdentifySecondaryObjects** or
**IdentifyTertiaryObjects**.
""",
        )

        self.remaining_objects = cps.ObjectNameProvider(
            "Name the masked objects",
            "MaskedNuclei",
            doc="""\
Enter a name for the objects that remain after
the masking operation. You can refer to the masked objects in
subsequent modules by this name.
""",
        )

        self.mask_choice = cps.Choice(
            "Mask using a region defined by other objects or by binary image?",
            [MC_OBJECTS, MC_IMAGE],
            doc="""\
You can mask your objects by defining a region using objects you
previously identified in your pipeline (*%(MC_OBJECTS)s*) or by
defining a region based on the white regions in a binary image
previously loaded or created in your pipeline (*%(MC_IMAGE)s*).
""" % globals(),
        )

        self.masking_objects = cps.ObjectNameSubscriber(
            "Select the masking object",
            "None",
            doc="""\
*(Used only if mask is to be made from objects)*

Select the objects that will be used to define the masking region. You
can choose from any objects created by a previous object processing
module, such as **IdentifyPrimaryObjects**,
**IdentifySecondaryObjects**, or **IdentifyTertiaryObjects**.
""",
        )

        self.masking_image = cps.ImageNameSubscriber(
            "Select the masking image",
            "None",
            doc="""\
*(Used only if mask is to be made from an image)*

Select an image that was either loaded or created by a previous module.
The image should be a binary image where the white portion of the image
is the region(s) you will use for masking. Binary images can be loaded
from disk using the **NamesAndTypes** module by selecting “Binary mask”
for the image type. You can also create a binary image from a grayscale
image using **ApplyThreshold**.
""",
        )

        self.wants_inverted_mask = cps.Binary(
            "Invert the mask?",
            False,
            doc="""\
This option reverses the foreground/background relationship of the mask.

-  Select "*No*" for the mask to be composed of the foreground (white
   portion) of the masking image or the area within the masking objects.
-  Select "*Yes*" for the mask to instead be composed of the
   *background* (black portions) of the masking image or the area
   *outside* the masking objects.
   """ % globals(),
        )

        self.overlap_choice = cps.Choice(
            "Handling of objects that are partially masked",
            [P_MASK, P_KEEP, P_REMOVE, P_REMOVE_PERCENTAGE],
            doc="""\
An object might partially overlap the mask region, with pixels both
inside and outside the region. **MaskObjects** can handle this in one
of three ways:

-  *%(P_MASK)s:* Choosing this option will reduce the size of partially
   overlapping objects. The part of the object that overlaps the masking
   region will be retained. The part of the object that is outside of the
   masking region will be removed.
-  *%(P_KEEP)s:* If you choose this option, **MaskObjects** will keep
   the whole object if any part of it overlaps the masking region.
-  *%(P_REMOVE)s:* Objects that are partially outside of the masking
   region will be completely removed if you choose this option.
-  *%(P_REMOVE_PERCENTAGE)s:* Determine whether to remove or keep an
   object depending on how much of the object overlaps the masking
   region. **MaskObjects** will keep an object if at least a certain
   fraction (which you enter below) of the object falls within the
   masking region. **MaskObjects** completely removes the object if too
   little of it overlaps the masking region.""" % globals(),
        )

        self.overlap_fraction = cps.Float(
            "Fraction of object that must overlap",
            0.5,
            minval=0,
            maxval=1,
            doc="""\
*(Used only if removing based on overlap)*

Specify the minimum fraction of an object that must overlap the masking
region for that object to be retained. For instance, if the fraction is
0.75, then 3/4 of an object must be within the masking region for that
object to be retained.
""",
        )

        self.retain_or_renumber = cps.Choice(
            "Numbering of resulting objects",
            [R_RENUMBER, R_RETAIN],
            doc="""\
Choose how to number the objects that remain after masking, which
controls how remaining objects are associated with their predecessors:

-  *%(R_RENUMBER)s:* The objects that remain will be renumbered using
   consecutive numbers. This is a good choice if you do not plan to use
   measurements from the original objects; your object measurements for
   the masked objects will not have gaps (where removed objects are
   missing).
-  *%(R_RETAIN)s:* The original labels for the objects will be
   retained. This allows any measurements you make from the masked
   objects to be directly aligned with measurements you might have made
   of the original, unmasked objects (or objects directly associated
   with them).
""" % globals(),
        )
Beispiel #13
0
    def create_settings(self):
        """Create your settings by subclassing this function

        create_settings is called at the end of initialization.
        """
        self.grid_name = cps.GridNameSubscriber(
            "Select the defined grid",
            "None",
            doc="""Select the name of a grid created by a previous **DefineGrid** module.""",
        )

        self.output_objects_name = cps.ObjectNameProvider(
            "Name the objects to be identified",
            "Wells",
            doc="""\
Enter the name of the grid objects identified by this module. These objects
will be available for further measurement and processing in subsequent modules.""",
        )

        self.shape_choice = cps.Choice(
            "Select object shapes and locations",
            [SHAPE_RECTANGLE, SHAPE_CIRCLE_FORCED, SHAPE_CIRCLE_NATURAL, SHAPE_NATURAL],
            doc="""\
Use this setting to choose the method to be used to determine the grid
objects’ shapes and locations:

-  *%(SHAPE_RECTANGLE)s:* Each object will be created as a rectangle,
   completely occupying the entire grid compartment (rectangle). This
   option creates the rectangular objects based solely on the grid’s
   specifications, not on any previously identified guiding objects.
-  *%(SHAPE_CIRCLE_FORCED)s:* Each object will be created as a circle,
   centered in the middle of each grid compartment. This option places
   the circular objects’ locations based solely on the grid’s
   specifications, not on any previously identified guiding objects. The
   radius of all circles in a grid will be constant for the entire grid
   in each image cycle, and can be determined automatically for each
   image cycle based on the average radius of previously identified
   guiding objects for that image cycle, or instead it can be specified
   as a single radius for all circles in all grids in the entire
   analysis run.
-  *%(SHAPE_CIRCLE_NATURAL)s:* Each object will be created as a
   circle, and each circle’s location within its grid compartment will
   be determined based on the location of any previously identified
   guiding objects within that grid compartment. Thus, if a guiding
   object lies within a particular grid compartment, that object’s
   center will be the center of the created circular object. If no
   guiding objects lie within a particular grid compartment, the
   circular object is placed within the center of that grid compartment.
   If more than one guiding object lies within the grid compartment,
   they will be combined and the centroid of this combined object will
   be the location of the created circular object. Note that guiding
   objects whose centers are close to the grid edge are ignored.
-  *%(SHAPE_NATURAL)s:* Within each grid compartment, the object will
   be identified based on combining all of the parts of guiding objects,
   if any, that fall within the grid compartment. Note that guiding
   objects whose centers are close to the grid edge are ignored. If a
   guiding object does not exist within a grid compartment, an object
   consisting of one single pixel in the middle of the grid compartment
   will be created.
"""
            % globals(),
        )

        self.diameter_choice = cps.Choice(
            "Specify the circle diameter automatically?",
            [AM_AUTOMATIC, AM_MANUAL],
            doc="""\
*(Used only if "Circle" is selected as object shape)*

There are two methods for selecting the circle diameter:

-  *%(AM_AUTOMATIC)s:* Uses the average diameter of previously
   identified guiding objects as the diameter.
-  *%(AM_MANUAL)s:* Lets you specify the diameter directly, as a
   number.
"""
            % globals(),
        )

        self.diameter = cps.Integer(
            "Circle diameter",
            20,
            minval=2,
            doc="""\
*(Used only if "Circle" is selected as object shape and diameter is
specified manually)*

Enter the diameter to be used for each grid circle, in pixels.
%(HELP_ON_MEASURING_DISTANCES)s
"""
            % globals(),
        )

        self.guiding_object_name = cps.ObjectNameSubscriber(
            "Select the guiding objects",
            "None",
            doc="""\
*(Used only if "Circle" is selected as object shape and diameter is
specified automatically, or if "Natural Location" is selected as the
object shape)*

Select the names of previously identified objects that will be used to
guide the shape and/or location of the objects created by this module,
depending on the method chosen.
""",
        )
    def create_settings(self):
        """Create your settings by subclassing this function

        create_settings is called at the end of initialization.

        You should create the setting variables for your module here:
            # Ask the user for the input image
            self.image_name = cellprofiler_core.settings.ImageNameSubscriber(...)
            # Ask the user for the name of the output image
            self.output_image = cellprofiler_core.settings.ImageNameProvider(...)
            # Ask the user for a parameter
            self.smoothing_size = cellprofiler_core.settings.Float(...)
        """
        self.object_name = cps.ObjectNameSubscriber(
            "Select the objects to be edited",
            "None",
            doc="""\
Choose a set of previously identified objects
for editing, such as those produced by one of the
**Identify** modules (e.g., "*IdentifyPrimaryObjects*", "*IdentifySecondaryObjects*" etc.).""",
        )

        self.filtered_objects = cps.ObjectNameProvider(
            "Name the edited objects",
            "EditedObjects",
            doc="""\
Enter the name for the objects that remain
after editing. These objects will be available for use by
subsequent modules.""",
        )

        self.allow_overlap = cps.Binary(
            "Allow overlapping objects?",
            False,
            doc="""\
**EditObjectsManually** can allow you to edit an object so that it
overlaps another or it can prevent you from overlapping one object with
another. Objects such as worms or the neurites of neurons may cross each
other and might need to be edited with overlapping allowed, whereas a
monolayer of cells might be best edited with overlapping off.
Select "*Yes*" to allow overlaps or select "*No*" to prevent them.
""" % globals(),
        )

        self.renumber_choice = cps.Choice(
            "Numbering of the edited objects",
            [R_RENUMBER, R_RETAIN],
            doc="""\
Choose how to number the objects that remain after editing, which
controls how edited objects are associated with their predecessors:

-  *%(R_RENUMBER)s:* The module will number the objects that remain
   using consecutive numbers. This is a good choice if you do not plan
   to use measurements from the original objects and you only want to
   use the edited objects in downstream modules; the objects that remain
   after editing will not have gaps in numbering where removed objects
   are missing.
-  *%(R_RETAIN)s:* This option will retain each object’s original
   number so that the edited object’s number matches its original
   number. This allows any measurements you make from the edited objects
   to be directly aligned with measurements you might have made of the
   original, unedited objects (or objects directly associated with
   them).
""" % globals(),
        )

        self.wants_image_display = cps.Binary(
            "Display a guiding image?",
            True,
            doc="""\
Select "*Yes*" to display an image and outlines of the objects.

Select "*No*" if you do not want a guide image while editing.
""" % globals(),
        )

        self.image_name = cps.ImageNameSubscriber(
            "Select the guiding image",
            "None",
            doc="""\
*(Used only if a guiding image is desired)*

This is the image that will appear when editing objects. Choose an image
supplied by a previous module.
""",
        )
Beispiel #15
0
    def create_settings(self):
        """Create your settings by subclassing this function

        create_settings is called at the end of initialization.
        """
        self.grid_image = cps.GridNameProvider(
            "Name the grid",
            doc="""\
This is the name of the grid. You can use this name to
retrieve the grid in subsequent modules.""",
        )

        self.grid_rows = cps.Integer(
            "Number of rows",
            8,
            1,
            doc="""Along the height of the grid, define the number of rows.""",
        )

        self.grid_columns = cps.Integer(
            "Number of columns",
            12,
            1,
            doc=
            """Along the width of the grid, define the number of columns.""",
        )

        self.origin = cps.Choice(
            "Location of the first spot",
            [NUM_TOP_LEFT, NUM_BOTTOM_LEFT, NUM_TOP_RIGHT, NUM_BOTTOM_RIGHT],
            doc="""\
Grid cells are numbered consecutively; this option identifies the
origin for the numbering system and the direction for numbering.
For instance, if you choose "*%(NUM_TOP_LEFT)s*", the top left cell is
cell #1 and cells to the right and bottom are indexed with
larger numbers.""" % globals(),
        )

        self.ordering = cps.Choice(
            "Order of the spots",
            [NUM_BY_ROWS, NUM_BY_COLUMNS],
            doc="""\
Grid cells can either be numbered by rows, then columns or by columns,
then rows. For instance, if you asked to start numbering a 96-well
plate at the top left (by specifying the location of the first spot), then:

-  *%(NUM_BY_ROWS)s:* this option will give well A01 the index 1, B01
   the index 2, and so on up to H01 which receives the index 8. Well A02
   will be assigned the index 9.
-  *%(NUM_BY_COLUMNS)s:* with this option, the well A02 will be
   assigned 2, well A12 will be assigned 12 and well B01 will be
   assigned 13.
""" % globals(),
        )

        self.each_or_once = cps.Choice(
            "Define a grid for which cycle?",
            [EO_EACH, EO_ONCE],
            doc="""\
The setting allows you choose when you want to define a new grid:

-  *%(EO_ONCE)s:* If all of your images are perfectly aligned with each
   other (due to very consistent image acquisition, consistent grid
   location within the plate, and/or automatic cropping precisely within
   each plate), you can define the location of the marker spots once for
   all of the image cycles.
-  *%(EO_EACH)s:* If the location of the grid will vary from one image
   cycle to the next then you should define the location of the marker
   spots for each cycle independently.
""" % globals(),
        )

        self.auto_or_manual = cps.Choice(
            "Select the method to define the grid",
            [AM_AUTOMATIC, AM_MANUAL],
            doc="""\
Select whether you would like to define the grid automatically (based on
objects you have identified in a previous module) or manually. This
setting controls how the grid is defined:

-  *%(AM_MANUAL)s:* In manual mode, you manually indicate known
   locations of marker spots in the grid and have the rest of the
   positions calculated from those marks, no matter what the image
   itself looks like. You can define the grid either by clicking on the
   image with a mouse or by entering coordinates.
-  *%(AM_AUTOMATIC)s:* If you would like the grid to be defined
   automatically, an **IdentifyPrimaryObjects** module must be run prior
   to this module to identify the objects that will be used to define
   the grid. The left-most, right-most, top-most, and bottom-most object
   will be used to define the edges of the grid, and the rows and
   columns will be evenly spaced between these edges. Note that
   Automatic mode requires that the incoming objects are nicely defined:
   for example, if there is an object at the edge of the images that is
   not really an object that ought to be in the grid, a skewed grid will
   result. You might wish to use a **FilterObjects** module to clean up
   badly identified objects prior to defining the grid. If the spots are
   slightly out of alignment with each other from one image cycle to the
   next, this allows the identification to be a bit flexible and adapt
   to the real location of the spots.
""" % globals(),
        )

        self.object_name = cps.ObjectNameSubscriber(
            "Select the previously identified objects",
            "None",
            doc="""\
*(Used only if you selected "%(AM_AUTOMATIC)s" to define the grid)*

Select the previously identified objects you want to use to define the
grid. Use this setting to specify the name of the objects that will be
used to define the grid.
""" % globals(),
        )

        self.manual_choice = cps.Choice(
            "Select the method to define the grid manually",
            [MAN_MOUSE, MAN_COORDINATES],
            doc="""\
*(Used only if you selected "%(AM_MANUAL)s" to define the grid)*

Specify whether you want to define the grid using the mouse or by
entering the coordinates of the cells.

-  *%(MAN_MOUSE)s:* The user interface displays the image you specify.
   You will be asked to click in the center of two of the grid cells and
   specify the row and column for each. The grid coordinates will be
   computed from this information.
-  *%(MAN_COORDINATES)s:* Enter the X and Y coordinates of the grid
   cells directly. You can display an image of your grid to find the
   locations of the centers of the cells, then enter the X and Y
   position and cell coordinates for each of two cells.
""" % globals(),
        )

        self.manual_image = cps.ImageNameSubscriber(
            "Select the image to display when drawing",
            "None",
            doc="""\
*(Used only if you selected "%(AM_MANUAL)s" and "%(MAN_MOUSE)s" to define
the grid)*

Specify the image you want to display when defining the grid. This
setting lets you choose the image to display in the grid definition user
interface.
""" % globals(),
        )

        self.first_spot_coordinates = cps.Coordinates(
            "Coordinates of the first cell",
            (0, 0),
            doc="""\
*(Used only if you selected "%(AM_MANUAL)s" and "%(MAN_COORDINATES)s" to
define the grid)*

Enter the coordinates of the first cell on your grid. This setting
defines the location of the first of two cells in your grid. You should
enter the coordinates of the center of the cell. You can display an
image of your grid and use the pixel coordinate display to determine the
coordinates of the center of your cell.
""" % globals(),
        )

        self.first_spot_row = cps.Integer(
            "Row number of the first cell",
            1,
            minval=1,
            doc="""\
*(Used only if you selected "%(AM_MANUAL)s" and "%(MAN_COORDINATES)s" to
define the grid)*

Enter the row index for the first cell here. Rows are numbered starting
at the origin. For instance, if you chose "*%(NUM_TOP_LEFT)s*" as your
origin, well A01 will be row number 1 and H01 will be row number 8. If
you chose "*%(NUM_BOTTOM_LEFT)s*", A01 will be row number 8 and H01 will
be row number 12.
""" % globals(),
        )

        self.first_spot_col = cps.Integer(
            "Column number of the first cell",
            1,
            minval=1,
            doc="""\
*(Used only if you selected "%(AM_MANUAL)s" and "%(MAN_COORDINATES)s" to
define the grid)*

Enter the column index for the first cell here. Columns are numbered
starting at the origin. For instance, if you chose "*%(NUM_TOP_LEFT)s*"
as your origin, well A01 will be column number *1* and A12 will be
column number *12*. If you chose "*%(NUM_TOP_RIGHT)s*", A01 and A12 will
be *12* and *1*, respectively.
""" % globals(),
        )

        self.second_spot_coordinates = cps.Coordinates(
            "Coordinates of the second cell",
            (0, 0),
            doc="""\
*(Used only if you selected "%(AM_MANUAL)s" and "%(MAN_COORDINATES)s" to
define the grid)*

This setting defines the location of the second of two cells in your
grid. You should enter the coordinates of the center of the cell. You
can display an image of your grid and use the pixel coordinate
display to determine the coordinates (X,Y) of the center of your cell.
""" % globals(),
        )

        self.second_spot_row = cps.Integer(
            "Row number of the second cell",
            1,
            minval=1,
            doc="""\
*(Used only if you selected "%(AM_MANUAL)s" and "%(MAN_COORDINATES)s" to
define the grid)*

Enter the row index for the second cell here. Rows are numbered starting
at the origin. For instance, if you chose "*%(NUM_TOP_LEFT)s*" as your
origin, well A01 will be row number 1 and H01 will be row number 8. If
you chose "*%(NUM_BOTTOM_LEFT)s*", A01 will be row number 8 and H01 will
be row number 12.
""" % globals(),
        )

        self.second_spot_col = cps.Integer(
            "Column number of the second cell",
            1,
            minval=1,
            doc="""\
*(Used only if you selected "%(AM_MANUAL)s" and "%(MAN_COORDINATES)s" to
define the grid)*

Enter the column index for the second cell here. Columns are numbered
starting at the origin. For instance, if you chose "*%(NUM_TOP_LEFT)s*"
as your origin, well A01 will be column number 1 and A12 will be column
number 12. If you chose "*%(NUM_TOP_RIGHT)s*", A01 and A12 will be 12
and 1, respectively.
""" % globals(),
        )

        self.wants_image = cps.Binary(
            "Retain an image of the grid?",
            False,
            doc="""\
Select "*Yes*" to retain an image of the grid for use later in the
pipeline. This module can create an annotated image of the grid that can
be saved using the **SaveImages** module.
""" % globals(),
        )

        self.display_image_name = cps.ImageNameSubscriber(
            "Select the image on which to display the grid",
            "Leave blank",
            can_be_blank=True,
            doc="""\
*(Used only if saving an image of the grid)*

Enter the name of the image that should be used as the background for
annotations (grid lines and grid indexes). This image will be used for
the figure and for the saved image.
""",
        )

        self.save_image_name = cps.ImageNameProvider(
            "Name the output image",
            "Grid",
            doc="""\
*(Used only if retaining an image of the grid for use later in the
pipeline)*

Enter the name you want to use for the output image. You can save this
image using the **SaveImages** module.
""",
        )

        self.failed_grid_choice = cps.Choice(
            "Use a previous grid if gridding fails?",
            [FAIL_NO, FAIL_ANY_PREVIOUS, FAIL_FIRST],
            doc="""\
If the gridding fails, this setting allows you to control how the module
responds to the error:

-  *%(FAIL_NO)s:* The module will stop the pipeline if gridding fails.
-  *%(FAIL_ANY_PREVIOUS)s:* The module will use the the most recent
   successful gridding.
-  *%(FAIL_FIRST)s:* The module will use the first gridding.

Note that the pipeline will stop in all cases if gridding fails on the
first image.
""" % globals(),
        )
Beispiel #16
0
    def add_measurement(self, flag_settings, can_delete=True):
        measurement_settings = flag_settings.measurement_settings

        group = cps.SettingsGroup()
        group.append("divider1", cps.Divider(line=False))
        group.append(
            "source_choice",
            cps.Choice(
                "Flag is based on",
                S_ALL,
                doc="""\
-  *%(S_IMAGE)s:* A per-image measurement, such as intensity or
   granularity.
-  *%(S_AVERAGE_OBJECT)s:* The average of all object measurements in
   the image.
-  *%(S_ALL_OBJECTS)s:* All the object measurements in an image,
   without averaging. In other words, if *any* of the objects meet the
   criteria, the image will be flagged.
-  *%(S_RULES)s:* Use a text file of rules produced by CellProfiler
   Analyst. With this option, you will have to ensure that this pipeline
   produces every measurement in the rules file upstream of this module.
-  *%(S_CLASSIFIER)s:* Use a classifier built by CellProfiler Analyst.
""" % globals(),
            ),
        )

        group.append(
            "object_name",
            cps.ObjectNameSubscriber(
                "Select the object to be used for flagging",
                "None",
                doc="""\
*(Used only when flag is based on an object measurement)*

Select the objects whose measurements you want to use for flagging.
""",
            ),
        )

        def object_fn():
            if group.source_choice == S_IMAGE:
                return cpmeas.IMAGE
            return group.object_name.value

        group.append(
            "rules_directory",
            cps.DirectoryPath(
                "Rules file location",
                doc="""\
*(Used only when flagging using "%(S_RULES)s")*

Select the location of the rules file that will be used for flagging images.
%(IO_FOLDER_CHOICE_HELP_TEXT)s
""" % globals(),
            ),
        )

        def get_directory_fn():
            """Get the directory for the rules file name"""
            return group.rules_directory.get_absolute_path()

        def set_directory_fn(path):
            dir_choice, custom_path = group.rules_directory.get_parts_from_path(
                path)
            group.rules_directory.join_parts(dir_choice, custom_path)

        group.append(
            "rules_file_name",
            cps.FilenameText(
                "Rules file name",
                "rules.txt",
                get_directory_fn=get_directory_fn,
                set_directory_fn=set_directory_fn,
                doc="""\
*(Used only when flagging using "%(S_RULES)s")*

The name of the rules file, most commonly from CellProfiler Analyst's
Classifier. This file should be a plain text file
containing the complete set of rules.

Each line of this file should be a rule naming a measurement to be made
on an image, for instance:

    IF (Image_ImageQuality_PowerLogLogSlope_DNA < -2.5, [0.79, -0.79], [-0.94, 0.94])

The above rule will score +0.79 for the positive category and -0.94
for the negative category for images whose power log slope is less
than -2.5 pixels and will score the opposite for images whose slope is
larger. The filter adds positive and negative and flags the images
whose positive score is higher than the negative score.
""" % globals(),
            ),
        )

        def get_rules_class_choices(group=group):
            """Get the available choices from the rules file"""
            try:
                if group.source_choice == S_CLASSIFIER:
                    return self.get_bin_labels(group)
                elif group.source_choice == S_RULES:
                    rules = self.get_rules(group)
                    nclasses = len(rules.rules[0].weights[0])
                    return [str(i) for i in range(1, nclasses + 1)]
                else:
                    return ["None"]
                rules = self.get_rules(group)
                nclasses = len(rules.rules[0].weights[0])
                return [str(i) for i in range(1, nclasses + 1)]
            except:
                return [str(i) for i in range(1, 3)]

        group.append(
            "rules_class",
            cps.MultiChoice(
                "Class number",
                choices=["1", "2"],
                doc="""\
*(Used only when flagging using "%(S_RULES)s")*

Select which classes to flag when filtering. The CellProfiler Analyst
Classifier user interface lists the names of the classes in order. By
default, these are the positive (class 1) and negative (class 2)
classes. **FlagImage** uses the first class from CellProfiler Analyst
if you choose “1”, etc.

Please note the following:

-  The flag is set if the image falls into the selected class.
-  You can make multiple class selections. If you do so, the module will
   set the flag if the image falls into any of the selected classes.
""" % globals(),
            ),
        )

        group.rules_class.get_choices = get_rules_class_choices

        group.append(
            "measurement",
            cps.Measurement(
                "Which measurement?",
                object_fn,
                doc="""Choose the measurement to be used as criteria.""",
            ),
        )

        group.append(
            "wants_minimum",
            cps.Binary(
                "Flag images based on low values?",
                True,
                doc="""\
Select *Yes* to flag images with measurements below the specified
cutoff. If the measurement evaluates to Not-A-Number (NaN), then the
image is not flagged.
""" % globals(),
            ),
        )

        group.append(
            "minimum_value",
            cps.Float("Minimum value",
                      0,
                      doc="""Set a value as a lower limit."""),
        )

        group.append(
            "wants_maximum",
            cps.Binary(
                "Flag images based on high values?",
                True,
                doc="""\
Select *Yes* to flag images with measurements above the specified
cutoff. If the measurement evaluates to Not-A-Number (NaN), then the
image is not flagged.
""" % globals(),
            ),
        )

        group.append(
            "maximum_value",
            cps.Float("Maximum value",
                      1,
                      doc="""Set a value as an upper limit."""),
        )

        if can_delete:
            group.append(
                "remover",
                cps.RemoveSettingButton("", "Remove this measurement",
                                        measurement_settings, group),
            )

        group.append("divider2", cps.Divider(line=True))
        measurement_settings.append(group)
Beispiel #17
0
    def create_settings(self):
        self.x_object = cps.ObjectNameSubscriber(
            "Select the object to display on the X-axis",
            "None",
            doc="""\
Choose the name of objects identified by some previous module (such as
**IdentifyPrimaryObjects** or **IdentifySecondaryObjects**) whose
measurements are to be displayed on the X-axis.
""",
        )

        self.x_axis = cps.Measurement(
            "Select the object measurement to plot on the X-axis",
            self.get_x_object,
            "None",
            doc=
            """Choose the object measurement made by a previous module to display on the X-axis.""",
        )

        self.y_object = cps.ObjectNameSubscriber(
            "Select the object to display on the Y-axis",
            "None",
            doc="""\
Choose the name of objects identified by some previous module (such as
**IdentifyPrimaryObjects** or **IdentifySecondaryObjects**) whose
measurements are to be displayed on the Y-axis.
""",
        )

        self.y_axis = cps.Measurement(
            "Select the object measurement to plot on the Y-axis",
            self.get_y_object,
            "None",
            doc=
            """Choose the object measurement made by a previous module to display on the Y-axis.""",
        )

        self.gridsize = cps.Integer(
            "Select the grid size",
            100,
            1,
            1000,
            doc="""\
Enter the number of grid regions you want used on each
axis. Increasing the number of grid regions increases the
resolution of the plot.""",
        )

        self.xscale = cps.Choice(
            "How should the X-axis be scaled?",
            ["linear", "log"],
            None,
            doc="""\
The X-axis can be scaled either with a *linear* scale or with a *log*
(base 10) scaling.

Using a log scaling is useful when one of the measurements being plotted
covers a large range of values; a log scale can bring out features in
the measurements that would not easily be seen if the measurement is
plotted linearly.
""",
        )

        self.yscale = cps.Choice(
            "How should the Y-axis be scaled?",
            ["linear", "log"],
            None,
            doc="""\
The Y-axis can be scaled either with a *linear* scale or with a *log*
(base 10) scaling.

Using a log scaling is useful when one of the measurements being plotted
covers a large range of values; a log scale can bring out features in
the measurements that would not easily be seen if the measurement is
plotted linearly.
""",
        )

        self.bins = cps.Choice(
            "How should the colorbar be scaled?",
            ["linear", "log"],
            None,
            doc="""\
The colorbar can be scaled either with a *linear* scale or with a *log*
(base 10) scaling.

Using a log scaling is useful when one of the measurements being plotted
covers a large range of values; a log scale can bring out features in
the measurements that would not easily be seen if the measurement is
plotted linearly.
""",
        )

        maps = [
            m for m in list(matplotlib.cm.datad.keys()) if not m.endswith("_r")
        ]
        maps.sort()

        self.colormap = cps.Choice(
            "Select the color map",
            maps,
            "jet",
            doc="""\
Select the color map for the density plot. See `this page`_ for pictures
of the available colormaps.

.. _this page: http://matplotlib.org/users/colormaps.html
""",
        )

        self.title = cps.Text(
            "Enter a title for the plot, if desired",
            "",
            doc="""\
Enter a title for the plot. If you leave this blank, the title will
default to *(cycle N)* where *N* is the current image cycle being
executed.
""",
        )
    def create_settings(self):
        """Create the UI settings for the module"""
        self.seed_objects_name = cps.ObjectNameSubscriber(
            "Select the seed objects",
            "None",
            doc="""\
Select the previously identified objects that you want to use as the
seeds for measuring branches and distances. Branches and trunks are assigned
per seed object. Seed objects are typically not single points/pixels but
instead are usually objects of varying sizes.""",
        )

        self.image_name = cps.ImageNameSubscriber(
            "Select the skeletonized image",
            "None",
            doc="""\
Select the skeletonized image of the dendrites and/or axons as produced
by the **Morph** module’s *Skel* operation.""",
        )

        self.wants_branchpoint_image = cps.Binary(
            "Retain the branchpoint image?",
            False,
            doc="""\
Select "*Yes*" if you want to save the color image of branchpoints and
trunks. This is the image that is displayed in the output window for
this module.""" % globals(),
        )

        self.branchpoint_image_name = cps.ImageNameProvider(
            "Name the branchpoint image",
            "BranchpointImage",
            doc="""\
*(Used only if a branchpoint image is to be retained)*

Enter a name for the branchpoint image here. You can then use this image
in a later module, such as **SaveImages**.""",
        )

        self.wants_to_fill_holes = cps.Binary(
            "Fill small holes?",
            True,
            doc="""\
The algorithm reskeletonizes the image and this can leave artifacts
caused by small holes in the image prior to skeletonizing. These holes
result in false trunks and branchpoints. Select "*Yes*" to fill in
these small holes prior to skeletonizing.""" % globals(),
        )

        self.maximum_hole_size = cps.Integer(
            "Maximum hole size",
            10,
            minval=1,
            doc="""\
*(Used only when filling small holes)*

This is the area of the largest hole to fill, measured in pixels. The
algorithm will fill in any hole whose area is this size or smaller.""",
        )

        self.wants_objskeleton_graph = cps.Binary(
            "Export the skeleton graph relationships?",
            False,
            doc="""\
Select "*Yes*" to produce an edge file and a vertex file that gives the
relationships between vertices (trunks, branchpoints and endpoints).""" %
            globals(),
        )

        self.intensity_image_name = cps.ImageNameSubscriber(
            "Intensity image",
            "None",
            doc="""\
Select the image to be used to calculate
the total intensity along the edges between the vertices (trunks, branchpoints, and endpoints).""",
        )

        self.directory = cps.DirectoryPath(
            "File output directory",
            doc=
            "Select the directory you want to save the graph relationships to.",
            dir_choices=[
                cpprefs.DEFAULT_OUTPUT_FOLDER_NAME,
                cpprefs.DEFAULT_INPUT_FOLDER_NAME,
                cpprefs.ABSOLUTE_FOLDER_NAME,
                cpprefs.DEFAULT_OUTPUT_SUBFOLDER_NAME,
                cpprefs.DEFAULT_INPUT_SUBFOLDER_NAME,
            ],
        )
        self.directory.dir_choice = cpprefs.DEFAULT_OUTPUT_FOLDER_NAME

        self.vertex_file_name = cps.Text(
            "Vertex file name",
            "vertices.csv",
            doc="""\
*(Used only when exporting graph relationships)*

Enter the name of the file that will hold the edge information. You can
use metadata tags in the file name.

Each line of the file is a row of comma-separated values. The first
row is the header; this names the file’s columns. Each subsequent row
represents a vertex in the skeleton graph: either a trunk, a
branchpoint or an endpoint. The file has the following columns:

-  *image\_number:* The image number of the associated image.
-  *vertex\_number:* The number of the vertex within the image.
-  *i:* The I coordinate of the vertex.
-  *j:* The J coordinate of the vertex.
-  *label:* The label of the seed object associated with the vertex.
-  *kind:* The vertex type, with the following choices:

   -  **T:** Trunk
   -  **B:** Branchpoint
   -  **E:** Endpoint
""",
        )

        self.edge_file_name = cps.Text(
            "Edge file name",
            "edges.csv",
            doc="""\
*(Used only when exporting graph relationships)*

Enter the name of the file that will hold the edge information. You can
use metadata tags in the file name. Each line of the file is a row of
comma-separated values. The first row is the header; this names the
file’s columns. Each subsequent row represents an edge or connection
between two vertices (including between a vertex and itself for certain
loops). Note that vertices include trunks, branchpoints, and endpoints.

The file has the following columns:

-  *image\_number:* The image number of the associated image.
-  *v1:* The zero-based index into the vertex table of the first vertex
   in the edge.
-  *v2:* The zero-based index into the vertex table of the second vertex
   in the edge.
-  *length:* The number of pixels in the path connecting the two
   vertices, including both vertex pixels.
-  *total\_intensity:* The sum of the intensities of the pixels in the
   edge, including both vertex pixel intensities.
""",
        )