示例#1
0
    def get_image_from_features(radius, feature_dictionary):
        '''Reconstruct the intensity image from the zernike features
        
        radius - the radius of the minimum enclosing circle
        
        feature_dictionary - keys are (n, m) tuples and values are the
        magnitudes.
        
        returns a greyscale image based on the feature dictionary.
        '''
        i, j = np.mgrid[-radius:(radius + 1),
                        -radius:(radius + 1)].astype(float) / radius
        mask = (i * i + j * j) <= 1

        zernike_indexes = np.array(feature_dictionary.keys())
        zernike_features = np.array(feature_dictionary.values())

        z = construct_zernike_polynomials(j,
                                          i,
                                          np.abs(zernike_indexes),
                                          mask=mask)
        zn = (2 * zernike_indexes[:, 0] + 2) / (
            (zernike_indexes[:, 1] == 0) + 1) / np.pi
        z = z * zn[np.newaxis, np.newaxis, :]
        z = z.real * (zernike_indexes[:, 1] >= 0)[np.newaxis, np.newaxis, :] +\
            z.imag * (zernike_indexes[:, 1] <= 0)[np.newaxis, np.newaxis, :]
        return np.sum(z * zernike_features[np.newaxis, np.newaxis, :], 2)
示例#2
0
 def test_00_00_zeros(self):
     """Test construct_zernike_polynomials on an empty image"""
     zi = self.make_zernike_indexes()
     zf = z.construct_zernike_polynomials(np.zeros((100, 100)),
                                          np.zeros((100, 100)), zi)
     # All zernikes with m!=0 should be zero
     m_ne_0 = np.array([i for i in range(zi.shape[0]) if zi[i, 1]])
     m_eq_0 = np.array([i for i in range(zi.shape[0]) if zi[i, 1] == 0])
     self.assertTrue(np.all(zf[:, :, m_ne_0] == 0))
     self.assertTrue(np.all(zf[:, :, m_eq_0] != 0))
     scores = z.score_zernike(zf, np.array([]), np.zeros((100, 100), int))
     self.assertEqual(np.product(scores.shape), 0)
示例#3
0
 def test_00_00_zeros(self):
     """Test construct_zernike_polynomials on an empty image"""
     zi = self.make_zernike_indexes()
     zf = z.construct_zernike_polynomials(np.zeros((100,100)),
                                          np.zeros((100,100)),
                                          zi)
     # All zernikes with m!=0 should be zero
     m_ne_0 = np.array([i for i in range(zi.shape[0]) if zi[i,1]])
     m_eq_0 = np.array([i for i in range(zi.shape[0]) if zi[i,1]==0])
     self.assertTrue(np.all(zf[:,:,m_ne_0]==0))
     self.assertTrue(np.all(zf[:,:,m_eq_0]!=0))
     scores = z.score_zernike(zf, np.array([]), np.zeros((100,100),int))
     self.assertEqual(np.product(scores.shape), 0)
示例#4
0
 def test_01_01_one_object(self):
     """Test Zernike on one single circle"""
     zi = self.make_zernike_indexes()
     y,x = np.mgrid[-50:51,-50:51].astype(float)/50
     labels = x**2+y**2 <=1
     x[labels==0]=0
     y[labels==0]=0
     zf = z.construct_zernike_polynomials(x, y, zi)
     scores = z.score_zernike(zf,[50], labels)
     # Zernike 0,0 should be 1 and others should be zero within
     # an approximation of 1/radius
     epsilon = 1.0/50.0
     self.assertTrue(abs(scores[0,0]-1) < epsilon )
     self.assertTrue(np.all(scores[0,1:] < epsilon))
示例#5
0
 def test_01_01_one_object(self):
     """Test Zernike on one single circle"""
     zi = self.make_zernike_indexes()
     y, x = np.mgrid[-50:51, -50:51].astype(float) / 50
     labels = x**2 + y**2 <= 1
     x[labels == 0] = 0
     y[labels == 0] = 0
     zf = z.construct_zernike_polynomials(x, y, zi)
     scores = z.score_zernike(zf, [50], labels)
     # Zernike 0,0 should be 1 and others should be zero within
     # an approximation of 1/radius
     epsilon = 1.0 / 50.0
     self.assertTrue(abs(scores[0, 0] - 1) < epsilon)
     self.assertTrue(np.all(scores[0, 1:] < epsilon))
示例#6
0
    def score_rotations(self, labels, n):
        """Score the result of n rotations of the label matrix then test for equality"""
        self.assertEqual(labels.shape[0], labels.shape[1],
                         "Must use square matrix for test")
        self.assertEqual(labels.shape[0] & 1, 1, "Must be odd width/height")

        zi = self.make_zernike_indexes()
        test_labels = np.zeros((labels.shape[0] * n, labels.shape[0]))
        test_x = np.zeros((labels.shape[0] * n, labels.shape[0]))
        test_y = np.zeros((labels.shape[0] * n, labels.shape[0]))
        diameter = labels.shape[0]
        radius = labels.shape[0] / 2
        y, x = np.mgrid[-radius:radius + 1,
                        -radius:radius + 1].astype(float) / radius
        anti_mask = x**2 + y**2 > 1
        x[anti_mask] = 0
        y[anti_mask] = 0
        min_pixels = 100000
        max_pixels = 0
        for i in range(0, n):
            angle = 360 * i / n  # believe it or not, in degrees!
            off_x = labels.shape[0] * i
            off_y = 0
            rotated_labels = scind.rotate(labels,
                                          angle,
                                          order=0,
                                          reshape=False)
            pixels = np.sum(rotated_labels)
            min_pixels = min(min_pixels, pixels)
            max_pixels = max(max_pixels, pixels)
            x_mask = x.copy()
            y_mask = y.copy()
            x_mask[rotated_labels == 0] = 0
            y_mask[rotated_labels == 0] = 0
            test_labels[off_x:off_x + diameter,
                        off_y:off_y + diameter] = rotated_labels * (i + 1)
            test_x[off_x:off_x + diameter, off_y:off_y + diameter] = x_mask
            test_y[off_x:off_x + diameter, off_y:off_y + diameter] = y_mask
        zf = z.construct_zernike_polynomials(test_x, test_y, zi)
        scores = z.score_zernike(zf, np.ones((n, )) * radius, test_labels)
        score_0 = scores[0]
        epsilon = 2.0 * (max(1, max_pixels - min_pixels)) / max_pixels
        for score in scores[1:, :]:
            self.assertTrue(np.all(np.abs(score - score_0) < epsilon))
示例#7
0
    def score_rotations(self,labels,n):
        """Score the result of n rotations of the label matrix then test for equality"""
        self.assertEqual(labels.shape[0],labels.shape[1],"Must use square matrix for test")
        self.assertEqual(labels.shape[0] & 1,1,"Must be odd width/height")

        zi = self.make_zernike_indexes()
        test_labels = np.zeros((labels.shape[0]*n,labels.shape[0]))
        test_x      = np.zeros((labels.shape[0]*n,labels.shape[0]))
        test_y      = np.zeros((labels.shape[0]*n,labels.shape[0]))
        diameter = labels.shape[0]
        radius = labels.shape[0]/2
        y,x=np.mgrid[-radius:radius+1,-radius:radius+1].astype(float)/radius
        anti_mask = x**2+y**2 > 1
        x[anti_mask] = 0
        y[anti_mask] = 0 
        min_pixels = 100000
        max_pixels = 0
        for i in range(0,n):
            angle = 360*i / n # believe it or not, in degrees!
            off_x = labels.shape[0]*i
            off_y = 0
            rotated_labels = scind.rotate(labels,angle,order=0,reshape=False)
            pixels = np.sum(rotated_labels)
            min_pixels = min(min_pixels,pixels)
            max_pixels = max(max_pixels,pixels)
            x_mask = x.copy()
            y_mask = y.copy()
            x_mask[rotated_labels==0]=0
            y_mask[rotated_labels==0]=0
            test_labels[off_x:off_x+diameter,
                        off_y:off_y+diameter] = rotated_labels * (i+1)
            test_x[off_x:off_x+diameter,
                        off_y:off_y+diameter] = x_mask 
            test_y[off_x:off_x+diameter,
                        off_y:off_y+diameter] = y_mask 
        zf = z.construct_zernike_polynomials(test_x,test_y,zi)
        scores = z.score_zernike(zf,np.ones((n,))*radius,test_labels)
        score_0=scores[0]
        epsilon = 2.0*(max(1,max_pixels-min_pixels))/max_pixels
        for score in scores[1:,:]:
            self.assertTrue(np.all(np.abs(score-score_0)<epsilon))
 def get_image_from_features(radius, feature_dictionary):
     '''Reconstruct the intensity image from the zernike features
     
     radius - the radius of the minimum enclosing circle
     
     feature_dictionary - keys are (n, m) tuples and values are the
     magnitudes.
     
     returns a greyscale image based on the feature dictionary.
     '''
     i, j = np.mgrid[-radius:(radius+1), -radius:(radius+1)].astype(float) / radius
     mask = (i*i + j*j) <= 1
     
     zernike_indexes = np.array(feature_dictionary.keys())
     zernike_features = np.array(feature_dictionary.values())
     
     z = construct_zernike_polynomials(
         j, i, np.abs(zernike_indexes), mask=mask)
     zn = (2*zernike_indexes[:, 0] + 2) / ((zernike_indexes[:, 1] == 0) + 1) / np.pi
     z = z * zn[np.newaxis, np.newaxis, :]
     z = z.real * (zernike_indexes[:, 1] >= 0)[np.newaxis, np.newaxis, :] +\
         z.imag * (zernike_indexes[:, 1] <= 0)[np.newaxis, np.newaxis, :]
     return np.sum(z * zernike_features[np.newaxis, np.newaxis, :], 2)
示例#9
0
    def score_scales(self,labels,n):
        """Score the result of n 3x scalings of the label matrix then test for equality"""
        self.assertEqual(labels.shape[0],labels.shape[1],"Must use square matrix for test")
        self.assertEqual(labels.shape[0] & 1,1,"Must be odd width/height")

        width = labels.shape[0] * 3**n
        height = width * (n+1)
        zi = self.make_zernike_indexes()
        test_labels = np.zeros((height,width))
        test_x      = np.zeros((height,width))
        test_y      = np.zeros((height,width))
        radii = []
        for i in range(n+1):
            scaled_labels = scind.zoom(labels,3**i,order=0)
            diameter = scaled_labels.shape[0]
            radius = scaled_labels.shape[0]/2
            radii.append(radius)
            y,x=np.mgrid[-radius:radius+1,-radius:radius+1].astype(float)/radius
            anti_mask = x**2+y**2 > 1
            x[anti_mask] = 0
            y[anti_mask] = 0 
            off_x = width*i
            off_y = 0
            x[scaled_labels==0]=0
            y[scaled_labels==0]=0
            test_labels[off_x:off_x+diameter,
                        off_y:off_y+diameter] = scaled_labels * (i+1)
            test_x[off_x:off_x+diameter,
                        off_y:off_y+diameter] = x 
            test_y[off_x:off_x+diameter,
                        off_y:off_y+diameter] = y 
        zf = z.construct_zernike_polynomials(test_x,test_y,zi)
        scores = z.score_zernike(zf,np.array(radii),test_labels)
        score_0=scores[0]
        epsilon = .02
        for score in scores[1:,:]:
            self.assertTrue(np.all(np.abs(score-score_0)<epsilon))
示例#10
0
    def score_scales(self, labels, n):
        """Score the result of n 3x scalings of the label matrix then test for equality"""
        self.assertEqual(labels.shape[0], labels.shape[1],
                         "Must use square matrix for test")
        self.assertEqual(labels.shape[0] & 1, 1, "Must be odd width/height")

        width = labels.shape[0] * 3**n
        height = width * (n + 1)
        zi = self.make_zernike_indexes()
        test_labels = np.zeros((height, width))
        test_x = np.zeros((height, width))
        test_y = np.zeros((height, width))
        radii = []
        for i in range(n + 1):
            scaled_labels = scind.zoom(labels, 3**i, order=0)
            diameter = scaled_labels.shape[0]
            radius = scaled_labels.shape[0] / 2
            radii.append(radius)
            y, x = np.mgrid[-radius:radius + 1,
                            -radius:radius + 1].astype(float) / radius
            anti_mask = x**2 + y**2 > 1
            x[anti_mask] = 0
            y[anti_mask] = 0
            off_x = width * i
            off_y = 0
            x[scaled_labels == 0] = 0
            y[scaled_labels == 0] = 0
            test_labels[off_x:off_x + diameter,
                        off_y:off_y + diameter] = scaled_labels * (i + 1)
            test_x[off_x:off_x + diameter, off_y:off_y + diameter] = x
            test_y[off_x:off_x + diameter, off_y:off_y + diameter] = y
        zf = z.construct_zernike_polynomials(test_x, test_y, zi)
        scores = z.score_zernike(zf, np.array(radii), test_labels)
        score_0 = scores[0]
        epsilon = .02
        for score in scores[1:, :]:
            self.assertTrue(np.all(np.abs(score - score_0) < epsilon))
 def measure_zernike(self, pixels, labels, indexes, centers, radius, 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
     indexes - the label #s in the image
     centers - the centers of the minimum enclosing circle for each object
     radius - the radius of the minimum enclosing circle for each object
     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.
     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 ]]), labels > 0)
     #
     # For historical reasons, CellProfiler didn't multiply by the per/zernike
     # normalizing factor: 2*n + 2 / E / pi where E is 2 if m is zero and 1
     # if m is one. We do it here to aid with the reconstruction
     #
     zernike_polynomial *= (2*n + 2) / (2 if m == 0 else 1) / np.pi
     #
     # Multiply the Zernike polynomial by the image to dissect
     # the image by the Zernike basis set.
     #
     output_pixels = pixels * zernike_polynomial[:,:,0]
     #
     # 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
     #
     zr = fix(scind.sum(output_pixels.real, labels, indexes))
     zi = fix(scind.sum(output_pixels.imag, labels, indexes))
     #
     # And we're done! Did you like it? Did you get it?
     #
     return zr, zi
示例#12
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
示例#13
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
 def measure_zernike(self, pixels, labels, indexes, centers, radius, 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
     indexes - the label #s in the image
     centers - the centers of the minimum enclosing circle for each object
     radius - the radius of the minimum enclosing circle for each object
     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.
     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 ]]), labels > 0)
     #
     # For historical reasons, CellProfiler didn't multiply by the per/zernike
     # normalizing factor: 2*n + 2 / E / pi where E is 2 if m is zero and 1
     # if m is one. We do it here to aid with the reconstruction
     #
     zernike_polynomial *= (2*n + 2) / (2 if m == 0 else 1) / np.pi
     #
     # Multiply the Zernike polynomial by the image to dissect
     # the image by the Zernike basis set.
     #
     output_pixels = pixels * zernike_polynomial[:,:,0]
     #
     # 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
     #
     zr = fix(scind.sum(output_pixels.real, labels, indexes))
     zi = fix(scind.sum(output_pixels.imag, labels, indexes))
     #
     # And we're done! Did you like it? Did you get it?
     #
     return zr, zi