def test_00_00_oh_so_empty(self): ind = I.Indexes([[]]) self.assertEqual(ind.length, 0) self.assertEqual(len(ind.fwd_idx), 0) self.assertEqual(len(ind.rev_idx), 0) self.assertEqual(tuple(ind.idx.shape), (1, 0)) np.testing.assert_array_equal([[]], ind.counts)
def test_00_02_other_ways_to_be_empty(self): ind = I.Indexes([(0, 1), (1, 0)]) self.assertEqual(ind.length, 0) self.assertEqual(len(ind.fwd_idx), 2) self.assertTrue(np.all(ind.fwd_idx == 0)) self.assertEqual(len(ind.rev_idx), 0) self.assertEqual(tuple(ind.idx.shape), (2, 0))
def test_01_01_one_object_1_subobject(self): ind = I.Indexes([[1]]) self.assertEqual(ind.length, 1) self.assertEqual(len(ind.fwd_idx), 1) self.assertEqual(ind.fwd_idx[0], 0) self.assertEqual(len(ind.rev_idx), 1) self.assertEqual(ind.rev_idx, 0) self.assertEqual(tuple(ind.idx.shape), (1, 1)) self.assertEqual(ind.idx[0, 0], 0)
def test_00_01_all_are_empty(self): counts = [[0]] ind = I.Indexes(counts) self.assertEqual(ind.length, 0) self.assertEqual(len(ind.fwd_idx), 1) self.assertEqual(ind.fwd_idx[0], 0) self.assertEqual(len(ind.rev_idx), 0) self.assertEqual(tuple(ind.idx.shape), (1, 0)) np.testing.assert_array_equal(counts, ind.counts)
def test_01_03_one_object_NxM(self): counts = np.array([[4], [3]]) hits = np.zeros(counts[:, 0], int) ind = I.Indexes(counts) self.assertEqual(ind.length, np.prod(counts)) self.assertEqual(len(ind.fwd_idx), 1) self.assertEqual(ind.fwd_idx[0], 0) self.assertEqual(len(ind.rev_idx), ind.length) np.testing.assert_array_equal(ind.rev_idx, 0) self.assertEqual(tuple(ind.idx.shape), (2, ind.length)) hits[ind.idx[0], ind.idx[1]] = np.arange(ind.length) + 1 self.assertEqual(len(np.unique(hits.ravel())), ind.length)
def test_02_02_multiple_objects_and_one_is_0x0(self): counts = np.array([[4, 2, 0, 3], [3, 6, 4, 5]]) ind = I.Indexes(counts) self.assertEqual(ind.length, np.sum(np.prod(counts, 0))) self.assertEqual(len(ind.fwd_idx), counts.shape[1]) np.testing.assert_array_equal(ind.fwd_idx, [0, 12, 24, 24]) self.assertEqual(len(ind.rev_idx), ind.length) start = 0 for i, count in enumerate(ind.counts.transpose()): if np.prod(count) == 0: continue hits = np.zeros(count) n = np.prod(count) hits[ind.idx[0, start:(start + n)], ind.idx[1, start:(start + n)]] = np.arange(np.prod(count)) self.assertEqual(len(np.unique(hits.ravel())), n) start += n
def test_02_01_two_objects_NxM(self): counts = [[4, 2], [3, 6]] c0 = counts[0][0] * counts[1][0] ind = I.Indexes(counts) self.assertEqual(ind.length, np.sum(np.prod(counts, 0))) self.assertEqual(len(ind.fwd_idx), 2) self.assertEqual(ind.fwd_idx[0], 0) self.assertEqual(ind.fwd_idx[1], c0) self.assertEqual(len(ind.rev_idx), ind.length) np.testing.assert_array_equal(ind.rev_idx[:c0], 0) np.testing.assert_array_equal(ind.rev_idx[c0:], 1) start = 0 for i, count in enumerate(ind.counts.transpose()): hits = np.zeros(count) n = np.prod(count) hits[ind.idx[0, start:(start + n)], ind.idx[1, start:(start + n)]] = np.arange(np.prod(count)) self.assertEqual(len(np.unique(hits.ravel())), n) start += n
def test_02_03_one_at_end(self): ind = I.Indexes(np.array([[0, 0, 1]])) pass
def test_02_05_none_at_start_and_one(self): ind = I.Indexes(np.array([[0, 2]])) np.testing.assert_array_equal(ind.rev_idx, np.array([1, 1]))
def measure_worms(self, workspace, labels, nworms, width): m = workspace.measurements assert isinstance(m, cpmeas.Measurements) object_name = self.straightened_objects_name.value nbins_vertical = self.number_of_segments.value nbins_horizontal = self.number_of_stripes.value params = self.read_params(workspace) if nworms == 0: # # # # # # # # # # # # # # # # # # # # # # # # Record measurements if no worms # # # # # # # # # # # # # # # # # # # # # # # for ftr in (FTR_MEAN_INTENSITY, FTR_STD_INTENSITY): for group in self.images: image_name = group.straightened_image_name.value if nbins_vertical > 1: for b in range(nbins_vertical): measurement = "_".join( (C_WORM, ftr, image_name, self.get_scale_name(None, b))) m.add_measurement(object_name, measurement, np.zeros((0))) if nbins_horizontal > 1: for b in range(nbins_horizontal): measurement = "_".join( (C_WORM, ftr, image_name, self.get_scale_name(b, None))) m.add_measurement(object_name, measurement, np.zeros((0))) if nbins_vertical > 1: for v in range(nbins_vertical): for h in range(nbins_horizontal): measurement = "_".join( (C_WORM, ftr, image_name, self.get_scale_name(h, v))) m.add_measurement(object_name, measurement, np.zeros((0))) else: # # Find the minimum and maximum i coordinate of each worm # object_set = workspace.object_set assert isinstance(object_set, cpo.ObjectSet) orig_objects = object_set.get_objects(self.objects_name.value) i,j = np.mgrid[0:labels.shape[0], 0:labels.shape[1]] min_i, max_i, _, _ = extrema(i, labels, orig_objects.indices) min_i = np.hstack(([0], min_i)) max_i = np.hstack(([labels.shape[0]], max_i)) + 1 heights = max_i - min_i # # # # # # # # # # # # # # # # # # # Create up to 3 spaces which represent the gridding # of the worm and create a coordinate mapping into # this gridding for each straightened worm # # # # # # # # # # # # # # # # # # griddings = [] if nbins_vertical > 1: scales = np.array([self.get_scale_name(None, b) for b in range(nbins_vertical)]) scales.shape = (nbins_vertical, 1) griddings += [(nbins_vertical, 1, scales)] if nbins_horizontal > 1: scales = np.array([self.get_scale_name(b, None) for b in range(nbins_horizontal)]) scales.shape = (1, nbins_horizontal) griddings += [(1, nbins_horizontal, scales)] if nbins_vertical > 1: scales = np.array([ [self.get_scale_name(h,v) for h in range(nbins_horizontal)] for v in range(nbins_vertical)]) griddings += [(nbins_vertical, nbins_horizontal, scales)] for i_dim, j_dim, scales in griddings: # # # # # # # # # # # # # # # # # # # # # # # # Start out mapping every point to a 1x1 space # # # # # # # # # # # # # # # # # # # # # # # labels1 = labels.copy() i,j = np.mgrid[0:labels.shape[0], 0:labels.shape[1]] i_frac = (i - min_i[labels]).astype(float) / heights[labels] i_frac_end = i_frac + 1.0 / heights[labels].astype(float) i_radius_frac = (i - min_i[labels]).astype(float) / (heights[labels] - 1) labels1[(i_frac >= 1) | (i_frac_end <= 0)] = 0 # # # # # # # # # # # # # # # # # # # # # # # # Map the horizontal onto the grid. # # # # # # # # # # # # # # # # # # # # # # # radii = np.array(params.radii_from_training) # # For each pixel in the image, find the center of its worm # in the j direction (the width) # j_center = int(width / 2) + width * (labels-1) # # Find which segment (from the training set) per pixel in # a fractional form # i_index = i_radius_frac * (len(radii) - 1) # # Interpolate # i_index_frac = i_index - np.floor(i_index) i_index_frac[i_index >= len(radii) - 1] = 1 i_index = np.minimum(i_index.astype(int), len(radii) - 2) r = np.ceil((radii[i_index] * (1 - i_index_frac) + radii[i_index+1] * i_index_frac)) # # Map the worm width into the space 0-1 # j_frac = (j - j_center + r) / (r * 2 + 1) j_frac_end = j_frac + 1.0 / (r * 2 + 1) labels1[(j_frac >= 1) | (j_frac_end <= 0)] = 0 # # Map the worms onto the gridding. # i_mapping = np.maximum(i_frac * i_dim, 0) i_mapping_end = np.minimum(i_frac_end * i_dim, i_dim) j_mapping = np.maximum(j_frac * j_dim, 0) j_mapping_end = np.minimum(j_frac_end * j_dim, j_dim) i_mapping = i_mapping[labels1 > 0] i_mapping_end = i_mapping_end[labels1 > 0] j_mapping = j_mapping[labels1 > 0] j_mapping_end = j_mapping_end[labels1 > 0] labels_1d = labels1[labels1 > 0] i = i[labels1 > 0] j = j[labels1 > 0] # # There are easy cases and hard cases. The easy cases are # when a pixel in the input space wholly falls in the # output space. # easy = ((i_mapping.astype(int) == i_mapping_end.astype(int)) & (j_mapping.astype(int) == j_mapping_end.astype(int))) i_src = i[easy] j_src = j[easy] i_dest = i_mapping[easy].astype(int) j_dest = j_mapping[easy].astype(int) weight = np.ones(i_src.shape) labels_src = labels_1d[easy] # # The hard cases start in one pixel in the binning space, # possibly continue through one or more intermediate pixels # in horribly degenerate cases and end in a final # partial pixel. # # More horribly, a pixel in the straightened space # might span two or more in the binning space in the I # direction, the J direction or both. # if not np.all(easy): i = i[~ easy] j = j[~ easy] i_mapping = i_mapping[~ easy] j_mapping = j_mapping[~ easy] i_mapping_end = i_mapping_end[~ easy] j_mapping_end = j_mapping_end[~ easy] labels_1d = labels_1d[~ easy] # # A pixel in the straightened space can be wholly within # a pixel in the bin space, it can straddle two pixels # or straddle two and span one or more. It can do different # things in the I and J direction. # # --- The number of pixels wholly spanned --- # i_span = np.maximum(np.floor(i_mapping_end) - np.ceil(i_mapping), 0) j_span = np.maximum(np.floor(j_mapping_end) - np.ceil(j_mapping), 0) # # --- The fraction of a pixel covered by the lower straddle # i_low_straddle = i_mapping.astype(int) + 1 - i_mapping j_low_straddle = j_mapping.astype(int) + 1 - j_mapping # # Segments that start at exact pixel boundaries and span # whole pixels have low fractions that are 1. The span # length needs to have these subtracted from it. # i_span[i_low_straddle == 1] -= 1 j_span[j_low_straddle == 1] -= 1 # # --- the fraction covered by the upper straddle # i_high_straddle = i_mapping_end - i_mapping_end.astype(int) j_high_straddle = j_mapping_end - j_mapping_end.astype(int) # # --- the total distance across the binning space # i_total = i_low_straddle + i_span + i_high_straddle j_total = j_low_straddle + j_span + j_high_straddle # # --- The fraction in the lower straddle # i_low_frac = i_low_straddle / i_total j_low_frac = j_low_straddle / j_total # # --- The fraction in the upper straddle # i_high_frac = i_high_straddle / i_total j_high_frac = j_high_straddle / j_total # # later on, the high fraction will overwrite the low fraction # for i and j hitting on a single pixel in the bin space # i_high_frac[(i_mapping.astype(int) == i_mapping_end.astype(int))] = 1 j_high_frac[(j_mapping.astype(int) == j_mapping_end.astype(int))] = 1 # # --- The fraction in spans # i_span_frac = i_span / i_total j_span_frac = j_span / j_total # # --- The number of bins touched by each pixel # i_count = (np.ceil(i_mapping_end) - np.floor(i_mapping)).astype(int) j_count = (np.ceil(j_mapping_end) - np.floor(j_mapping)).astype(int) # # --- For I and J, calculate the weights for each pixel # along each axis. # i_idx = INDEX.Indexes([i_count]) j_idx = INDEX.Indexes([j_count]) i_weights = i_span_frac[i_idx.rev_idx] j_weights = j_span_frac[j_idx.rev_idx] i_weights[i_idx.fwd_idx] = i_low_frac j_weights[j_idx.fwd_idx] = j_low_frac mask = i_high_frac > 0 i_weights[i_idx.fwd_idx[mask]+ i_count[mask] - 1] = \ i_high_frac[mask] mask = j_high_frac > 0 j_weights[j_idx.fwd_idx[mask] + j_count[mask] - 1] = \ j_high_frac[mask] # # Get indexes for the 2-d array, i_count x j_count # idx = INDEX.Indexes([i_count, j_count]) # # The coordinates in the straightened space # i_src_hard = i[idx.rev_idx] j_src_hard = j[idx.rev_idx] # # The coordinates in the bin space # i_dest_hard = i_mapping[idx.rev_idx].astype(int) + idx.idx[0] j_dest_hard = j_mapping[idx.rev_idx].astype(int) + idx.idx[1] # # The weights are the i-weight times the j-weight # # The i-weight can be found at the nth index of # i_weights relative to the start of the i_weights # for the pixel in the straightened space. # # The start is found at i_idx.fwd_idx[idx.rev_idx] # the I offset is found at idx.idx[0] # # Similarly for J. # weight_hard = (i_weights[i_idx.fwd_idx[idx.rev_idx] + idx.idx[0]] * j_weights[j_idx.fwd_idx[idx.rev_idx] + idx.idx[1]]) i_src = np.hstack((i_src, i_src_hard)) j_src = np.hstack((j_src, j_src_hard)) i_dest = np.hstack((i_dest, i_dest_hard)) j_dest = np.hstack((j_dest, j_dest_hard)) weight = np.hstack((weight, weight_hard)) labels_src = np.hstack((labels_src, labels_1d[idx.rev_idx])) self.measure_bins(workspace, i_src, j_src, i_dest, j_dest, weight, labels_src, scales, nworms)