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(),
                    cps.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.""",
                )
    def create_settings(self) -> None:
        module_explanation = "Creates a binary mask of the wedge."
        self.set_notes([module_explanation])

        self.wedge_mask_name = cps.ObjectNameProvider(
            text="Name the wedge mask",
            value="WedgeMask",
            doc="Enter the name of the wedge mask.",
        )

        self.image_name = cps.ImageNameProvider(
            text="Select image to overlay on",
            value="None",
            doc="""\
Choose the image_name upon which a wedge mask constructed from the given 
parameters is laid. Can be either RGB or grayscale.
""",
        )

        self.divider = cps.Divider(line=True)

        self.thickness = cps.Float(text="Enter thickness of wedge (um)",
                                   value=400.0,
                                   doc="")

        self.span = cps.Float(text="Enter span of wedge (deg)",
                              value=90.0,
                              doc="")

        self.radial_offset = cps.Float(
            text="Enter radial offset",
            value=0.0,
            doc=
            "Enter offset of the inner edge of wedge from well, in microns.",
        )

        self.angular_offset = cps.Float(
            text="Enter angular offset",
            value=0.0,
            doc="""\
Enter offset of the wedge midline from well midline, in degrees, clockwise positive.
""",
        )

        self.mask_color = cps.Color(
            text="Select wedge fill color",
            value=DEFAULT_MASK_COLOR,
            doc="""\
The wedge is outlined in this color. Only applies when the result of this 
module is visualized.""",
        )
Beispiel #3
0
    def create_settings(self):
        '''Create the initial settings for the module'''
        self.image_groups = []
        self.add_image(can_delete=False)
        self.spacer_1 = cps.Divider()
        self.add_image(can_delete=False)
        self.image_count = cps.HiddenCount(self.image_groups)

        self.add_image_button = cps.DoSomething("", 'Add another image', self.add_image)
        self.spacer_2 = cps.Divider()
        self.thr = cps.Float(
                "Set threshold as percentage of maximum intensity for the images",
                15, minval=0, maxval=99, doc='''\
            Select the threshold as a percentage of the maximum intensity of the above image [0-99].''')

        self.images_or_objects = cps.Choice(
                'Select where to measure correlation',
                [M_IMAGES, M_OBJECTS, M_IMAGES_AND_OBJECTS], doc='''
            You can measure the correlation in several ways:
            <ul>
            <li><i>%(M_OBJECTS)s:</i> Measure correlation only in those pixels previously
            identified as an object. You will be asked to specify which object to measure from.</li>
            <li><i>%(M_IMAGES)s:</i> Measure the correlation across all pixels in the images.</li>
            <li><i>%(M_IMAGES_AND_OBJECTS)s:</i> Calculate both measurements above.</li>
            </ul>
            All methods measure correlation on a pixel by pixel basis.''' % globals())

        self.object_groups = []
        self.add_object(can_delete=False)
        self.object_count = cps.HiddenCount(self.object_groups)

        self.spacer_2 = cps.Divider(line=True)

        self.add_object_button = cps.DoSomething("", 'Add another object', self.add_object)
    def add_image(self, removable=True):
        # The text for these settings will be replaced in renumber_settings()
        group = cps.SettingsGroup()
        group.removable = removable
        group.append("image_or_measurement", cps.Choice(
                "Image or measurement?", [IM_IMAGE, IM_MEASUREMENT], doc="""
            You can perform math operations using two images or you
            can use a measurement for one of the operands. For instance,
            to divide the intensity of one image by another, choose <i>%(IM_IMAGE)s</i>
            for both and pick the respective images. To divide the intensity
            of an image by its median intensity, use <b>MeasureImageIntensity</b>
            prior to this module to calculate the median intensity, then
            select <i>%(IM_MEASUREMENT)s</i> and use the median intensity measurement as
            the denominator""" % globals()))

        group.append("image_name", cps.ImageNameSubscriber("", "", doc="""
            Selec the image that you want to use for this operation."""))

        group.append("measurement", cps.Measurement(
                "Measurement", lambda: cpmeas.IMAGE, "", doc="""
            This is a measurement made on the image. The value of the
            measurement is used for the operand for all of the pixels of the
            other operand's image."""))

        group.append("factor", cps.Float("", 1, doc="""
            Enter the number that you would like to multiply the above image by. This multiplication
            is applied before other operations."""))

        if removable:
            group.append("remover", cps.RemoveSettingButton("", "Remove this image", self.images, group))
        group.append("divider", cps.Divider())
        self.images.append(group)
Beispiel #5
0
    def add_channel(self, can_remove=True):
        '''Add another channel to the channels list'''
        group = cps.SettingsGroup()
        group.can_remove = can_remove
        group.append("channel_choice", cps.Choice(
                "Channel number", self.channel_names,
                self.channel_names[len(self.channels) % len(self.channel_names)], doc="""
            This setting chooses a channel to be processed.
            <i>Red: 1</i> is the first channel in a .TIF or the red channel
            in a traditional image file. <i>Green: 2</i> and <i>Blue: 3</i>
            are the second and third channels of a TIF or the green and blue
            channels in other formats. <i>Alpha: 4</i> is the transparency
            channel for image formats that support transparency and is
            channel # 4 for a .TIF file.

            <b>ColorToGray</b> will fail to process an image if you select
            a channel that is not supported by that image, for example, "5"
            for a .PNG file"""))

        group.append("contribution", cps.Float(
                "Relative weight of the channel", 1, 0, doc='''
            <i>(Used only when combining channels)</i><br>
            Relative weights: If all relative weights are equal, all three
            colors contribute equally in the final image. To weight colors relative
            to each other, increase or decrease the relative weights.'''))

        group.append("image_name", cps.ImageNameProvider(
                "Image name", value="Channel%d" % (len(self.channels) + 1), doc="""
            This is the name of the grayscale image that holds
            the image data from the chosen channel."""))

        if group.can_remove:
            group.append("remover", cps.RemoveSettingButton(
                    "", "Remove this channel", self.channels, group))
        self.channels.append(group)
    def create_settings(self):
        self.object_name = cps.ObjectNameSubscriber("Select the input objects",
                                                    cps.NONE,
                                                    doc='''
            Select the objects that you want to rescale.''')

        self.output_object_name = cps.ObjectNameProvider(
            "Name the output objects",
            "RescaledObject",
            doc='''
            Enter a name for the resulting objects.''')

        self.operation = cps.Choice("Select the operation",
                                    O_ALL,
                                    doc='''
            Select the operation that you want to perform:
            <ul>
            <li><i>%(O_DOWNSCALE)s:</i> Downscale the Object Masks to a smaller image size.</li>
            <li><i>%(O_UPSCALE)s:</i> Expand objects, assigning every pixel in the image to an
            object. Background pixels are assigned to the nearest object.</li>
            </ul>''' % globals())

        self.scaling = cps.Float("Factor to scale the object mask",
                                 1,
                                 minval=0)
 def test_01_02_set_value(self):
     s = cps.Float("foo", value=5)
     for test_case in ("6.00", "-1.75"):
         s.value_text = test_case
         self.assertEqual(s, float(test_case))
         self.assertEqual(s.value_text, test_case)
         s.test_valid(None)
Beispiel #8
0
    def add_channel(self, can_remove=True):
        """Add another channel to the channels list"""
        group = cps.SettingsGroup()
        group.can_remove = can_remove
        group.append(
            "channel_choice",
            cps.Integer(
                text="Channel number",
                value=len(self.channels) + 1,
                minval=1,
                doc="""\
*(Used only when splitting images)*

This setting chooses a channel to be processed. For example, *1*
is the first
channel in a .TIF or the red channel in a traditional image file.
*2* and *3* are the second and third channels of a TIF or
the green and blue channels in other formats. *4* is the
transparency channel for image formats that support transparency and is
channel # 4 for a .TIF file. **ColorToGray** will fail to process an
image if you select a channel that is not supported by that image, for
example, “5” for a three-channel .PNG file.""",
            ),
        )

        group.append(
            "contribution",
            cps.Float(
                "Relative weight of the channel",
                1,
                0,
                doc="""\
*(Used only when combining channels)*

Relative weights: If all relative weights are equal, all three colors
contribute equally in the final image. To weight colors relative to each
other, increase or decrease the relative weights.""",
            ),
        )

        group.append(
            "image_name",
            cps.ImageNameProvider(
                "Image name",
                value="Channel%d" % (len(self.channels) + 1),
                doc="""\
*(Used only when splitting images)*

Select the name of the output grayscale image.""",
            ),
        )

        if group.can_remove:
            group.append(
                "remover",
                cps.RemoveSettingButton("", "Remove this channel",
                                        self.channels, group),
            )
        self.channels.append(group)
Beispiel #9
0
    def add_stack_channel_cb(self, can_remove=True):
        group = cps.SettingsGroup()
        default_color = DEFAULT_COLORS[len(self.stack_channels) %
                                       len(DEFAULT_COLORS)]
        group.append(
            "image_name",
            cps.ImageNameSubscriber(
                "Image name",
                cps.NONE,
                doc="""\
*(Used only if "%(SCHEME_STACK)s" or "%(SCHEME_COMPOSITE)s" is chosen)*

Select the input image to add to the stacked image.
""" % globals(),
            ),
        )
        group.append(
            "color",
            cps.Color(
                "Color",
                default_color,
                doc="""\
*(Used only if "%(SCHEME_COMPOSITE)s" is chosen)*

The color to be assigned to the above image.
""" % globals(),
            ),
        )
        group.append(
            "weight",
            cps.Float(
                "Weight",
                1.0,
                minval=0.5 / 255,
                doc="""\
*(Used only if "%(SCHEME_COMPOSITE)s" is chosen)*

The weighting of the above image relative to the others. The image’s
pixel values are multiplied by this weight before assigning the color.
""" % globals(),
            ),
        )

        if can_remove:
            group.append(
                "remover",
                cps.RemoveSettingButton("", "Remove this image",
                                        self.stack_channels, group),
            )
        self.stack_channels.append(group)
Beispiel #10
0
    def create_settings(self):
        self.image_name = cps.ImageNameSubscriber(
                "Select the input image", cps.NONE, doc="""Select the multichannel image you want to convert to grayscale.""")

        self.combine_or_split = cps.Choice(
                "Conversion method",
                [COMBINE, SPLIT], doc='''\
How do you want to convert the color image?

-  *%(SPLIT)s:* Splits the channels of a color
   image (e.g., red, green, blue) into separate grayscale images.
-  *%(COMBINE)s:* Converts a color image to a grayscale image by
   combining channels together (e.g., red, green, blue).''' % globals())

        self.rgb_or_channels = cps.Choice(
                "Image type", [CH_RGB, CH_HSV, CH_CHANNELS], doc="""\
This setting provides three options to choose from:

-  *%(CH_RGB)s:* The RGB (red, green, blue) color space is the typical
   model in which color images are stored. Choosing this option will
   split the image into red, green, and blue component images.
-  *%(CH_HSV)s:* The HSV (hue, saturation, value) color space is based
   on color characteristics such as tint, shade, and tone.
   Choosing this option will split the image into the hue,
   saturation, and value component images.
-  *%(CH_CHANNELS)s:* Many images contain color channels other than RGB
   or HSV. For instance, GIF and PNG formats can have an alpha
   channel that encodes transparency. TIF formats can have an arbitrary
   number of channels which represent pixel measurements made by
   different detectors, filters or lighting conditions. This setting
   allows you to handle a more complex model for images that
   have more than three channels.""" % globals())

        # The following settings are used for the combine option
        self.grayscale_name = cps.ImageNameProvider(
                "Name the output image", "OrigGray", doc="""\
*(Used only when combining channels)*

Enter a name for the resulting grayscale image.""")

        self.red_contribution = cps.Float(
                "Relative weight of the red channel",
                1, 0, doc='''\
*(Used only when combining channels)*

Relative weights: If all relative weights are equal, all three colors
contribute equally in the final image. To weight colors relative to each
other, increase or decrease the relative weights.''')

        self.green_contribution = cps.Float(
                "Relative weight of the green channel",
                1, 0, doc='''\
*(Used only when combining channels)*

Relative weights: If all relative weights are equal, all three colors
contribute equally in the final image. To weight colors relative to each
other, increase or decrease the relative weights.''')

        self.blue_contribution = cps.Float(
                "Relative weight of the blue channel",
                1, 0, doc='''\
*(Used only when combining channels)*

Relative weights: If all relative weights are equal, all three colors
contribute equally in the final image. To weight colors relative to each
other, increase or decrease the relative weights.''')

        # The following settings are used for the split RGB option
        self.use_red = cps.Binary('Convert red to gray?', True, doc="""\
*(Used only when splitting RGB images)*

Select *"%(YES)s"* to extract the red channel to grayscale. Otherwise, the
red channel will be ignored.
""" % globals())

        self.red_name = cps.ImageNameProvider('Name the output image', "OrigRed", doc="""\
*(Used only when splitting RGB images)*

Enter a name for the resulting grayscale image coming from the red channel.""")

        self.use_green = cps.Binary('Convert green to gray?', True, doc="""\
*(Used only when splitting RGB images)*

Select *"%(YES)s"* to extract the green channel to grayscale. Otherwise, the
green channel will be ignored.
""" % globals())

        self.green_name = cps.ImageNameProvider('Name the output image', "OrigGreen", doc="""\
*(Used only when splitting RGB images)*

Enter a name for the resulting grayscale image coming from the green channel.""")

        self.use_blue = cps.Binary('Convert blue to gray?', True, doc="""\
*(Used only when splitting RGB images)*

Select *"%(YES)s"* to extract the blue channel to grayscale. Otherwise, the
blue channel will be ignored.
""" % globals())

        self.blue_name = cps.ImageNameProvider('Name the output image', "OrigBlue", doc="""\
*(Used only when splitting RGB images)*

Enter a name for the resulting grayscale image coming from the blue channel.""")

        # The following settings are used for the split HSV ption
        self.use_hue = cps.Binary('Convert hue to gray?', True, doc="""\
*(Used only when splitting HSV images)*

Select *"%(YES)s"* to extract the hue to grayscale. Otherwise, the hue
will be ignored.
""" % globals())

        self.hue_name = cps.ImageNameProvider('Name the output image', "OrigHue", doc="""\
*(Used only when splitting HSV images)*

Enter a name for the resulting grayscale image coming from the hue.""")

        self.use_saturation = cps.Binary('Convert saturation to gray?', True, doc="""\
*(Used only when splitting HSV images)*

Select *"%(YES)s"* to extract the saturation to grayscale. Otherwise, the
saturation will be ignored.
""" % globals())

        self.saturation_name = cps.ImageNameProvider('Name the output image', "OrigSaturation", doc="""\
*(Used only when splitting HSV images)*

Enter a name for the resulting grayscale image coming from the saturation.""")

        self.use_value = cps.Binary('Convert value to gray?', True, doc="""\
*(Used only when splitting HSV images)*

Select *"%(YES)s"* to extract the value to grayscale. Otherwise, the
value will be ignored.
""" % globals())

        self.value_name = cps.ImageNameProvider('Name the output image', "OrigValue", doc="""\
*(Used only when splitting HSV images)*

Enter a name for the resulting grayscale image coming from the value.""")

        # The alternative model:
        self.channels = []
        self.add_channel(False)
        self.channel_button = cps.DoSomething(
                "", "Add another channel", self.add_channel)

        self.channel_count = cps.HiddenCount(self.channels, "Channel count")
Beispiel #11
0
    def create_settings(self):
        self.image_name = cps.ImageNameSubscriber(
            'Select the input image',
            cps.NONE,
            doc="""Select the image to be smoothed.""")

        self.filtered_image_name = cps.ImageNameProvider(
            'Name the output image',
            'FilteredImage',
            doc="""Enter a name for the resulting image.""")

        self.smoothing_method = cps.Choice('Select smoothing method', [
            FIT_POLYNOMIAL, GAUSSIAN_FILTER, MEDIAN_FILTER,
            SMOOTH_KEEPING_EDGES, CIRCULAR_AVERAGE_FILTER, SM_TO_AVERAGE
        ],
                                           doc="""\
This module smooths images using one of several filters. Fitting a
polynomial is fastest but does not allow a very tight fit compared to
the other methods:

-  *%(FIT_POLYNOMIAL)s:* This method is fastest but does not allow
   a very tight “fit” compared to the other methods. Thus, it will usually be less
   accurate. The method treats the intensity of the image
   pixels as a polynomial function of the x and y position of each
   pixel. It fits the intensity to the polynomial, *A x* :sup:`2` *+ B
   y* :sup:`2` *+ C xy + D x + E y + F*. This will produce a smoothed
   image with a single peak or trough of intensity that tapers off
   elsewhere in the image. For many microscopy images (where the
   illumination of the lamp is brightest in the center of field of
   view), this method will produce an image with a bright central region
   and dimmer edges. But, in some cases the peak/trough of the
   polynomial may actually occur outside of the image itself.
-  *%(GAUSSIAN_FILTER)s:* This method convolves the image with a
   Gaussian whose full width at half maximum is the artifact diameter
   entered. Its effect is to blur and obscure features smaller than the
   specified diameter and spread bright or dim features larger than the
   specified diameter.
-  *%(MEDIAN_FILTER)s:* This method finds the median pixel value within
   the diameter you specify. It removes bright or dim features
   that are significantly smaller than the specified diameter.
-  *%(SMOOTH_KEEPING_EDGES)s:* This method uses a bilateral filter
   which limits Gaussian smoothing across an edge while applying
   smoothing perpendicular to an edge. The effect is to respect edges in
   an image while smoothing other features. *%(SMOOTH_KEEPING_EDGES)s*
   will filter an image with reasonable speed for artifact diameters
   greater than 10 and for intensity differences greater than 0.1. The
   algorithm will consume more memory and operate more slowly as you
   lower these numbers.
-  *%(CIRCULAR_AVERAGE_FILTER)s:* This method convolves the image with
   a uniform circular averaging filter whose size is the artifact
   diameter entered. This filter is useful for re-creating an
   out-of-focus blur to an image.
-  *%(SM_TO_AVERAGE)s:* Creates a flat, smooth image where every pixel
   of the image equals the average value of the original image.

*Note, when deciding between %(MEDIAN_FILTER)s and %(GAUSSIAN_FILTER)s
we typically recommend
%(MEDIAN_FILTER)s over %(GAUSSIAN_FILTER)s because the
median is less sensitive to outliers, although the results are also
slightly less smooth and the fact that images are in the range of 0
to 1 means that outliers typically will not dominate too strongly
anyway.*
""" % globals())

        self.wants_automatic_object_size = cps.Binary(
            'Calculate artifact diameter automatically?',
            True,
            doc="""\
*(Used only if “%(GAUSSIAN_FILTER)s”, “%(MEDIAN_FILTER)s”, “%(SMOOTH_KEEPING_EDGES)s” or “%(CIRCULAR_AVERAGE_FILTER)s” is selected)*

Select *%(YES)s* to choose an artifact diameter based on the size of
the image. The minimum size it will choose is 30 pixels, otherwise the
size is 1/40 of the size of the image.

Select *%(NO)s* to manually enter an artifact diameter.
""" % globals())

        self.object_size = cps.Float('Typical artifact diameter',
                                     16.0,
                                     doc="""\
*(Used only if choosing the artifact diameter automatically is set to
“%(NO)s”)*

Enter the approximate diameter (in pixels) of the features to be blurred
by the smoothing algorithm. This value is used to calculate the size of
the spatial filter. %(HELP_ON_MEASURING_DISTANCES)s For most
smoothing methods, selecting a diameter over ~50 will take substantial
amounts of time to process.
""" % globals())

        self.sigma_range = cps.Float('Edge intensity difference',
                                     0.1,
                                     doc="""\
*(Used only if “%(SMOOTH_KEEPING_EDGES)s” is selected)*

Enter the intensity step (which indicates an edge in an image) that you
want to preserve. Edges are locations where the intensity changes
precipitously, so this setting is used to adjust the rough magnitude of
these changes. A lower number will preserve weaker edges. A higher
number will preserve only stronger edges. Values should be between zero
and one. %(HELP_ON_PIXEL_INTENSITIES)s
""" % globals())

        self.clip = cps.Binary('Clip intensities to 0 and 1?',
                               True,
                               doc="""\
*(Used only if "%(FIT_POLYNOMIAL)s" is selected)*

The *%(FIT_POLYNOMIAL)s* method is the only smoothing option that can
yield an output image whose values are outside of the values of the
input image. This setting controls whether to limit the image
intensity to the 0 - 1 range used by CellProfiler.

Select *%(YES)s* to set all output image pixels less than zero to zero
and all pixels greater than one to one.

Select *%(NO)s* to allow values less than zero and greater than one in
the output image.
""" % globals())
Beispiel #12
0
    def create_settings(self):
        self.image_name = cps.ImageNameSubscriber("Select the input image",
                                                  cps.NONE,
                                                  doc='''
            Select the image to be resized.''')

        self.resized_image_name = cps.ImageNameProvider(
            "Name the output image",
            "ResizedBlue",
            doc='''
            Enter the name of the resized image.''')

        self.size_method = cps.Choice("Resizing method",
                                      R_ALL,
                                      doc="""
            The following options are available:
            <ul>
            <li><i>Resize by a fraction or multiple of the original size:</i>
            Enter a single value which specifies the scaling. </li>
            <li><i>Resize by specifying desired final dimensions:</i></li>
            Enter the new height and width of the resized image.</ul>""")

        self.resizing_factor = cps.Float("Resizing factor",
                                         0.25,
                                         minval=0,
                                         doc='''
            <i>(Used only if resizing by a fraction or multiple of the original size)</i><br>
            Numbers less than one (that is, fractions) will shrink the image;
            numbers greater than one (that is, multiples) will enlarge the image.'''
                                         )

        self.use_manual_or_image = cps.Choice(
            "Method to specify the dimensions",
            C_ALL,
            doc="""
            <i>(Used only if resizing by specifying the dimensions)</i><br>
            You have two options on how to resize your image:
            <ul>
            <li><i>%(C_MANUAL)s:</i> Specify the height and width of the output image.</li>
            <li><i>>%(C_IMAGE)s::</i> Specify an image and the input image will be resized
            to the same dimensions.</li>
            </ul>""" % globals())

        self.specific_width = cps.Integer("Width of the final image",
                                          100,
                                          minval=1,
                                          doc='''
            <i>(Used only if resizing by specifying desired final dimensions)</i><br>
            Enter the desired width of the final image, in pixels.''')

        self.specific_height = cps.Integer("Height of the final image",
                                           100,
                                           minval=1,
                                           doc='''
            <i>(Used only if resizing by specifying desired final dimensions)</i><br>
            Enter the desired height of the final image, in pixels.''')

        self.specific_image = cps.ImageNameSubscriber(
            "Select the image with the desired dimensions",
            cps.NONE,
            doc=""""
            <i>(Used only if resizing by specifying desired final dimensions using an image)</i><br>
            The input image will be resized to the dimensions of the specified image."""
        )

        self.interpolation = cps.Choice("Interpolation method",
                                        I_ALL,
                                        doc='''
            <ul><li><i>Nearest Neighbor:</i> Each output pixel is given the intensity of the nearest
            corresponding pixel in the input image.</li>
            <li><i>Bilinear:</i> Each output pixel is given the intensity of the weighted average
            of the 2x2 neighborhood at the corresponding position in the input image.</li>
            <li><i>Bicubic:</i> Each output pixel is given the intensity of the weighted average
            of the 4x4 neighborhood at the corresponding position in the input image.</li>
            </ul>''')

        self.separator = cps.Divider(line=False)

        self.additional_images = []

        self.additional_image_count = cps.HiddenCount(
            self.additional_images, "Additional image count")

        self.add_button = cps.DoSomething("", "Add another image",
                                          self.add_image)
Beispiel #13
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",
                cps.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)
    def create_settings(self):
        """Create the settings for the module

        Create the settings for the module during initialization.
        """
        self.image_name = cps.ImageNameSubscriber("Select the input image",
                                                  cps.NONE,
                                                  doc="""
            The name of a binary image from a previous module.
            <b>IdentifyLinearObjects</b> will use this image to establish the
            foreground and background for the fitting operation. You can use
            <b>ApplyThreshold</b> to threshold a grayscale image and
            create the binary mask. You can also use a module such as
            <b>IdentifyPrimaryObjects</b> to label each linear object and then use
            <b>ConvertObjectsToImage</b> to make the result a mask.""")

        self.object_name = cps.ObjectNameProvider(
            "Name the linear objects to be identified",
            "LinearObjects",
            doc="""
            This is the name for the linear objects. You can refer
            to this name in subsequent modules such as
            <b>IdentifySecondaryObjects</b>""")

        self.object_width = cps.Integer("Linear object width",
                                        10,
                                        minval=1,
                                        doc="""
            This is the width (the short axis), measured in pixels,
            of the diamond used as a template when
            matching against the linear object. It should be less than the width
            of a linear object.""")

        self.object_length = cps.Integer("Linear object length",
                                         100,
                                         minval=1,
                                         doc="""
            This is the length (the long axis), measured in pixels,
            of the diamond used as a template when matching against the
            linear object. It should be less than the length of a linear object"""
                                         )

        self.angle_count = cps.Integer("Number of angles",
                                       32,
                                       minval=1,
                                       doc="""
            This is the number of different angles at which the
            template will be tried. For instance, if there are 12 angles,
            the template will be rotated by 0&deg;, 15&deg;, 30&deg;, 45&deg; ... 165&deg;.
            The shape is bilaterally symmetric; that is, you will get the same shape
            after rotating it by 180&deg;.""")

        self.wants_automatic_distance = cps.Binary(
            "Automatically calculate distance parameters?",
            True,
            doc="""
            This setting determines whether or not
            <b>IdentifyLinearObjects</b> automatically calculates the parameters
            used to determine whether two found-linear object centers belong to the
            same linear object.
            <p>Select <i>%(YES)s</i> to have <b>IdentifyLinearObjects</b>
            automatically calculate the distance from the linear object length
            and width. Select <i>%(NO)s</i> to set the distances manually.</p>"""
            % globals())

        self.space_distance = cps.Float("Spatial distance",
                                        5,
                                        minval=1,
                                        doc="""
            <i>(Used only if not automatically calculating distance parameters)</i><br>
            Enter the distance for calculating the linear object centers, in units of pixels.
            The linear object centers must be at least many pixels apart for the centers to
            be considered two separate linear objects.""")

        self.angular_distance = cps.Float("Angular distance",
                                          30,
                                          minval=1,
                                          doc="""
            <i>(Used only if automatically calculating distance parameters)</i><br>
            <b>IdentifyLinearObjects</b> calculates the linear object centers at different
            angles. Two linear object centers are considered to represent different
            linear objects if their angular distance is larger than this number. The
            number is measured in degrees.""")

        self.overlap_within_angle = cps.Binary(
            "Combine if overlapping and within angular distance?",
            False,
            doc="""
            This setting determines whether or not
            <b>IdentifyLinearObjects</b> merges putative linear objects that are within the
            angular distance specified AND in which pixels from the two 
            linear objects overlap.
            <p>Select <i>%(YES)s</i> to have <b>IdentifyLinearObjects</b>
            merge these linear objects. Select <i>%(NO)s</i> use only the spatial
            distance and angular distance parameters above.</p>""" % globals())
Beispiel #15
0
    def create_settings(self):
        # XXX needs to use cps.SettingsGroup
        class Operand(object):
            '''Represents the collection of settings needed by each operand'''
            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(),
                    cps.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."""
                )

            @property
            def operand_choice(self):
                '''Either MC_IMAGE for image measurements or MC_OBJECT for object'''
                return self.__operand_choice

            @property
            def operand_objects(self):
                '''Get measurements from these objects'''
                return self.__operand_objects

            @property
            def operand_measurement(self):
                '''The measurement providing the value of the operand'''
                return self.__operand_measurement

            @property
            def multiplicand(self):
                '''Premultiply the measurement by this value'''
                return self.__multiplicand

            @property
            def exponent(self):
                '''Raise the measurement to this power'''
                return self.__exponent

            @property
            def object(self):
                '''The name of the object for measurement or "Image"'''
                if self.operand_choice == MC_IMAGE:
                    return cpmeas.IMAGE
                else:
                    return self.operand_objects.value

            def object_fn(self):
                if self.__operand_choice == MC_IMAGE:
                    return cpmeas.IMAGE
                elif self.__operand_choice == MC_OBJECT:
                    return self.__operand_objects.value
                else:
                    raise NotImplementedError(
                        "Measurement type %s is not supported" %
                        self.__operand_choice.value)

            def operand_name(self):
                '''A fancy name based on what operation is being performed'''
                if self.__index == 0:
                    return ("first operand" if self.__operation
                            in (O_ADD, O_MULTIPLY) else "minuend"
                            if self.__operation == O_SUBTRACT else "numerator")
                elif self.__index == 1:
                    return ("second operand" if self.__operation
                            in (O_ADD, O_MULTIPLY) else "subtrahend" if
                            self.__operation == O_SUBTRACT else "denominator")

            def operand_choice_text(self):
                return self.operand_text("Select the %s measurement type")

            def operand_objects_text(self):
                return self.operand_text("Select the %s objects")

            def operand_text(self, format):
                return format % self.operand_name()

            def operand_measurement_text(self):
                return self.operand_text("Select the %s measurement")

            def settings(self):
                '''The operand settings to be saved in the output file'''
                return [
                    self.operand_choice, self.operand_objects,
                    self.operand_measurement, self.multiplicand, self.exponent
                ]

            def visible_settings(self):
                '''The operand settings to be displayed'''
                self.operand_choice.text = self.operand_choice_text()
                self.operand_objects.text = self.operand_objects_text()
                self.operand_measurement.text = self.operand_measurement_text()
                result = [self.operand_choice]
                result += ([self.operand_objects] if self.operand_choice == MC_OBJECT \
                               else [])
                result += [
                    self.operand_measurement, self.multiplicand, self.exponent
                ]
                return result

        self.output_feature_name = cps.AlphanumericText(
            "Name the output measurement",
            "Measurement",
            doc=
            """Enter a name for the measurement calculated by this module.""")

        self.operation = cps.Choice("Operation",
                                    O_ALL,
                                    doc="""\
Choose the arithmetic operation you would like to perform. *None* is
useful if you simply want to select some of the later options in the
module, such as multiplying or exponentiating your image by a constant.
""")

        self.operands = (Operand(0,
                                 self.operation), Operand(1, self.operation))

        self.spacer_1 = cps.Divider(line=True)

        self.spacer_2 = cps.Divider(line=True)

        self.spacer_3 = cps.Divider(line=True)

        self.wants_log = cps.Binary(
            "Take log10 of result?",
            False,
            doc=
            """Select *%(YES)s* if you want the log (base 10) of the result."""
            % globals())

        self.final_multiplicand = cps.Float("Multiply the result by",
                                            1,
                                            doc="""\
*(Used only for operations other than "None")*

Enter the number by which you would like to multiply the result.
""")

        self.final_exponent = cps.Float("Raise the power of result by",
                                        1,
                                        doc="""\
*(Used only for operations other than "None")*

Enter the power by which you would like to raise the result.
""")

        self.final_addend = cps.Float(
            "Add to the result",
            0,
            doc="""Enter the number you would like to add to the result.""")

        self.constrain_lower_bound = cps.Binary(
            "Constrain the result to a lower bound?",
            False,
            doc=
            """Select *%(YES)s* if you want the result to be constrained to a lower bound."""
            % globals())

        self.lower_bound = cps.Float(
            "Enter the lower bound",
            0,
            doc="""Enter the lower bound of the result here.""")

        self.constrain_upper_bound = cps.Binary(
            "Constrain the result to an upper bound?",
            False,
            doc=
            """Select *%(YES)s* if you want the result to be constrained to an upper bound."""
            % globals())

        self.upper_bound = cps.Float(
            "Enter the upper bound",
            1,
            doc="""Enter the upper bound of the result here.""")
Beispiel #16
0
    def create_settings(self):
        self.image_name = cps.ImageNameSubscriber(
                "Select the input image", cps.NONE, doc='''Select the image whose edges you want to enhance.''')

        self.output_image_name = cps.ImageNameProvider(
                "Name the output image", "EdgedImage", doc='''Enter a name for the resulting image with edges enhanced.''')

        self.method = cps.Choice(
                "Select an edge-finding method",
                [M_SOBEL, M_PREWITT, M_ROBERTS, M_LOG, M_CANNY, M_KIRSCH], doc='''\
There are several methods that can be used to enhance edges. Often, it
is best to test them against each other empirically:

-  *%(M_SOBEL)s:* Finds edges using the %(M_SOBEL)s approximation to
   the derivative. The %(M_SOBEL)s method derives a horizontal and
   vertical gradient measure and returns the square-root of the sum of
   the two squared signals.
-  *%(M_PREWITT)s:* Finds edges using the %(M_PREWITT)s approximation
   to the derivative. It returns edges at those points where the
   gradient of the image is maximum.
-  *%(M_ROBERTS)s:* Finds edges using the Roberts approximation to the
   derivative. The %(M_ROBERTS)s method looks for gradients in the
   diagonal and anti-diagonal directions and returns the square-root of
   the sum of the two squared signals. This method is fast, but it
   creates diagonal artifacts that may need to be removed by smoothing.
-  *%(M_LOG)s:* Applies a Laplacian of Gaussian filter to the image and
   finds zero crossings.
-  *%(M_CANNY)s:* Finds edges by looking for local maxima of the
   gradient of the image. The gradient is calculated using the
   derivative of a Gaussian filter. The method uses two thresholds to
   detect strong and weak edges, and includes the weak edges in the
   output only if they are connected to strong edges. This method is
   therefore less likely than the others to be fooled by noise, and more
   likely to detect true weak edges.
-  *%(M_KIRSCH)s:* Finds edges by calculating the gradient among the 8
   compass points (North, North-east, etc.) and selecting the maximum as
   the pixel’s value.
''' % globals())

        self.wants_automatic_threshold = cps.Binary(
                "Automatically calculate the threshold?", True, doc='''\
*(Used only with the "%(M_CANNY)s" option and automatic thresholding)*

Select *%(YES)s* to automatically calculate the threshold using a
three-category Otsu algorithm performed on the Sobel transform of the
image.

Select *%(NO)s* to manually enter the threshold value.
''' % globals())

        self.manual_threshold = cps.Float(
                "Absolute threshold", 0.2, 0, 1, doc='''\
*(Used only with the "%(M_CANNY)s" option and manual thresholding)*

The upper cutoff for Canny edges. All Sobel-transformed pixels with this
value or higher will be marked as an edge. You can enter a threshold
between 0 and 1.
''' % globals())

        self.threshold_adjustment_factor = cps.Float(
                "Threshold adjustment factor", 1, doc='''\
*(Used only with the "%(M_CANNY)s" option and automatic thresholding)*

This threshold adjustment factor is a multiplier that is applied to both
the lower and upper Canny thresholds if they are calculated
automatically. An adjustment factor of 1 indicates no adjustment. The
adjustment factor has no effect on any threshold entered manually.
''' % globals())

        self.direction = cps.Choice(
                "Select edge direction to enhance",
                [E_ALL, E_HORIZONTAL, E_VERTICAL], doc='''\
*(Used only with "%(M_PREWITT)s" and "%(M_SOBEL)s" methods)*

Select the direction of the edges you aim to identify in the image
(predominantly horizontal, predominantly vertical, or both).
''' % globals())

        self.wants_automatic_sigma = cps.Binary("Calculate Gaussian's sigma automatically?", True, doc="""\
Select *%(YES)s* to automatically calculate the Gaussian's sigma.

Select *%(NO)s* to manually enter the value.
""" % globals())

        self.sigma = cps.Float("Gaussian's sigma value", 10, doc="""Set a value for Gaussian's sigma.""")

        self.wants_automatic_low_threshold = cps.Binary(
                "Calculate value for low threshold automatically?", True, doc="""\
*(Used only with the "%(M_CANNY)s" option and automatic thresholding)*

Select *%(YES)s* to automatically calculate the low / soft threshold
cutoff for the %(M_CANNY)s method.

Select *%(NO)s* to manually enter the low threshold value.
""" % globals())

        self.low_threshold = cps.Float(
                "Low threshold value", 0.1, 0, 1, doc="""\
*(Used only with the "%(M_CANNY)s" option and manual thresholding)*

Enter the soft threshold cutoff for the %(M_CANNY)s method. The
%(M_CANNY)s method will mark all %(M_SOBEL)s-transformed pixels with
values below this threshold as not being edges.
""" % globals())
    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",
                cps.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",
                cps.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)
    def create_settings(self):
        self.image_name = cps.ImageNameSubscriber("Select the input image",
                                                  cps.NONE)

        self.combine_or_split = cps.Choice("Conversion method",
                                           [COMBINE, SPLIT],
                                           doc='''
            How do you want to convert the color image?
            <ul>
            <li><i>%(SPLIT)s:</i> Splits the three channels
            (red, green, blue) of a color image into three separate grayscale images. </li>
            <li><i>%(COMBINE)s</i> Converts a color image to a grayscale
            image by combining the three channels (red, green, blue) together.</li>
            </ul>''' % globals())

        self.rgb_or_channels = cps.Choice("Image type",
                                          [CH_RGB, CH_HSV, CH_CHANNELS],
                                          doc="""
            Many images contain color channels other than red, green
            and blue. For instance, GIF and PNG formats can have an alpha
            channel that encodes transparency. TIF formats can have an arbitrary
            number of channels which represent pixel measurements made by
            different detectors, filters or lighting conditions. This setting
            provides three options to choose from:
            <ul>
            <li><i>%(CH_RGB)s:</i> The RGB (red,green,blue) color space is the typical model in which color images are stored. Choosing this option
            will split the image into any of the red, green and blue component images.</li>
            <li><i>%(CH_HSV)s:</i>The HSV (hue, saturation, value) color space is based on more intuitive color characteristics as
            tint, shade and tone. Choosing
            this option will split the image into any of the hue, saturation, and value component images.</li>
            <li><i>%(CH_CHANNELS)s:</i>This is a more complex model for images which involve more than three channels.</li>
            </ul>""" % globals())

        # The following settings are used for the combine option
        self.grayscale_name = cps.ImageNameProvider("Name the output image",
                                                    "OrigGray")

        self.red_contribution = cps.Float("Relative weight of the red channel",
                                          1,
                                          0,
                                          doc='''
            <i>(Used only when combining channels)</i><br>
            Relative weights: If all relative weights are equal, all three
            colors contribute equally in the final image. To weight colors relative
            to each other, increase or decrease the relative weights.''')

        self.green_contribution = cps.Float(
            "Relative weight of the green channel",
            1,
            0,
            doc='''
            <i>(Used only when combining channels)</i><br>
            Relative weights: If all relative weights are equal, all three
            colors contribute equally in the final image. To weight colors relative
            to each other, increase or decrease the relative weights.''')

        self.blue_contribution = cps.Float(
            "Relative weight of the blue channel",
            1,
            0,
            doc='''
            <i>(Used only when combining channels)</i><br>
            Relative weights: If all relative weights are equal, all three
            colors contribute equally in the final image. To weight colors relative
            to each other, increase or decrease the relative weights.''')

        # The following settings are used for the split RGB option
        self.use_red = cps.Binary('Convert red to gray?', True)
        self.red_name = cps.ImageNameProvider('Name the output image',
                                              "OrigRed")

        self.use_green = cps.Binary('Convert green to gray?', True)
        self.green_name = cps.ImageNameProvider('Name the output image',
                                                "OrigGreen")

        self.use_blue = cps.Binary('Convert blue to gray?', True)
        self.blue_name = cps.ImageNameProvider('Name the output image',
                                               "OrigBlue")

        # The following settings are used for the split HSV ption
        self.use_hue = cps.Binary('Convert hue to gray?', True)
        self.hue_name = cps.ImageNameProvider('Name the output image',
                                              "OrigHue")

        self.use_saturation = cps.Binary('Convert saturation to gray?', True)
        self.saturation_name = cps.ImageNameProvider('Name the output image',
                                                     "OrigSaturation")

        self.use_value = cps.Binary('Convert value to gray?', True)
        self.value_name = cps.ImageNameProvider('Name the output image',
                                                "OrigValue")

        # The alternative model:
        self.channels = []
        self.add_channel(False)
        self.channel_button = cps.DoSomething("", "Add another channel",
                                              self.add_channel)

        self.channel_count = cps.HiddenCount(self.channels, "Channel count")
Beispiel #19
0
    def create_settings(self):
        self.objects_name = cps.ObjectNameSubscriber(
            "Select the input objects",
            cps.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", [cps.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)s* 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",
            cps.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",
            .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())
Beispiel #20
0
    def add_image(self, can_remove=True):
        group = cps.SettingsGroup()
        group.can_remove = can_remove
        if can_remove:
            group.append("divider", cps.Divider())
        idx = len(self.outputs)
        default_name = STAINS_BY_POPULARITY[idx % len(STAINS_BY_POPULARITY)]
        default_name = default_name.replace(" ", "")

        group.append("image_name", cps.ImageNameProvider(
                "Name the output name", default_name, doc="""
            Use this setting to name one of the images produced by the
            module for a particular stain. The image can be used in
            subsequent modules in the pipeline."""))

        choices = list(sorted(STAIN_DICTIONARY.keys())) + [CHOICE_CUSTOM]

        group.append("stain_choice", cps.Choice(
                "Stain", choices=choices, doc="""
            Use this setting to choose the absorbance values for a
            particular stain. The stains are:
            <br>
            <table><tr><th>Stain</th><th>Color</th><th>Specific to</th></tr>
            <tr><td>%(CHOICE_AEC)s (3-Amino-9-ethylcarbazole)</td><td bgcolor="%(COLOR_AEC)s">&nbsp;</td><td>Peroxidase</td></tr>
            <tr><td>%(CHOICE_ALICAN_BLUE)s</td><td bgcolor="%(COLOR_ALICAN_BLUE)s">&nbsp;</td><td>Mucopolysaccharides</td></tr>
            <tr><td>%(CHOICE_ANILINE_BLUE)s</td><td bgcolor="%(COLOR_ANILINE_BLUE)s">&nbsp;</td><td>Pollen tubes</td></tr>
            <tr><td>%(CHOICE_AZOCARMINE)s</td><td bgcolor="%(COLOR_AZOCARMINE)s">&nbsp;</td><td>Plasma</td></tr>
            <tr><td>%(CHOICE_DAB)s</td><td bgcolor="%(COLOR_DAB)s">&nbsp;</td><td>Peroxisomes, mitochondria</td></tr>
            <tr><td>%(CHOICE_EOSIN)s</td><td bgcolor="%(COLOR_EOSIN)s">&nbsp;</td><td>Elastic, collagen and reticular fibers</td></tr>
            <tr><td>%(CHOICE_FAST_RED)s</td><td bgcolor="%(COLOR_FAST_RED)s">&nbsp;</td><td>Nuclei</td></tr>
            <tr><td>%(CHOICE_FAST_BLUE)s</td><td bgcolor="%(COLOR_FAST_BLUE)s">&nbsp;</td><td>Myelin fibers</td></tr>
            <tr><td>%(CHOICE_FEULGEN)s</td><td bgcolor="%(COLOR_FEULGEN)s">&nbsp;</td><td>DNA</td></tr>
            <tr><td>%(CHOICE_HEMATOXYLIN)s</td><td bgcolor="%(COLOR_HEMATOXYLIN)s">&nbsp;</td><td>Nucleic acids, endoplasmic reticulum</td></tr>
            <tr><td>%(CHOICE_HEMATOXYLIN_AND_PAS)s</td><td bgcolor="%(COLOR_HEMATOXYLIN_AND_PAS)s">&nbsp;</td><td>Nucleus (stained with both Hematoxylin and PAS)</td></tr>
            <tr><td>%(CHOICE_METHYL_BLUE)s</td><td bgcolor="%(COLOR_METHYL_BLUE)s">&nbsp;</td><td>Collagen</td></tr>
            <tr><td>%(CHOICE_METHYL_GREEN)s</td><td bgcolor="%(COLOR_METHYL_GREEN)s">&nbsp;</td><td>Chromatin</td></tr>
            <tr><td>%(CHOICE_METHYLENE_BLUE)s</td><td bgcolor="%(COLOR_METHYLENE_BLUE)s">&nbsp;</td><td>Nuclei</td></tr>
            <tr><td>%(CHOICE_ORANGE_G)s</td><td bgcolor="%(COLOR_ORANGE_G)s">&nbsp;</td><td>Erythrocytes, pancreas, pituitary</td></tr>
            <tr><td>%(CHOICE_PAS)s</td><td bgcolor="%(COLOR_PAS)s">&nbsp;</td><td>Glycogen, carbohydrates</td></tr>
            <tr><td>%(CHOICE_PONCEAU_FUCHSIN)s</td><td bgcolor="%(COLOR_PONCEAU_FUCHSIN)s">&nbsp;</td><td>Red counterstain for Masson's trichrome</td></tr>
            </table>
            <br>
            (Information taken from <a href="http://en.wikipedia.org/wiki/Histology#Staining">here</a>,
            <a href="http://en.wikipedia.org/wiki/Staining">here</a>, and
            <a href="http://stainsfile.info">here</a>.)
            <br>
            You can choose <i>%(CHOICE_CUSTOM)s</i> and enter your custom
            values for the absorbance (or use the estimator to determine values
            from a single-stain image).
            """ % globals()))

        group.append("red_absorbance", cps.Float(
                "Red absorbance", 0.5, 0, 1, doc="""
            <i>(Used only if %(CHOICE_CUSTOM)s is selected for the stain)</i><br>
            The red absorbance setting estimates the dye's
            absorbance of light in the red channel.You should enter a value
            between 0 and 1 where 0 is no absorbance and 1 is complete
            absorbance. You can use the estimator to calculate this
            value automatically.""" % globals()))

        group.append("green_absorbance", cps.Float(
                "Green absorbance", 0.5, 0, 1, doc="""
            <i>(Used only if %(CHOICE_CUSTOM)s is selected for the stain)</i><br>
            The green absorbance setting estimates the dye's
            absorbance of light in the green channel. You should enter a value
            between 0 and 1 where 0 is no absorbance and 1 is complete
            absorbance. You can use the estimator to calculate this
            value automatically.""" % globals()))

        group.append("blue_absorbance", cps.Float(
                "Blue absorbance", 0.5, 0, 1, doc="""
            <i>(Used only if %(CHOICE_CUSTOM)s is selected for the stain)</i><br>
            The blue absorbance setting estimates the dye's
            absorbance of light in the blue channel. You should enter a value
            between 0 and 1 where 0 is no absorbance and 1 is complete
            absorbance. You can use the estimator to calculate this
            value automatically.""" % globals()))

        def on_estimate():
            result = self.estimate_absorbance()
            if result is not None:
                (group.red_absorbance.value,
                 group.green_absorbance.value,
                 group.blue_absorbance.value) = result

        group.append("estimator_button", cps.DoSomething(
                "Estimate absorbance from image",
                "Estimate", on_estimate, doc="""
            Press this button to load an image of a sample stained
            only with the dye of interest. <b>UnmixColors</b> will estimate
            appropriate red, green and blue absorbance values from the
            image."""))

        if can_remove:
            group.append("remover", cps.RemoveSettingButton(
                    "", "Remove this image", self.outputs, group))
        self.outputs.append(group)
Beispiel #21
0
    def create_settings(self):
        '''Create the settings that control this module'''
        self.object_name = cps.ObjectNameSubscriber(
                "Select objects to be masked", cps.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 <b>IdentifyPrimaryObjects</b>,
            <b>IdentifySecondaryObjects</b> or <b>IdentifyTertiaryObjects</b>.""")

        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 (<i>%(MC_OBJECTS)s</i>) or by defining a
            region based on the white regions in a binary image (<i>%(MC_IMAGE)s</i>).""" % globals())

        self.masking_objects = cps.ObjectNameSubscriber(
                "Select the masking object", cps.NONE, doc="""
            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 <b>IdentifyPrimaryObjects</b>,
            <b>IdentifySecondaryObjects</b>, or <b>IdentifyTertiaryObjects</b>.""")

        self.masking_image = cps.ImageNameSubscriber(
                "Select the masking image", cps.NONE, doc="""
            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
            <b>NamesAndTypes</b> module by selecting "Binary mask" for the image type.
            You can also create a binary image from a grayscale
            image using <b>ApplyThreshold</b>.""")

        self.wants_inverted_mask = cps.Binary(
                "Invert the mask?", False, doc="""
            This option reverses the foreground/background relationship of
            the mask.
            <ul>
            <li>Select <i>%(NO)s</i> for the mask to be composed of the foregound
            (white portion) of the masking image or the area within the masking
            objects.</li>
            <li>Select <i>%(YES)s</i> for the mask to instead be composed of the
            <i>background</i> (black portions) of the masking image or the area
            <i>outside</i> the masking objects.</li>
            </ul>""" % 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. <b>MaskObjects</b>
            can handle this in one of three ways:<br>
            <ul>
            <li><i>%(P_MASK)s:</i> Choosing this option
            will reduce the size of partially overlapping objects. The part
            of the object that overlaps the region will be retained. The
            part of the object that is outside of the region will be removed.</li>
            <li><i>%(P_KEEP)s:</i> If you choose this option, <b>MaskObjects</b>
            will keep the whole object if any part of it overlaps the masking
            region.</li>
            <li><i>%(P_REMOVE)s:</i> Objects that are partially outside
            of the masking region will be completely removed if you choose
            this option.</li>
            <li><i>%(P_REMOVE_PERCENTAGE)s:</i> Determine whether to
            remove or keep an object depending on how much of the object
            overlaps the masking region. <b>MaskObjects</b> will keep an
            object if at least a certain fraction (which you enter below) of
            the object falls within the masking region. <b>MaskObjects</b>
            completely removes the object if too little of it overlaps
            the masking region.</li>
            </ul>""" % globals())

        self.overlap_fraction = cps.Float(
                "Fraction of object that must overlap", .5,
                minval=0, maxval=1, doc="""
            <i>(Used only if removing based on a overlap)</i><br>
            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:
            <ul>
            <li><i>%(R_RENUMBER)s:</i> 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).</li>
            <li><i>%(R_RETAIN)s:</i>: 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).</li>
            </ul>""" % globals())

        self.wants_outlines = cps.Binary(
                "Retain outlines of the resulting objects?", False, doc="""
            %(RETAINING_OUTLINES_HELP)s""" % globals())

        self.outlines_name = cps.OutlineNameProvider(
                "Name the outline image", "MaskedOutlines", doc="""
            %(NAMING_OUTLINES_HELP)s""" % globals())
Beispiel #22
0
    def create_settings(self):
        self.scheme_choice = cps.Choice(
            "Select a color scheme",
            [SCHEME_RGB, SCHEME_CMYK, SCHEME_STACK, SCHEME_COMPOSITE],
            doc="""\
This module can use one of two color schemes to combine images:

-  *%(SCHEME_RGB)s*: Each input image determines the intensity of one
   of the color channels: red, green, and blue.
-  *%(SCHEME_CMYK)s*: Three of the input images are combined to
   determine the colors (cyan, magenta, and yellow) and a fourth is used
   only for brightness. The cyan image adds equally to the green and
   blue intensities. The magenta image adds equally to the red and blue
   intensities. The yellow image adds equally to the red and green
   intensities.
-  *%(SCHEME_STACK)s*: The channels are stacked in order. An arbitrary
   number of channels is allowed.
-  *%(SCHEME_COMPOSITE)s*: A color is assigned to each grayscale image.
   Each grayscale image is converted to color by multiplying the
   intensity by the color and the resulting color images are added
   together. An arbitrary number of channels can be composited into a
   single color image.
""" % globals())

        # # # # # # # # # # # # # # # #
        #
        # RGB settings
        #
        # # # # # # # # # # # # # # # #
        self.red_image_name = cps.ImageNameSubscriber(
            "Select the image to be colored red",
            can_be_blank=True,
            blank_text=LEAVE_THIS_BLACK,
            doc="""\
*(Used only if "%(SCHEME_RGB)s" is selected as the color scheme)*

Select the input image to be displayed in red
""" % globals())

        self.green_image_name = cps.ImageNameSubscriber(
            "Select the image to be colored green",
            can_be_blank=True,
            blank_text=LEAVE_THIS_BLACK,
            doc="""\
*(Used only if "%(SCHEME_RGB)s" is selected as the color scheme)*

Select the input image to be displayed in green
""" % globals())

        self.blue_image_name = cps.ImageNameSubscriber(
            "Select the image to be colored blue",
            can_be_blank=True,
            blank_text=LEAVE_THIS_BLACK,
            doc="""\
*(Used only if "%(SCHEME_RGB)s" is selected as the color scheme)*

Select the input image to be displayed in blue
""" % globals())

        self.rgb_image_name = cps.ImageNameProvider(
            "Name the output image",
            "ColorImage",
            doc="""Enter a name for the resulting image""")

        self.red_adjustment_factor = cps.Float(
            "Relative weight for the red image",
            value=1,
            minval=0,
            doc='''\
*(Used only if "%(SCHEME_RGB)s" is selected as the color scheme)*

Enter the relative weight for the red image. If all relative weights are
equal, all three colors contribute equally in the final image. To weight
colors relative to each other, increase or decrease the relative
weights.
''' % globals())

        self.green_adjustment_factor = cps.Float(
            "Relative weight for the green image",
            value=1,
            minval=0,
            doc='''\
*(Used only if "%(SCHEME_RGB)s" is selected as the color scheme)*

Enter the relative weight for the green image. If all relative weights
are equal, all three colors contribute equally in the final image. To
weight colors relative to each other, increase or decrease the relative
weights.
''' % globals())

        self.blue_adjustment_factor = cps.Float(
            "Relative weight for the blue image",
            value=1,
            minval=0,
            doc='''\
*(Used only if "%(SCHEME_RGB)s" is selected as the color scheme)*

Enter the relative weight for the blue image. If all relative weights
are equal, all three colors contribute equally in the final image. To
weight colors relative to each other, increase or decrease the relative
weights.
''' % globals())
        # # # # # # # # # # # # # #
        #
        # CYMK settings
        #
        # # # # # # # # # # # # # #
        self.cyan_image_name = cps.ImageNameSubscriber(
            "Select the image to be colored cyan",
            can_be_blank=True,
            blank_text=LEAVE_THIS_BLACK,
            doc="""\
*(Used only if "%(SCHEME_CMYK)s" is selected as the color scheme)*

Select the input image to be displayed in cyan
""" % globals())

        self.magenta_image_name = cps.ImageNameSubscriber(
            "Select the image to be colored magenta",
            can_be_blank=True,
            blank_text=LEAVE_THIS_BLACK,
            doc="""\
*(Used only if "%(SCHEME_CMYK)s" is selected as the color scheme)*

Select the input image to be displayed in magenta
""" % globals())

        self.yellow_image_name = cps.ImageNameSubscriber(
            "Select the image to be colored yellow",
            can_be_blank=True,
            blank_text=LEAVE_THIS_BLACK,
            doc="""\
*(Used only if "%(SCHEME_CMYK)s" is selected as the color scheme)*

Select the input image to be displayed in yellow
""" % globals())

        self.gray_image_name = cps.ImageNameSubscriber(
            "Select the image that determines brightness",
            can_be_blank=True,
            blank_text=LEAVE_THIS_BLACK,
            doc="""\
*(Used only if "%(SCHEME_CMYK)s" is selected as the color scheme)*

Select the input image that will determine each pixel's brightness
""" % globals())

        self.cyan_adjustment_factor = cps.Float(
            "Relative weight for the cyan image",
            value=1,
            minval=0,
            doc='''\
*(Used only if "%(SCHEME_CMYK)s" is selected as the color scheme)*

Enter the relative weight for the cyan image. If all relative weights
are equal, all colors contribute equally in the final image. To weight
colors relative to each other, increase or decrease the relative
weights.
''' % globals())

        self.magenta_adjustment_factor = cps.Float(
            "Relative weight for the magenta image",
            value=1,
            minval=0,
            doc='''\
*(Used only if "%(SCHEME_CMYK)s" is selected as the color scheme)*

Enter the relative weight for the magenta image. If all relative weights
are equal, all colors contribute equally in the final image. To weight
colors relative to each other, increase or decrease the relative
weights.
''' % globals())

        self.yellow_adjustment_factor = cps.Float(
            "Relative weight for the yellow image",
            value=1,
            minval=0,
            doc='''\
*(Used only if "%(SCHEME_CMYK)s" is selected as the color scheme)*

Enter the relative weight for the yellow image. If all relative weights
are equal, all colors contribute equally in the final image. To weight
colors relative to each other, increase or decrease the relative
weights.
''' % globals())

        self.gray_adjustment_factor = cps.Float(
            "Relative weight for the brightness image",
            value=1,
            minval=0,
            doc='''\
*(Used only if "%(SCHEME_CMYK)s" is selected as the color scheme)*

Enter the relative weight for the brightness image. If all relative
weights are equal, all colors contribute equally in the final image. To
weight colors relative to each other, increase or decrease the relative
weights.
''' % globals())

        # # # # # # # # # # # # # #
        #
        # Stack settings
        #
        # # # # # # # # # # # # # #

        self.stack_channels = []
        self.stack_channel_count = cps.HiddenCount(self.stack_channels)
        self.add_stack_channel_cb(can_remove=False)
        self.add_stack_channel = cps.DoSomething("Add another channel",
                                                 "Add another channel",
                                                 self.add_stack_channel_cb,
                                                 doc="""\
    Press this button to add another image to the stack.
    """)
Beispiel #23
0
    def add_image(self, can_remove=True):
        group = cps.SettingsGroup()
        group.can_remove = can_remove
        if can_remove:
            group.append("divider", cps.Divider())
        idx = len(self.outputs)
        default_name = STAINS_BY_POPULARITY[idx % len(STAINS_BY_POPULARITY)]
        default_name = default_name.replace(" ", "")

        group.append("image_name", cps.ImageNameProvider(
                "Name the output name", default_name, doc="""\
Use this setting to name one of the images produced by the
module for a particular stain. The image can be used in
subsequent modules in the pipeline.
"""))

        choices = list(sorted(STAIN_DICTIONARY.keys())) + [CHOICE_CUSTOM]

        group.append("stain_choice", cps.Choice(
                "Stain", choices=choices, doc="""\
Use this setting to choose the absorbance values for a particular stain.

The stains are:

+-----------------------------------+--------------------------------------------------+
| Stain                             |Specific to                                       |
+===================================+==================================================+
| AEC (3-Amino-9-ethylcarbazole)    |Peroxidase                                        |
+-----------------------------------+--------------------------------------------------+
| Alican blue                       |Mucopolysaccharides                               |
+-----------------------------------+--------------------------------------------------+
| Aniline blue                      |Pollen tubes                                      |
+-----------------------------------+--------------------------------------------------+
| Azocarmine                        |Plasma                                            |
+-----------------------------------+--------------------------------------------------+
| DAB                               |Peroxisomes, mitochondria                         |
+-----------------------------------+--------------------------------------------------+
| Eosin                             |Elastic, collagen and reticular fibers            |
+-----------------------------------+--------------------------------------------------+
| Fast red                          |Nuclei                                            |
+-----------------------------------+--------------------------------------------------+
| Fast blue                         |Myelin fibers                                     |
+-----------------------------------+--------------------------------------------------+
| Feulgen                           |DNA                                               |
+-----------------------------------+--------------------------------------------------+
| Hematoxylin                       |Nucleic acids, endoplasmic reticulum              |
+-----------------------------------+--------------------------------------------------+
| Hematoxylin and PAS               |Nucleus (stained with both Hematoxylin and PAS)   |
+-----------------------------------+--------------------------------------------------+
| Methyl blue                       |Collagen                                          |
+-----------------------------------+--------------------------------------------------+
| Methyl green                      |Chromatin                                         |
+-----------------------------------+--------------------------------------------------+
| Methylene blue                    |Nuclei                                            |
+-----------------------------------+--------------------------------------------------+
| Orange G                          |Erythrocytes, pancreas, pituitary                 |
+-----------------------------------+--------------------------------------------------+
| PAS                               |Glycogen, carbohydrates                           |
+-----------------------------------+--------------------------------------------------+
| Ponceau Fuchsin                   |Red counterstain for Masson’s trichrome           |
+-----------------------------------+--------------------------------------------------+

(Information taken from `here`_,
`here <http://en.wikipedia.org/wiki/Staining>`__, and
`here <http://stainsfile.info>`__.)
You can choose *%(CHOICE_CUSTOM)s* and enter your custom values for the
absorbance (or use the estimator to determine values from a single-stain
image).

.. _here: http://en.wikipedia.org/wiki/Histology#Staining

""" % globals()))

        group.append("red_absorbance", cps.Float(
                "Red absorbance", 0.5, 0, 1, doc="""\
*(Used only if "%(CHOICE_CUSTOM)s" is selected for the stain)*

The red absorbance setting estimates the dye’s absorbance of light in
the red channel.You should enter a value between 0 and 1 where 0 is no
absorbance and 1 is complete absorbance. You can use the estimator to
calculate this value automatically.
""" % globals()))

        group.append("green_absorbance", cps.Float(
                "Green absorbance", 0.5, 0, 1, doc="""\
*(Used only if "%(CHOICE_CUSTOM)s" is selected for the stain)*

The green absorbance setting estimates the dye’s absorbance of light in
the green channel. You should enter a value between 0 and 1 where 0 is
no absorbance and 1 is complete absorbance. You can use the estimator to
calculate this value automatically.
""" % globals()))

        group.append("blue_absorbance", cps.Float(
                "Blue absorbance", 0.5, 0, 1, doc="""\
*(Used only if "%(CHOICE_CUSTOM)s" is selected for the stain)*

The blue absorbance setting estimates the dye’s absorbance of light in
the blue channel. You should enter a value between 0 and 1 where 0 is no
absorbance and 1 is complete absorbance. You can use the estimator to
calculate this value automatically.
""" % globals()))

        def on_estimate():
            result = self.estimate_absorbance()
            if result is not None:
                (group.red_absorbance.value,
                 group.green_absorbance.value,
                 group.blue_absorbance.value) = result

        group.append("estimator_button", cps.DoSomething(
                "Estimate absorbance from image",
                "Estimate", on_estimate, doc="""\
Press this button to load an image of a sample stained only with the dye
of interest. **UnmixColors** will estimate appropriate red, green and
blue absorbance values from the image.
            """))

        if can_remove:
            group.append("remover", cps.RemoveSettingButton(
                    "", "Remove this image", self.outputs, group))
        self.outputs.append(group)
    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",
            cps.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",
            cps.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.""",
        )
    def create_settings(self):
        self.image_name = cps.ImageNameSubscriber("Select the input image",
                                                  cps.NONE)

        self.output_name = cps.ImageNameProvider("Name the output image",
                                                 "FlippedOrigBlue")

        self.flip_choice = cps.Choice("Select method to flip image",
                                      FLIP_ALL,
                                      doc="""
            Select how the image is to be flipped.""")

        self.rotate_choice = cps.Choice("Select method to rotate image",
                                        ROTATE_ALL,
                                        doc='''
            <ul>
            <li><i>%(ROTATE_NONE)s:</i> Leave the image unrotated. This should be used
            if you want to flip the image only.</li>
            <li><i>%(ROTATE_ANGLE)s:</i> Provide the numerical angle by which the
            image should be rotated.</li>
            <li><i>%(ROTATE_COORDINATES)s:</i> Provide the X,Y pixel locations of
            two points in the image that should be aligned horizontally or
            vertically.</li>
            <li><i>%(ROTATE_MOUSE)s:</i> CellProfiler will pause so you can select the
            rotation interactively. When prompted during the analysis run, grab the image by
            clicking the left mouse button, rotate the image by
            dragging with the mouse, then release the mouse button. Press the <i>Done</i> button on the image
            after rotating the image appropriately.</li>
            </ul>''' % globals())

        self.wants_crop = cps.Binary("Crop away the rotated edges?",
                                     True,
                                     doc='''
            <i>(Used only when rotating images)</i> <br>
            When an image is rotated, there will be black space at the
            corners/edges; select <i>%(YES)s</i> to crop away the incomplete rows
            and columns of the image, or select <i>%(NO)s</i> to leave it as-is.
            <p>This cropping will produce an image that
            is not exactly the same size as the original, which may affect
            downstream modules.</p>''' % globals())

        self.how_often = cps.Choice("Calculate rotation",
                                    IO_ALL,
                                    doc='''
            <i>(Used only when using "%(ROTATE_MOUSE)s" to rotate images)</i> <br>
            Select the cycle(s) at which the calculation is requested and calculated.
            <ul>
            <li><i>%(IO_INDIVIDUALLY)s:</i> Determine the amount of rotation for each image
            individually, e.g., for each cycle.</li>
            <li><i>%(IO_ONCE)s:</i> Define the rotation only once (on the first image), then
            then apply it to all images.</li>
            </ul>''' % globals())

        self.first_pixel = cps.Coordinates(
            "Enter coordinates of the top or left pixel", (0, 0))

        self.second_pixel = cps.Coordinates(
            "Enter the coordinates of the bottom or right pixel", (0, 100))

        self.horiz_or_vert = cps.Choice(
            "Select how the specified points should be aligned",
            C_ALL,
            doc="""
            <i>(Used only when using "%(ROTATE_COORDINATES)s" to rotate images)</i><br>
            Specify whether you would like the coordinate points that
            you entered to be horizontally or
            vertically aligned after the rotation is complete.""" % globals())

        self.angle = cps.Float("Enter angle of rotation",
                               0,
                               doc="""
            <i>(Used only when using "%(ROTATE_ANGLE)s" to rotate images)</i> <br>
            Enter the angle you would like to rotate the image.
            This setting is in degrees, with positive angles corresponding
            to counterclockwise and negative as clockwise.""" % globals())
Beispiel #26
0
    def create_settings(self):
        """Create the settings for the module

        Create the settings for the module during initialization.
        """
        self.image_name = cps.ImageNameSubscriber("Select the input image",
                                                  cps.NONE,
                                                  doc="""\
The name of a binary image from a previous module. **IdentifyDeadWorms**
will use this image to establish the foreground and background for the
fitting operation. You can use **ApplyThreshold** to threshold a
grayscale image and create the binary mask. You can also use a module
such as **IdentifyPrimaryObjects** to label each worm and then use
**ConvertObjectsToImage** to make the result a mask.
""")

        self.object_name = cps.ObjectNameProvider(
            "Name the dead worm objects to be identified",
            "DeadWorms",
            doc="""\
This is the name for the dead worm objects. You can refer
to this name in subsequent modules such as
**IdentifySecondaryObjects**""")

        self.worm_width = cps.Integer("Worm width",
                                      10,
                                      minval=1,
                                      doc="""\
This is the width (the short axis), measured in pixels,
of the diamond used as a template when
matching against the worm. It should be less than the width
of a worm.""")

        self.worm_length = cps.Integer("Worm length",
                                       100,
                                       minval=1,
                                       doc="""\
This is the length (the long axis), measured in pixels,
of the diamond used as a template when matching against the
worm. It should be less than the length of a worm""")

        self.angle_count = cps.Integer("Number of angles",
                                       32,
                                       minval=1,
                                       doc="""\
This is the number of different angles at which the template will be
tried. For instance, if there are 12 angles, the template will be
rotated by 0°, 15°, 30°, 45° … 165°. The shape is bilaterally symmetric;
that is, you will get the same shape after rotating it by 180°.
""")

        self.wants_automatic_distance = cps.Binary(
            "Automatically calculate distance parameters?",
            True,
            doc="""\
This setting determines whether or not **IdentifyDeadWorms**
automatically calculates the parameters used to determine whether two
found-worm centers belong to the same worm.

Select "*%(YES)s*" to have **IdentifyDeadWorms** automatically calculate
the distance from the worm length and width. Select "*%(NO)s*" to set the
distances manually.
""" % globals())

        self.space_distance = cps.Float("Spatial distance",
                                        5,
                                        minval=1,
                                        doc="""\
*(Used only if not automatically calculating distance parameters)*

Enter the distance for calculating the worm centers, in units of pixels.
The worm centers must be at least many pixels apart for the centers to
be considered two separate worms.
""")

        self.angular_distance = cps.Float("Angular distance",
                                          30,
                                          minval=1,
                                          doc="""\
*(Used only if automatically calculating distance parameters)*

**IdentifyDeadWorms** calculates the worm centers at different angles.
Two worm centers are considered to represent different worms if their
angular distance is larger than this number. The number is measured in
degrees.
""")
Beispiel #27
0
    def create_settings(self):
        '''Create the settings that control this module'''
        self.object_name = cps.ObjectNameSubscriber(
            "Select objects to be masked",
            cps.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",
            cps.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",
            cps.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)s*" for the mask to be composed of the foreground (white
   portion) of the masking image or the area within the masking objects.
-  Select "*%(YES)s*" 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",
            .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 #28
0
 def create_settings(self):
     #
     # The ImageNameSubscriber "subscribes" to all ImageNameProviders in
     # prior modules. Modules before yours will put images into CellProfiler.
     # The ImageSubscriber gives your user a list of these images
     # which can then be used as inputs in your module.
     #
     self.input_image_name = cps.ImageNameSubscriber(
         # The text to the left of the edit box
         "Input image name:",
         # HTML help that gets displayed when the user presses the
         # help button to the right of the edit box
         doc="""This is the image that the module operates on. You can
         choose any image that is made available by a prior module.
         <br>
         <b>ImageTemplate</b> will do something to this image.
         """)
     #
     # The ImageNameProvider makes the image available to subsequent
     # modules.
     #
     self.output_image_name = cps.ImageNameProvider(
         "Output image name:",
         # The second parameter holds a suggested name for the image.
         "OutputImage",
         doc="""This is the image resulting from the operation.""")
     #
     # Here's a choice box - the user gets a drop-down list of what
     # can be done.
     #
     self.gradient_choice = cps.Choice(
         "Gradient choice:",
         # The choice takes a list of possibilities. The first one
         # is the default - the one the user will typically choose.
         [GRADIENT_MAGNITUDE, GRADIENT_DIRECTION_X, GRADIENT_DIRECTION_Y],
         #
         # Here, in the documentation, we do a little trick so that
         # we use the actual text that's displayed in the documentation.
         #
         # %(GRADIENT_MAGNITUDE)s will get changed into "Gradient magnitude"
         # etc. Python will look in globals() for the "GRADIENT_" names
         # and paste them in where it sees %(GRADIENT_...)s
         #
         # The <ul> and <li> tags make a neat bullet-point list in the docs
         #
         doc="""Choose what to calculate:
         <ul>
         <li><i>%(GRADIENT_MAGNITUDE)s</i> to calculate the
         magnitude of the gradient at each pixel.</li>
         <li><i>%(GRADIENT_DIRECTION_X)s</i> to get the relative contribution
         of the gradient in the X direction (.5 = no contribution,
         0 to .5 = decreasing with increasing X, .5 to 1 = increasing
         with increasing X).</li>
         <li><i>%(GRADIENT_DIRECTION_Y)s</i> to get the relative
         contribution of the gradient in the Y direction.</li></ul>
         """ % globals())
     #
     # A binary setting displays a checkbox.
     #
     self.automatic_smoothing = cps.Binary(
         "Automatically choose the smoothing scale?",
         # The default value is to choose automatically
         True,
         doc="""The module will automatically choose a
         smoothing scale for you if you leave this checked.""")
     #
     # We do a little smoothing which supplies a scale to the gradient.
     #
     # We use a float setting so that the user can give us a number
     # for the scale. The control will turn red if the user types in
     # an invalid scale.
     #
     self.scale = cps.Float(
         "Scale:",
         # The default value is 1 - a short-range scale
         1,
         # We don't let the user type in really small values
         minval=.1,
         # or large values
         maxval=100,
         doc="""This is a scaling factor that supplies the sigma for
         a gaussian that's used to smooth the image. The gradient is
         calculated on the smoothed image, so large scales will give
         you long-range gradients and small scales will give you
         short-range gradients""")
    def create_settings(self):
        self.image_name = cps.ImageNameSubscriber(
                'Select the input image', cps.NONE, doc="Select the images to be made into a projection.")

        self.projection_type = cps.Choice(
                'Type of projection',
                P_ALL, doc="""\
The final projection image can be created by the following methods:

-  *%(P_AVERAGE)s:* Use the average pixel intensity at each pixel
   position.
-  *%(P_MAXIMUM)s:* Use the maximum pixel value at each pixel position.
-  *%(P_MINIMUM)s:* Use the minimum pixel value at each pixel position.
-  *%(P_SUM)s:* Add the pixel values at each pixel position.
-  *%(P_VARIANCE)s:* Compute the variance at each pixel position.
   The variance method is described in Selinummi et al (2009). The
   method is designed to operate on a Z-stack of brightfield images
   taken at different focus planes. Background pixels will have
   relatively uniform illumination whereas cytoplasm pixels will have
   higher variance across the Z-stack.
-  *%(P_POWER)s:* Compute the power at a given frequency at each pixel
   position.
   The power method is experimental. The method computes the power at a
   given frequency through the Z-stack. It might be used with a phase
   contrast image where the signal at a given pixel will vary
   sinusoidally with depth. The frequency is measured in Z-stack steps
   and pixels that vary with the given frequency will have a higher
   score than other pixels with similar variance, but different
   frequencies.
-  *%(P_BRIGHTFIELD)s:* Perform the brightfield projection at each
   pixel position.
   Artifacts such as dust appear as black spots that are most strongly
   resolved at their focal plane with gradually increasing signals
   below. The brightfield method scores these as zero since the dark
   appears in the early Z-stacks. These pixels have a high score for the
   variance method but have a reduced score when using the brightfield
   method.
-  *%(P_MASK)s:* Compute a binary image of the pixels that are masked
   in any of the input images.
   The mask method operates on any masks that might have been applied to
   the images in a group. The output is a binary image where the “1”
   pixels are those that are not masked in all of the images and the “0”
   pixels are those that are masked in one or more of the images.
   You can use the output of the mask method to mask or crop all of the
   images in a group similarly. Use the mask method to combine all of
   the masks in a group, save the image and then use **Crop**,
   **MaskImage** or **MaskObjects** in another pipeline to mask all
   images or objects in the group similarly.

References
^^^^^^^^^^

-  Selinummi J, Ruusuvuori P, Podolsky I, Ozinsky A, Gold E, et al.
   (2009) “Bright field microscopy as an alternative to whole cell
   fluorescence in automated analysis of macrophage images”, *PLoS ONE*
   4(10): e7497 `(link)`_.

.. _(link): https://doi.org/10.1371/journal.pone.0007497
"""% globals())

        self.projection_image_name = cps.ImageNameProvider(
                'Name the output image',
                'ProjectionBlue', doc="Enter the name for the projected image.",
                provided_attributes={cps.AGGREGATE_IMAGE_ATTRIBUTE: True,
                                     cps.AVAILABLE_ON_LAST_ATTRIBUTE: True})
        self.frequency = cps.Float(
                "Frequency", 6.0, minval=1.0, doc="""\
*(Used only if "%(P_POWER)s" is selected as the projection method)*

This setting controls the frequency at which the power is measured. A
frequency of 2 will respond most strongly to pixels that alternate
between dark and light in successive z-stack slices. A frequency of N
will respond most strongly to pixels whose brightness cycles every N
slices.""" % globals())
    def add_image(self, can_remove=True):
        group = GranularitySettingsGroup()
        group.can_remove = can_remove
        if can_remove:
            group.append("divider", cps.Divider(line=True))

        group.append(
            "image_name",
            cps.ImageNameSubscriber(
                "Select an image to measure",
                cps.NONE,
                doc=
                "Select the grayscale images whose granularity you want to measure."
            ))

        group.append(
            "subsample_size",
            cps.Float("Subsampling factor for granularity measurements",
                      0.25,
                      minval=np.finfo(float).eps,
                      maxval=1,
                      doc="""\
If the textures of interest are larger than a few pixels, we recommend
you subsample the image with a factor <1 to speed up the processing.
Down sampling the image will let you detect larger structures with a
smaller sized structure element. A factor >1 might increase the accuracy
but also require more processing time. Images are typically of higher
resolution than is required for granularity measurements, so the default
value is 0.25. For low-resolution images, increase the subsampling
fraction; for high-resolution images, decrease the subsampling fraction.
Subsampling by 1/4 reduces computation time by (1/4) :sup:`3` because the
size of the image is (1/4) :sup:`2` of original and the range of granular
spectrum can be 1/4 of original. Moreover, the results are sometimes
actually a little better with subsampling, which is probably because
with subsampling the individual granular spectrum components can be used
as features, whereas without subsampling a feature should be a sum of
several adjacent granular spectrum components. The recommendation on the
numerical value cannot be determined in advance; an analysis as in this
reference may be required before running the whole set. See this `pdf`_,
slides 27-31, 49-50.

.. _pdf: http://www.ravkin.net/presentations/Statistical%20properties%20of%20algorithms%20for%20analysis%20of%20cell%20images.pdf"""
                      ))

        group.append(
            "image_sample_size",
            cps.Float("Subsampling factor for background reduction",
                      .25,
                      minval=np.finfo(float).eps,
                      maxval=1,
                      doc="""\
It is important to remove low frequency image background variations as
they will affect the final granularity measurement. Any method can be
used as a pre-processing step prior to this module; we have chosen to
simply subtract a highly open image. To do it quickly, we subsample the
image first. The subsampling factor for background reduction is usually
[0.125 – 0.25]. This is highly empirical, but a small factor should be
used if the structures of interest are large. The significance of
background removal in the context of granulometry is that image volume
at certain granular size is normalized by total image volume, which
depends on how the background was removed."""))

        group.append(
            "element_size",
            cps.Integer("Radius of structuring element",
                        10,
                        minval=1,
                        doc="""\
This radius should correspond to the radius of the textures of interest
*after* subsampling; i.e., if textures in the original image scale have
a radius of 40 pixels, and a subsampling factor of 0.25 is used, the
structuring element size should be 10 or slightly smaller, and the range
of the spectrum defined below will cover more sizes."""))

        group.append(
            "granular_spectrum_length",
            cps.Integer("Range of the granular spectrum",
                        16,
                        minval=1,
                        doc="""\
You may need a trial run to see which granular
spectrum range yields informative measurements. Start by using a wide spectrum and
narrow it down to the informative range to save time."""))

        group.append(
            "add_objects_button",
            cps.DoSomething("",
                            "Add another object",
                            group.add_objects,
                            doc="""\
Press this button to add granularity measurements for objects, such as
those identified by a prior **IdentifyPrimaryObjects** module.
**MeasureGranularity** will measure the image’s granularity within each
object at the requested scales."""))

        group.objects = []

        group.object_count = cps.HiddenCount(group.objects, "Object count")

        if can_remove:
            group.append(
                "remover",
                cps.RemoveSettingButton("", "Remove this image", self.images,
                                        group))
        self.images.append(group)
        return group