Exemple #1
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 ExportToCellH5 module'''
        self.directory = cps.DirectoryPath("Output file location",
                                           doc="""
            This setting lets you choose the folder for the output files.
            %(IO_FOLDER_CHOICE_HELP_TEXT)s
            """ % globals())

        def get_directory_fn():
            '''Get the directory for the CellH5 file'''
            return self.directory.get_absolute_path()

        def set_directory_fn(path):
            dir_choice, custom_path = self.directory.get_parts_from_path(path)
            self.directory.join_parts(dir_choice, custom_path)

        self.file_name = cps.FilenameText("Output file name",
                                          "DefaultOut.ch5",
                                          get_directory_fn=get_directory_fn,
                                          set_directory_fn=set_directory_fn,
                                          metadata=True,
                                          browse_msg="Choose CellH5 file",
                                          mode=cps.FilenameText.MODE_APPEND,
                                          exts=[("CellH5 file (*.cellh5)",
                                                 "*.ch5"),
                                                ("HDF5 file (*.h5)", "*.h5"),
                                                ("All files (*.*", "*.*")],
                                          doc="""
            This setting lets you name your CellH5 file. If you choose an
            existing file, CellProfiler will add new data to the file
            or overwrite existing locations.
            <p>%(IO_WITH_METADATA_HELP_TEXT)s %(USING_METADATA_TAGS_REF)s.
            For instance, if you have a metadata tag named
            "Plate", you can create a per-plate folder by selecting one the subfolder options
            and then specifying the subfolder name as "\g&lt;Plate&gt;". The module will
            substitute the metadata values for the current image set for any metadata tags in the
            folder name.%(USING_METADATA_HELP_REF)s.</p>

            """ % globals())
        self.overwrite_ok = cps.Binary(
            "Overwrite existing data without warning?",
            False,
            doc="""
            Select <i>%(YES)s</i> to automatically overwrite any existing data
            for a site. Select <i>%(NO)s</i> to be prompted first.

            If you are running the pipeline on a computing cluster,
            select <i>%(YES)s</i> unless you want execution to stop because you
            will not be prompted to intervene. Also note that two instances
            of CellProfiler cannot write to the same file at the same time,
            so you must ensure that separate names are used on a cluster.
            """ % globals())
        self.repack = cps.Binary("Repack after analysis",
                                 True,
                                 doc="""
            This setting determines whether CellProfiler in multiprocessing mode
            repacks the data at the end of analysis. If you select <i>%(YES)s</i>,
            CellProfiler will combine all of the satellite files into a single
            file upon completion. This option requires some extra temporary disk
            space and takes some time at the end of analysis, but results in
            a single file which may occupy less disk space. If you select
            <i>%(NO)s</i>, CellProfiler will create a master file using the
            name that you give and this file will have links to individual
            data files that contain the actual data. Using the data generated by
            this option requires that you keep the master file and the linked
            files together when copying them to a new folder.
            """ % globals())
        self.plate_metadata = cps.Choice("Plate metadata", [],
                                         value="Plate",
                                         choices_fn=self.get_metadata_choices,
                                         doc="""
            This is the metadata tag that identifies the plate name of
            the images for the current cycle. Choose <i>None</i> if
            your assay does not have metadata for plate name. If your
            assay is slide-based, you can use a metadata item that identifies
            the slide as the choice for this setting and set the well
            and site metadata items to <i>None</i>.""")
        self.well_metadata = cps.Choice(
            "Well metadata", [],
            value="Well",
            choices_fn=self.get_metadata_choices,
            doc="""This is the metadata tag that identifies the well name
            for the images in the current cycle. Choose <i>None</i> if
            your assay does not have metadata for the well.""")
        self.site_metadata = cps.Choice(
            "Site metadata", [],
            value="Site",
            choices_fn=self.get_metadata_choices,
            doc="""This is the metadata tag that identifies the site name
                for the images in the current cycle. Choose <i>None</i> if
                your assay doesn't divide wells up into sites or if this
                tag is not required for other reasons.""")
        self.divider = cps.Divider()
        self.wants_to_choose_measurements = cps.Binary("Choose measurements?",
                                                       False,
                                                       doc="""
            This setting lets you choose between exporting all measurements or
            just the ones that you choose. Select <i>%(YES)s</i> to pick the
            measurements to be exported. Select <i>%(NO)s</i> to automatically
            export all measurements available at this stage of the pipeline.
            """ % globals())
        self.measurements = cps.MeasurementMultiChoice(
            "Measurements to export",
            doc="""
            <i>(Used only if choosing measurements.)</i>
            <br>
            This setting lets you choose individual measurements to be exported.
            Check the measurements you want to export.
            """)
        self.objects_to_export = []
        self.add_objects_button = cps.DoSomething("Add objects to export",
                                                  "Add objects",
                                                  self.add_objects)
        self.images_to_export = []
        self.add_image_button = cps.DoSomething("Add an image to export",
                                                "Add image", self.add_image)
        self.objects_count = cps.HiddenCount(self.objects_to_export)
        self.images_count = cps.HiddenCount(self.images_to_export)
    def add_file(self, can_remove=True):
        """Add settings for another file to the list"""
        group = cps.SettingsGroup()
        if can_remove:
            group.append("divider", cps.Divider(line=False))

        def get_directory_fn():
            return self.directory.get_absolute_path()

        group.append(
            "file_name",
            cps.FilenameText(
                FILE_TEXT,
                cps.NONE,
                metadata=True,
                get_directory_fn=get_directory_fn,
                exts=[("TIF - Tagged Image File format (*.tif,*.tiff)",
                       "*.tif;*.tiff"),
                      ("PNG - Portable Network Graphics (*.png)", "*.png"),
                      ("JPG/JPEG file (*.jpg,*.jpeg)", "*.jpg,*.jpeg"),
                      ("BMP - Windows Bitmap (*.bmp)", "*.bmp"),
                      ("Compuserve GIF file (*.gif)", "*.gif"),
                      ("MATLAB image (*.mat)", "*.mat"),
                      ("NumPy array (*.npy)", "*.npy"),
                      ("All files (*.*)", "*.*")],
                doc="""\
The filename can be constructed in one of two ways:

-  As a fixed filename (e.g., *Exp1\_D03f00d0.tif*).
-  Using the metadata associated with an image set in **LoadImages** or
   **LoadData**. This is especially useful if you want your output given
   a unique label according to the metadata corresponding to an image
   group. The name of the metadata to substitute is included in a
   special tag format embedded in your file specification.

{USING_METADATA_TAGS_REF}

{USING_METADATA_HELP_REF}

Keep in mind that in either case, the image file extension, if any, must
be included.
""".format(
                    **{
                        "USING_METADATA_TAGS_REF": USING_METADATA_TAGS_REF,
                        "USING_METADATA_HELP_REF": USING_METADATA_HELP_REF
                    })))

        group.append(
            "image_objects_choice",
            cps.Choice('Load as images or objects?',
                       IO_ALL,
                       doc="""\
This setting determines whether you load an image as image data or as
segmentation results (i.e., objects):

-  *{IO_IMAGES}:* The input image will be given the name you specify, by
   which it will be referred downstream. This is the most common usage
   for this module.
-  *{IO_OBJECTS}:* Use this option if the input image is a label matrix
   and you want to obtain the objects that it defines. A *label matrix*
   is a grayscale or color image in which the connected regions share
   the same label, and defines how objects are represented in
   CellProfiler. The labels are integer values greater than or equal to
   0. The elements equal to 0 are the background, whereas the elements
   equal to 1 make up one object, the elements equal to 2 make up a
   second object, and so on. This option allows you to use the objects
   without needing to insert an **Identify** module to extract them
   first. See **IdentifyPrimaryObjects** for more details.
""".format(**{
                           "IO_IMAGES": IO_IMAGES,
                           "IO_OBJECTS": IO_OBJECTS
                       })))

        group.append(
            "image_name",
            cps.FileImageNameProvider("Name the image that will be loaded",
                                      "OrigBlue",
                                      doc="""\
*(Used only if an image is output)*

Enter the name of the image that will be loaded. You can use this name
to select the image in downstream modules.
"""))

        group.append(
            "rescale",
            cps.Binary("Rescale intensities?",
                       True,
                       doc="""\
*(Used only if an image is output)*

This option determines whether image metadata should be used to
rescale the image’s intensities. Some image formats save the maximum
possible intensity value along with the pixel data. For instance, a
microscope might acquire images using a 12-bit A/D converter which
outputs intensity values between zero and 4095, but stores the values
in a field that can take values up to 65535.

Select *{YES}* to rescale the image intensity so that saturated values
are rescaled to 1.0 by dividing all pixels in the image by the maximum
possible intensity value.

Select *{NO}* to ignore the image metadata and rescale the image to 0 –
1.0 by dividing by 255 or 65535, depending on the number of bits used to
store the image.
""".format(**{
                           "NO": NO,
                           "YES": YES
                       })))

        group.append(
            "objects_name",
            cps.ObjectNameProvider('Name this loaded object',
                                   "Nuclei",
                                   doc="""\
*(Used only if objects are output)*

This is the name for the objects loaded from your image
"""))

        group.append(
            "wants_outlines",
            cps.Binary("Retain outlines of loaded objects?",
                       False,
                       doc="""\
*(Used only if objects are output)*

Select *{YES}* if you want to save an image of the outlines of the
loaded objects.
""".format(**{"YES": YES})))

        group.append(
            "outlines_name",
            cps.OutlineNameProvider('Name the outlines',
                                    'NucleiOutlines',
                                    doc="""\
*(Used only if objects are output)*

Enter a name that will allow the outlines to be selected later in the
pipeline.
"""))

        if can_remove:
            group.append(
                "remove",
                cps.RemoveSettingButton("", "Remove this image",
                                        self.file_settings, group))
        self.file_settings.append(group)
    def create_settings(self):
        self.mode = cps.Choice("Classify or train?",
                               [MODE_CLASSIFY, MODE_TRAIN])
        self.advanced_or_automatic = cps.Choice(
            "Configuration mode", [AA_AUTOMATIC, AA_ADVANCED],
            doc="""Do you want to automatically choose the training parameters
            or use the defaults?""")
        self.radius = cps.Integer("Radius", DEFAULT_RADIUS, 1)
        self.n_features = cps.Integer(
            "Number of features",
            DEFAULT_N_FEATURES,
            1,
            doc="""The classifier runs a feature reduction set. This creates
            <i>Eigentextures</i> which are representative texture patches
            found throughout the image. The module scores each patch around
            a pixel according to how much it has each of these textures and
            those scores are fed into the final classifier. Raise the number of
            features if some of the textures or edges of your classes are
            misclassified. Lower the number of features to improve processing
            time or to reduce overfitting if you have a smaller amount of
            ground truth.
            """)
        self.n_estimators = cps.Integer(
            "Number of estimators",
            DEFAULT_N_ESTIMATORS,
            1,
            doc="""The classifier uses a voting scheme where it trains this
            many estimators. It purposefully does a bad job training and makes
            up for this deficit by having many poor classification judges.
            This protects against overfitting by not relying on having a single
            classifier that is very good at classifying the ground truth, but
            mistakenly uses irrelevant information to do so. Raise the number
            of estimators if the classifier is making obvious mistakes with
            unwarranted certainty. Lower the number of estimators to improve
            processing speed.""")
        self.min_samples_per_leaf = cps.Integer(
            "Minimum samples per leaf",
            DEFAULT_MIN_SAMPLES_PER_LEAF,
            1,
            doc="""This setting determines the minimum number of ground truth
            pixels that the classifier will use to split a decision tree.
            There must be at least this number of example pixels in each branch
            for the classifier to have confidence that the split is real and
            not just an artifact of an irrelevant measurement.
            
            Lower this setting if the classifier does a good job on most of the
            pixels but does not draw sharp distinctions between one class and
            another at the border between the classes (e.g. at the edges of
            cells). Raise this setting if the classifier misclassifies pixels
            that are clearly not the right class - this is overtraining.
            """)
        self.path = cps.DirectoryPath("Classifier folder")

        def get_directory_fn():
            '''Get the directory for the file name'''
            return self.path.get_absolute_path()

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

        self.filename = cps.FilenameText(
            "Classifier file",
            "Classifier.cpclassifier",
            get_directory_fn=get_directory_fn,
            set_directory_fn=set_directory_fn,
            exts=[("Pixel classifier (*.cpclassifier)", "*.cpclassifier"),
                  ("All files (*.*)", "*.*")])
        self.gt_source = cps.Choice("Ground truth source",
                                    [SRC_OBJECTS, SRC_ILASTIK],
                                    doc="""
        The ground truth data can either be taken from objects or can be
        the exported TIF "labels" output of Ilastik.
        """)
        self.labels_image = cps.ImageNameSubscriber("Ilastik labels image",
                                                    "labels.tif",
                                                    doc="""
            <i>Used only if the ground truth source is "Ilastik"</i>
            <br>
            This image should be the exported labels image from Ilastik.
            """)
        self.wants_background_class = cps.Binary(
            "Do you want a background class?", True)
        self.background_class_name = cps.Text("Background class name",
                                              "Background")
        self.object_classes = []
        self.object_class_count = cps.HiddenCount(self.object_classes,
                                                  "Object class count")
        self.add_objects(False)
        self.add_objects_button = cps.DoSomething("Add another class", "Add",
                                                  self.add_objects)
        self.label_classes = []
        self.label_class_count = cps.HiddenCount(self.label_classes,
                                                 "Label class count")
        self.add_labels(False)
        self.add_labels_button = cps.DoSomething("Add another class", "Add",
                                                 self.add_labels)

        self.images = []
        self.image_count = cps.HiddenCount(self.images, "Image count")
        self.add_image(False)
        self.add_image_button = cps.DoSomething("Add another image", "Add",
                                                self.add_image)
        self.outputs = []
        self.output_count = cps.HiddenCount(self.outputs, "Output count")
        self.add_output(False)
        self.add_output_button = cps.DoSomething("Add another output", "Add",
                                                 self.add_output)