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((cellprofiler.measurement.C_COUNT, OBJECTS_NAME)))
     self.assertEqual(count, 1)
     x = m.get_current_measurement(OBJECTS_NAME,
                                   cellprofiler.measurement.M_LOCATION_CENTER_X)
     self.assertEqual(len(x), 1)
     self.assertAlmostEqual(x[0], 9., 1)
     y = m.get_current_measurement(OBJECTS_NAME,
                                   cellprofiler.measurement.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)
Example #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((cellprofiler.measurement.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,
                                   cellprofiler.measurement.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,
                                   cellprofiler.measurement.M_LOCATION_CENTER_Y)
     self.assertEqual(len(y), 2)
     self.assertAlmostEqual(y[order[0]], 10., 0)
     self.assertAlmostEqual(y[order[1]], 9., 0)
Example #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)
    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(numpy.sin(angle) * worm_length / 2)
        x1 = int(numpy.cos(angle) * worm_width / 2)
        x2 = -x0
        x3 = -x1
        y2 = int(numpy.cos(angle) * worm_length / 2)
        y1 = int(numpy.sin(angle) * worm_width / 2)
        y0 = -y2
        y3 = -y1
        xmax = numpy.max(numpy.abs([x0, x1, x2, x3]))
        ymax = numpy.max(numpy.abs([y0, y1, y2, y3]))
        strel = numpy.zeros((ymax * 2 + 1, xmax * 2 + 1), bool)
        index, count, i, j = get_line_pts(
            numpy.array([y0, y1, y2, y3]) + ymax,
            numpy.array([x0, x1, x2, x3]) + xmax,
            numpy.array([y1, y2, y3, y0]) + ymax,
            numpy.array([x1, x2, x3, x0]) + xmax,
        )
        strel[i, j] = True
        strel = binary_fill_holes(strel)
        return strel
    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
Example #7
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
Example #8
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
    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