def run(self, workspace):
     #
     # Get the measurements object - we put the measurements we
     # make in here
     #
     meas = workspace.measurements
     assert isinstance(meas, cpmeas.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
     assert isinstance(object_set, cpo.ObjectSet)
     #
     # 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.get_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 = 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:
             meas.add_measurement(input_object_name, feature, zr)
             #
             # Do the same with -m
             #
             feature = self.get_measurement_name(n, -m)
             meas.add_measurement(input_object_name, feature, zi)
         else:
             # For zero, the total is the sum of real and imaginary parts
             meas.add_measurement(input_object_name, feature, zr + zi)
         #
         # Record the statistics. 
         #
         zmean = np.mean(zr)
         zmedian = np.median(zr)
         zsd = np.std(zr)
         statistics.append( [ feature, zmean, zmedian, zsd ] )
Exemplo n.º 2
0
 def measure_zernike(self, pixels, labels, n, m):
     # I'll put some documentation in here to explain what it does.
     # If someone ever wants to call it, their editor might display
     # the documentation.
     '''Measure the intensity of the image with Zernike (N, M)
     
     pixels - the intensity image to be measured
     labels - the labels matrix that labels each object with an integer
     n, m - the Zernike coefficients.
     
     See http://en.wikipedia.org/wiki/Zernike_polynomials for an
     explanation of the Zernike polynomials
     '''
     #
     # The strategy here is to operate on the whole array instead
     # of operating on one object at a time. The most important thing
     # is to avoid having to run the Python interpreter once per pixel
     # in the image and the second most important is to avoid running
     # it per object in case there are hundreds of objects.
     #
     # We play lots of indexing tricks here to operate on the whole image.
     # I'll try to explain some - hopefully, you can reuse.
     #
     # You could move the calculation of the minimum enclosing circle
     # outside of this function. The function gets called more than
     # 10 times, so the same calculation is performed 10 times.
     # It would make the code a little more confusing, so I'm leaving
     # it as-is.
     ###########################################
     #
     # 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 = np.arange(1, np.max(labels) + 1, dtype=np.int32)
     #
     # 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 = minimum_enclosing_circle(labels, indexes)
     center_x = centers[:, 1]
     center_y = centers[:, 0]
     #
     # Make up fake values for 0 (the background). This lets us do our
     # indexing tricks. Really, we're going to ignore the background,
     # but we want to do the indexing without ignoring the background
     # because that's easier.
     #
     center_x = np.hstack([[0], center_x])
     center_y = np.hstack([[0], center_y])
     radius = np.hstack([[1], radius])
     #
     # Now get one array that's the y coordinate of each pixel and one
     # that's the x coordinate. This might look stupid and wasteful,
     # but these "arrays" are never actually realized and made into
     # real memory.
     #
     y, x = np.mgrid[0:labels.shape[0], 0:labels.shape[1]]
     #
     # Get the x and y coordinates relative to the object centers.
     # This uses Numpy broadcasting. For each pixel, we use the
     # value in the labels matrix as an index into the appropriate
     # one-dimensional array. So we get the value for that object.
     #
     y -= center_y[labels]
     x -= center_x[labels]
     #
     # Zernikes take x and y values from zero to one. We scale the
     # integer coordinate values by dividing them by the radius of
     # the circle. Again, we use the indexing trick to look up the
     # values for each object.
     #
     y = y.astype(float) / radius[labels]
     x = x.astype(float) / radius[labels]
     #
     #################################
     #
     # ZERNIKE POLYNOMIALS
     #
     # Now we can get Zernike polynomials per-pixel where each pixel
     # value is calculated according to its object's MEC.
     #
     # We use a mask of all of the non-zero labels so the calculation
     # runs a little faster.
     #
     zernike_polynomial = construct_zernike_polynomials(
         x, y, np.array([[n, m]]))
     #
     # Multiply the Zernike polynomial by the image to dissect
     # the image by the Zernike basis set.
     #
     output_pixels = pixels * zernike_polynomial[:, :, 0]
     #
     # The zernike polynomial is a complex number. We get a power
     # spectrum here to combine the real and imaginary parts
     #
     output_pixels = np.sqrt(output_pixels * output_pixels.conjugate())
     #
     # Finally, we use Scipy to sum the intensities. Scipy has different
     # versions with different quirks. The "fix" function takes all
     # of that into account.
     #
     # The sum function calculates the sum of the pixel values for
     # each pixel in an object, using the labels matrix to name
     # the pixels in an object
     #
     result = fix(scind.sum(output_pixels.real, labels, indexes))
     #
     # And we're done! Did you like it? Did you get it?
     #
     return result
Exemplo n.º 3
0
 def measure_zernike(self, pixels, labels, n, m):
     # I'll put some documentation in here to explain what it does.
     # If someone ever wants to call it, their editor might display
     # the documentation.
     '''Measure the intensity of the image with Zernike (N, M)
     
     pixels - the intensity image to be measured
     labels - the labels matrix that labels each object with an integer
     n, m - the Zernike coefficients.
     
     See http://en.wikipedia.org/wiki/Zernike_polynomials for an
     explanation of the Zernike polynomials
     '''
     #
     # The strategy here is to operate on the whole array instead
     # of operating on one object at a time. The most important thing
     # is to avoid having to run the Python interpreter once per pixel
     # in the image and the second most important is to avoid running
     # it per object in case there are hundreds of objects.
     #
     # We play lots of indexing tricks here to operate on the whole image.
     # I'll try to explain some - hopefully, you can reuse.
     #
     # You could move the calculation of the minimum enclosing circle
     # outside of this function. The function gets called more than
     # 10 times, so the same calculation is performed 10 times.
     # It would make the code a little more confusing, so I'm leaving
     # it as-is.
     ###########################################
     #
     # 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 = np.arange(1, np.max(labels)+1,dtype=np.int32)
     #
     # 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 = minimum_enclosing_circle(labels, indexes)
     center_x = centers[:, 1]
     center_y = centers[:, 0]
     #
     # Make up fake values for 0 (the background). This lets us do our
     # indexing tricks. Really, we're going to ignore the background,
     # but we want to do the indexing without ignoring the background
     # because that's easier.
     #
     center_x = np.hstack([[0], center_x])
     center_y = np.hstack([[0], center_y])
     radius = np.hstack([[1], radius])
     #
     # Now get one array that's the y coordinate of each pixel and one
     # that's the x coordinate. This might look stupid and wasteful,
     # but these "arrays" are never actually realized and made into
     # real memory.
     #
     y, x = np.mgrid[0:labels.shape[0], 0:labels.shape[1]]
     #
     # Get the x and y coordinates relative to the object centers.
     # This uses Numpy broadcasting. For each pixel, we use the
     # value in the labels matrix as an index into the appropriate
     # one-dimensional array. So we get the value for that object.
     #
     y -= center_y[labels]
     x -= center_x[labels]
     #
     # Zernikes take x and y values from zero to one. We scale the
     # integer coordinate values by dividing them by the radius of
     # the circle. Again, we use the indexing trick to look up the
     # values for each object.
     #
     y = y.astype(float) / radius[labels]
     x = x.astype(float) / radius[labels]
     #
     #################################
     #
     # ZERNIKE POLYNOMIALS
     #
     # Now we can get Zernike polynomials per-pixel where each pixel
     # value is calculated according to its object's MEC.
     #
     # We use a mask of all of the non-zero labels so the calculation
     # runs a little faster.
     #
     zernike_polynomial = construct_zernike_polynomials(
         x, y, np.array([ [ n, m ]]))
     #
     # Multiply the Zernike polynomial by the image to dissect
     # the image by the Zernike basis set.
     #
     output_pixels = pixels * zernike_polynomial[:,:,0]
     #
     # The zernike polynomial is a complex number. We get a power
     # spectrum here to combine the real and imaginary parts
     #
     output_pixels = np.sqrt(output_pixels * output_pixels.conjugate())
     #
     # Finally, we use Scipy to sum the intensities. Scipy has different
     # versions with different quirks. The "fix" function takes all
     # of that into account.
     #
     # The sum function calculates the sum of the pixel values for
     # each pixel in an object, using the labels matrix to name
     # the pixels in an object
     #
     result = fix(scind.sum(output_pixels.real, labels, indexes))
     #
     # And we're done! Did you like it? Did you get it?
     #
     return result
Exemplo n.º 4
0
 def run(self, workspace):
     #
     # Get the measurements object - we put the measurements we
     # make in here
     #
     meas = workspace.measurements
     assert isinstance(meas, cpmeas.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
     assert isinstance(object_set, cpo.ObjectSet)
     #
     # 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.get_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 = 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:
             meas.add_measurement(input_object_name, feature, zr)
             #
             # Do the same with -m
             #
             feature = self.get_measurement_name(n, -m)
             meas.add_measurement(input_object_name, feature, zi)
         else:
             # For zero, the total is the sum of real and imaginary parts
             meas.add_measurement(input_object_name, feature, zr + zi)
         #
         # Record the statistics. 
         #
         zmean = np.mean(zr)
         zmedian = np.median(zr)
         zsd = np.std(zr)
         statistics.append( [ feature, zmean, zmedian, zsd ] )