def run(self, workspace):
        '''Run the algorithm on one image set'''
        #
        # Get the image as a binary image
        #
        image_set = workspace.image_set
        image = image_set.get_image(self.image_name.value, must_be_binary=True)
        mask = image.pixel_data
        if image.has_mask:
            mask = mask & image.mask
        angle_count = self.angle_count.value
        #
        # We collect the i,j and angle of pairs of points that
        # are 3-d adjacent after erosion.
        #
        # i - the i coordinate of each point found after erosion
        # j - the j coordinate of each point found after erosion
        # a - the angle of the structuring element for each point found
        #
        i = np.zeros(0, int)
        j = np.zeros(0, int)
        a = np.zeros(0, int)

        ig, jg = np.mgrid[0:mask.shape[0], 0:mask.shape[1]]
        #this_idx = 0
        for angle_number in range(angle_count):
            angle = float(angle_number) * np.pi / float(angle_count)
            strel = self.get_diamond(angle)
            erosion = binary_erosion(mask, strel)
            #
            # Accumulate the count, i, j and angle for all foreground points
            # in the erosion
            #
            this_count = np.sum(erosion)
            i = np.hstack((i, ig[erosion]))
            j = np.hstack((j, jg[erosion]))
            a = np.hstack((a, np.ones(this_count, float) * angle))
        #
        # Find connections based on distances, not adjacency
        #
        first, second = self.find_adjacent_by_distance(i, j, a)
        #
        # Do all connected components.
        #
        if len(first) > 0:
            ij_labels = all_connected_components(first, second) + 1
            nlabels = np.max(ij_labels)
            label_indexes = np.arange(1, nlabels + 1)
            #
            # Compute the measurements
            #
            center_x = fix(mean_of_labels(j, ij_labels, label_indexes))
            center_y = fix(mean_of_labels(i, ij_labels, label_indexes))
            #
            # The angles are wierdly complicated because of the wrap-around.
            # You can imagine some horrible cases, like a circular patch of
            # "linear object" in which all angles are represented or a gentle "U"
            # curve.
            #
            # For now, I'm going to use the following heuristic:
            #
            # Compute two different "angles". The angles of one go
            # from 0 to 180 and the angles of the other go from -90 to 90.
            # Take the variance of these from the mean and
            # choose the representation with the lowest variance.
            #
            # An alternative would be to compute the variance at each possible
            # dividing point. Another alternative would be to actually trace through
            # the connected components - both overkill for such an inconsequential
            # measurement I hope.
            #
            angles = fix(mean_of_labels(a, ij_labels, label_indexes))
            vangles = fix(
                mean_of_labels((a - angles[ij_labels - 1])**2, ij_labels,
                               label_indexes))
            aa = a.copy()
            aa[a > np.pi / 2] -= np.pi
            aangles = fix(mean_of_labels(aa, ij_labels, label_indexes))
            vaangles = fix(
                mean_of_labels((aa - aangles[ij_labels - 1])**2, ij_labels,
                               label_indexes))
            aangles[aangles < 0] += np.pi
            angles[vaangles < vangles] = aangles[vaangles < vangles]
        else:
            center_x = np.zeros(0, int)
            center_y = np.zeros(0, int)
            angles = np.zeros(0)
            nlabels = 0
            label_indexes = np.zeros(0, int)
            labels = np.zeros(mask.shape, int)

        ifull = []
        jfull = []
        ij_labelsfull = []
        labeldict = {}

        for label_id in np.unique(label_indexes):
            r = np.array(i) * (ij_labels == label_id)
            r = r[r != 0]
            c = np.array(j) * (ij_labels == label_id)
            c = c[c != 0]
            rect_strel = self.get_rectangle(angles[label_id - 1])
            seedmask = np.zeros_like(mask, int)
            seedmask[r, c] = label_id

            reconstructedlinearobject = skimage.filter.rank.maximum(
                seedmask, rect_strel)
            reconstructedlinearobject = reconstructedlinearobject * mask
            if self.overlap_within_angle == False:
                itemp, jtemp = np.where(reconstructedlinearobject == label_id)
                ifull += list(itemp)
                jfull += list(jtemp)
                ij_labelsfull += [label_id] * len(itemp)

            else:
                itemp, jtemp = np.where(reconstructedlinearobject == label_id)
                labeldict[label_id] = zip(itemp, jtemp)

        if self.overlap_within_angle == True:
            angledict = {}
            for eachangle in range(len(angles)):
                angledict[eachangle + 1] = [angles[eachangle]]
            nmerges = 1
            while nmerges != 0:
                nmerges = sum([
                    self.mergeduplicates(firstlabel, secondlabel, labeldict,
                                         angledict)
                    for firstlabel in label_indexes
                    for secondlabel in label_indexes
                    if firstlabel != secondlabel
                ])

            newlabels = labeldict.keys()
            newlabels.sort()
            newangles = angledict.keys()
            newangles.sort()
            angles = []
            for eachnewlabel in range(len(newlabels)):
                ifull += [
                    int(eachloc[0])
                    for eachloc in labeldict[newlabels[eachnewlabel]]
                ]
                jfull += [
                    int(eachloc[1])
                    for eachloc in labeldict[newlabels[eachnewlabel]]
                ]
                ij_labelsfull += [eachnewlabel + 1] * len(
                    labeldict[newlabels[eachnewlabel]])
                angles.append(np.mean(angledict[newlabels[eachnewlabel]]))
            angles = np.array(angles)

        ijv = np.zeros([len(ifull), 3], dtype=int)
        ijv[:, 0] = ifull
        ijv[:, 1] = jfull
        ijv[:, 2] = ij_labelsfull

        #
        # Make the objects
        #
        object_set = workspace.object_set
        object_name = self.object_name.value
        assert isinstance(object_set, cpo.ObjectSet)
        objects = cpo.Objects()
        objects.ijv = ijv
        objects.parent_image = image
        object_set.add_objects(objects, object_name)
        if self.show_window:
            workspace.display_data.mask = mask
            workspace.display_data.overlapping_labels = [
                l for l, idx in objects.get_labels()
            ]
        if self.overlap_within_angle == True:
            center_x = np.bincount(ijv[:, 2],
                                   ijv[:, 1])[objects.indices] / objects.areas
            center_y = np.bincount(ijv[:, 2],
                                   ijv[:, 0])[objects.indices] / objects.areas

        m = workspace.measurements
        assert isinstance(m, cpmeas.Measurements)
        m.add_measurement(object_name, "Location_Center_X", center_x)
        m.add_measurement(object_name, "Location_Center_Y", center_y)
        m.add_measurement(object_name, M_ANGLE, angles * 180 / np.pi)
        m.add_measurement(object_name, "Number_Object_Number", label_indexes)
        m.add_image_measurement("Count_%s" % object_name, nlabels)
Ejemplo n.º 2
0
    def run(self, workspace):
        '''Run the algorithm on one image set'''
        #
        # Get the image as a binary image
        #
        image_set = workspace.image_set
        image = image_set.get_image(self.image_name.value, must_be_binary=True)
        mask = image.pixel_data
        if image.has_mask:
            mask = mask & image.mask
        angle_count = self.angle_count.value
        #
        # We collect the i,j and angle of pairs of points that
        # are 3-d adjacent after erosion.
        #
        # i - the i coordinate of each point found after erosion
        # j - the j coordinate of each point found after erosion
        # a - the angle of the structuring element for each point found
        #
        i = np.zeros(0, int)
        j = np.zeros(0, int)
        a = np.zeros(0, int)

        ig, jg = np.mgrid[0:mask.shape[0], 0:mask.shape[1]]
        this_idx = 0
        for angle_number in range(angle_count):
            angle = float(angle_number) * np.pi / float(angle_count)
            strel = self.get_diamond(angle)
            erosion = binary_erosion(mask, strel)
            #
            # Accumulate the count, i, j and angle for all foreground points
            # in the erosion
            #
            this_count = np.sum(erosion)
            i = np.hstack((i, ig[erosion]))
            j = np.hstack((j, jg[erosion]))
            a = np.hstack((a, np.ones(this_count, float) * angle))
        #
        # Find connections based on distances, not adjacency
        #
        first, second = self.find_adjacent_by_distance(i, j, a)
        #
        # Do all connected components.
        #
        if len(first) > 0:
            ij_labels = all_connected_components(first, second) + 1
            nlabels = np.max(ij_labels)
            label_indexes = np.arange(1, nlabels + 1)
            #
            # Compute the measurements
            #
            center_x = fix(mean_of_labels(j, ij_labels, label_indexes))
            center_y = fix(mean_of_labels(i, ij_labels, label_indexes))
            #
            # The angles are wierdly complicated because of the wrap-around.
            # You can imagine some horrible cases, like a circular patch of
            # "worm" in which all angles are represented or a gentle "U"
            # curve.
            #
            # For now, I'm going to use the following heuristic:
            #
            # Compute two different "angles". The angles of one go
            # from 0 to 180 and the angles of the other go from -90 to 90.
            # Take the variance of these from the mean and
            # choose the representation with the lowest variance.
            #
            # An alternative would be to compute the variance at each possible
            # dividing point. Another alternative would be to actually trace through
            # the connected components - both overkill for such an inconsequential
            # measurement I hope.
            #
            angles = fix(mean_of_labels(a, ij_labels, label_indexes))
            vangles = fix(
                mean_of_labels((a - angles[ij_labels - 1])**2, ij_labels,
                               label_indexes))
            aa = a.copy()
            aa[a > np.pi / 2] -= np.pi
            aangles = fix(mean_of_labels(aa, ij_labels, label_indexes))
            vaangles = fix(
                mean_of_labels((aa - aangles[ij_labels - 1])**2, ij_labels,
                               label_indexes))
            aangles[aangles < 0] += np.pi
            angles[vaangles < vangles] = aangles[vaangles < vangles]
            #
            # Squish the labels to 2-d. The labels for overlaps are arbitrary.
            #
            labels = np.zeros(mask.shape, int)
            labels[i, j] = ij_labels
        else:
            center_x = np.zeros(0, int)
            center_y = np.zeros(0, int)
            angles = np.zeros(0)
            nlabels = 0
            label_indexes = np.zeros(0, int)
            labels = np.zeros(mask.shape, int)

        m = workspace.measurements
        assert isinstance(m, cpmeas.Measurements)
        object_name = self.object_name.value
        m.add_measurement(object_name, I.M_LOCATION_CENTER_X, center_x)
        m.add_measurement(object_name, I.M_LOCATION_CENTER_Y, center_y)
        m.add_measurement(object_name, M_ANGLE, angles * 180 / np.pi)
        m.add_measurement(object_name, I.M_NUMBER_OBJECT_NUMBER, label_indexes)
        m.add_image_measurement(I.FF_COUNT % object_name, nlabels)
        #
        # Make the objects
        #
        object_set = workspace.object_set
        assert isinstance(object_set, cpo.ObjectSet)
        objects = cpo.Objects()
        objects.segmented = labels
        objects.parent_image = image
        object_set.add_objects(objects, object_name)
        if self.show_window:
            workspace.display_data.i = center_y
            workspace.display_data.j = center_x
            workspace.display_data.angle = angles
            workspace.display_data.mask = mask
            workspace.display_data.labels = labels
            workspace.display_data.count = nlabels
Ejemplo n.º 3
0
 def run(self, workspace):
     '''Run the algorithm on one image set'''
     #
     # Get the image as a binary image
     #
     image_set = workspace.image_set
     image = image_set.get_image(self.image_name.value,
                                 must_be_binary = True)
     mask = image.pixel_data
     if image.has_mask:
         mask = mask & image.mask
     angle_count = self.angle_count.value
     #
     # We collect the i,j and angle of pairs of points that
     # are 3-d adjacent after erosion.
     #
     # i - the i coordinate of each point found after erosion
     # j - the j coordinate of each point found after erosion
     # a - the angle of the structuring element for each point found
     #
     i = np.zeros(0, int)
     j = np.zeros(0, int)
     a = np.zeros(0, int)
     
     ig, jg = np.mgrid[0:mask.shape[0], 0:mask.shape[1]]
     this_idx = 0
     for angle_number in range(angle_count):
         angle = float(angle_number) * np.pi / float(angle_count)
         strel = self.get_diamond(angle)
         erosion = binary_erosion(mask, strel)
         #
         # Accumulate the count, i, j and angle for all foreground points
         # in the erosion
         #
         this_count = np.sum(erosion)
         i = np.hstack((i, ig[erosion]))
         j = np.hstack((j, jg[erosion]))
         a = np.hstack((a, np.ones(this_count, float) * angle))
     #
     # Find connections based on distances, not adjacency
     #
     first, second = self.find_adjacent_by_distance(i,j,a)
     #
     # Do all connected components.
     #
     if len(first) > 0:
         ij_labels = all_connected_components(first, second) + 1
         nlabels = np.max(ij_labels)
         label_indexes = np.arange(1, nlabels + 1)
         #
         # Compute the measurements
         #
         center_x = fix(mean_of_labels(j, ij_labels, label_indexes))
         center_y = fix(mean_of_labels(i, ij_labels, label_indexes))
         #
         # The angles are wierdly complicated because of the wrap-around.
         # You can imagine some horrible cases, like a circular patch of
         # "worm" in which all angles are represented or a gentle "U"
         # curve.
         #
         # For now, I'm going to use the following heuristic:
         #
         # Compute two different "angles". The angles of one go
         # from 0 to 180 and the angles of the other go from -90 to 90.
         # Take the variance of these from the mean and
         # choose the representation with the lowest variance.
         #
         # An alternative would be to compute the variance at each possible
         # dividing point. Another alternative would be to actually trace through
         # the connected components - both overkill for such an inconsequential
         # measurement I hope.
         #
         angles = fix(mean_of_labels(a, ij_labels, label_indexes))
         vangles = fix(mean_of_labels((a - angles[ij_labels-1])**2, 
                                      ij_labels, label_indexes))
         aa = a.copy()
         aa[a > np.pi / 2] -= np.pi
         aangles = fix(mean_of_labels(aa, ij_labels, label_indexes))
         vaangles = fix(mean_of_labels((aa-aangles[ij_labels-1])**2,
                                       ij_labels, label_indexes))
         aangles[aangles < 0] += np.pi
         angles[vaangles < vangles] = aangles[vaangles < vangles]
         #
         # Squish the labels to 2-d. The labels for overlaps are arbitrary.
         #
         labels = np.zeros(mask.shape, int)
         labels[i, j] = ij_labels
     else:
         center_x = np.zeros(0, int)
         center_y = np.zeros(0, int)
         angles = np.zeros(0)
         nlabels = 0
         label_indexes = np.zeros(0, int)
         labels = np.zeros(mask.shape, int)
     
     m = workspace.measurements
     assert isinstance(m, cpmeas.Measurements)
     object_name = self.object_name.value
     m.add_measurement(object_name, I.M_LOCATION_CENTER_X, center_x)
     m.add_measurement(object_name, I.M_LOCATION_CENTER_Y, center_y)
     m.add_measurement(object_name, M_ANGLE, angles * 180 / np.pi)
     m.add_measurement(object_name, I.M_NUMBER_OBJECT_NUMBER, label_indexes)
     m.add_image_measurement(I.FF_COUNT % object_name, nlabels)
     #
     # Make the objects
     #
     object_set = workspace.object_set
     assert isinstance(object_set, cpo.ObjectSet)
     objects = cpo.Objects()
     objects.segmented = labels
     objects.parent_image = image
     object_set.add_objects(objects, object_name)
     if self.show_window:
         workspace.display_data.i = center_y
         workspace.display_data.j = center_x
         workspace.display_data.angle = angles
         workspace.display_data.mask = mask
         workspace.display_data.labels = labels
         workspace.display_data.count = nlabels