code: def run(self, workspace):
      #
      # Get the measurements object - we put the measurements we
      # make in here
      #
      measurements = workspace.measurements
  
      #
      # We record some statistics which we will display later.
      # We format them so that Matplotlib can display them in a table.
      # The first row is a header that tells what the fields are.
      #
      statistics = [["Feature", "Mean", "Median", "SD"]]
  
      #
      # Put the statistics in the workspace display data so we
      # can get at them when we display
      #
      workspace.display_data.statistics = statistics
  
      #
      # Get the input image and object. You need to get the .value
      # because otherwise you'll get the setting object instead of
      # the string name.
      #
      input_image_name = self.input_image_name.value
      input_object_name = self.input_object_name.value
  
      ################################################################
      #
      # GETTING AN IMAGE FROM THE IMAGE SET
      #
      # Get the image set. The image set has all of the images in it.
      #
      image_set = workspace.image_set
      #
      # Get the input image object. We want a grayscale image here.
      # The image set will convert a color image to a grayscale one
      # and warn the user.
      #
      input_image = image_set.get_image(
          input_image_name, must_be_grayscale=True
      )
      #
      # Get the pixels - these are a 2-d Numpy array.
      #
      pixels = input_image.pixel_data
      #
      ###############################################################
  
      ###############################################################
      #
      # GETTING THE LABELS MATRIX FROM THE OBJECT SET
      #
      # The object set has all of the objects in it.
      #
      object_set = workspace.object_set
      #
      # Get objects from the object set. The most useful array in
      # the objects is "objects.segmented" which is a labels matrix
      # in which each pixel has an integer value.
      #
      # The value, "0", is reserved for "background" - a pixel with
      # a zero value is not in an object. Each object has an object
      # number, starting at "1" and each pixel in the object is
      # labeled with that number.
      #
      # The other useful array is "objects.small_removed_segmented" which
      # is another labels matrix. There are objects that touch the edge of
      # the image and get filtered out and there are large objects that
      # get filtered out. Modules like "IdentifySecondaryObjects" may
      # want to associate pixels near the objects in the labels matrix to
      # those objects - the large and touching objects should compete with
      # the real ones, so you should use "objects.small_removed_segmented"
      # for those cases.
      #
      objects = object_set.get_objects(input_object_name)
      labels = objects.segmented
      ###############################################################
  
      #
      # The minimum enclosing circle (MEC) is the smallest circle that
      # will fit around the object. We get the centers and radii of
      # all of the objects at once. You'll see how that lets us
      # compute the X and Y position of each pixel in a label all at
      # one go.
      #
      # First, get an array that lists the whole range of indexes in
      # the labels matrix.
      #
      indexes = objects.indices
      #
      # Then ask for the minimum_enclosing_circle for each object named
      # in those indexes. MEC returns the i and j coordinate of the center
      # and the radius of the circle and that defines the circle entirely.
      #
      (
          centers,
          radius,
      ) = centrosome.cpmorphology.minimum_enclosing_circle(
          labels, indexes
      )
      #
      # The module computes a measurement based on the image intensity
      # inside an object times a Zernike polynomial inscribed in the
      # minimum enclosing circle around the object. The details are
      # in the "measure_zernike" function. We call into the function with
      # an N and M which describe the polynomial.
      #
      for n, m in self.get_zernike_indexes():
          # Compute the zernikes for each object, returned in an array
          zr, zi = self.measure_zernike(
              pixels, labels, indexes, centers, radius, n, m
          )
  
          # Get the name of the measurement feature for this zernike
          feature = self.get_measurement_name(n, m)
  
          # Add a measurement for this kind of object
          if m != 0:
              measurements.add_measurement(
                  input_object_name, feature, zr
              )
  
              # Do the same with -m
              feature = self.get_measurement_name(n, -m)
              measurements.add_measurement(
                  input_object_name, feature, zi
              )
          else:
              # For zero, the total is the sum of real and imaginary parts
              measurements.add_measurement(
                  input_object_name, feature, zr + zi
              )
  
          # Record the statistics.
          zmean = numpy.mean(zr)
          zmedian = numpy.median(zr)
          zsd = numpy.std(zr)
          statistics.append([feature, zmean, zmedian, zsd])
  
imports: import centrosome.cpmorphology
  import centrosome.zernike
  import numpy
  import scipy.ndimage
  from cellprofiler_core.constants.measurement import COLTYPE_FLOAT
  from cellprofiler_core.module import Module
  from cellprofiler_core.setting.subscriber import ImageSubscriber, LabelSubscriber
  from cellprofiler_core.setting.text import Integer
label_desc: Use image node_id 3 for calling the MeasurementTemplate obj's underlying member method code with example usage: obj.run(workspace) without return types