Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add "Quick Cutto" ROI function #1576

Merged
merged 32 commits into from
Aug 16, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
32 commits
Select commit Hold shift + click to select a range
65c6b11
add quick_cutto function
HaleySchuhl Aug 7, 2024
05a6bef
add quick_cutto to init
HaleySchuhl Aug 7, 2024
9924a0f
refactor function name to _quick_cutto
HaleySchuhl Aug 7, 2024
3159d9b
add _quick_cutto unit test
HaleySchuhl Aug 7, 2024
c124436
Create roi_quick_cutto.md
HaleySchuhl Aug 7, 2024
d6fdebf
add last two doc imgs
HaleySchuhl Aug 7, 2024
dc6617d
remaining doc images
HaleySchuhl Aug 7, 2024
075cf97
return num_labels also
HaleySchuhl Aug 7, 2024
295634c
update for loop to be range instead of enumerate
HaleySchuhl Aug 7, 2024
574a273
deepsource fixes
HaleySchuhl Aug 7, 2024
02891f2
update docstring too with additional return
HaleySchuhl Aug 7, 2024
f4f06ff
Update roi_quick_cutto.md
HaleySchuhl Aug 8, 2024
86f48a4
Update mkdocs.yml
HaleySchuhl Aug 8, 2024
28bb36e
datatype casting, handle >255 objects
HaleySchuhl Aug 8, 2024
018a0c8
cast as uint8 rather than int8
HaleySchuhl Aug 8, 2024
563dd18
replace rgb image in doc page
HaleySchuhl Aug 8, 2024
a180611
Update mask.png
HaleySchuhl Aug 8, 2024
1e0d610
Update roi.png
HaleySchuhl Aug 8, 2024
bac1e98
Update colored_mask.png
HaleySchuhl Aug 8, 2024
b1ca09a
remove trailing whitespace
HaleySchuhl Aug 8, 2024
0f81ba2
Delete rgb_img.jpg
HaleySchuhl Aug 12, 2024
0a53193
remove helper function from init
HaleySchuhl Aug 12, 2024
a1000f5
Update roi_quick_cutto.md
HaleySchuhl Aug 12, 2024
1936dbe
Merge branch 'main' into quick_cutto
HaleySchuhl Aug 14, 2024
a67c2d6
Merge branch 'main' into quick_cutto
k034b363 Aug 16, 2024
231e381
Remove quick_cutto docs
k034b363 Aug 16, 2024
70a1cda
Merge branch 'main' into quick_cutto
nfahlgren Aug 16, 2024
ab069a2
Remove docs images for now
nfahlgren Aug 16, 2024
0d769a7
Add newline at end of file
nfahlgren Aug 16, 2024
5ca88eb
Update docstrings to numpy style
nfahlgren Aug 16, 2024
0dc4cb6
Import logical_and from main package
nfahlgren Aug 16, 2024
a3939ce
Revert "Import logical_and from main package"
nfahlgren Aug 16, 2024
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
60 changes: 55 additions & 5 deletions plantcv/plantcv/roi/quick_filter.py
Original file line number Diff line number Diff line change
@@ -1,22 +1,29 @@
"""PlantCV quick_filter module."""
import os
import cv2
import numpy as np
from skimage.measure import label
from skimage.color import label2rgb
from plantcv.plantcv import params
from plantcv.plantcv.roi import roi2mask
from plantcv.plantcv._debug import _debug
from plantcv.plantcv.logical_and import logical_and


def quick_filter(mask, roi):
"""Quickly filter a binary mask using a region of interest.
Inputs
------
mask = binary mask
roi = PlantCV ROI object

Parameters
----------
mask : numpy.ndarray
Binary mask to filter.
roi : plantcv.plantcv.classes.Objects
PlantCV ROI object.

Returns
-------
filtered_mask = Filtered binary mask
numpy.ndarray
Filtered binary mask.
"""
# Increment the device counter
params.device += 1
Expand Down Expand Up @@ -68,3 +75,46 @@ def quick_filter(mask, roi):
_debug(visual=summed, filename=os.path.join(params.debug_outdir, f"{params.device}_roi_filter.png"), cmap="gray")

return summed


def _quick_cutto(mask, roi):
"""Quickly filter a binary mask using a region of interest by cutting to each ROI.

Parameters
----------
mask : numpy.ndarray
Binary mask to filter.
roi : plantcv.plantcv.classes.Objects
PlantCV ROI object.

Returns
-------
numpy.ndarray, numpy.ndarray, int
Filtered binary mask, labeled mask, number of labels.
"""
# Increment the device counter
params.device += 1

# Store debug
debug = params.debug
params.debug = None

mask_copy = np.copy(mask).astype(np.int32)
labeled_mask = np.zeros(mask.shape, dtype=np.int32)
bin_mask = np.copy(labeled_mask)
num_labels = len(roi.contours)
for i in range(num_labels):
# Pixel intensity of (i+1) such that the first object has value
cv2.drawContours(labeled_mask, roi.contours[i], -1, (i+1), -1)
cv2.drawContours(bin_mask, roi.contours[i], -1, (255), -1)
cropped_mask = logical_and(mask_copy, bin_mask)
# Make a labeled mask from the cropped objects
label_mask_where = np.where(cropped_mask == 255, labeled_mask, 0)

# Print/plot debug image
colorful = label2rgb(label_mask_where)
colorful2 = (255*colorful).astype(np.uint8)
params.debug = debug
_debug(visual=colorful2, filename=os.path.join(params.debug_outdir, f"{params.device}_label_colored_mask.png"))

return cropped_mask.astype(np.uint8), label_mask_where, num_labels
18 changes: 17 additions & 1 deletion tests/plantcv/roi/test_quick_filter.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
import cv2
import numpy as np
from plantcv.plantcv import Objects
from plantcv.plantcv.roi import quick_filter
from plantcv.plantcv.roi.quick_filter import quick_filter, _quick_cutto


def test_quick_filter(test_data):
Expand All @@ -19,3 +19,19 @@ def test_quick_filter(test_data):
area = cv2.countNonZero(filtered_mask)
# Assert that the contours were filtered as expected
assert area == 221


def test_quick_cutto(test_data):
"""Test for PlantCV."""
# Read in test data
img = cv2.imread(test_data.small_rgb_img)
mask = np.zeros(np.shape(img)[:2], dtype=np.uint8)
cnt, cnt_str = test_data.load_contours(test_data.small_contours_file)
cv2.drawContours(mask, cnt, -1, (255), -1, lineType=8, hierarchy=cnt_str)
roi = [np.array([[[200, 200]], [[200, 190]], [[249, 190]], [[249, 200]]], dtype=np.int32)]
roi_str = np.array([[[-1, -1, -1, -1]]], dtype=np.int32)
roi_obj = Objects(contours=[roi], hierarchy=[roi_str])
filtered_mask, _, _ = _quick_cutto(mask=mask, roi=roi_obj)
area = cv2.countNonZero(filtered_mask)
# Assert that the contours were filtered as expected
assert area == 7