def create_settings(self): """Create the module settings and name the module""" self.wants_default_output_directory = cps.Binary( "Store batch files in default output folder?", True, doc="""\ Select "*Yes*" to store batch files in the Default Output folder. Select "*No*" to enter the path to the folder that will be used to store these files. The Default Output folder can be set by clicking the "View output settings" button in the main CP window, or in CellProfiler Preferences. """ % globals(), ) self.custom_output_directory = cps.Text( "Output folder path", cpprefs.get_default_output_directory(), doc= "Enter the path to the output folder. (Used only if not using the default output folder)", ) # Worded this way not because I am windows-centric but because it's # easier than listing every other OS in the universe except for VMS self.remote_host_is_windows = cps.Binary( "Are the cluster computers running Windows?", False, doc="""\ Select "*Yes*" if the cluster computers are running one of the Microsoft Windows operating systems. In this case, **CreateBatchFiles** will modify all paths to use the Windows file separator (backslash \\\\ ). Select "*No*" for **CreateBatchFiles** to modify all paths to use the Unix or Macintosh file separator (slash / ).""" % globals(), ) self.batch_mode = cps.Binary("Hidden: in batch mode", False) self.distributed_mode = cps.Binary("Hidden: in distributed mode", False) self.default_image_directory = cps.Setting( "Hidden: default input folder at time of save", cpprefs.get_default_image_directory(), ) self.revision = cps.Integer("Hidden: revision number", 0) self.from_old_matlab = cps.Binary("Hidden: from old matlab", False) self.acknowledge_old_matlab = cps.DoSomething( "Could not update CP1.0 pipeline to be compatible with CP2.0. See module notes.", "OK", self.clear_old_matlab, ) self.mappings = [] self.add_mapping() self.add_mapping_button = cps.DoSomething( "", "Add another path mapping", self.add_mapping, doc="""\ Use this option if another path must be mapped because there is a difference between how the local computer sees a folder location vs. how the cluster computer sees the folder location.""", )
def create_settings(self): """Create the settings for the module at startup. The module allows for an unlimited number of measured objects, each of which has an entry in self.object_groups. """ self.image_groups = [] self.object_groups = [] self.scale_groups = [] self.image_count = cps.HiddenCount(self.image_groups) self.object_count = cps.HiddenCount(self.object_groups) self.scale_count = cps.HiddenCount(self.scale_groups) self.add_image_cb(can_remove = False) self.add_images = DoSomething("", "Add another image", self.add_image_cb) self.image_divider = cps.Divider() self.add_object_cb(can_remove = True) self.add_objects = DoSomething("", "Add another object", self.add_object_cb) self.object_divider = cps.Divider() self.add_scale_cb(can_remove = False) self.add_scales = DoSomething("", "Add another scale", self.add_scale_cb) self.scale_divider = cps.Divider() self.wants_gabor = cps.Binary( "Measure Gabor features?", True, doc = """The Gabor features measure striped texture in an object. They take a substantial time to calculate. Check this setting to measure the Gabor features. Uncheck this setting to skip the Gabor feature calculation if it is not informative for your images""") self.gabor_angles = Integer("Number of angles to compute for Gabor",4,2, doc=""" <i>(Used only if Gabor features are measured)</i><br> How many angles do you want to use for each Gabor texture measurement? The default value is 4 which detects bands in the horizontal, vertical and diagonal orientations.""") self.gabor_divider = cps.Divider() self.wants_tamura = cps.Binary( "Measure Tamura features?", True, doc = """The Tamura features are very ugly.""") self.tamura_feats=MultiChoice( "Features to compute", F_ALL, F_ALL, doc = """Tamura Features: <p><ul> <li><i>%(F_1)s</i> - bla.</li> <li><i>%(F_2)s</i> - bla.</li> <li><i>%(F_3)s</i> - bla.</li> </ul><p> Choose one or more features to compute.""" % globals())
def add_image_measurement(self, can_remove=True): group = cps.SettingsGroup() if can_remove: group.append("divider", cps.Divider()) group.append( "image_name", cps.ImageNameSubscriber( "Select the image to measure", "None", doc="""\ Choose an image name from the drop-down menu to calculate intensity for that image. Use the *Add another image* button below to add additional images to be measured. You can add the same image multiple times if you want to measure the intensity within several different objects.""", ), ) group.append( "wants_objects", cps.Binary( "Measure the intensity only from areas enclosed by objects?", False, doc="""\ Select *Yes* to measure only those pixels within an object type you choose, identified by a prior module. Note that this module will aggregate intensities across all objects in the image: to measure each object individually, see **MeasureObjectIntensity** instead. """ % globals(), ), ) group.append( "object_name", cps.ObjectNameSubscriber( "Select the input objects", "None", doc="""\ *(Used only when measuring intensity from area occupied by objects)* Select the objects that the intensity will be aggregated within. The intensity measurement will be restricted to the pixels within these objects.""", ), ) if can_remove: group.append( "remover", cps.RemoveSettingButton("", "Remove this image", self.images, group), ) self.images.append(group)
def create_settings(self): """Create the settings for the module Create the settings for the module during initialization. """ self.secondary_objects_name = cps.ObjectNameSubscriber( "Select the larger identified objects", "None", doc="""\ Select the larger identified objects. This will usually be an object previously identified by an **IdentifySecondaryObjects** module.""", ) self.primary_objects_name = cps.ObjectNameSubscriber( "Select the smaller identified objects", "None", doc="""\ Select the smaller identified objects. This will usually be an object previously identified by an **IdentifyPrimaryObjects** module.""", ) self.subregion_objects_name = cps.ObjectNameProvider( "Name the tertiary objects to be identified", "Cytoplasm", doc="""\ Enter a name for the new tertiary objects. The tertiary objects will consist of the smaller object subtracted from the larger object.""", ) self.shrink_primary = cps.Binary( "Shrink smaller object prior to subtraction?", True, doc="""\ Select *Yes* to shrink the smaller objects by 1 pixel before subtracting them from the larger objects. this approach will ensure that there is always a tertiary object produced, even if it is only 1 pixel wide. If you need alternate amounts of shrinking, use the **ExpandOrShrink** module prior to **IdentifyTertiaryObjects**. Select *No* to subtract the objects directly, which will ensure that no pixels are shared between the primary/secondary/tertiary objects and hence measurements for all three sets of objects will not use the same pixels multiple times. However, this may result in the creation of objects with no area. Measurements can still be made on such objects, but the results will be zero or not-a-number (NaN). """ % globals(), )
def create_settings(self): self.flags = [] self.flag_count = cps.HiddenCount(self.flags) self.add_flag_button = cps.DoSomething("", "Add another flag", self.add_flag) self.spacer_1 = cps.Divider() self.add_flag(can_delete=False) self.ignore_flag_on_last = cps.Binary( "Ignore flag skips on last cycle?", False, doc="""\ When set to *{YES}*, this option allows you to bypass skipping on the last cycle of an image group. This behavior is usually not desired, but may be useful when using SaveImages 'Save on last cycle' option for an image made by any other module than MakeProjection, CorrectIlluminationCalculate, and Tile. """.format(**{"YES": "Yes"}), )
def create_settings(self): # choose the tracked objects to measure TrAM on self.object_name = LabelSubscriber( "Tracked objects", "None", doc=""" Select the tracked objects for computing TrAM.""") # which measurements will go into the TrAM computation self.tram_measurements = MeasurementMultiChoiceForCategory( "TrAM measurements", category_chooser=self.object_name, doc=""" These are measurements for the selected tracked objects which will be used in the TrAM computation. At least one must be selected.""") # Treat X-Y value pairs as isotropic in the TrAM measure? self.isotropic = cps.Binary( 'Isotropic XY metric?', True, doc=""" If selected (the default) then measurements that are available as X-Y pairs (e.g. location) will be have an isotropic metric applied in TrAM. Note that the X-Y-Z extension of this feature is not currently available. """) # number of spline knots self.num_knots = Integer( "Number of spline knots", 4, minval=self.MIN_NUM_KNOTS, doc=""" The number of knots (indpendent values) used when computing smoothing splines. This should be around 1/5th the number of frames for reasonably oversampled time lapse sequences, and must be 3 or greater. It is approximately the maximum number of wiggles expected in well-tracked trajectories """) # TrAM exponent self.tram_exponent = Float( "TrAM exponent", 0.5, minval=0.01, maxval=1.0, doc=""" This number is between 0.01 and 1 (default 0.5), and specifies how strongly simultaneous sudden changes in multiple features synergize in the TrAM metric. A lower value signifies higher synergy (at the risk of missing tracking failures that are reflected in only some of the features). """)
def add_function(self, can_remove=True): group = MorphSettingsGroup() group.can_remove = can_remove if can_remove: group.append("divider", cps.Divider(line=False)) group.append( "function", cps.Choice( "Select the operation to perform", F_ALL, doc= """Choose one of the operations described in this module's help.""", ), ) group.append( "repeats_choice", cps.Choice( "Number of times to repeat operation", R_ALL, doc="""\ This setting controls the number of times that the same operation is applied successively to the image. - *%(R_ONCE)s:* Perform the operation once on the image. - *%(R_FOREVER)s:* Perform the operation on the image until successive iterations yield the same image. - *%(R_CUSTOM)s:* Perform the operation a custom number of times.""" % globals(), ), ) group.append( "custom_repeats", cps.Integer(self.CUSTOM_REPEATS_TEXT, 2, 1, doc=self.CUSTOM_REPEATS_DOC), ) group.append( "rescale_values", cps.Binary( "Rescale values from 0 to 1?", True, doc="""\ *(Used only for the "%(F_DISTANCE)s" operation).* Select "*Yes*" to rescale the transformed values to lie between 0 and 1. This is the option to use if the distance transformed image is to be used for thresholding by an **Identify** module or the like, which assumes a 0-1 scaling. Select "*No*" to leave the values in absolute pixel units. This useful in cases where the actual pixel distances are to be used downstream as input for a measurement module.""" % globals(), ), ) if can_remove: group.append( "remove", cps.RemoveSettingButton("", "Remove this operation", self.functions, group), ) self.functions.append(group)
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. """, )
def add_measurement(self, flag_settings, can_delete=True): measurement_settings = flag_settings.measurement_settings group = cps.SettingsGroup() group.append("divider1", cps.Divider(line=False)) group.append( "source_choice", cps.Choice( "Flag is based on", S_ALL, doc="""\ - *%(S_IMAGE)s:* A per-image measurement, such as intensity or granularity. - *%(S_AVERAGE_OBJECT)s:* The average of all object measurements in the image. - *%(S_ALL_OBJECTS)s:* All the object measurements in an image, without averaging. In other words, if *any* of the objects meet the criteria, the image will be flagged. - *%(S_RULES)s:* Use a text file of rules produced by CellProfiler Analyst. With this option, you will have to ensure that this pipeline produces every measurement in the rules file upstream of this module. - *%(S_CLASSIFIER)s:* Use a classifier built by CellProfiler Analyst. """ % globals(), ), ) group.append( "object_name", cps.ObjectNameSubscriber( "Select the object to be used for flagging", "None", doc="""\ *(Used only when flag is based on an object measurement)* Select the objects whose measurements you want to use for flagging. """, ), ) def object_fn(): if group.source_choice == S_IMAGE: return cpmeas.IMAGE return group.object_name.value group.append( "rules_directory", cps.DirectoryPath( "Rules file location", doc="""\ *(Used only when flagging using "%(S_RULES)s")* Select the location of the rules file that will be used for flagging images. %(IO_FOLDER_CHOICE_HELP_TEXT)s """ % globals(), ), ) def get_directory_fn(): """Get the directory for the rules file name""" return group.rules_directory.get_absolute_path() def set_directory_fn(path): dir_choice, custom_path = group.rules_directory.get_parts_from_path( path) group.rules_directory.join_parts(dir_choice, custom_path) group.append( "rules_file_name", cps.FilenameText( "Rules file name", "rules.txt", get_directory_fn=get_directory_fn, set_directory_fn=set_directory_fn, doc="""\ *(Used only when flagging using "%(S_RULES)s")* The name of the rules file, most commonly from CellProfiler Analyst's Classifier. This file should be a plain text file containing the complete set of rules. Each line of this file should be a rule naming a measurement to be made on an image, for instance: IF (Image_ImageQuality_PowerLogLogSlope_DNA < -2.5, [0.79, -0.79], [-0.94, 0.94]) The above rule will score +0.79 for the positive category and -0.94 for the negative category for images whose power log slope is less than -2.5 pixels and will score the opposite for images whose slope is larger. The filter adds positive and negative and flags the images whose positive score is higher than the negative score. """ % globals(), ), ) def get_rules_class_choices(group=group): """Get the available choices from the rules file""" try: if group.source_choice == S_CLASSIFIER: return self.get_bin_labels(group) elif group.source_choice == S_RULES: rules = self.get_rules(group) nclasses = len(rules.rules[0].weights[0]) return [str(i) for i in range(1, nclasses + 1)] else: return ["None"] rules = self.get_rules(group) nclasses = len(rules.rules[0].weights[0]) return [str(i) for i in range(1, nclasses + 1)] except: return [str(i) for i in range(1, 3)] group.append( "rules_class", cps.MultiChoice( "Class number", choices=["1", "2"], doc="""\ *(Used only when flagging using "%(S_RULES)s")* Select which classes to flag when filtering. The CellProfiler Analyst Classifier user interface lists the names of the classes in order. By default, these are the positive (class 1) and negative (class 2) classes. **FlagImage** uses the first class from CellProfiler Analyst if you choose “1”, etc. Please note the following: - The flag is set if the image falls into the selected class. - You can make multiple class selections. If you do so, the module will set the flag if the image falls into any of the selected classes. """ % globals(), ), ) group.rules_class.get_choices = get_rules_class_choices group.append( "measurement", cps.Measurement( "Which measurement?", object_fn, doc="""Choose the measurement to be used as criteria.""", ), ) group.append( "wants_minimum", cps.Binary( "Flag images based on low values?", True, doc="""\ Select *Yes* to flag images with measurements below the specified cutoff. If the measurement evaluates to Not-A-Number (NaN), then the image is not flagged. """ % globals(), ), ) group.append( "minimum_value", cps.Float("Minimum value", 0, doc="""Set a value as a lower limit."""), ) group.append( "wants_maximum", cps.Binary( "Flag images based on high values?", True, doc="""\ Select *Yes* to flag images with measurements above the specified cutoff. If the measurement evaluates to Not-A-Number (NaN), then the image is not flagged. """ % globals(), ), ) group.append( "maximum_value", cps.Float("Maximum value", 1, doc="""Set a value as an upper limit."""), ) if can_delete: group.append( "remover", cps.RemoveSettingButton("", "Remove this measurement", measurement_settings, group), ) group.append("divider2", cps.Divider(line=True)) measurement_settings.append(group)
def create_settings(self): # XXX needs to use cps.SettingsGroup class Operand(object): """Represents the collection of settings needed by each operand""" def __init__(self, index, operation): self.__index = index self.__operation = operation self.__operand_choice = cps.Choice( self.operand_choice_text(), MC_ALL, doc="""Indicate whether the operand is an image or object measurement.""", ) self.__operand_objects = cps.ObjectNameSubscriber( self.operand_objects_text(), "None", doc="""Choose the objects you want to measure for this operation.""", ) self.__operand_measurement = cps.Measurement( self.operand_measurement_text(), self.object_fn, doc="""\ Enter the category that was used to create the measurement. You will be prompted to add additional information depending on the type of measurement that is requested.""", ) self.__multiplicand = cps.Float( "Multiply the above operand by", 1, doc="""Enter the number by which you would like to multiply the above operand.""", ) self.__exponent = cps.Float( "Raise the power of above operand by", 1, doc="""Enter the power by which you would like to raise the above operand.""", ) @property def operand_choice(self): """Either MC_IMAGE for image measurements or MC_OBJECT for object""" return self.__operand_choice @property def operand_objects(self): """Get measurements from these objects""" return self.__operand_objects @property def operand_measurement(self): """The measurement providing the value of the operand""" return self.__operand_measurement @property def multiplicand(self): """Premultiply the measurement by this value""" return self.__multiplicand @property def exponent(self): """Raise the measurement to this power""" return self.__exponent @property def object(self): """The name of the object for measurement or "Image\"""" if self.operand_choice == MC_IMAGE: return cpmeas.IMAGE else: return self.operand_objects.value def object_fn(self): if self.__operand_choice == MC_IMAGE: return cpmeas.IMAGE elif self.__operand_choice == MC_OBJECT: return self.__operand_objects.value else: raise NotImplementedError( "Measurement type %s is not supported" % self.__operand_choice.value ) def operand_name(self): """A fancy name based on what operation is being performed""" if self.__index == 0: return ( "first operand" if self.__operation in (O_ADD, O_MULTIPLY) else "minuend" if self.__operation == O_SUBTRACT else "numerator" ) elif self.__index == 1: return ( "second operand" if self.__operation in (O_ADD, O_MULTIPLY) else "subtrahend" if self.__operation == O_SUBTRACT else "denominator" ) def operand_choice_text(self): return self.operand_text("Select the %s measurement type") def operand_objects_text(self): return self.operand_text("Select the %s objects") def operand_text(self, format): return format % self.operand_name() def operand_measurement_text(self): return self.operand_text("Select the %s measurement") def settings(self): """The operand settings to be saved in the output file""" return [ self.operand_choice, self.operand_objects, self.operand_measurement, self.multiplicand, self.exponent, ] def visible_settings(self): """The operand settings to be displayed""" self.operand_choice.text = self.operand_choice_text() self.operand_objects.text = self.operand_objects_text() self.operand_measurement.text = self.operand_measurement_text() result = [self.operand_choice] result += ( [self.operand_objects] if self.operand_choice == MC_OBJECT else [] ) result += [self.operand_measurement, self.multiplicand, self.exponent] return result self.output_feature_name = cps.AlphanumericText( "Name the output measurement", "Measurement", doc="""Enter a name for the measurement calculated by this module.""", ) self.operation = cps.Choice( "Operation", O_ALL, doc="""\ Choose the arithmetic operation you would like to perform. *None* is useful if you simply want to select some of the later options in the module, such as multiplying or exponentiating your image by a constant. """, ) self.operands = (Operand(0, self.operation), Operand(1, self.operation)) self.spacer_1 = cps.Divider(line=True) self.spacer_2 = cps.Divider(line=True) self.spacer_3 = cps.Divider(line=True) self.wants_log = cps.Binary( "Take log10 of result?", False, doc="""Select *Yes* if you want the log (base 10) of the result.""" % globals(), ) self.final_multiplicand = cps.Float( "Multiply the result by", 1, doc="""\ *(Used only for operations other than "None")* Enter the number by which you would like to multiply the result. """, ) self.final_exponent = cps.Float( "Raise the power of result by", 1, doc="""\ *(Used only for operations other than "None")* Enter the power by which you would like to raise the result. """, ) self.final_addend = cps.Float( "Add to the result", 0, doc="""Enter the number you would like to add to the result.""", ) self.constrain_lower_bound = cps.Binary( "Constrain the result to a lower bound?", False, doc="""Select *Yes* if you want the result to be constrained to a lower bound.""" % globals(), ) self.lower_bound = cps.Float( "Enter the lower bound", 0, doc="""Enter the lower bound of the result here.""", ) self.constrain_upper_bound = cps.Binary( "Constrain the result to an upper bound?", False, doc="""Select *Yes* if you want the result to be constrained to an upper bound.""" % globals(), ) self.upper_bound = cps.Float( "Enter the upper bound", 1, doc="""Enter the upper bound of the result here.""", ) self.rounding = cps.Choice( "How should the output value be rounded?", ROUNDING, doc="""\ Choose how the values should be rounded- not at all, to a specified number of decimal places, to the next lowest integer ("floor rounding"), or to the next highest integer ("ceiling rounding"). Note that for rounding to an arbitrary number of decimal places, Python uses "round to even" rounding, such that ties round to the nearest even number. Thus, 1.5 and 2.5 both round to to 2 at 0 decimal places, 2.45 rounds to 2.4, 2.451 rounds to 2.5, and 2.55 rounds to 2.6 at 1 decimal place. See the numpy documentation for more information. """, ) self.rounding_digit = cps.Integer( "Enter how many decimal places the value should be rounded to", 0, doc="""\ Enter how many decimal places the value should be rounded to. 0 will round to an integer (e.g. 1, 2), 1 to one decimal place (e.g. 0.1, 0.2), -1 to one value before the decimal place (e.g. 10, 20), etc. """, )
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): """Create the settings for the module Create the settings for the module during initialization. """ self.image_name = ImageSubscriber( "Select the input image", "None",doc=""" The name of a binary image from a previous module. <b>IdentifyLinearObjects</b> will use this image to establish the foreground and background for the fitting operation. You can use <b>ApplyThreshold</b> to threshold a grayscale image and create the binary mask. You can also use a module such as <b>IdentifyPrimaryObjects</b> to label each linear object and then use <b>ConvertObjectsToImage</b> to make the result a mask.""") self.object_name = LabelName( "Name the linear objects to be identified", "LinearObjects",doc=""" This is the name for the linear objects. You can refer to this name in subsequent modules such as <b>IdentifySecondaryObjects</b>""") self.object_width = Integer( "Linear object width", 10, minval = 1,doc = """ This is the width (the short axis), measured in pixels, of the diamond used as a template when matching against the linear object. It should be less than the width of a linear object.""") self.object_length = Integer( "Linear object length", 100, minval= 1,doc = """ This is the length (the long axis), measured in pixels, of the diamond used as a template when matching against the linear object. It should be less than the length of a linear object""") self.angle_count = 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 <b>IdentifyLinearObjects</b> automatically calculates the parameters used to determine whether two found-linear object centers belong to the same linear object. <p>Select <i>"Yes"</i> to have <b>IdentifyLinearObjects</b> automatically calculate the distance from the linear object length and width. Select <i>"No"</i> to set the distances manually.</p>"""%globals()) self.space_distance = Float( "Spatial distance", 5, minval = 1,doc = """ <i>(Used only if not automatically calculating distance parameters)</i><br> Enter the distance for calculating the linear object centers, in units of pixels. The linear object centers must be at least many pixels apart for the centers to be considered two separate linear objects.""") self.angular_distance = Float( "Angular distance", 30, minval = 1,doc = """ <i>(Used only if automatically calculating distance parameters)</i><br> <b>IdentifyLinearObjects</b> calculates the linear object centers at different angles. Two linear object centers are considered to represent different linear objects if their angular distance is larger than this number. The number is measured in degrees.""") self.overlap_within_angle = cps.Binary( "Combine if overlapping and within angular distance?", False,doc = """ This setting determines whether or not <b>IdentifyLinearObjects</b> merges putative linear objects that are within the angular distance specified AND in which pixels from the two linear objects overlap. <p>Select <i>"Yes"</i> to have <b>IdentifyLinearObjects</b> merge these linear objects. Select <i>"No"</i> use only the spatial distance and angular distance parameters above.</p>"""%globals())
def add_dose_value(self, can_remove=True): """Add a dose value measurement to the list can_delete - set this to False to keep from showing the "remove" button for images that must be present.""" group = cps.SettingsGroup() group.append( "measurement", cps.Measurement( "Select the image measurement describing the treatment dose", lambda: cpmeas.IMAGE, doc="""\ The V and Z’ factors, metrics of assay quality, and the EC50, indicating dose-response, are calculated by this module based on each image being specified as a particular treatment dose. Choose a measurement that gives the dose of some treatment for each of your images. See the help for the previous setting for details.""", ), ) group.append( "log_transform", cps.Binary( "Log-transform the dose values?", False, doc="""\ Select *Yes* if you have dose-response data and you want to log-transform the dose values before fitting a sigmoid curve. Select *No* if your data values indicate only positive vs. negative controls. """ % globals(), ), ) group.append( "wants_save_figure", cps.Binary( """Create dose-response plots?""", False, doc= """Select *Yes* if you want to create and save dose-response plots. You will be asked for information on how to save the plots.""" % globals(), ), ) group.append( "figure_name", cps.Text( "Figure prefix", "", doc="""\ *(Used only when creating dose-response plots)* CellProfiler will create a file name by appending the measurement name to the prefix you enter here. For instance, if you specify a prefix of “Dose\_”, when saving a file related to objects you have chosen (for example, *Cells*) and a particular measurement (for example, *AreaShape_Area*), CellProfiler will save the figure as *Dose_Cells_AreaShape_Area.m*. Leave this setting blank if you do not want a prefix. """, ), ) group.append( "pathname", cps.DirectoryPath( "Output file location", 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, ], doc="""\ *(Used only when creating dose-response plots)* This setting lets you choose the folder for the output files. %(IO_FOLDER_CHOICE_HELP_TEXT)s %(IO_WITH_METADATA_HELP_TEXT)s """ % globals(), ), ) group.append("divider", cps.Divider()) group.append( "remover", cps.RemoveSettingButton("", "Remove this dose measurement", self.dose_values, group), ) self.dose_values.append(group)
def add_single_measurement(self, can_delete=True): """Add a single measurement to the group of single measurements can_delete - True to include a "remove" button, False if you're not allowed to remove it. """ group = cps.SettingsGroup() if can_delete: group.append("divider", cps.Divider(line=True)) group.append( "object_name", cps.ObjectNameSubscriber( "Select the object to be classified", "None", doc="""\ The name of the objects to be classified. You can choose from objects created by any previous module. See **IdentifyPrimaryObjects**, **IdentifySecondaryObjects**, **IdentifyTertiaryObjects**, or **Watershed** """, ), ) def object_fn(): return group.object_name.value group.append( "measurement", cps.Measurement( "Select the measurement to classify by", object_fn, doc="""\ *(Used only if using a single measurement)* Select a measurement made by a previous module. The objects will be classified according to their values for this measurement. """, ), ) group.append( "bin_choice", cps.Choice( "Select bin spacing", [BC_EVEN, BC_CUSTOM], doc="""\ *(Used only if using a single measurement)* Select how you want to define the spacing of the bins. You have the following options: - *%(BC_EVEN)s:* Choose this if you want to specify bins of equal size, bounded by upper and lower limits. If you want two bins, choose this option and then provide a single threshold when asked. - *%(BC_CUSTOM)s:* Choose this option to create the indicated number of bins at evenly spaced intervals between the low and high threshold. You also have the option to create bins for objects that fall below or above the low and high threshold. """ % globals(), ), ) group.append( "bin_count", cps.Integer( "Number of bins", 3, minval=1, doc="""\ *(Used only if using a single measurement)* This is the number of bins that will be created between the low and high threshold""", ), ) group.append( "low_threshold", cps.Float( "Lower threshold", 0, doc="""\ *(Used only if using a single measurement and "%(BC_EVEN)s" selected)* This is the threshold that separates the lowest bin from the others. The lower threshold, upper threshold, and number of bins define the thresholds of bins between the lowest and highest. """ % globals(), ), ) group.append( "wants_low_bin", cps.Binary( "Use a bin for objects below the threshold?", False, doc="""\ *(Used only if using a single measurement)* Select "*Yes*" if you want to create a bin for objects whose values fall below the low threshold. Select "*No*" if you do not want a bin for these objects. """ % globals(), ), ) def min_upper_threshold(): return group.low_threshold.value + np.finfo(float).eps group.append( "high_threshold", cps.Float( "Upper threshold", 1, minval=cps.NumberConnector(min_upper_threshold), doc="""\ *(Used only if using a single measurement and "%(BC_EVEN)s" selected)* This is the threshold that separates the last bin from the others. Note that if you would like two bins, you should select "*%(BC_CUSTOM)s*". """ % globals(), ), ) group.append( "wants_high_bin", cps.Binary( "Use a bin for objects above the threshold?", False, doc="""\ *(Used only if using a single measurement)* Select "*Yes*" if you want to create a bin for objects whose values are above the high threshold. Select "*No*" if you do not want a bin for these objects. """ % globals(), ), ) group.append( "custom_thresholds", cps.Text( "Enter the custom thresholds separating the values between bins", "0,1", doc="""\ *(Used only if using a single measurement and "%(BC_CUSTOM)s" selected)* This setting establishes the threshold values for the bins. You should enter one threshold between each bin, separating thresholds with commas (for example, *0.3, 1.5, 2.1* for four bins). The module will create one more bin than there are thresholds. """ % globals(), ), ) group.append( "wants_custom_names", cps.Binary( "Give each bin a name?", False, doc="""\ *(Used only if using a single measurement)* Select "*Yes*" to assign custom names to bins you have specified. Select "*No*" for the module to automatically assign names based on the measurements and the bin number. """ % globals(), ), ) group.append( "bin_names", cps.Text( "Enter the bin names separated by commas", "None", doc="""\ *(Used only if "Give each bin a name?" is checked)* Enter names for each of the bins, separated by commas. An example including three bins might be *First,Second,Third*.""", ), ) group.append( "wants_images", cps.Binary( "Retain an image of the classified objects?", False, doc="""\ Select "*Yes*" to keep an image of the objects which is color-coded according to their classification, for use later in the pipeline (for example, to be saved by a **SaveImages** module). """ % globals(), ), ) group.append( "image_name", cps.ImageNameProvider( "Name the output image", "ClassifiedNuclei", doc= """Enter the name to be given to the classified object image.""", ), ) group.can_delete = can_delete def number_of_bins(): """Return the # of bins in this classification""" if group.bin_choice == BC_EVEN: value = group.bin_count.value else: value = len(group.custom_thresholds.value.split(",")) - 1 if group.wants_low_bin: value += 1 if group.wants_high_bin: value += 1 return value group.number_of_bins = number_of_bins def measurement_name(): """Get the measurement name to use inside the bin name Account for conflicts with previous measurements """ measurement_name = group.measurement.value other_same = 0 for other in self.single_measurements: if id(other) == id(group): break if other.measurement.value == measurement_name: other_same += 1 if other_same > 0: measurement_name += str(other_same) return measurement_name def bin_feature_names(): """Return the feature names for each bin""" if group.wants_custom_names: return [ name.strip() for name in group.bin_names.value.split(",") ] return [ "_".join((measurement_name(), "Bin_%d" % (i + 1))) for i in range(number_of_bins()) ] group.bin_feature_names = bin_feature_names def validate_group(): bin_name_count = len(bin_feature_names()) bin_count = number_of_bins() if bin_count < 1: bad_setting = (group.bin_count if group.bin_choice == BC_EVEN else group.custom_thresholds) raise cps.ValidationError( "You must have at least one bin in order to take measurements. " "Either add more bins or ask for bins for objects above or below threshold", bad_setting, ) if bin_name_count != number_of_bins(): raise cps.ValidationError( "The number of bin names (%d) does not match the number of bins (%d)." % (bin_name_count, bin_count), group.bin_names, ) for bin_feature_name in bin_feature_names(): cps.AlphanumericText.validate_alphanumeric_text( bin_feature_name, group.bin_names, True) if group.bin_choice == BC_CUSTOM: try: [ float(x.strip()) for x in group.custom_thresholds.value.split(",") ] except ValueError: raise cps.ValidationError( "Custom thresholds must be a comma-separated list " 'of numbers (example: "1.0, 2.3, 4.5")', group.custom_thresholds, ) group.validate_group = validate_group if can_delete: group.remove_settings_button = cps.RemoveSettingButton( "", "Remove this classification", self.single_measurements, group) self.single_measurements.append(group)
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(), )
def add_flag(self, can_delete=True): group = cps.SettingsGroup() group.append("divider1", cps.Divider(line=False)) group.append("measurement_settings", []) group.append("measurement_count", cps.HiddenCount(group.measurement_settings)) group.append( "category", cps.Text( "Name the flag's category", "Metadata", doc="""\ Name a measurement category by which to categorize the flag. The *Metadata* category is the default used in CellProfiler to store information about images (referred to as *metadata*). The flag is stored as a per-image measurement whose name is a combination of the flag’s category and the flag name that you choose, separated by underscores. For instance, if the measurement category is *Metadata* and the flag name is *QCFlag*, then the default measurement name would be *Metadata_QCFlag*. """, ), ) group.append( "feature_name", cps.Text( "Name the flag", "QCFlag", doc="""\ The flag is stored as a per-image measurement whose name is a combination of the flag’s category and the flag name that you choose, separated by underscores. For instance, if the measurement category is *Metadata* and the flag name is *QCFlag*, then the default measurement name would be *Metadata_QCFlag*. """, ), ) group.append( "combination_choice", cps.Choice( "How should measurements be linked?", [C_ANY, C_ALL], doc="""\ For combinations of measurements, you can set the criteria under which an image set is flagged: - *%(C_ANY)s:* An image set will be flagged if any of its measurements fail. This can be useful for flagging images possessing multiple QC flaws; for example, you can flag all bright images and all out of focus images with one flag. - *%(C_ALL)s:* A flag will only be assigned if all measurements fail. This can be useful for flagging images that possess only a combination of QC flaws; for example, you can flag only images that are both bright and out of focus. """ % globals(), ), ) group.append( "wants_skip", cps.Binary( "Skip image set if flagged?", False, doc="""\ Select *Yes* to skip the remainder of the pipeline for image sets that are flagged. CellProfiler will not run subsequent modules in the pipeline on the images for any image set that is flagged. Select *No* for CellProfiler to continue to process the pipeline regardless of flagging. You may want to skip processing in order to filter out unwanted images. For instance, you may want to exclude out of focus images when running **CorrectIllumination_Calculate**. You can do this with a pipeline that measures image quality and flags inappropriate images before it runs **CorrectIllumination_Calculate**. """ % globals(), ), ) group.append( "add_measurement_button", cps.DoSomething( "", "Add another measurement", self.add_measurement, group, doc="""Add another measurement as a criteria.""", ), ) self.add_measurement(group, False if not can_delete else True) if can_delete: group.append( "remover", cps.RemoveSettingButton("", "Remove this flag", self.flags, group), ) group.append("divider2", cps.Divider(line=True)) self.flags.append(group)
def create_settings(self): self.image_name = cps.subscriber.ImageSubscriber( "Select the input image", NONE, doc="""Select the image to be smoothed.""", ) self.filtered_image_name = cps.text.ImageName( "Name the output image", "FilteredImage", doc="""Enter a name for the resulting image.""", ) self.smoothing_method = cps.choice.Choice( "Select smoothing method", [ CLIP_HOT_PIXELS, FIT_POLYNOMIAL, GAUSSIAN_FILTER, MEDIAN_FILTER, MEDIAN_FILTER_SCIPY, SMOOTH_KEEPING_EDGES, CIRCULAR_AVERAGE_FILTER, SM_TO_AVERAGE, ], doc="""\ This module smooths images using one of several filters. Fitting a polynomial is fastest but does not allow a very tight fit compared to the other methods: - *%(FIT_POLYNOMIAL)s:* This method is fastest but does not allow a very tight “fit” compared to the other methods. Thus, it will usually be less accurate. The method treats the intensity of the image pixels as a polynomial function of the x and y position of each pixel. It fits the intensity to the polynomial, *A x* :sup:`2` *+ B y* :sup:`2` *+ C xy + D x + E y + F*. This will produce a smoothed image with a single peak or trough of intensity that tapers off elsewhere in the image. For many microscopy images (where the illumination of the lamp is brightest in the center of field of view), this method will produce an image with a bright central region and dimmer edges. But, in some cases the peak/trough of the polynomial may actually occur outside of the image itself. - *%(GAUSSIAN_FILTER)s:* This method convolves the image with a Gaussian whose full width at half maximum is the artifact diameter entered. Its effect is to blur and obscure features smaller than the specified diameter and spread bright or dim features larger than the specified diameter. - *%(MEDIAN_FILTER)s:* This method finds the median pixel value within the diameter you specify. It removes bright or dim features that are significantly smaller than the specified diameter. - *%(MEDIAN_FILTER_SCIPY)s:* This method finds the median pixel value within the diameter you specify. The scipy inplementation has been taken, as the centrosome one has problems with small diameter artifacts (=single pixel artefacts) Does NOT work with masked images! - *%(SMOOTH_KEEPING_EDGES)s:* This method uses a bilateral filter which limits Gaussian smoothing across an edge while applying smoothing perpendicular to an edge. The effect is to respect edges in an image while smoothing other features. *%(SMOOTH_KEEPING_EDGES)s* will filter an image with reasonable speed for artifact diameters greater than 10 and for intensity differences greater than 0.1. The algorithm will consume more memory and operate more slowly as you lower these numbers. - *%(CIRCULAR_AVERAGE_FILTER)s:* This method convolves the image with a uniform circular averaging filter whose size is the artifact diameter entered. This filter is useful for re-creating an out-of-focus blur to an image. - *%(SM_TO_AVERAGE)s:* Creates a flat, smooth image where every pixel of the image equals the average value of the original image. - *%(CLIP_HOT_PIXELS)s:* Clips hot pixels to the maximum local neighbor intensity. Hot pixels are identified by thresholding on the difference between the pixel intensity and it's maximum local neighbor intensity. *Note, when deciding between %(MEDIAN_FILTER)s and %(GAUSSIAN_FILTER)s we typically recommend %(MEDIAN_FILTER)s over %(GAUSSIAN_FILTER)s because the median is less sensitive to outliers, although the results are also slightly less smooth and the fact that images are in the range of 0 to 1 means that outliers typically will not dominate too strongly anyway.* """ % globals(), ) self.wants_automatic_object_size = cps.Binary( "Calculate artifact diameter automatically?", True, doc="""\ *(Used only if “%(GAUSSIAN_FILTER)s”, “%(MEDIAN_FILTER)s”, “%(SMOOTH_KEEPING_EDGES)s” or “%(CIRCULAR_AVERAGE_FILTER)s” is selected)* Select *%(YES)s* to choose an artifact diameter based on the size of the image. The minimum size it will choose is 30 pixels, otherwise the size is 1/40 of the size of the image. Select *%(NO)s* to manually enter an artifact diameter. """ % globals(), ) self.object_size = cps.text.Float( "Typical artifact diameter", 16.0, doc="""\ *(Used only if choosing the artifact diameter automatically is set to “%(NO)s”)* Enter the approximate diameter (in pixels) of the features to be blurred by the smoothing algorithm. This value is used to calculate the size of the spatial filter. %(HELP_ON_MEASURING_DISTANCES)s For most smoothing methods, selecting a diameter over ~50 will take substantial amounts of time to process. """ % globals(), ) self.sigma_range = cps.text.Float( "Edge intensity difference", 0.1, doc="""\ *(Used only if “%(SMOOTH_KEEPING_EDGES)s” is selected)* Enter the intensity step (which indicates an edge in an image) that you want to preserve. Edges are locations where the intensity changes precipitously, so this setting is used to adjust the rough magnitude of these changes. A lower number will preserve weaker edges. A higher number will preserve only stronger edges. Values should be between zero and one. %(HELP_ON_PIXEL_INTENSITIES)s """ % globals(), ) self.clip = cps.Binary( "Clip intensities to 0 and 1?", True, doc="""\ *(Used only if "%(FIT_POLYNOMIAL)s" is selected)* The *%(FIT_POLYNOMIAL)s* method is the only smoothing option that can yield an output image whose values are outside of the values of the input image. This setting controls whether to limit the image intensity to the 0 - 1 range used by CellProfiler. Select *%(YES)s* to set all output image pixels less than zero to zero and all pixels greater than one to one. Select *%(NO)s* to allow values less than zero and greater than one in the output image. """ % globals(), ) self.hp_filter_size = cps.text.Integer( "Neighborhood filter size", 3, minval=3, doc="""\ *(Used only if "%(CLIP_HOT_PIXELS)s" is selected)*) Enter the size of the local neighborhood filter (recommended value: 3). This value will be used to define the maximum distance around an individual pixel within which other pixels will be considered as neighboring pixels. Note that this value can be interpreted as diameter and thus has to be odd. """ % globals(), ) self.hp_threshold = cps.text.Float( "Hot pixel threshold", 50, minval=0, doc="""\ *(Used only if "%(CLIP_HOT_PIXELS)s" is selected)*) Enter the absolute threshold on the difference between the individual pixel intensity and it's maximum local neighbor intensity. This value will be used to identify "hot pixels" whose intensity values will be clipped to the maximum local neighbor intensity. """ % globals(), ) self.scale_hp_threshold = cps.Binary( "Scale hot pixel threshold to image scale?", True, doc="""\ *(Used only if "%(CLIP_HOT_PIXELS)s" is selected)*) Specify whether the hot pixel threshold should be scaled to the image scale or be taken as-is. In CellProfiler, the image values are usually rescaled to 0-1. Thus, if the threshold should be selected based on the raw data values, it needs to be scaled. Example: If the image data type was uint16, the image is rescaled automatically upon import. Thus all absolute values now have to be divided by 2^16. For example, if one wants to set a threshold of 100 counts, a value of either 100 / 2^16 = 0.0015 (no scaling) or 100 (scaling) needs to be specified. """ % globals(), )
def create_settings(self): self.input_type = Choice("Select the type of input", [IF_IMAGE], IF_IMAGE) self.image_name = cps.subscriber.ImageSubscriber( "Select the image to save", "None", doc=""" <i>(Used only if "%(IF_IMAGE)s", "%(IF_MASK)s" or "%(IF_CROPPING)s" are selected to save)</i><br> Select the image you want to save.""" % globals(), ) self.input_object_name = cps.subscriber.LabelSubscriber( "Select the objects to save", "None") self.objects_name = cps.subscriber.LabelSubscriber( "Select the objects to crop and save", "None", doc=""" Select the objects that you want to save.""" % globals(), ) self.file_name_method = Choice( "Select method for constructing file names", [ FN_FROM_IMAGE, ], doc=""" Several choices are available for constructing the image file name: <ul> <li><i>%(FN_FROM_IMAGE)s:</i> The filename will be constructed based on the original filename of an input image specified in <b>NamesAndTypes</b>. You will have the opportunity to prefix or append additional text. <p>If you have metadata associated with your images, you can append an text to the image filename using a metadata tag. 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 can be provided for each image for each cycle using the <b>Metadata</b> module. %(USING_METADATA_TAGS_REF)s%(USING_METADATA_HELP_REF)s.</p></li> </ul>""" % globals(), ) self.file_image_name = FileImageSubscriber( "Select image name for file prefix", "None", doc=""" <i>(Used only when "%(FN_FROM_IMAGE)s" is selected for contructing the filename)</i><br> Select an image loaded using <b>NamesAndTypes</b>. The original filename will be used as the prefix for the output filename.""" % globals(), ) self.wants_file_name_suffix = cps.Binary( "Append a suffix to the image file name?", False, doc=""" Select <i>%(YES)s</i> to add a suffix to the image's file name. Select <i>%(NO)s</i> to use the image name as-is.""" % globals(), ) self.file_name_suffix = cps.text.Text( "Text to append to the image name", "", metadata=True, doc=""" <i>(Used only when constructing the filename from the image filename)</i><br> Enter the text that should be appended to the filename specified above.""", ) self.file_format = cps.choice.Choice( "Saved file format", [FF_TIFF], value=FF_TIFF, doc=""" <i>(Used only when saving non-movie files)</i><br> Select the image or movie format to save the image(s). Most common image formats are available; MAT-files are readable by MATLAB.""", ) self.pathname = SaveImagesDirectoryPath( "Output file location", self.file_image_name, doc=""" <i>(Used only when saving non-movie files)</i><br> This setting lets you choose the folder for the output files. %(IO_FOLDER_CHOICE_HELP_TEXT)s <p>An additional option is the following: <ul> <li><i>Same folder as image</i>: Place the output file in the same folder that the source image is located.</li> </ul></p> <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<Plate>". 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> <p>If the subfolder does not exist when the pipeline is run, CellProfiler will create it.</p> <p>If you are creating nested subfolders using the sub-folder options, you can specify the additional folders separated with slashes. For example, "Outlines/Plate1" will create a "Plate1" folder in the "Outlines" folder, which in turn is under the Default Input/Output Folder. The use of a forward slash ("/") as a folder separator will avoid ambiguity between the various operating systems.</p>""" % globals(), ) self.bit_depth = cps.choice.Choice( "Image bit depth", [BIT_DEPTH_8, BIT_DEPTH_16, BIT_DEPTH_FLOAT], doc=""" <i>(Used only when saving files in a non-MAT format)</i><br> Select the bit-depth at which you want to save the images. <i>%(BIT_DEPTH_FLOAT)s</i> saves the image as floating-point decimals with 32-bit precision in its raw form, typically scaled between 0 and 1. <b>%(BIT_DEPTH_16)s and %(BIT_DEPTH_FLOAT)s images are supported only for TIF formats. Currently, saving images in 12-bit is not supported.</b>""" % globals(), ) self.object_extension = Integer( "Object extension", value=1, doc=""" How many pixels should the bounding box of the objects be extended before cropping""", ) self.overwrite = cps.Binary( "Overwrite existing files without warning?", False, doc=""" Select <i>%(YES)s</i> to automatically overwrite a file if it already exists. Select <i>%(NO)s</i> to be prompted for confirmation first. <p>If you are running the pipeline on a computing cluster, select <i>%(YES)s</i> since you will not be able to intervene and answer the confirmation prompt.</p>""" % globals(), ) self.when_to_save = cps.choice.Choice( "When to save", [WS_FIRST_CYCLE], doc="""<a name='when_to_save'> <i>(Used only when saving non-movie files)</i><br> Specify at what point during pipeline execution to save file(s). </a> <ul> <li><i>%(WS_EVERY_CYCLE)s:</i> Useful for when the image of interest is created every cycle and is not dependent on results from a prior cycle.</li> </ul> """ % globals(), ) self.update_file_names = cps.Binary( "Record the file and path information to the saved image?", False, doc=""" Select <i>%(YES)s</i> to store filename and pathname data for each of the new files created via this module as a per-image measurement. <p>Instances in which this information may be useful include: <ul> <li>Exporting measurements to a database, allowing access to the saved image. If you are using the machine-learning tools or image viewer in CellProfiler Analyst, for example, you will want to enable this setting if you want the saved images to be displayed along with the original images.</li> <li>Allowing downstream modules (e.g., <b>CreateWebPage</b>) to access the newly saved files.</li> </ul></p>""" % globals(), ) self.create_subdirectories = cps.Binary( "Create subfolders in the output folder?", False, doc=""" Select <i>%(YES)s</i> to create subfolders to match the input image folder structure.""" % globals(), ) self.root_dir = cps.text.Directory( "Base image folder", doc=""" <i>Used only if creating subfolders in the output folder</i> In subfolder mode, <b>SaveImages</b> determines the folder for an image file by examining the path of the matching input file. The path that SaveImages uses is relative to the image folder chosen using this setting. As an example, input images might be stored in a folder structure of "images%(sep)s<i>experiment-name</i>%(sep)s <i>date</i>%(sep)s<i>plate-name</i>". If the image folder is "images", <b>SaveImages</b> will store images in the subfolder, "<i>experiment-name</i>%(sep)s<i>date</i>%(sep)s<i>plate-name</i>". If the image folder is "images%(sep)s<i>experiment-name</i>", <b>SaveImages</b> will store images in the subfolder, <i>date</i>%(sep)s<i>plate-name</i>". """ % dict(sep=os.path.sep), )
def create_settings(self): '''Create the settings for the ExportToCellH5 module''' self.directory = Directory("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.text.Filename("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.text.Filename.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<Plate>". 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"</i> to automatically overwrite any existing data for a site. Select <i>"No"</i> to be prompted first. If you are running the pipeline on a computing cluster, select <i>"Yes"</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"</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"</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 = 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 = 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 = 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"</i> to pick the measurements to be exported. Select <i>"No"</i> to automatically export all measurements available at this stage of the pipeline. """ % globals()) self.measurements = 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 = DoSomething("Add objects to export", "Add objects", self.add_objects) self.images_to_export = [] self.add_image_button = 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 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(), )
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. """, )
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): self.object_name = cps.ObjectNameSubscriber( "Select objects to measure", "None", doc="""\ Select the objects whose neighbors you want to measure.""", ) self.neighbors_name = cps.ObjectNameSubscriber( "Select neighboring objects to measure", "None", doc="""\ This is the name of the objects that are potential neighbors of the above objects. You can find the neighbors within the same set of objects by selecting the same objects as above.""", ) self.distance_method = cps.Choice( "Method to determine neighbors", D_ALL, D_EXPAND, doc="""\ There are several methods by which to determine whether objects are neighbors: - *%(D_ADJACENT)s:* In this mode, two objects must have adjacent boundary pixels to be neighbors. - *%(D_EXPAND)s:* The objects are expanded until all pixels on the object boundaries are touching another. Two objects are neighbors if any of their boundary pixels are adjacent after expansion. - *%(D_WITHIN)s:* Each object is expanded by the number of pixels you specify. Two objects are neighbors if they have adjacent pixels after expansion. For *%(D_ADJACENT)s* and *%(D_EXPAND)s*, the *%(M_PERCENT_TOUCHING)s* measurement is the percentage of pixels on the boundary of an object that touch adjacent objects. For *%(D_WITHIN)s*, two objects are touching if any of their boundary pixels are adjacent after expansion and *%(M_PERCENT_TOUCHING)s* measures the percentage of boundary pixels of an *expanded* object that touch adjacent objects. """ % globals(), ) self.distance = cps.Integer( "Neighbor distance", 5, 1, doc="""\ *(Used only when “%(D_WITHIN)s” is selected)* The Neighbor distance is the number of pixels that each object is expanded for the neighbor calculation. Expanded objects that touch are considered neighbors. """ % globals(), ) self.wants_count_image = cps.Binary( "Retain the image of objects colored by numbers of neighbors?", False, doc="""\ An output image showing the input objects colored by numbers of neighbors may be retained. A colormap of your choice shows how many neighbors each object has. The background is set to -1. Objects are colored with an increasing color value corresponding to the number of neighbors, such that objects with no neighbors are given a color corresponding to 0. Use the **SaveImages** module to save this image to a file.""", ) self.count_image_name = cps.ImageNameProvider( "Name the output image", "ObjectNeighborCount", doc="""\ *(Used only if the image of objects colored by numbers of neighbors is to be retained for later use in the pipeline)* Specify a name that will allow the image of objects colored by numbers of neighbors to be selected later in the pipeline.""", ) self.count_colormap = cps.Colormap( "Select colormap", doc="""\ *(Used only if the image of objects colored by numbers of neighbors is to be retained for later use in the pipeline)* Select the colormap to use to color the neighbor number image. All available colormaps can be seen `here`_. .. _here: http://matplotlib.org/examples/color/colormaps_reference.html""", ) self.wants_percent_touching_image = cps.Binary( "Retain the image of objects colored by percent of touching pixels?", False, doc="""\ Select *Yes* to keep an image of the input objects colored by the percentage of the boundary touching their neighbors. A colormap of your choice is used to show the touching percentage of each object. Use the **SaveImages** module to save this image to a file. """ % globals(), ) self.touching_image_name = cps.ImageNameProvider( "Name the output image", "PercentTouching", doc="""\ *(Used only if the image of objects colored by percent touching is to be retained for later use in the pipeline)* Specify a name that will allow the image of objects colored by percent of touching pixels to be selected later in the pipeline.""", ) self.touching_colormap = cps.Colormap( "Select colormap", doc="""\ *(Used only if the image of objects colored by percent touching is to be retained for later use in the pipeline)* Select the colormap to use to color the percent touching image. All available colormaps can be seen `here`_. .. _here: http://matplotlib.org/examples/color/colormaps_reference.html""", ) self.wants_excluded_objects = cps.Binary( "Consider objects discarded for touching image border?", True, doc="""\ When set to *{YES}*, objects which were previously discarded for touching the image borders will be considered as potential object neighbours in this analysis. You may want to disable this if using object sets which were further filtered, since those filters won't have been applied to the previously discarded objects.""".format(**{"YES": "Yes"}), )
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")
def create_settings(self): self.objects_name = cps.ObjectNameSubscriber( "Select the input objects", "None", doc="""\ Select the objects you would like to split or merge (that is, whose object numbers you want to reassign). You can use any objects that were created in previous modules, such as **IdentifyPrimaryObjects** or **IdentifySecondaryObjects**.""", ) self.output_objects_name = cps.ObjectNameProvider( "Name the new objects", "RelabeledNuclei", doc="""\ Enter a name for the objects that have been split or merged (that is, whose numbers have been reassigned). You can use this name in subsequent modules that take objects as inputs.""", ) self.relabel_option = cps.Choice( "Operation", [OPTION_MERGE, OPTION_SPLIT], doc="""\ You can choose one of the following options: - *%(OPTION_MERGE)s:* Assign adjacent or nearby objects the same label based on certain criteria. It can be useful, for example, to merge together touching objects that were incorrectly split into two pieces by an **Identify** module. - *%(OPTION_SPLIT)s:* Assign a unique number to separate objects that currently share the same label. This can occur if you applied certain operations in the **Morph** module to objects.""" % globals(), ) self.merge_option = cps.Choice( "Merging method", [UNIFY_DISTANCE, UNIFY_PARENT], doc="""\ *(Used only with the "%(OPTION_MERGE)s" option)* You can merge objects in one of two ways: - *%(UNIFY_DISTANCE)s:* All objects within a certain pixel radius from each other will be merged. - *%(UNIFY_PARENT)s:* All objects which share the same parent relationship to another object will be merged. This is not to be confused with using the **RelateObjects** module, in which the related objects remain as individual objects. See **RelateObjects** for more details.""" % globals(), ) self.merging_method = cps.Choice( "Output object type", [UM_DISCONNECTED, UM_CONVEX_HULL], doc="""\ *(Used only with the "%(UNIFY_PARENT)s" merging method)* **SplitOrMergeObjects** can either merge the child objects and keep them disconnected or it can find the smallest convex polygon (the convex hull) that encloses all of a parent’s child objects. The convex hull will be truncated to include only those pixels in the parent - in that case it may not truly be convex. Choose *%(UM_DISCONNECTED)s* to leave the children as disconnected pieces. Choose *%(UM_CONVEX_HULL)s* to create an output object that is the convex hull around them all.""" % globals(), ) self.parent_object = cps.Choice( "Select the parent object", ["None"], choices_fn=self.get_parent_choices, doc="""\ Select the parent object that will be used to merge the child objects. Please note the following: - You must have established a parent-child relationship between the objects using a prior **RelateObjects** module. - Primary objects and their associated secondary objects are already in a one-to-one parent-child relationship, so it makes no sense to merge them here.""", ) self.distance_threshold = cps.Integer( "Maximum distance within which to merge objects", 0, minval=0, doc="""\ *(Used only with the "%(OPTION_MERGE)s" option and the "%(UNIFY_DISTANCE)s" method)* Objects that are less than or equal to the distance you enter here, in pixels, will be merged. If you choose zero (the default), only objects that are touching will be merged. Note that *%(OPTION_MERGE)s* will not actually connect or bridge the two objects by adding any new pixels; it simply assigns the same object number to the portions of the object. The new, merged object may therefore consist of two or more unconnected components. If you want to add pixels around objects, see **ExpandOrShrink** or **Morph**.""" % globals(), ) self.wants_image = cps.Binary( "Merge using a grayscale image?", False, doc="""\ *(Used only with the "%(OPTION_MERGE)s" option)* Select *Yes* to use the objects’ intensity features to determine whether two objects should be merged. If you choose to use a grayscale image, *%(OPTION_MERGE)s* will merge two objects only if they are within the distance you have specified *and* certain criteria about the objects within the grayscale image are met.""" % globals(), ) self.image_name = cps.ImageNameSubscriber( "Select the grayscale image to guide merging", "None", doc="""\ *(Used only if a grayscale image is to be used as a guide for merging)* Select the name of an image loaded or created by a previous module.""", ) self.minimum_intensity_fraction = cps.Float( "Minimum intensity fraction", 0.9, minval=0, maxval=1, doc="""\ *(Used only if a grayscale image is to be used as a guide for merging)* Select the minimum acceptable intensity fraction. This will be used as described for the method you choose in the next setting.""", ) self.where_algorithm = cps.Choice( "Method to find object intensity", [CA_CLOSEST_POINT, CA_CENTROIDS], doc="""\ *(Used only if a grayscale image is to be used as a guide for merging)* You can use one of two methods to determine whether two objects should merged, assuming they meet the distance criteria (as specified above): - *%(CA_CENTROIDS)s:* When the module considers merging two objects, this method identifies the centroid of each object, records the intensity value of the dimmer of the two centroids, multiplies this value by the *minimum intensity fraction* to generate a threshold, and draws a line between the centroids. The method will merge the two objects only if the intensity of every point along the line is above the threshold. For instance, if the intensity of one centroid is 0.75 and the other is 0.50 and the *minimum intensity fraction* has been chosen to be 0.9, all points along the line would need to have an intensity of min(0.75, 0.50) \* 0.9 = 0.50 \* 0.9 = 0.45. This method works well for round cells whose maximum intensity is in the center of the cell: a single cell that was incorrectly segmented into two objects will typically not have a dim line between the centroids of the two halves and will be correctly merged. - *%(CA_CLOSEST_POINT)s:* This method is useful for unifying irregularly shaped cells that are connected. It starts by assigning background pixels in the vicinity of the objects to the nearest object. Objects are then merged if each object has background pixels that are: - Within a distance threshold from each object; - Above the minimum intensity fraction of the nearest object pixel; - Adjacent to background pixels assigned to a neighboring object. An example of a feature that satisfies the above constraints is a line of pixels that connects two neighboring objects and is roughly the same intensity as the boundary pixels of both (such as an axon connecting two neurons' soma).""" % globals(), )
def create_settings(self): """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. """, )
def create_settings(self): """Create the settings for the module Create the settings for the module during initialization. """ self.contrast_choice = cps.Choice( "Make each classification decision on how many measurements?", [BY_SINGLE_MEASUREMENT, BY_TWO_MEASUREMENTS], doc="""\ This setting controls how many measurements are used to make a classifications decision for each object: - *%(BY_SINGLE_MEASUREMENT)s:* Classifies each object based on a single measurement. - *%(BY_TWO_MEASUREMENTS)s:* Classifies each object based on a pair of measurements taken together (that is, an object must meet two criteria to belong to a class). """ % globals(), ) ############### Single measurement settings ################## # # A list holding groupings for each of the single measurements # to be done # self.single_measurements = [] # # A count of # of measurements # self.single_measurement_count = cps.HiddenCount( self.single_measurements) # # Add one single measurement to start off # self.add_single_measurement(False) # # A button to press to get another measurement # self.add_measurement_button = cps.DoSomething( "", "Add another classification", self.add_single_measurement) # ############### Two-measurement settings ##################### # # The object for the contrasting method # self.object_name = cps.ObjectNameSubscriber( "Select the object name", "None", doc="""\ Choose the object that you want to measure from the list. This should be an object created by a previous module such as **IdentifyPrimaryObjects**, **IdentifySecondaryObjects**, **IdentifyTertiaryObjects**, or **Watershed** """, ) # # The two measurements for the contrasting method # def object_fn(): return self.object_name.value self.first_measurement = cps.Measurement( "Select the first measurement", object_fn, doc="""\ *(Used only if using a pair of measurements)* Choose a measurement made on the above object. This is the first of two measurements that will be contrasted together. The measurement should be one made on the object in a prior module. """, ) self.first_threshold_method = cps.Choice( "Method to select the cutoff", [TM_MEAN, TM_MEDIAN, TM_CUSTOM], doc="""\ *(Used only if using a pair of measurements)* Objects are classified as being above or below a cutoff value for a measurement. You can set this cutoff threshold in one of three ways: - *%(TM_MEAN)s*: At the mean of the measurement’s value for all objects in the image cycle. - *%(TM_MEDIAN)s*: At the median of the measurement’s value for all objects in the image set. - *%(TM_CUSTOM)s*: You specify a custom threshold value. """ % globals(), ) self.first_threshold = cps.Float( "Enter the cutoff value", 0.5, doc="""\ *(Used only if using a pair of measurements)* This is the cutoff value separating objects in the two classes.""", ) self.second_measurement = cps.Measurement( "Select the second measurement", object_fn, doc="""\ *(Used only if using a pair of measurements)* Select a measurement made on the above object. This is the second of two measurements that will be contrasted together. The measurement should be one made on the object in a prior module.""", ) self.second_threshold_method = cps.Choice( "Method to select the cutoff", [TM_MEAN, TM_MEDIAN, TM_CUSTOM], doc="""\ *(Used only if using a pair of measurements)* Objects are classified as being above or below a cutoff value for a measurement. You can set this cutoff threshold in one of three ways: - *%(TM_MEAN)s:* At the mean of the measurement’s value for all objects in the image cycle. - *%(TM_MEDIAN)s:* At the median of the measurement’s value for all objects in the image set. - *%(TM_CUSTOM)s:* You specify a custom threshold value. """ % globals(), ) self.second_threshold = cps.Float( "Enter the cutoff value", 0.5, doc="""\ *(Used only if using a pair of measurements)* This is the cutoff value separating objects in the two classes.""", ) self.wants_custom_names = cps.Binary( "Use custom names for the bins?", False, doc="""\ *(Used only if using a pair of measurements)* Select "*Yes*" if you want to specify the names of each bin measurement. Select "*No*" to create names based on the measurements. For instance, for “Intensity_MeanIntensity_Green” and “Intensity_TotalIntensity_Blue”, the module generates measurements such as “Classify_Intensity_MeanIntensity_Green_High_Intensity_TotalIntensity_Low”. """ % globals(), ) self.low_low_custom_name = cps.AlphanumericText( "Enter the low-low bin name", "low_low", doc="""\ *(Used only if using a pair of measurements)* Name of the measurement for objects that fall below the threshold for both measurements. """, ) self.low_high_custom_name = cps.AlphanumericText( "Enter the low-high bin name", "low_high", doc="""\ *(Used only if using a pair of measurements)* Name of the measurement for objects whose first measurement is below threshold and whose second measurement is above threshold. """, ) self.high_low_custom_name = cps.AlphanumericText( "Enter the high-low bin name", "high_low", doc="""\ *(Used only if using a pair of measurements)* Name of the measurement for objects whose first measurement is above threshold and whose second measurement is below threshold.""", ) self.high_high_custom_name = cps.AlphanumericText( "Enter the high-high bin name", "high_high", doc="""\ *(Used only if using a pair of measurements)* Name of the measurement for objects that are above the threshold for both measurements.""", ) self.wants_image = cps.Binary( "Retain an image of the classified objects?", False, doc="""\ Select "*Yes*" to retain the image of the objects color-coded according to their classification, for use later in the pipeline (for example, to be saved by a **SaveImages** module). """ % globals(), ) self.image_name = cps.ImageNameProvider( "Enter the image name", "None", doc="""\ *(Used only if the classified object image is to be retained for later use in the pipeline)* Enter the name to be given to the classified object image.""", )
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(), )
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(), )
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(), )