Skip to content

Commit

Permalink
Merge pull request #933 from danforthcenter/morphology-segment_combin…
Browse files Browse the repository at this point in the history
…e-update

Morphology segment combine update
  • Loading branch information
nfahlgren committed Nov 8, 2022
2 parents 8f58ab7 + 4cc24e4 commit df07ef6
Show file tree
Hide file tree
Showing 3 changed files with 25 additions and 56 deletions.
10 changes: 5 additions & 5 deletions docs/segment_combine.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,14 +7,14 @@ Manually combine segments from a segmented skeleton
**returns** Labeled image, new segment objects list

- **Parameters:**
- segment_list - List of segments to get combined, or list of lists of segments to get combined
- segment_list - List of segments to get combined
- objects - Segment objects (output from either [plantcv.morphology.prune](prune.md),,
[plantcv.morphology.segment_skeleton](segment_skeleton.md), or
[plantcv.morphology.segment_sort](segment_sort.md)).
- mask - Binary mask for debugging images.

- **Context:**
- Images with more complexity will often cause issues with the algorithms used in functions within the
- Objects with more complexity will often cause issues with the algorithms used in functions within the
`plantcv.morphology` sub-package. However, it is still possible to collect accurate data from such images
with a manual step such as `plantcv.morphology.segment_combine`. An example workflow would use
[plantcv.morphology.check_cycles](check_cycles.md) to identify images that have parts of plant that occlude
Expand All @@ -37,13 +37,13 @@ pcv.params.text_thickness = 3

# Plot an image with ID's labeled so the specific segment ID's can get used
# to combine segments
segment_img, id_labeled_img = pcv.morphology.segment_id(pruned_img, segment_objects, mask)
segment_img, id_labeled_img = pcv.morphology.segment_id(skel_img=pruned_img, objects=segment_objects, mask=mask)

# Combine the segments of the really floppy leaf
labeled_img, new_objects = pcv.morphology.segment_combine([12,6], segment_objects, mask)
labeled_img, new_objects = pcv.morphology.segment_combine(segment_list=[12,6], objects=segment_objects, mask=mask)

# Combine the segments of the leaf obscuring the floppy leaf
labeled_img2, new_objects = pcv.morphology.segment_combine([7,6], new_objects, mask)
labeled_img2, new_objects = pcv.morphology.segment_combine(segment_list=[7,6], objects=new_objects, mask=mask)

# Optionally, if all ID's were legible we could combine multiple segments in one step.
# Users can provide a list of lists in which each list contains segments that should
Expand Down
63 changes: 20 additions & 43 deletions plantcv/plantcv/morphology/segment_combine.py
Original file line number Diff line number Diff line change
Expand Up @@ -13,15 +13,13 @@ def segment_combine(segment_list, objects, mask):
"""Combine user specified segments together.
Inputs:
segment_list = List of segments to get combined, or list of lists of segments to get combined
segment_list = List of segment indices to get combined
objects = List of contours
hierarchy = Contour hierarchy NumPy array
mask = Binary mask for debugging image
Returns:
segmented_img = Segmented image
objects = Updated list of contours
hierarchy = Updated contour hierarchy NumPy array
:param segment_list: list
:param objects: list
Expand All @@ -32,54 +30,33 @@ def segment_combine(segment_list, objects, mask):
label_coord_x = []
label_coord_y = []
all_objects = objects[:]
if type(segment_list[0]) is not int:
fatal_error("segment_list must be a list of object ID's")
segment_list_copy = sorted(segment_list, reverse=True)

# If user provides a single list of objects to combine
if type(segment_list[0]) is int:
num_contours = len(segment_list)
count = 1

# Store the first object into the new object array
new_objects = all_objects[segment_list[0]]
# Remove the objects getting combined from the list of all objects
all_objects.remove(objects[segment_list[0]])

while count < num_contours:
# Combine objects into a single array
new_objects = np.append(new_objects, objects[segment_list[count]], 0)
# Remove the objects getting combined from the list of all objects
all_objects.remove(objects[segment_list[count]])
count += 1
# Replace with the combined object
all_objects.append(new_objects)

# If user provides a list of lists of objects to combine
elif type(segment_list[0]) is list:
# For each list provided
for lists in segment_list:
num_contours = len(lists)
count = 1
# Store the first object into the new object array
new_objects = all_objects[lists[0]]
# Remove the objects getting combined from the list of all objects
all_objects.remove(objects[lists[0]])

while count < num_contours:
# Combine objects into a single array
new_objects = np.append(new_objects, objects[lists[count]], 0)
# Remove the objects getting combined from the list of all objects
all_objects.remove(objects[lists[count]])
count += 1
# Add combined contour to list of all contours
all_objects.append(new_objects)
else:
fatal_error("segment_list must be a list of object ID's or a list of lists of ID's!")
num_contours = len(segment_list)
count = 1

# Store the first object into the new object array
combined_object = objects[segment_list_copy[0]]
# Remove the objects getting combined from the list of all objects
all_objects.pop(segment_list_copy[0])

while count < num_contours:
# Combine segments into a single object
combined_object = np.append(combined_object, objects[segment_list_copy[count]], 0)
# Remove the segment that was combined from the list of all objects
all_objects.pop(segment_list_copy[count])
count += 1
# Replace with the combined object
all_objects.append(combined_object)

labeled_img = mask.copy()
labeled_img = cv2.cvtColor(labeled_img, cv2.COLOR_GRAY2RGB)

# Color each segment a different color, use a previously saved scale if available
rand_color = color_palette(num=len(all_objects), saved=True)

# Plot all segment contours
for i, cnt in enumerate(all_objects):
cv2.drawContours(labeled_img, all_objects[i], -1, rand_color[i], params.line_thickness, lineType=8)
Expand Down
8 changes: 0 additions & 8 deletions tests/plantcv/morphology/test_segment_combine.py
Original file line number Diff line number Diff line change
Expand Up @@ -12,14 +12,6 @@ def test_segment_combine(morphology_test_data):
assert len(new_objects) + 1 == len(edges)


def test_segment_combine_lists(morphology_test_data):
"""Test for PlantCV."""
skel = cv2.imread(morphology_test_data.skel_img, -1)
edges = morphology_test_data.load_segments(morphology_test_data.segments_file, "edges")
# Test with list of lists input
_, new_objects = segment_combine(segment_list=[[0, 1, 2], [3, 4]], objects=edges, mask=skel)
assert len(new_objects) + 3 == len(edges)


def test_segment_combine_bad_input(morphology_test_data):
"""Test for PlantCV."""
Expand Down

0 comments on commit df07ef6

Please sign in to comment.