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): # 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. """, )