def test_02_02_one_worm(self):
     '''Find a single worm'''
     image = np.zeros((20, 20), bool)
     index, count, i, j = get_line_pts(
         np.array([1,6,19,14]),
         np.array([5,0,13,18]),
         np.array([6,19,14,1]),
         np.array([0,13,18,5]))
     image[i,j] = True
     image = binary_fill_holes(image)
     workspace, module = self.make_workspace(image)
     module.worm_length.value = 12
     module.worm_width.value = 5
     module.angle_count.value = 16
     module.run(workspace)
     m = workspace.measurements
     self.assertTrue(isinstance(m, cpmeas.Measurements))
     count = m.get_current_image_measurement(
         '_'.join((ID.I.C_COUNT, OBJECTS_NAME)))
     self.assertEqual(count, 1)
     x = m.get_current_measurement(OBJECTS_NAME,
                                   ID.I.M_LOCATION_CENTER_X)
     self.assertEqual(len(x), 1)
     self.assertAlmostEqual(x[0], 9., 1)
     y = m.get_current_measurement(OBJECTS_NAME,
                                   ID.I.M_LOCATION_CENTER_Y)
     self.assertEqual(len(y), 1)
     self.assertAlmostEqual(y[0], 10., 1)
     a = m.get_current_measurement(OBJECTS_NAME,
                                   ID.M_ANGLE)
     self.assertEqual(len(a), 1)
     self.assertAlmostEqual(a[0], 135, 0)
예제 #2
0
 def test_02_02_one_worm(self):
     '''Find a single worm'''
     image = np.zeros((20, 20), bool)
     index, count, i, j = get_line_pts(np.array([1, 6, 19, 14]),
                                       np.array([5, 0, 13, 18]),
                                       np.array([6, 19, 14, 1]),
                                       np.array([0, 13, 18, 5]))
     image[i, j] = True
     image = binary_fill_holes(image)
     workspace, module = self.make_workspace(image)
     module.worm_length.value = 12
     module.worm_width.value = 5
     module.angle_count.value = 16
     module.run(workspace)
     m = workspace.measurements
     self.assertTrue(isinstance(m, cpmeas.Measurements))
     count = m.get_current_image_measurement('_'.join(
         (ID.I.C_COUNT, OBJECTS_NAME)))
     self.assertEqual(count, 1)
     x = m.get_current_measurement(OBJECTS_NAME, ID.I.M_LOCATION_CENTER_X)
     self.assertEqual(len(x), 1)
     self.assertAlmostEqual(x[0], 9., 1)
     y = m.get_current_measurement(OBJECTS_NAME, ID.I.M_LOCATION_CENTER_Y)
     self.assertEqual(len(y), 1)
     self.assertAlmostEqual(y[0], 10., 1)
     a = m.get_current_measurement(OBJECTS_NAME, ID.M_ANGLE)
     self.assertEqual(len(a), 1)
     self.assertAlmostEqual(a[0], 135, 0)
 def test_02_03_crossing_worms(self):
     '''Find two worms that cross'''
     image = np.zeros((20, 20), bool)
     index, count, i, j = get_line_pts(
         np.array([1,4,19,16]),
         np.array([3,0,15,18]),
         np.array([4,19,16,1]),
         np.array([0,15,18,3]))
     image[i,j] = True
     index, count, i, j = get_line_pts(
         np.array([0,3,18,15]),
         np.array([16,19,4,1]),
         np.array([3,18,15,0]),
         np.array([19,4,1,16])
     )
     image[i,j] = True
     image = binary_fill_holes(image)
     workspace, module = self.make_workspace(image)
     module.worm_length.value = 17
     module.worm_width.value = 5
     module.angle_count.value = 16
     module.run(workspace)
     m = workspace.measurements
     self.assertTrue(isinstance(m, cpmeas.Measurements))
     count = m.get_current_image_measurement(
         '_'.join((ID.I.C_COUNT, OBJECTS_NAME)))
     self.assertEqual(count, 2)
     a = m.get_current_measurement(OBJECTS_NAME,
                                   ID.M_ANGLE)
     self.assertEqual(len(a), 2)
     if a[0] > 90:
         order = np.array([0,1])
     else:
         order = np.array([1,0])
     self.assertAlmostEqual(a[order[0]], 135, 0)
     self.assertAlmostEqual(a[order[1]], 45, 0)
     x = m.get_current_measurement(OBJECTS_NAME,
                                   ID.I.M_LOCATION_CENTER_X)
     self.assertEqual(len(x), 2)
     self.assertAlmostEqual(x[order[0]], 9., 0)
     self.assertAlmostEqual(x[order[1]], 10., 0)
     y = m.get_current_measurement(OBJECTS_NAME,
                                   ID.I.M_LOCATION_CENTER_Y)
     self.assertEqual(len(y), 2)
     self.assertAlmostEqual(y[order[0]], 10., 0)
     self.assertAlmostEqual(y[order[1]], 9., 0)
예제 #4
0
 def test_02_03_crossing_worms(self):
     '''Find two worms that cross'''
     image = np.zeros((20, 20), bool)
     index, count, i, j = get_line_pts(
         np.array([1,4,19,16]),
         np.array([3,0,15,18]),
         np.array([4,19,16,1]),
         np.array([0,15,18,3]))
     image[i,j] = True
     index, count, i, j = get_line_pts(
         np.array([0,3,18,15]),
         np.array([16,19,4,1]),
         np.array([3,18,15,0]),
         np.array([19,4,1,16])
     )
     image[i,j] = True
     image = binary_fill_holes(image)
     workspace, module = self.make_workspace(image)
     module.worm_length.value = 17
     module.worm_width.value = 5
     module.angle_count.value = 16
     module.run(workspace)
     m = workspace.measurements
     self.assertTrue(isinstance(m, cpmeas.Measurements))
     count = m.get_current_image_measurement(
         '_'.join((ID.I.C_COUNT, OBJECTS_NAME)))
     self.assertEqual(count, 2)
     a = m.get_current_measurement(OBJECTS_NAME,
                                   ID.M_ANGLE)
     self.assertEqual(len(a), 2)
     if a[0] > 90:
         order = np.array([0,1])
     else:
         order = np.array([1,0])
     self.assertAlmostEqual(a[order[0]], 135, 0)
     self.assertAlmostEqual(a[order[1]], 45, 0)
     x = m.get_current_measurement(OBJECTS_NAME,
                                   ID.I.M_LOCATION_CENTER_X)
     self.assertEqual(len(x), 2)
     self.assertAlmostEqual(x[order[0]], 9., 0)
     self.assertAlmostEqual(x[order[1]], 10., 0)
     y = m.get_current_measurement(OBJECTS_NAME,
                                   ID.I.M_LOCATION_CENTER_Y)
     self.assertEqual(len(y), 2)
     self.assertAlmostEqual(y[order[0]], 10., 0)
     self.assertAlmostEqual(y[order[1]], 9., 0)
예제 #5
0
 def get_diamond(self, angle):
     """Get a diamond-shaped structuring element
     
     angle - angle at which to tilt the diamond
     
     returns a binary array that can be used as a footprint for
     the erosion
     """
     worm_width = self.worm_width.value
     worm_length = self.worm_length.value
     #
     # The shape:
     #
     #                   + x1,y1
     #
     # x0,y0 +                          + x2, y2
     #
     #                   + x3,y3
     #
     x0 = int(np.sin(angle) * worm_length / 2)
     x1 = int(np.cos(angle) * worm_width / 2)
     x2 = -x0
     x3 = -x1
     y2 = int(np.cos(angle) * worm_length / 2)
     y1 = int(np.sin(angle) * worm_width / 2)
     y0 = -y2
     y3 = -y1
     xmax = np.max(np.abs([x0, x1, x2, x3]))
     ymax = np.max(np.abs([y0, y1, y2, y3]))
     strel = np.zeros((ymax * 2 + 1, xmax * 2 + 1), bool)
     index, count, i, j = get_line_pts(
         np.array([y0, y1, y2, y3]) + ymax,
         np.array([x0, x1, x2, x3]) + xmax,
         np.array([y1, y2, y3, y0]) + ymax,
         np.array([x1, x2, x3, x0]) + xmax,
     )
     strel[i, j] = True
     strel = binary_fill_holes(strel)
     return strel
예제 #6
0
 def get_diamond(self, angle):
     '''Get a diamond-shaped structuring element
     
     angle - angle at which to tilt the diamond
     
     returns a binary array that can be used as a footprint for
     the erosion
     '''
     worm_width = self.worm_width.value
     worm_length = self.worm_length.value
     #
     # The shape:
     #
     #                   + x1,y1
     #
     # x0,y0 +                          + x2, y2
     #
     #                   + x3,y3
     #
     x0 = int(np.sin(angle) * worm_length / 2)
     x1 = int(np.cos(angle) * worm_width / 2)
     x2 = -x0
     x3 = -x1
     y2 = int(np.cos(angle) * worm_length / 2)
     y1 = int(np.sin(angle) * worm_width / 2)
     y0 = -y2
     y3 = -y1
     xmax = np.max(np.abs([x0, x1, x2, x3]))
     ymax = np.max(np.abs([y0, y1, y2, y3]))
     strel = np.zeros((ymax * 2 + 1, xmax * 2 + 1), bool)
     index, count, i, j = get_line_pts(
         np.array([y0, y1, y2, y3]) + ymax,
         np.array([x0, x1, x2, x3]) + xmax,
         np.array([y1, y2, y3, y0]) + ymax,
         np.array([x1, x2, x3, x0]) + xmax)
     strel[i, j] = True
     strel = binary_fill_holes(strel)
     return strel
 def filter_using_image(self, workspace, mask):
     '''Filter out connections using local intensity minima between objects
     
     workspace - the workspace for the image set
     mask - mask of background points within the minimum distance
     '''
     #
     # NOTE: This is an efficient implementation and an improvement
     #       in accuracy over the Matlab version. It would be faster and
     #       more accurate to eliminate the line-connecting and instead
     #       do the following:
     #     * Distance transform to get the coordinates of the closest
     #       point in an object for points in the background that are
     #       at most 1/2 of the max distance between objects.
     #     * Take the intensity at this closest point and similarly
     #       label the background point if the background intensity
     #       is at least the minimum intensity fraction
     #     * Assume there is a connection between objects if, after this
     #       labeling, there are adjacent points in each object.
     #
     # As it is, the algorithm duplicates the Matlab version but suffers
     # for cells whose intensity isn't high in the centroid and clearly
     # suffers when two cells touch at some point that's off of the line
     # between the two.
     #
     objects = workspace.object_set.get_objects(self.objects_name.value)
     labels = objects.segmented
     image = self.get_image(workspace)
     if self.show_window:
         # Save the image for display
         workspace.display_data.image = image
     #
     # Do a distance transform into the background to label points
     # in the background with their closest foreground object
     #
     i, j = scind.distance_transform_edt(labels==0, 
                                         return_indices=True,
                                         return_distances=False)
     confluent_labels = labels[i,j]
     confluent_labels[~mask] = 0
     if self.where_algorithm == CA_CLOSEST_POINT:
         #
         # For the closest point method, find the intensity at
         # the closest point in the object (which will be the point itself
         # for points in the object).
         # 
         object_intensity = image[i,j] * self.minimum_intensity_fraction.value
         confluent_labels[object_intensity > image] = 0
     count, index, c_j = morph.find_neighbors(confluent_labels)
     if len(c_j) == 0:
         # Nobody touches - return the labels matrix
         return labels
     #
     # Make a row of i matching the touching j
     #
     c_i = np.zeros(len(c_j))
     #
     # Eliminate labels without matches
     #
     label_numbers = np.arange(1,len(count)+1)[count > 0]
     index = index[count > 0]
     count = count[count > 0]
     #
     # Get the differences between labels so we can use a cumsum trick
     # to increment to the next label when they change
     #
     label_numbers[1:] = label_numbers[1:] - label_numbers[:-1]
     c_i[index] = label_numbers
     c_i = np.cumsum(c_i).astype(int)
     if self.where_algorithm == CA_CENTROIDS:
         #
         # Only connect points > minimum intensity fraction
         #
         center_i, center_j = morph.centers_of_labels(labels)
         indexes, counts, i, j = morph.get_line_pts(
             center_i[c_i-1], center_j[c_i-1],
             center_i[c_j-1], center_j[c_j-1])
         #
         # The indexes of the centroids at pt1
         #
         last_indexes = indexes+counts-1
         #
         # The minimum of the intensities at pt0 and pt1
         #
         centroid_intensities = np.minimum(
             image[i[indexes],j[indexes]],
             image[i[last_indexes], j[last_indexes]])
         #
         # Assign label numbers to each point so we can use
         # scipy.ndimage.minimum. The label numbers are indexes into
         # "connections" above.
         #
         pt_labels = np.zeros(len(i), int)
         pt_labels[indexes[1:]] = 1
         pt_labels = np.cumsum(pt_labels)
         minima = scind.minimum(image[i,j], pt_labels, np.arange(len(indexes)))
         minima = morph.fixup_scipy_ndimage_result(minima)
         #
         # Filter the connections using the image
         #
         mif = self.minimum_intensity_fraction.value
         i = c_i[centroid_intensities * mif <= minima]
         j = c_j[centroid_intensities * mif <= minima]
     else:
         i = c_i
         j = c_j
     #
     # Add in connections from self to self
     #
     unique_labels = np.unique(labels)
     i = np.hstack((i, unique_labels))
     j = np.hstack((j, unique_labels))
     #
     # Run "all_connected_components" to get a component # for
     # objects identified as same.
     #
     new_indexes = morph.all_connected_components(i, j)
     new_labels = np.zeros(labels.shape, int)
     new_labels[labels != 0] = new_indexes[labels[labels != 0]]
     return new_labels
    def rebuild_worm_from_control_points_approx(self, control_coords, 
                                                worm_radii, labels, idx):
        '''Rebuild a worm from its control coordinates
         
        Given a worm specified by some control points along its spline,
        reconstructs an approximate binary image representing the worm.

        Specifically, this function generates an image where successive control
        points have been joined by line segments, and then dilates that by a
        certain (specified) radius.

        Inputs:

        control_coords: A N x 2 double array, where each column contains the x
        and y coordinates for a control point.

        worm_radius: Scalar double. Approximate radius of a typical worm; the
        radius by which the reconstructed worm spline is dilated to form the
        final worm.

        Outputs:
        The coordinates of all pixels in the worm in an N x 2 array'''
        index, count, i, j = morph.get_line_pts(control_coords[:-1,0],
                                                control_coords[:-1,1],
                                                control_coords[1:,0],
                                                control_coords[1:,1])
        #
        # Get rid of the last point for the middle elements - these are
        # duplicated by the first point in the next line
        #
        i = np.delete(i,index[1:])
        j = np.delete(j,index[1:])
        index = index - np.arange(len(index))
        count -= 1
        #
        # Find the control point and within-control-point index of each point
        #
        label = np.zeros(len(i), int)
        label[index[1:]] = 1
        label = np.cumsum(label)
        order = np.arange(len(i)) - index[label]
        frac = order.astype(float) / count[label].astype(float)
        radius = (worm_radii[label] * (1-frac) + 
                  worm_radii[label+1] * frac)
        iworm_radius = int(np.max(np.ceil(radius)))
        #
        # Get dilation coordinates
        #
        ii, jj = np.mgrid[-iworm_radius:iworm_radius+1,
                          -iworm_radius:iworm_radius+1]
        dd = np.sqrt((ii*ii + jj*jj).astype(float))
        mask = ii*ii + jj*jj <= iworm_radius * iworm_radius
        ii = ii[mask]
        jj = jj[mask]
        dd = dd[mask]
        #
        # All points (with repeats)
        #
        i = (i[:,np.newaxis] + ii[np.newaxis, :]).flatten()
        j = (j[:,np.newaxis] + jj[np.newaxis, :]).flatten()
        #
        # We further mask out any dilation coordinates outside of
        # the radius at our point in question
        #
        m = (radius[:,np.newaxis] >= dd[np.newaxis, :]).flatten()
        i = i[m]
        j = j[m]
        #
        # Find repeats by sorting and comparing against next
        #
        order = np.lexsort((i,j))
        i = i[order]
        j = j[order]
        mask = np.hstack([[True], (i[:-1] != i[1:]) | (j[:-1] != j[1:])])
        i = i[mask]
        j = j[mask]
        mask = (i >= 0) & (j >= 0) & (i < labels.shape[0]) & (j < labels.shape[1])
        labels[i[mask], j[mask]] = idx
예제 #9
0
 def filter_using_image(self, workspace, mask):
     '''Filter out connections using local intensity minima between objects
     
     workspace - the workspace for the image set
     mask - mask of background points within the minimum distance
     '''
     #
     # NOTE: This is an efficient implementation and an improvement
     #       in accuracy over the Matlab version. It would be faster and
     #       more accurate to eliminate the line-connecting and instead
     #       do the following:
     #     * Distance transform to get the coordinates of the closest
     #       point in an object for points in the background that are
     #       at most 1/2 of the max distance between objects.
     #     * Take the intensity at this closest point and similarly
     #       label the background point if the background intensity
     #       is at least the minimum intensity fraction
     #     * Assume there is a connection between objects if, after this
     #       labeling, there are adjacent points in each object.
     #
     # As it is, the algorithm duplicates the Matlab version but suffers
     # for cells whose intensity isn't high in the centroid and clearly
     # suffers when two cells touch at some point that's off of the line
     # between the two.
     #
     objects = workspace.object_set.get_objects(self.objects_name.value)
     labels = objects.segmented
     image = self.get_image(workspace)
     if self.show_window:
         # Save the image for display
         workspace.display_data.image = image
     #
     # Do a distance transform into the background to label points
     # in the background with their closest foreground object
     #
     i, j = scind.distance_transform_edt(labels == 0,
                                         return_indices=True,
                                         return_distances=False)
     confluent_labels = labels[i, j]
     confluent_labels[~mask] = 0
     if self.where_algorithm == CA_CLOSEST_POINT:
         #
         # For the closest point method, find the intensity at
         # the closest point in the object (which will be the point itself
         # for points in the object).
         #
         object_intensity = image[i,
                                  j] * self.minimum_intensity_fraction.value
         confluent_labels[object_intensity > image] = 0
     count, index, c_j = morph.find_neighbors(confluent_labels)
     if len(c_j) == 0:
         # Nobody touches - return the labels matrix
         return labels
     #
     # Make a row of i matching the touching j
     #
     c_i = np.zeros(len(c_j))
     #
     # Eliminate labels without matches
     #
     label_numbers = np.arange(1, len(count) + 1)[count > 0]
     index = index[count > 0]
     count = count[count > 0]
     #
     # Get the differences between labels so we can use a cumsum trick
     # to increment to the next label when they change
     #
     label_numbers[1:] = label_numbers[1:] - label_numbers[:-1]
     c_i[index] = label_numbers
     c_i = np.cumsum(c_i).astype(int)
     if self.where_algorithm == CA_CENTROIDS:
         #
         # Only connect points > minimum intensity fraction
         #
         center_i, center_j = morph.centers_of_labels(labels)
         indexes, counts, i, j = morph.get_line_pts(center_i[c_i - 1],
                                                    center_j[c_i - 1],
                                                    center_i[c_j - 1],
                                                    center_j[c_j - 1])
         #
         # The indexes of the centroids at pt1
         #
         last_indexes = indexes + counts - 1
         #
         # The minimum of the intensities at pt0 and pt1
         #
         centroid_intensities = np.minimum(
             image[i[indexes], j[indexes]], image[i[last_indexes],
                                                  j[last_indexes]])
         #
         # Assign label numbers to each point so we can use
         # scipy.ndimage.minimum. The label numbers are indexes into
         # "connections" above.
         #
         pt_labels = np.zeros(len(i), int)
         pt_labels[indexes[1:]] = 1
         pt_labels = np.cumsum(pt_labels)
         minima = scind.minimum(image[i, j], pt_labels,
                                np.arange(len(indexes)))
         minima = morph.fixup_scipy_ndimage_result(minima)
         #
         # Filter the connections using the image
         #
         mif = self.minimum_intensity_fraction.value
         i = c_i[centroid_intensities * mif <= minima]
         j = c_j[centroid_intensities * mif <= minima]
     else:
         i = c_i
         j = c_j
     #
     # Add in connections from self to self
     #
     unique_labels = np.unique(labels)
     i = np.hstack((i, unique_labels))
     j = np.hstack((j, unique_labels))
     #
     # Run "all_connected_components" to get a component # for
     # objects identified as same.
     #
     new_indexes = morph.all_connected_components(i, j)
     new_labels = np.zeros(labels.shape, int)
     new_labels[labels != 0] = new_indexes[labels[labels != 0]]
     return new_labels
예제 #10
0
    def rebuild_worm_from_control_points_approx(self, control_coords,
                                                worm_radii, labels, idx):
        '''Rebuild a worm from its control coordinates
         
        Given a worm specified by some control points along its spline,
        reconstructs an approximate binary image representing the worm.

        Specifically, this function generates an image where successive control
        points have been joined by line segments, and then dilates that by a
        certain (specified) radius.

        Inputs:

        control_coords: A N x 2 double array, where each column contains the x
        and y coordinates for a control point.

        worm_radius: Scalar double. Approximate radius of a typical worm; the
        radius by which the reconstructed worm spline is dilated to form the
        final worm.

        Outputs:
        The coordinates of all pixels in the worm in an N x 2 array'''
        index, count, i, j = morph.get_line_pts(control_coords[:-1, 0],
                                                control_coords[:-1, 1],
                                                control_coords[1:, 0],
                                                control_coords[1:, 1])
        #
        # Get rid of the last point for the middle elements - these are
        # duplicated by the first point in the next line
        #
        i = np.delete(i, index[1:])
        j = np.delete(j, index[1:])
        index = index - np.arange(len(index))
        count -= 1
        #
        # Find the control point and within-control-point index of each point
        #
        label = np.zeros(len(i), int)
        label[index[1:]] = 1
        label = np.cumsum(label)
        order = np.arange(len(i)) - index[label]
        frac = order.astype(float) / count[label].astype(float)
        radius = (worm_radii[label] * (1 - frac) +
                  worm_radii[label + 1] * frac)
        iworm_radius = int(np.max(np.ceil(radius)))
        #
        # Get dilation coordinates
        #
        ii, jj = np.mgrid[-iworm_radius:iworm_radius + 1,
                          -iworm_radius:iworm_radius + 1]
        dd = np.sqrt((ii * ii + jj * jj).astype(float))
        mask = ii * ii + jj * jj <= iworm_radius * iworm_radius
        ii = ii[mask]
        jj = jj[mask]
        dd = dd[mask]
        #
        # All points (with repeats)
        #
        i = (i[:, np.newaxis] + ii[np.newaxis, :]).flatten()
        j = (j[:, np.newaxis] + jj[np.newaxis, :]).flatten()
        #
        # We further mask out any dilation coordinates outside of
        # the radius at our point in question
        #
        m = (radius[:, np.newaxis] >= dd[np.newaxis, :]).flatten()
        i = i[m]
        j = j[m]
        #
        # Find repeats by sorting and comparing against next
        #
        order = np.lexsort((i, j))
        i = i[order]
        j = j[order]
        mask = np.hstack([[True], (i[:-1] != i[1:]) | (j[:-1] != j[1:])])
        i = i[mask]
        j = j[mask]
        mask = (i >= 0) & (j >= 0) & (i < labels.shape[0]) & (j <
                                                              labels.shape[1])
        labels[i[mask], j[mask]] = idx