code: def create_settings(self):
      self.image_name = ImageSubscriber(
          "Select the input image",
          "None",
          doc="Choose the image to be used to calculate the illumination function.",
      )
  
      self.illumination_image_name = ImageName(
          "Name the output image",
          "IllumBlue",
          doc="""Enter a name for the resultant illumination function.""",
          provided_attributes={
              "aggregate_image": True,
              "available_on_last": False,
          },
      )
  
      self.intensity_choice = Choice(
          "Select how the illumination function is calculated",
          [IC_REGULAR, IC_BACKGROUND],
          IC_REGULAR,
          doc="""\
  Choose which method you want to use to calculate the illumination
  function. You may chose from the following options:
  
  -  *{IC_REGULAR}:* If you have objects that are evenly dispersed across
     your image(s) and cover most of the image, the *Regular* method might
     be appropriate. *Regular* makes the illumination function
     based on the intensity at each pixel of the image (or group of images
     if you are in *{EA_ALL}* mode) and is most often rescaled (see
     below) and applied by division using **CorrectIlluminationApply.**
     Note that if you are in *{EA_EACH}* mode or using a small set of
     images with few objects, there will be regions in the average image
     that contain no objects and smoothing by median filtering is unlikely
     to work well. *Note:* it does not make sense to choose
     (*{IC_REGULAR} + {SM_NONE} + {EA_EACH}*) because the illumination
     function would be identical to the original image and applying it
     will yield a blank image. You either need to smooth each image, or
     you need to use *{EA_ALL}* images.
  -  *{IC_BACKGROUND}:* If you think that the background (dim regions)
     between objects show the same pattern of illumination as your objects
     of interest, you can choose the *{IC_BACKGROUND}* method. Background
     intensities finds the minimum pixel intensities in blocks across the
     image (or group of images if you are in *{EA_ALL}* mode) and is most
     often applied by subtraction using the **CorrectIlluminationApply**
     module. *Note:* if you will be using the *{DOS_SUBTRACT}* option in
     the **CorrectIlluminationApply** module, you almost certainly do not
     want to rescale the illumination function.
  
  Please note that if a mask was applied to the input image, the pixels
  outside of the mask will be excluded from consideration. This is useful,
  for instance, in cases where you have masked out the well edge in an
  image from a multi-well plate; the dark well edge would distort the
  illumination correction function along the interior well edge. Masking
  the image beforehand solves this problem.
  """.format(
              **{
                  "IC_REGULAR": IC_REGULAR,
                  "EA_ALL": EA_ALL,
                  "EA_EACH": EA_EACH,
                  "SM_NONE": SM_NONE,
                  "IC_BACKGROUND": IC_BACKGROUND,
                  "DOS_SUBTRACT": DOS_SUBTRACT,
              }
          ),
      )
  
      self.dilate_objects = Binary(
          "Dilate objects in the final averaged image?",
          False,
          doc="""\
  *(Used only if the “%(IC_REGULAR)s” method is selected)*
  
  For some applications, the incoming images are binary and each object
  should be dilated with a Gaussian filter in the final averaged
  (projection) image. This is for a sophisticated method of illumination
  correction where model objects are produced. Select *Yes* to dilate
  objects for this approach.
  """
          % globals(),
      )
  
      self.object_dilation_radius = Integer(
          "Dilation radius",
          1,
          0,
          doc="""\
  *(Used only if the “%(IC_REGULAR)s” method and dilation is selected)*
  
  This value should be roughly equal to the original radius of the objects.
  """
          % globals(),
      )
  
      self.block_size = Integer(
          "Block size",
          60,
          1,
          doc="""\
  *(Used only if “%(IC_BACKGROUND)s” is selected)*
  
  The block size should be large enough that every square block of pixels
  is likely to contain some background pixels, where no objects are
  located.
  """
          % globals(),
      )
  
      self.rescale_option = Choice(
          "Rescale the illumination function?",
          ["Yes", "No", RE_MEDIAN],
          doc="""\
  The illumination function can be rescaled so that the pixel intensities
  are all equal to or greater than 1. You have the following options:
  
  -  *Yes:* Rescaling is recommended if you plan to use the
     *%(IC_REGULAR)s* method (and hence, the *%(DOS_DIVIDE)s* option in
     **CorrectIlluminationApply**). Rescaling the illumination function to
     >1 ensures that the values in your corrected image will stay between
     0-1 after division.
  -  *No:* Rescaling is not recommended if you plan to use the
     *%(IC_BACKGROUND)s* method, which is paired with the
     *%(DOS_SUBTRACT)s* option in **CorrectIlluminationApply**. Because
     rescaling causes the illumination function to have values from 1 to
     infinity, subtracting those values from your image would cause the
     corrected images to be very dark, even negative.
  -  %(RE_MEDIAN)s\ *:* This option chooses the median value in the image
     to rescale so that division increases some values and decreases others.
  """
          % globals(),
      )
  
      self.each_or_all = Choice(
          "Calculate function for each image individually, or based on all images?",
          [EA_EACH, EA_ALL_FIRST, EA_ALL_ACROSS],
          doc="""\
  Calculate a separate function for each image, or one for all the
  images? You can calculate the illumination function using just the
  current image or you can calculate the illumination function using all
  of the images in each group (or in the entire experiment). The
  illumination function can be calculated in one of the three ways:
  
  -  *%(EA_EACH)s:* Calculate an illumination function for each image
     individually.
  -  *%(EA_ALL_FIRST)s:* Calculate an illumination function based on all
     of the images in a group, performing the calculation before
     proceeding to the next module. This means that the illumination
     function will be created in the first cycle (making the first cycle
     longer than subsequent cycles), and lets you use the function in a
     subsequent **CorrectIlluminationApply** module in the same
     pipeline, but also means that you will not have the ability to filter
     out images (e.g., by using **FlagImage**). The input images need to
     be assembled using the **Input** modules; using images produced by
     other modules will yield an error. Thus, typically,
     **CorrectIlluminationCalculate** will be the first module after the
     input modules.
  -  *%(EA_ALL_ACROSS)s:* Calculate an illumination function across all
     cycles in each group. This option takes any image as input; however,
     the illumination function will not be completed until the end of the
     last cycle in the group. You can use **SaveImages** to save the
     illumination function after the last cycle in the group and then use
     the resulting image in another pipeline. The option is useful if you
     want to exclude images that are filtered by a prior **FlagImage**
     module.
  """
          % globals(),
      )
      self.smoothing_method = Choice(
          "Smoothing method",
          [
              SM_NONE,
              SM_CONVEX_HULL,
              SM_FIT_POLYNOMIAL,
              SM_MEDIAN_FILTER,
              SM_GAUSSIAN_FILTER,
              SM_TO_AVERAGE,
              SM_SPLINES,
          ],
          doc="""\
  If requested, the resulting image is smoothed. If you are using *Each* mode,
  smoothing is definitely needed. For *All* modes, you usually also want to
  smooth, especially if you have few objects in each image or a small image set.
  
  You should smooth to the point where the illumination function resembles
  a believable pattern. For example, if you are trying to correct a lamp
  illumination problem, apply smoothing until you obtain a fairly smooth
  pattern without sharp bright or dim regions. Note that smoothing is a
  time-consuming process, but some methods are faster than others.
  
  -  *%(SM_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.
  -  *%(SM_MEDIAN_FILTER)s* and *%(SM_GAUSSIAN_FILTER)s:*
     We typically recommend
     *%(SM_MEDIAN_FILTER)s* vs. *%(SM_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. The *%(SM_GAUSSIAN_FILTER)s* 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. The *%(SM_MEDIAN_FILTER)s* finds the median pixel value within
     the diameter you specify. It removes bright or dim features
     that are significantly smaller than the specified diameter.
  -  *%(SM_TO_AVERAGE)s:* A less commonly used option is to completely
     smooth the entire image, which will create a flat, smooth image where
     every pixel of the image is the average of what the illumination
     function would otherwise have been.
  -  *%(SM_SPLINES)s:* This method (*Lindblad and Bengtsson, 2001*) fits
     a grid of cubic splines to the background while excluding foreground
     pixels from the calculation. It operates iteratively, classifying
     pixels as background, computing a best fit spline to this background
     and then reclassifying pixels as background until the spline
     converges on its final value. This method is best for backgrounds that
     are highly variable and irregular. Note that the computation time can
     be significant, especially with a large number of control points.
  -  *%(SM_CONVEX_HULL)s:* This method can be used on an image whose objects are
     darker than their background and whose illumination intensity
     decreases monotonically from the brightest point. It proceeds as follows:
     
     -  Choose 256 evenly-spaced intensity levels between the minimum and
        maximum intensity for the image
     -  Set the intensity of the output image to the minimum intensity of
        the input image
     -  Iterate over the intensity levels, from lowest to highest
     -  For a given intensity, find all pixels with equal or higher
        intensities
     -  Find the convex hull that encloses those pixels
     -  Set the intensity of the output image within the convex hull to
        the current intensity
  
     The *%(SM_CONVEX_HULL)s* method is useful for calculating illumination correction
     images in empty brightfield images. It is a good option if the image contains a whole well.
     The edges of the well will be preserved, where there is a sharp transition in
     intensity, because there is no smoothing involved with this method.
  
  **References**
  -  J Lindblad and E Bengtsson (2001) “A comparison of methods for estimation
  of intensity nonuniformities in 2D and 3D microscope images of fluorescence
  stained cells.”, Proceedings of the 12th Scandinavian Conference on Image Analysis
  (SCIA), pp. 264-271
  """
          % globals(),
      )
  
      self.automatic_object_width = Choice(
          "Method to calculate smoothing filter size",
          [FI_AUTOMATIC, FI_OBJECT_SIZE, FI_MANUALLY],
          doc="""\
  *(Used only if a smoothing method other than Fit Polynomial is selected)*
  
  Calculate the smoothing filter size. There are three options:
  
  -  *%(FI_AUTOMATIC)s:* The size is computed as 1/40 the size of the
     image or 30 pixels, whichever is smaller.
  -  *%(FI_OBJECT_SIZE)s:* The module will calculate the smoothing size
     based on the width of typical objects in your images.
  -  *%(FI_MANUALLY)s:* You can enter a value yourself.
  """
          % globals(),
      )
  
      self.object_width = Integer(
          "Approximate object diameter",
          10,
          doc="""\
  *(Used only if %(FI_OBJECT_SIZE)s is selected for smoothing filter size calculation)*
  
  Enter the approximate diameter of typical objects, in pixels.
  """
          % globals(),
      )
  
      self.size_of_smoothing_filter = Integer(
          "Smoothing filter size",
          10,
          doc="""\
  *(Used only if %(FI_MANUALLY)s is selected for smoothing filter size calculation)*
  
  Enter the size of the desired smoothing filter, in pixels.
  """
          % globals(),
      )
  
      self.save_average_image = Binary(
          "Retain the averaged image?",
          False,
          doc="""\
  The averaged image is the illumination function prior to dilation or
  smoothing. It is an image produced during the calculations, not
  typically needed for downstream modules. It can be helpful to retain it
  in case you wish to try several different smoothing methods without
  taking the time to recalculate the averaged image each time.
  
  Select *Yes* to retain this averaged image. Use the **SaveImages**
  module to save it to your hard drive.
  """
          % globals(),
      )
  
      self.average_image_name = ImageName(
          "Name the averaged image",
          "IllumBlueAvg",
          doc="""\
  *(Used only if the averaged image is to be retained for later use in the pipeline)*
  
  Enter a name that will allow the averaged image to be selected later in the pipeline.""",
      )
  
      self.save_dilated_image = Binary(
          "Retain the dilated image?",
          False,
          doc="""\
  The dilated image is the illumination function after dilation but prior
  to smoothing. It is an image produced during the calculations, and is
  not typically needed for downstream modules.
  
  Select *Yes* to retain this dilated image. Use the **SaveImages**
  module to save it to your hard drive.
  """
          % globals(),
      )
  
      self.dilated_image_name = ImageName(
          "Name the dilated image",
          "IllumBlueDilated",
          doc="""\
  *(Used only if the dilated image is to be retained for later use in the pipeline)*
  
  Enter a name that will allow the dilated image to be selected later in
  the pipeline.""",
      )
  
      self.automatic_splines = Binary(
          "Automatically calculate spline parameters?",
          True,
          doc="""\
  *(Used only if %(SM_SPLINES)s are selected for the smoothing method)*
  
  Select *Yes* to automatically calculate the parameters for spline
  fitting.
  
  Select *No* to specify the background mode, background threshold,
  scale, maximum number of iterations and convergence.
  """
          % globals(),
      )
  
      self.spline_bg_mode = Choice(
          "Background mode",
          [
              centrosome.bg_compensate.MODE_AUTO,
              centrosome.bg_compensate.MODE_DARK,
              centrosome.bg_compensate.MODE_BRIGHT,
              centrosome.bg_compensate.MODE_GRAY,
          ],
          doc="""\
  *(Used only if %(SM_SPLINES)s are selected for the smoothing method
  and spline parameters are not calculated automatically)*
  
  This setting determines which pixels are background and which are
  foreground.
  
  -  *{auto}*: Determine the mode from the image. This will set
     the mode to {dark} if most of the pixels are dark,
     {bright} if most of the pixels are bright and %(MODE_GRAY)s
     if there are relatively few dark and light pixels relative to the
     number of mid-level pixels
  -  *{dark}s*: Fit the spline to the darkest pixels in the image,
     excluding brighter pixels from consideration. This may be appropriate
     for a fluorescent image.
  -  *{bright}*: Fit the spline to the lightest pixels in the
     image, excluding the darker pixels. This may be appropriate for a
     histologically stained image.
  -  *{gray}*: Fit the spline to mid-range pixels, excluding both
     dark and light pixels. This may be appropriate for a brightfield
     image where the objects of interest have light and dark features.
  """.format(
              auto=centrosome.bg_compensate.MODE_AUTO,
              bright=centrosome.bg_compensate.MODE_BRIGHT,
              dark=centrosome.bg_compensate.MODE_DARK,
              gray=centrosome.bg_compensate.MODE_GRAY,
          ),
      )
  
      self.spline_threshold = Float(
          "Background threshold",
          2,
          minval=0.1,
          maxval=5.0,
          doc="""\
  *(Used only if %(SM_SPLINES)s are selected for the smoothing method
  and spline parameters are not calculated automatically)*
  
  This setting determines the cutoff used when excluding foreground
  pixels from consideration. On each iteration, the method computes the
  standard deviation of background pixels from the computed background.
  The number entered in this setting is the number of standard
  deviations a pixel can be from the computed background on the last
  pass if it is to be considered as background during the next pass.
  
  You should enter a higher number to converge stabily and slowly on a
  final background and a lower number to converge more rapidly, but with
  lower stability. The default for this parameter is two standard
  deviations; this will provide a fairly stable, smooth background estimate.
  """
          % globals(),
      )
  
      self.spline_points = Integer(
          "Number of spline points",
          5,
          4,
          doc="""\
  *(Used only if %(SM_SPLINES)s are selected for the smoothing method and
  spline parameters are not calculated automatically)*
  
  This is the number of control points for the spline. A value of 5
  results in a 5x5 grid of splines across the image and is the value
  suggested by the method’s authors. A lower value will give you a more
  stable background while a higher one will fit variations in the
  background more closely and take more time to compute.
  """
          % globals(),
      )
  
      self.spline_rescale = Float(
          "Image resampling factor",
          2,
          minval=1,
          doc="""\
  *(Used only if %(SM_SPLINES)s are selected for the smoothing method and
  spline parameters are not calculated automatically)*
  
  This setting controls how the image is resampled to make a smaller
  image. Resampling will speed up processing, but may degrade performance
  if the resampling factor is larger than the diameter of foreground
  objects. The image will be downsampled by the factor you enter. For
  instance, a 500x600 image will be downsampled into a 250x300 image if a
  factor of 2 is entered.
  """
          % globals(),
      )
  
      self.spline_maximum_iterations = Integer(
          "Maximum number of iterations",
          40,
          minval=1,
          doc="""\
  *(Used only if %(SM_SPLINES)s are selected for the smoothing method and
  spline parameters are not calculated automatically)*
  
  This setting determines the maximum number of iterations of the
  algorithm to be performed. The algorithm will perform fewer iterations
  if it converges.
  """
          % globals(),
      )
  
      self.spline_convergence = Float(
          "Residual value for convergence",
          value=0.001,
          minval=0.00001,
          maxval=0.1,
          doc="""\
  *(Used only if %(SM_SPLINES)s are selected for the smoothing method
  and spline parameters are not calculated automatically)*
  
  This setting determines the convergence criterion. The software sets
  the convergence criterion to the number entered here times the signal
  intensity; the convergence you enter is the fraction of the signal
  intensity that indicates convergence. The algorithm derives a standard
  deviation of the background pixels from the calculated background on
  each iteration. The algorithm terminates when the difference between
  the standard deviation for the current iteration and the previous
  iteration is less than the convergence criterion.
  
  Enter a smaller number for the convergence to calculate a more accurate
  background. Enter a larger number to calculate the background using
  fewer iterations, but less accuracy.
  """
          % globals(),
      )
  
imports: import centrosome.bg_compensate
  import centrosome.cpmorphology
  import centrosome.cpmorphology
  import centrosome.filter
  import centrosome.smooth
  import numpy
  import scipy.ndimage
  import skimage.filters
  from cellprofiler_core.image import AbstractImage
  from cellprofiler_core.image import Image
  from cellprofiler_core.measurement import Measurements
  from cellprofiler_core.module import Module
  from cellprofiler_core.pipeline import Pipeline
  from cellprofiler_core.setting import Binary
  from cellprofiler_core.setting import ValidationError
  from cellprofiler_core.setting.choice import Choice
  from cellprofiler_core.setting.subscriber import ImageSubscriber
  from cellprofiler_core.setting.text import Float
  from cellprofiler_core.setting.text import ImageName
  from cellprofiler_core.setting.text import Integer
label_desc: Use image node_id 1 for calling the CorrectIlluminationCalculate obj's underlying member method code with example usage: obj.create_settings() without return types