Skip to content

Commit

Permalink
Merge pull request #433 from danforthcenter/misc_function_improvements
Browse files Browse the repository at this point in the history
Misc function improvements
  • Loading branch information
nfahlgren committed Aug 22, 2019
2 parents 08774ff + e913026 commit dc27ad6
Show file tree
Hide file tree
Showing 8 changed files with 30 additions and 37 deletions.
7 changes: 3 additions & 4 deletions docs/segment_sort.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,14 +2,15 @@

Sort segments from a skeletonized image into two categories: leaf objects and other objects.

**plantcv.morphology.segment_sort**(*skel_img, objects, mask=None*)
**plantcv.morphology.segment_sort**(*skel_img, objects, mask=None, first_stem=True*)

**returns** Secondary objects, primary objects

- **Parameters:**
- skel_img - Skeleton image (output from [plantcv.morphology.skeletonize](skeletonize.md))
- objects - Segment objects (output from [plantcv.morphology.prune](prune.md), or [plantcv.morphology.segment_skeleton](segment_skeleton.md))
- mask - Binary mask for debugging. If provided, debug image will be overlaid on the mask.
- first_stem - When True, the first segment (the bottom segment) gets classified as stem. If False, then the algorithm classification is applied to each segment.
- **Context:**
- Sorts skeleton segments into two categories: primary and secondary segments. Segments get classified as primary
if both end points of the segment coincide with branch points. Segments get classified as secondary if at least one of their
Expand All @@ -34,12 +35,10 @@ pcv.params.debug = "print"
pcv.params.line_thickness = 3

leaf_obj, other_obj = pcv.morphology.segment_sort(skel_img=skeleton,
objects=obj,
hierarchies=hier)
objects=obj)

leaf_obj, other_obj = pcv.morphology.segment_sort(skel_img=skeleton,
objects=obj,
hierarchies=hier,
mask=plant_mask)

```
Expand Down
6 changes: 3 additions & 3 deletions plantcv/plantcv/morphology/__init__.py
Original file line number Diff line number Diff line change
@@ -1,12 +1,12 @@
from plantcv.plantcv.morphology.find_branch_pts import find_branch_pts
from plantcv.plantcv.morphology.segment_skeleton import segment_skeleton
from plantcv.plantcv.morphology.find_tips import find_tips
from plantcv.plantcv.morphology._iterative_prune import _iterative_prune
from plantcv.plantcv.morphology.segment_skeleton import segment_skeleton
from plantcv.plantcv.morphology.segment_sort import segment_sort
from plantcv.plantcv.morphology.prune import prune
from plantcv.plantcv.morphology.skeletonize import skeletonize
from plantcv.plantcv.morphology.check_cycles import check_cycles
from plantcv.plantcv.morphology.segment_skeleton import segment_skeleton
from plantcv.plantcv.morphology._iterative_prune import _iterative_prune
from plantcv.plantcv.morphology.segment_angle import segment_angle
from plantcv.plantcv.morphology.segment_path_length import segment_path_length
from plantcv.plantcv.morphology.segment_euclidean_length import segment_euclidean_length
Expand All @@ -18,4 +18,4 @@

__all__ = ["find_branch_pts", "find_tips", "prune", "skeletonize", "check_cycles", "segment_skeleton", "segment_angle",
"segment_path_length", "segment_euclidean_length", "segment_curvature", "segment_sort", "segment_id",
"segment_tangent_angle", "segment_insertion_angle", "segment_combine", "_iterative_prune"]
"segment_tangent_angle", "segment_insertion_angle", "segment_combine", "_iterative_prune"]
2 changes: 0 additions & 2 deletions plantcv/plantcv/morphology/_iterative_prune.py
Original file line number Diff line number Diff line change
Expand Up @@ -26,8 +26,6 @@ def _iterative_prune(skel_img, size):

# Check to see if the skeleton has multiple objects
objects, _ = find_objects(pruned_img, pruned_img)
if not len(objects) == 1:
print("Warning: Multiple objects detected! Pruning will further separate the difference pieces.")

# Iteratively remove endpoints (tips) from a skeleton
for i in range(0, size):
Expand Down
7 changes: 3 additions & 4 deletions plantcv/plantcv/morphology/prune.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,9 +8,9 @@
from plantcv.plantcv import print_image
from plantcv.plantcv import find_objects
from plantcv.plantcv import image_subtract
from plantcv.plantcv.morphology import find_tips
from plantcv.plantcv.morphology import segment_sort
from plantcv.plantcv.morphology import segment_skeleton
from plantcv.plantcv.morphology import _iterative_prune


def prune(skel_img, size=0, mask=None):
Expand Down Expand Up @@ -46,8 +46,6 @@ def prune(skel_img, size=0, mask=None):

# Check to see if the skeleton has multiple objects
skel_objects, _ = find_objects(skel_img, skel_img)
if not len(skel_objects) == 1:
print("Warning: Multiple objects detected! Pruning will further separate the difference pieces.")

_, objects = segment_skeleton(skel_img)
kept_segments = []
Expand All @@ -56,7 +54,6 @@ def prune(skel_img, size=0, mask=None):
if size>0:
# If size>0 then check for segments that are smaller than size pixels long


# Sort through segments since we don't want to remove primary segments
secondary_objects, primary_objects = segment_sort(skel_img, objects)

Expand All @@ -71,8 +68,10 @@ def prune(skel_img, size=0, mask=None):
removed_barbs = np.zeros(skel_img.shape[:2], np.uint8)
cv2.drawContours(removed_barbs, removed_segments, -1, 255, 1,
lineType=8)

# Subtract all short segments from the skeleton image
pruned_img = image_subtract(pruned_img, removed_barbs)
pruned_img = _iterative_prune(pruned_img, 1)

# Make debugging image
if mask is None:
Expand Down
2 changes: 1 addition & 1 deletion plantcv/plantcv/morphology/segment_id.py
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,7 @@ def segment_id(skel_img, objects, mask=None):

# Plot all segment contours
for i, cnt in enumerate(objects):
cv2.drawContours(segmented_img, objects, i, rand_color[i], params.line_thickness, lineType=8)
cv2.drawContours(segmented_img, cnt, -1, rand_color[i], params.line_thickness, lineType=8)
# Store coordinates for labels
label_coord_x.append(objects[i][0][0][0])
label_coord_y.append(objects[i][0][0][1])
Expand Down
23 changes: 5 additions & 18 deletions plantcv/plantcv/morphology/segment_insertion_angle.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@
from plantcv.plantcv import closing
from plantcv.plantcv import outputs
from plantcv.plantcv import plot_image
from plantcv.plantcv import logical_and
from plantcv.plantcv import fatal_error
from plantcv.plantcv import print_image
from plantcv.plantcv import find_objects
Expand Down Expand Up @@ -86,26 +87,12 @@ def segment_insertion_angle(skel_img, segmented_img, leaf_objects, stem_objects,
# Determine if a segment is leaf end or leaf insertion segment
for j, obj in enumerate(segment_end_obj):

cnt_as_tuples = []
num_pixels = len(obj)
count = 0

# Turn each contour into a list of tuples (can't search for list of coords, so reformat)
while num_pixels > count:
x_coord = obj[count][0][0]
y_coord = obj[count][0][1]
cnt_as_tuples.append((x_coord, y_coord))
count += 1

for tip_tups in tip_tuples:
# If a tip is inside the list of contour tuples then it is a leaf end segment
if tip_tups in cnt_as_tuples:
is_insertion_segment.append(False)
else:
is_insertion_segment.append(True)
segment_plot = np.zeros(segmented_img.shape[:2], np.uint8)
cv2.drawContours(segment_plot, obj, -1, 255, 1, lineType=8)
overlap_img = logical_and(segment_plot, tips)

# If none of the tips are within a segment_end then it's an insertion segment
if all(is_insertion_segment):
if np.sum(overlap_img) == 0:
insertion_segments.append(segment_end_obj[j])
insertion_hierarchies.append(segment_end_hierarchy[0][j])

Expand Down
9 changes: 5 additions & 4 deletions plantcv/plantcv/morphology/segment_sort.py
Original file line number Diff line number Diff line change
Expand Up @@ -10,13 +10,14 @@
from plantcv.plantcv.morphology import find_tips


def segment_sort(skel_img, objects, mask=None):
def segment_sort(skel_img, objects, mask=None, first_stem=True):
""" Calculate segment curvature as defined by the ratio between geodesic and euclidean distance
Inputs:
skel_img = Skeletonized image
objects = List of contours
mask = (Optional) binary mask for debugging. If provided, debug image will be overlaid on the mask.
first_stem = (Optional) if True, then the first (bottom) segment always gets classified as stem
Returns:
labeled_img = Segmented debugging image with lengths labeled
Expand All @@ -25,8 +26,8 @@ def segment_sort(skel_img, objects, mask=None):
:param skel_img: numpy.ndarray
:param objects: list
:param labeled_img: numpy.ndarray
:param mask: numpy.ndarray
:param first_stem: bool
:return secondary_objects: list
:return other_objects: list
"""
Expand All @@ -52,7 +53,7 @@ def segment_sort(skel_img, objects, mask=None):
overlap_img = logical_and(segment_plot, tips_img)

# The first contour is the base, and while it contains a tip, it isn't a leaf
if i == 0:
if i == 0 and first_stem:
primary_objects.append(cnt)

# Sort segments
Expand Down Expand Up @@ -81,4 +82,4 @@ def segment_sort(skel_img, objects, mask=None):
elif params.debug == 'plot':
plot_image(labeled_img)

return secondary_objects, primary_objects
return secondary_objects, primary_objects
11 changes: 10 additions & 1 deletion tests/tests.py
Original file line number Diff line number Diff line change
Expand Up @@ -3419,7 +3419,16 @@ def test_plantcv_morphology_segment_insertion_angle():
pcv.params.debug = "print"
insert_angles = pcv.morphology.segment_insertion_angle(pruned, segmented_img, leaf_obj, stem_obj, 10)
pcv.print_results(os.path.join(cache_dir, "results.txt"))
assert len(pcv.outputs.observations['segment_insertion_angle']['value']) == 14
assert pcv.outputs.observations['segment_insertion_angle']['value'] == [24.97999120101794, 50.75442037373474,
56.45078448114704, 64.19513117863062,
45.146799092975584, 57.80220388909291,
66.1559145648012, 77.57112958360631,
39.245580536881675, 84.24558178912076,
84.24558178912076, 50.75442037373474,
26.337516798081822, 58.46112771993523,
39.245580536881675, 28.645972294617223,
35.371548466069214, 20.64797104069403,
62.89851538735208]
pcv.outputs.clear()


Expand Down

0 comments on commit dc27ad6

Please sign in to comment.