def calculate_zernikes(self, workspace): zernike_indexes = cpmz.get_zernike_indexes(self.zernike_degree.value + 1) meas = workspace.measurements for o in self.objects: object_name = o.object_name.value objects = workspace.object_set.get_objects(object_name) # # First, get a table of centers and radii of minimum enclosing # circles per object # ij = np.zeros((objects.count + 1, 2)) r = np.zeros(objects.count + 1) for labels, indexes in objects.get_labels(): ij_, r_ = minimum_enclosing_circle(labels, indexes) ij[indexes] = ij_ r[indexes] = r_ # # Then compute x and y, the position of each labeled pixel # within a unit circle around the object # ijv = objects.ijv l = ijv[:, 2] yx = (ijv[:, :2] - ij[l, :]) / r[l, np.newaxis] z = cpmz.construct_zernike_polynomials( yx[:, 1], yx[:, 0], zernike_indexes) for image_group in self.images: image_name = image_group.image_name.value image = workspace.image_set.get_image( image_name, must_be_grayscale=True) pixels = image.pixel_data mask = (ijv[:, 0] < pixels.shape[0]) & \ (ijv[:, 1] < pixels.shape[1]) mask[mask] = image.mask[ijv[mask, 0], ijv[mask, 1]] yx_ = yx[mask, :] l_ = l[mask] z_ = z[mask, :] if len(l_) == 0: for i, (n, m) in enumerate(zernike_indexes): ftr = self.get_zernike_magnitude_name(image_name, n, m) meas[object_name, ftr] = np.zeros(0) if self.wants_zernikes == Z_MAGNITUDES_AND_PHASE: ftr = self.get_zernike_phase_name(image_name, n, m) meas[object_name, ftr] = np.zeros(0) continue areas = scind.sum( np.ones(l_.shape, int), labels=l_, index=objects.indices) for i, (n, m) in enumerate(zernike_indexes): vr = scind.sum( pixels[ijv[mask, 0], ijv[mask, 1]] * z_[:, i].real, labels=l_, index=objects.indices) vi = scind.sum( pixels[ijv[mask, 0], ijv[mask, 1]] * z_[:, i].imag, labels=l_, index=objects.indices) magnitude = np.sqrt(vr * vr + vi * vi) / areas ftr = self.get_zernike_magnitude_name(image_name, n, m) meas[object_name, ftr] = magnitude if self.wants_zernikes == Z_MAGNITUDES_AND_PHASE: phase = np.arctan2(vr, vi) ftr = self.get_zernike_phase_name(image_name, n, m) meas[object_name, ftr] = phase
def get_measurement_columns(self, pipeline): columns = [] for image in self.images: image_name = image.image_name.value for o in self.objects: object_name = o.object_name.value for bin_count_obj in self.bin_counts: bin_count = bin_count_obj.bin_count.value wants_scaling = bin_count_obj.wants_scaled.value for feature, ofeature in ( (MF_FRAC_AT_D, OF_FRAC_AT_D), (MF_MEAN_FRAC, OF_MEAN_FRAC), (MF_RADIAL_CV, OF_RADIAL_CV)): for bin in range(1, bin_count + 1): columns.append( (object_name, feature % (image_name, bin, bin_count), cpmeas.COLTYPE_FLOAT)) if not wants_scaling: columns.append( (object_name, ofeature % image.image_name.value, cpmeas.COLTYPE_FLOAT)) if self.wants_zernikes != Z_NONE: name_fns = [self.get_zernike_magnitude_name] if self.wants_zernikes == Z_MAGNITUDES_AND_PHASE: name_fns.append(self.get_zernike_phase_name) max_n = self.zernike_degree.value for name_fn in name_fns: for n, m in cpmz.get_zernike_indexes(max_n + 1): ftr = name_fn(image_name, n, m) columns.append( (object_name, ftr, cpmeas.COLTYPE_FLOAT)) return columns
def test_01_01_test_3(self): expected = np.array(((0, 0), (1, 1), (2, 0), (2, 2), (3, 1), (3, 3)), int) result = np.array(z.get_zernike_indexes(4)) order = np.lexsort((result[:, 1], result[:, 0])) result = result[order] self.assertTrue(np.all(expected == result))
def get_measurement_scales(self, pipeline, object_name, category, feature, image_name): if image_name in self.get_measurement_images(pipeline, object_name, category, feature): if feature in (FF_ZERNIKE_MAGNITUDE, FF_ZERNIKE_PHASE): n_max = self.zernike_degree.value result = ["%d_%d" % (n, m) for n, m in cpmz.get_zernike_indexes(n_max + 1)] else: result = [FF_SCALE % (bin, bin_count.bin_count.value) for bin_count in self.bin_counts for bin in range(1, bin_count.bin_count.value + 1)] if any([not bin_count.wants_scaled.value for bin_count in self.bin_counts]): result += [FF_OVERFLOW] return result return []
def get_zernike_indexes(self, wants_negative=False): '''Get an N x 2 numpy array containing the M and N Zernike degrees Use the radial_degree setting to determine which Zernikes to do. wants_negative - if True, return both positive and negative M, if false return only positive ''' zi = get_zernike_indexes(self.radial_degree.value + 1) if wants_negative: # # np.vstack means concatenate rows of two 2d arrays. # The multiplication by [1, -1] negates every m, but preserves n. # zi[zi[:, 1] != 0] picks out only elements with m not equal to zero. # zi = np.vstack([zi, zi[zi[:, 1] != 0] * np.array([1, -1])]) # # Sort by azimuth degree and radial degree so they are ordered # reasonably # order = np.lexsort((zi[:, 1], zi[:, 0])) zi = zi[order, :] return zi
def get_zernike_indexes(self, wants_negative = False): '''Get an N x 2 numpy array containing the M and N Zernike degrees Use the radial_degree setting to determine which Zernikes to do. wants_negative - if True, return both positive and negative M, if false return only positive ''' zi = get_zernike_indexes(self.radial_degree.value + 1) if wants_negative: # # np.vstack means concatenate rows of two 2d arrays. # The multiplication by [1, -1] negates every m, but preserves n. # zi[zi[:, 1] != 0] picks out only elements with m not equal to zero. # zi = np.vstack([zi, zi[zi[:, 1] != 0]*np.array([1, -1])]) # # Sort by azimuth degree and radial degree so they are ordered # reasonably # order = np.lexsort((zi[:, 1], zi[:, 0])) zi = zi[order, :] return zi
def get_zernike_numbers(self): """The Zernike numbers measured by this module""" if self.calculate_zernikes.value: return cpmz.get_zernike_indexes(ZERNIKE_N + 1) else: return []
def test_01_01_test_3(self): expected = np.array(((0,0),(1,1),(2,0),(2,2),(3,1),(3,3)),int) result = np.array(z.get_zernike_indexes(4)) order = np.lexsort((result[:,1],result[:,0])) result = result[order] self.assertTrue(np.all(expected == result))
def get_zernike_numbers(self): """The Zernike numbers measured by this module""" if self.calculate_zernikes.value: return cpmz.get_zernike_indexes(ZERNIKE_N+1) else: return []