Beispiel #1
0
    def create_settings(self):
        self.outputs = []
        self.stain_count = cps.HiddenCount(self.outputs, "Stain count")

        self.input_image_name = cps.ImageNameSubscriber(
            "Select the input color image",
            "None",
            doc="""\
Choose the name of the histologically stained color image
loaded or created by some prior module.""",
        )

        self.add_image(False)

        self.add_image_button = cps.DoSomething(
            "",
            "Add another stain",
            self.add_image,
            doc="""\
Press this button to add another stain to the list.

You will be able to name the image produced and to either pick
the stain from a list of pre-calibrated stains or to enter
custom values for the stain's red, green and blue absorbance.
            """,
        )
Beispiel #2
0
    def create_settings(self):
        self.image_name = cps.ImageNameSubscriber(
            "Select the input image",
            "None",
            doc="""\
Select the image that you want to perform a morphological operation on.
A grayscale image can be converted to binary using the **Threshold**
module. Objects can be converted to binary using the **ConvertToImage**
module.""",
        )

        self.output_image_name = cps.ImageNameProvider(
            "Name the output image",
            "MorphBlue",
            doc=
            """Enter the name for the output image. It will be of the same type as the input image.""",
        )

        self.add_button = cps.DoSomething(
            "",
            "Add another operation",
            self.add_function,
            doc="""\
Press this button to add an operation that will be applied to the
image resulting from the previous operation(s). The module repeats
the previous operation the number of times you select before applying
the operation added by this button.""",
        )

        self.functions = []
        self.add_function(can_remove=False)
    def add_image_measurement(self, can_remove=True):
        group = cps.SettingsGroup()
        if can_remove:
            group.append("divider", cps.Divider())

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

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

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

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

        if can_remove:
            group.append(
                "remover",
                cps.RemoveSettingButton("", "Remove this image", self.images,
                                        group),
            )
        self.images.append(group)
Beispiel #4
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",
                "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)
    def create_settings(self):
        self.image_name = cps.ImageNameSubscriber(
            "Select the input image",
            "None",
            doc="""Choose the name of the image to display in the object selection user interface.""",
        )

        self.objects_name = cps.ObjectNameProvider(
            "Name the objects to be identified",
            "Cells",
            doc="""\
What do you want to call the objects that you identify using this module? You can use this name to
refer to your objects in subsequent modules.""",
        )
Beispiel #6
0
    def add_image(self, can_remove=True):
        """Add an image + associated questions and buttons"""
        group = cps.SettingsGroup()
        if can_remove:
            group.append("divider", cps.Divider(line=True))

        group.append(
            "input_image_name",
            cps.ImageNameSubscriber(
                "Select an additional image to tile",
                "None",
                doc="""Select an additional image to tile?""",
            ),
        )
        if can_remove:
            group.append(
                "remover",
                cps.RemoveSettingButton("", "Remove above image",
                                        self.additional_images, group),
            )
        self.additional_images.append(group)
Beispiel #7
0
    def create_settings(self):
        """Create the settings that control this module"""
        self.object_name = cps.ObjectNameSubscriber(
            "Select objects to be masked",
            "None",
            doc="""\
Select the objects that will be masked (that is, excluded in whole or in
part based on the other settings in the module). You can choose from any
objects created by a previous object processing module, such as
**IdentifyPrimaryObjects**, **IdentifySecondaryObjects** or
**IdentifyTertiaryObjects**.
""",
        )

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

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

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

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

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

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

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

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

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

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

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

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

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

-  *%(R_RENUMBER)s:* The objects that remain will be renumbered using
   consecutive numbers. This is a good choice if you do not plan to use
   measurements from the original objects; your object measurements for
   the masked objects will not have gaps (where removed objects are
   missing).
-  *%(R_RETAIN)s:* The original labels for the objects will be
   retained. This allows any measurements you make from the masked
   objects to be directly aligned with measurements you might have made
   of the original, unmasked objects (or objects directly associated
   with them).
""" % globals(),
        )
Beispiel #8
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",
            "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*" to have **IdentifyDeadWorms** automatically calculate
the distance from the worm length and width. Select "*No*" 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 #9
0
    def create_settings(self):
        self.image_name = cps.ImageNameSubscriber(
            "Select the input image",
            "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"* 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"* 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"* 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 option
        self.use_hue = cps.Binary(
            "Convert hue to gray?",
            True,
            doc="""\
*(Used only when splitting HSV images)*

Select *"Yes"* 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"* 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"* 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 #10
0
    def create_settings(self):
        """Create the settings here and set the module name (initialization)

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

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

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

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

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

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

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

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

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

-  Select "*No*" to produce the mask from the foreground (white
   portion) of the masking image or the area within the masking objects.
-  Select "*Yes*" to instead produce the mask from the *background*
   (black portions) of the masking image or the area *outside* the
   masking objects.
       """
            % globals(),
        )
Beispiel #11
0
    def create_settings(self):
        self.objects_name = cps.ObjectNameSubscriber(
            "Select the input objects",
            "None",
            doc="""\
Select the objects you would like to split or merge (that is,
whose object numbers you want to reassign). You can
use any objects that were created in previous modules, such as
**IdentifyPrimaryObjects** or **IdentifySecondaryObjects**.""",
        )

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

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

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

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

You can merge objects in one of two ways:

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

   An example of a feature that satisfies the above constraints is a
   line of pixels that connects two neighboring objects and is roughly
   the same intensity as the boundary pixels of both (such as an axon
   connecting two neurons' soma).""" % globals(),
        )
    def 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",
                "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",
                0.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
    def create_settings(self):
        self.image_name = cps.ImageNameSubscriber(
            "Select the input image",
            "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={
                "aggregate_image": True,
                "available_on_last": 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 create_settings(self):
        """Create your settings by subclassing this function

        create_settings is called at the end of initialization.

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

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

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

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

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

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

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

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

This is the image that will appear when editing objects. Choose an image
supplied by a previous module.
""",
        )
    def create_settings(self):
        """Create the UI settings for the module"""
        self.seed_objects_name = cps.ObjectNameSubscriber(
            "Select the seed objects",
            "None",
            doc="""\
Select the previously identified objects that you want to use as the
seeds for measuring branches and distances. Branches and trunks are assigned
per seed object. Seed objects are typically not single points/pixels but
instead are usually objects of varying sizes.""",
        )

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

The file has the following columns:

-  *image\_number:* The image number of the associated image.
-  *v1:* The zero-based index into the vertex table of the first vertex
   in the edge.
-  *v2:* The zero-based index into the vertex table of the second vertex
   in the edge.
-  *length:* The number of pixels in the path connecting the two
   vertices, including both vertex pixels.
-  *total\_intensity:* The sum of the intensities of the pixels in the
   edge, including both vertex pixel intensities.
""",
        )
Beispiel #16
0
    def add_image(self, can_delete=True):
        """Add an image and its settings to the list of images"""
        image_name = cps.ImageNameSubscriber(
            "Select the input image", "None", doc="Select the image to be corrected."
        )

        corrected_image_name = cps.ImageNameProvider(
            "Name the output image",
            "CorrBlue",
            doc="Enter a name for the corrected image.",
        )

        illum_correct_function_image_name = cps.ImageNameSubscriber(
            "Select the illumination function",
            "None",
            doc="""\
Select the illumination correction function image that will be used to
carry out the correction. This image is usually produced by another
module or loaded as a .mat or .npy format image using the **Images** module
or a **Load** module, most commonly **LoadSingleImage**.

Note that loading .mat format images is deprecated and will be removed in
a future version of CellProfiler. You can export .mat format images as
.npy format images using **SaveImages** to ensure future compatibility.
""",
        )

        divide_or_subtract = cps.Choice(
            "Select how the illumination function is applied",
            [DOS_DIVIDE, DOS_SUBTRACT],
            doc="""\
This choice depends on how the illumination function was calculated and
on your physical model of the way illumination variation affects the
background of images relative to the objects in images; it is also
somewhat empirical.

-  *%(DOS_SUBTRACT)s:* Use this option if the background signal is
   significant relative to the real signal coming from the cells. If you
   created the illumination correction function using
   *Background*, then you will want to choose
   *%(DOS_SUBTRACT)s* here.
-  *%(DOS_DIVIDE)s:* Choose this option if the signal to background
   ratio is high (the cells are stained very strongly). If you created
   the illumination correction function using *Regular*, then
   you will want to choose *%(DOS_DIVIDE)s* here.
"""
            % globals(),
        )

        image_settings = cps.SettingsGroup()
        image_settings.append("image_name", image_name)
        image_settings.append("corrected_image_name", corrected_image_name)
        image_settings.append(
            "illum_correct_function_image_name", illum_correct_function_image_name
        )
        image_settings.append("divide_or_subtract", divide_or_subtract)
        image_settings.append("rescale_option", RE_NONE)

        if can_delete:
            image_settings.append(
                "remover",
                cps.RemoveSettingButton(
                    "", "Remove this image", self.images, image_settings
                ),
            )
        image_settings.append("divider", cps.Divider())
        self.images.append(image_settings)
Beispiel #17
0
    def create_settings(self):
        self.image_name = cps.ImageNameSubscriber(
            "Select the input image",
            "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* to automatically calculate the threshold using a
three-category Otsu algorithm performed on the Sobel transform of the
image.

Select *No* 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* to automatically calculate the Gaussian's sigma.

Select *No* 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* to automatically calculate the low / soft threshold
cutoff for the %(M_CANNY)s method.

Select *No* 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 create_settings(self):
        # Input settings
        self.input_color_choice = cps.Choice(
            "Input image type",
            CC_ALL,
            doc=
            "Specify whether you are combining several grayscale images or loading a single color image.",
        )

        self.wants_red_input = cps.Binary(
            "Use a red image?",
            True,
            doc="""\
*(Used only if input image type is "{CC_GRAYSCALE}")*

Select "*Yes*" to specify an image to use for the red channel.
""".format(**{"CC_GRAYSCALE": CC_GRAYSCALE}),
        )

        self.red_input_image = cps.ImageNameSubscriber(
            "Select the red image",
            "None",
            doc="""\
*(Used only if input image type is "{CC_GRAYSCALE}" and a red image is used)*

Provide an image for the red channel.
""".format(**{"CC_GRAYSCALE": CC_GRAYSCALE}),
        )

        self.wants_green_input = cps.Binary(
            "Use a green image?",
            True,
            doc="""\
*(Used only if input image type is "{CC_GRAYSCALE}")*

Select "*Yes*" to specify an image to use for the green channel.
""".format(**{"CC_GRAYSCALE": CC_GRAYSCALE}),
        )

        self.green_input_image = cps.ImageNameSubscriber(
            "Select the green image",
            "None",
            doc="""\
*(Used only if input image type is "{CC_GRAYSCALE}" and a green image is used)*

Provide an image for the green channel.
""".format(**{"CC_GRAYSCALE": CC_GRAYSCALE}),
        )

        self.wants_blue_input = cps.Binary(
            "Use a blue image?",
            True,
            doc="""\
*(Used only if input image type is "{CC_GRAYSCALE}")*

Select "*Yes*" to specify an image to use for the blue channel.
""".format(**{"CC_GRAYSCALE": CC_GRAYSCALE}),
        )

        self.blue_input_image = cps.ImageNameSubscriber(
            "Select the blue image",
            "None",
            doc="""\
*(Used only if input image type is "{CC_GRAYSCALE}" and a blue image is used)*

Provide an image for the blue channel.
""".format(**{"CC_GRAYSCALE": CC_GRAYSCALE}),
        )

        self.color_input_image = cps.ImageNameSubscriber(
            "Select the color image",
            "None",
            doc="""
*(Used only if input image type is "{CC_COLOR}")*

Select the color image to use.
""".format(**{"CC_COLOR": CC_COLOR}),
        )

        # Output settings
        self.output_color_choice = cps.Choice(
            "Output image type",
            CC_ALL,
            doc=
            "Specify whether you want to produce several grayscale images or one color image.",
        )

        self.wants_red_output = cps.Binary(
            'Select "*Yes*" to produce a red image.',
            True,
            doc="""\
*(Used only if output image type is "{CC_GRAYSCALE}")*

Select "*Yes*" to produce a grayscale image corresponding to the inverted red channel.
""".format(**{"CC_GRAYSCALE": CC_GRAYSCALE}),
        )

        self.red_output_image = cps.ImageNameProvider(
            "Name the red image",
            "InvertedRed",
            doc="""\
*(Used only if output image type is "{CC_GRAYSCALE}" and a red image is output)*

Provide a name for the inverted red channel image.
""".format(**{"CC_GRAYSCALE": CC_GRAYSCALE}),
        )

        self.wants_green_output = cps.Binary(
            'Select "*Yes*" to produce a green image.',
            True,
            doc="""\
*(Used only if output image type is "{CC_GRAYSCALE}")*

Select "*Yes*" to produce a grayscale image corresponding to the inverted green channel.
""".format(**{"CC_GRAYSCALE": CC_GRAYSCALE}),
        )

        self.green_output_image = cps.ImageNameProvider(
            "Name the green image",
            "InvertedGreen",
            doc="""\
*(Used only if output image type is "{CC_GRAYSCALE}" and a green image is output)*

Provide a name for the inverted green channel image.
""".format(**{"CC_GRAYSCALE": CC_GRAYSCALE}),
        )

        self.wants_blue_output = cps.Binary(
            'Select "*Yes*" to produce a blue image.',
            True,
            doc="""\
*(Used only if output image type is "{CC_GRAYSCALE}")*

Select "*Yes*" to produce a grayscale image corresponding to the inverted blue channel.
""".format(**{"CC_GRAYSCALE": CC_GRAYSCALE}),
        )

        self.blue_output_image = cps.ImageNameProvider(
            "Name the blue image",
            "InvertedBlue",
            doc="""\
*(Used only if output image type is "{CC_GRAYSCALE}" and a blue image is output)*

Provide a name for the inverted blue channel image.
""".format(**{"CC_GRAYSCALE": CC_GRAYSCALE}),
        )

        self.color_output_image = cps.ImageNameProvider(
            "Name the inverted color image",
            "InvertedColor",
            doc="""\
*(Used only when producing a color output image)*

Enter a name for the inverted color image.
""",
        )
Beispiel #19
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 the order listed,
   from top to bottom. An arbitrary number of channels is allowed.

   For example, you could create a 5-channel image by providing
   5 grayscale images. The first grayscale image you provide will fill
   the first channel, the second grayscale image you provide will fill
   the second channel, and so on.
-  *%(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 #20
0
    def create_settings(self):
        self.image_name = cps.ImageNameSubscriber(
            "Select the input image",
            "None",
            doc="Choose the image you want to flip or rotate.",
        )

        self.output_name = cps.ImageNameProvider(
            "Name the output image",
            "FlippedOrigBlue",
            doc="Provide a name for the transformed image.",
        )

        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="""\
-  *%(ROTATE_NONE)s:* Leave the image unrotated. This should be used if
   you want to flip the image only.
-  *%(ROTATE_ANGLE)s:* Provide the numerical angle by which the image
   should be rotated.
-  *%(ROTATE_COORDINATES)s:* Provide the X,Y pixel locations of two
   points in the image that should be aligned horizontally or
   vertically.
-  *%(ROTATE_MOUSE)s:* 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
   *Done* button on the image after rotating the image appropriately.
""" % globals(),
        )

        self.wants_crop = cps.Binary(
            "Crop away the rotated edges?",
            True,
            doc="""\
*(Used only when rotating images)*

When an image is rotated, there will be black space at the
corners/edges; select *Yes* to crop away the incomplete rows and
columns of the image, or select *No* to leave it as-is.

This cropping will produce an image that is not exactly the same size as
the original, which may affect downstream modules.
""" % globals(),
        )

        self.how_often = cps.Choice(
            "Calculate rotation",
            IO_ALL,
            doc="""\
*(Used only when using “%(ROTATE_MOUSE)s” to rotate images)*

Select the cycle(s) at which the calculation is requested and
calculated.
-  *%(IO_INDIVIDUALLY)s:* Determine the amount of rotation for each image individually, e.g., for each cycle.
-  *%(IO_ONCE)s:* Define the rotation only once (on the first image), then apply it to all images.
""" % globals(),
        )

        self.first_pixel = cps.Coordinates(
            "Enter coordinates of the top or left pixel",
            (0, 0),
            doc="""\
*(Used only when using {ROTATE_COORDINATES} to rotate images)*

After rotation, if the specified points are aligned horizontally, this point on the image will be positioned to the
left of the other point. If the specified points are aligned vertically, this point of the image will be positioned
above the other point.
""".format(**{"ROTATE_COORDINATES": ROTATE_COORDINATES}),
        )

        self.second_pixel = cps.Coordinates(
            "Enter the coordinates of the bottom or right pixel",
            (0, 100),
            doc="""\
*(Used only when using {ROTATE_COORDINATES} to rotate images)*

After rotation, if the specified points are aligned horizontally, this point on the image will be positioned to the
right of the other point. If the specified points are aligned vertically, this point of the image will be positioned
below the other point.
""".format(**{"ROTATE_COORDINATES": ROTATE_COORDINATES}),
        )

        self.horiz_or_vert = cps.Choice(
            "Select how the specified points should be aligned",
            C_ALL,
            doc="""\
*(Used only when using “%(ROTATE_COORDINATES)s” to rotate images)*

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="""\
*(Used only when using “%(ROTATE_ANGLE)s” to rotate images)*

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 #21
0
    def create_settings(self):
        """Create your settings by subclassing this function

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

Note that the pipeline will stop in all cases if gridding fails on the
first image.
""" % globals(),
        )
Beispiel #22
0
    def create_settings(self):
        self.input_image = cps.ImageNameSubscriber(
            "Select an input image",
            "None",
            doc=
            """Select the image to be tiled. Additional images within the cycle can be
added later by choosing the "*%(T_ACROSS_CYCLES)s*" option below.
""" % globals(),
        )

        self.output_image = cps.ImageNameProvider(
            "Name the output image",
            "TiledImage",
            doc="""Enter a name for the final tiled image.""",
        )

        self.additional_images = []

        self.add_button = cps.DoSomething(
            "",
            "Add another image",
            self.add_image,
            doc="""Add images from other channels to perform similar tiling""",
        )

        self.tile_method = cps.Choice(
            "Tile assembly method",
            T_ALL,
            doc="""\
This setting controls the method by which the final tiled image is
assembled:

-  *%(T_WITHIN_CYCLES)s:* If you have loaded more than one image for
   each cycle using modules upstream in the pipeline, the images can be
   tiled. For example, you may tile three different channels (OrigRed,
   OrigBlue, and OrigGreen), and a new tiled image will be created for
   every image cycle.
-  *%(T_ACROSS_CYCLES)s:* If you want to tile images from multiple
   cycles together, select this option. For example, you may tile all
   the images of the same type (e.g., OrigBlue) across all fields of
   view in your experiment, which will result in one final tiled image
   when processing is complete.
""" % globals(),
        )

        self.rows = cps.Integer(
            "Final number of rows",
            8,
            doc="""\
Specify the number of rows would you like to have in the tiled image.
For example, if you want to show your images in a 96-well format, enter
8.

*Special cases:* Let *M* be the total number of slots for images (i.e,
number of rows x number of columns) and *N* be the number of actual
images.

-  If *M* > *N*, blanks will be used for the empty slots.
-  If the *M* < *N*, an error will occur since there are not enough
   image slots. Check “Automatically calculate number of rows?” to avoid
   this error.
""",
        )

        self.columns = cps.Integer(
            "Final number of columns",
            12,
            doc="""\
Specify the number of columns you like to have in the tiled image. For
example, if you want to show your images in a 96-well format, enter 12.

*Special cases:* Let *M* be the total number of slots for images (i.e,
number of rows x number of columns) and *N* be the number of actual
images.

-  If *M* > *N*, blanks will be used for the empty slots.
-  If the *M* < *N*, an error will occur since there are not enough
   image slots. Check “Automatically calculate number of columns?” to
   avoid this error.
""",
        )

        self.place_first = cps.Choice(
            "Image corner to begin tiling",
            P_ALL,
            doc=
            """Where do you want the first image to be placed? Begin in the upper
left-hand corner for a typical multi-well plate format where the first image is A01.
""",
        )

        self.tile_style = cps.Choice(
            "Direction to begin tiling",
            S_ALL,
            doc=
            """This setting specifies the order that the images are to be arranged. For example, if
your images are named A01, A02, etc, enter "*%(S_ROW)s*".
""" % globals(),
        )

        self.meander = cps.Binary(
            "Use meander mode?",
            False,
            doc="""\
Select "*Yes*" to tile adjacent images in one direction, then the next
row/column is tiled in the opposite direction. Some microscopes capture
images in this fashion. The default mode is “comb”, or “typewriter”
mode; in this mode, when one row is completely tiled in one direction,
the next row starts near where the first row started and tiles again in
the same direction.
""" % globals(),
        )

        self.wants_automatic_rows = cps.Binary(
            "Automatically calculate number of rows?",
            False,
            doc="""\
**Tile** can automatically calculate the number of rows in the grid
based on the number of image cycles that will be processed. Select
"*Yes*" to create a grid that has the number of columns that you
entered and enough rows to display all of your images. Select "*No*"
to specify the number of rows.

If you check both automatic rows and automatic columns, **Tile** will
create a grid that has roughly the same number of rows and columns.
""" % globals(),
        )

        self.wants_automatic_columns = cps.Binary(
            "Automatically calculate number of columns?",
            False,
            doc="""\
**Tile** can automatically calculate the number of columns in the grid
from the number of image cycles that will be processed. Select "*Yes*"
to create a grid that has the number of rows that you entered and enough
columns to display all of your images. Select "*No*" to specify the
number of rows.

If you check both automatic rows and automatic columns, **Tile** will
create a grid that has roughly the same number of rows and columns.
""" % globals(),
        )