From 9c754ff7d843f5e2c191ad986125961246ef5d6f Mon Sep 17 00:00:00 2001 From: Dominik Schneider Date: Thu, 22 Jul 2021 10:43:59 -0700 Subject: [PATCH 01/63] support kwargs for plot_image --- plantcv/plantcv/_debug.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/plantcv/plantcv/_debug.py b/plantcv/plantcv/_debug.py index fb6b2cd15..cae4f5d88 100644 --- a/plantcv/plantcv/_debug.py +++ b/plantcv/plantcv/_debug.py @@ -5,7 +5,7 @@ from plantcv.plantcv import plot_image -def _debug(visual, filename=None): +def _debug(visual, filename=None, **kwargs): """Save or display a visual for debugging. Inputs: @@ -23,4 +23,4 @@ def _debug(visual, filename=None): print_image(img=visual, filename=filename) elif params.debug == "plot": # If debug is plot, print to the plotting device - plot_image(img=visual) + plot_image(img=visual, **kwargs) From ccc2f5690251e5d13bf03ac86717d0fa59421167 Mon Sep 17 00:00:00 2001 From: Dominik Schneider Date: Thu, 22 Jul 2021 12:02:30 -0700 Subject: [PATCH 02/63] autopep8 formatting on tests.py (--max-line-length=120) --- tests/tests.py | 44 ++++++++++++++++++++++++++++---------------- 1 file changed, 28 insertions(+), 16 deletions(-) diff --git a/tests/tests.py b/tests/tests.py index 4b6dc41c7..607681554 100755 --- a/tests/tests.py +++ b/tests/tests.py @@ -548,7 +548,8 @@ def test_plantcv_parallel_workflowconfig_subdaily_timestampformat(): # Create config instance config = plantcv.parallel.WorkflowConfig() config.input_dir = os.path.join(PARALLEL_TEST_DATA, TEST_IMG_DIR2) - config.json = os.path.join(TEST_IMG_DIR2, "test_plantcv_parallel_metadata_parser_subdaily_timestampformat", "output.json") + config.json = os.path.join( + TEST_IMG_DIR2, "test_plantcv_parallel_metadata_parser_subdaily_timestampformat", "output.json") config.filename_metadata = ["imgtype", "camera", "frame", "zoom", "lifter", "gain", "exposure", "timestamp"] config.workflow = TEST_PIPELINE config.metadata_filters = {"imgtype": "NIR", "camera": "SV"} @@ -562,7 +563,7 @@ def test_plantcv_parallel_workflowconfig_subdaily_timestampformat(): meta = plantcv.parallel.metadata_parser(config=config) assert meta == { 'NIR_SV_0_z1_h1_g0_e65_23_59_59.jpg': { - 'path': os.path.join(PARALLEL_TEST_DATA, 'images_w_date','NIR_SV_0_z1_h1_g0_e65_23_59_59.jpg'), + 'path': os.path.join(PARALLEL_TEST_DATA, 'images_w_date', 'NIR_SV_0_z1_h1_g0_e65_23_59_59.jpg'), 'imgtype': 'NIR', 'camera': 'SV', 'frame': '0', @@ -572,7 +573,7 @@ def test_plantcv_parallel_workflowconfig_subdaily_timestampformat(): 'exposure': 'e65', 'timestamp': '23_59_59', 'measurementlabel': 'none', - 'cartag':'none', + 'cartag': 'none', 'id': 'none', 'treatment': 'none', 'plantbarcode': 'none', @@ -580,7 +581,7 @@ def test_plantcv_parallel_workflowconfig_subdaily_timestampformat(): } } - + def test_plantcv_parallel_check_date_range_wrongdateformat(): start_date = 10 end_date = 10 @@ -1110,6 +1111,7 @@ def test_plantcv_outputs_add_observation_invalid_type(): outputs.add_observation(sample='default', variable='test', trait='test variable', method='type', scale='none', datatype=list, value=np.array([2]), label=[]) + def test_plantcv_outputs_save_results_json_newfile(tmpdir): # Create a test tmp directory cache_dir = tmpdir.mkdir("sub") @@ -1163,6 +1165,7 @@ def test_plantcv_outputs_save_results_csv(tmpdir): test_results = fp.read() assert results == test_results + def test_plantcv_acute(): # Read in test data mask = cv2.imread(os.path.join(TEST_DATA, TEST_MASK_SMALL), -1) @@ -1385,6 +1388,7 @@ def test_plantcv_analyze_color(): _ = pcv.analyze_color(rgb_img=img, mask=mask, hist_plot_type='rgb') assert pcv.outputs.observations['default']['hue_median']['value'] == 84.0 + def test_plantcv_analyze_color_incorrect_image(): img_binary = cv2.imread(os.path.join(TEST_DATA, TEST_INPUT_BINARY), -1) mask = cv2.imread(os.path.join(TEST_DATA, TEST_INPUT_BINARY), -1) @@ -1392,6 +1396,8 @@ def test_plantcv_analyze_color_incorrect_image(): _ = pcv.analyze_color(rgb_img=img_binary, mask=mask, hist_plot_type=None) # # + + def test_plantcv_analyze_color_bad_hist_type(): img = cv2.imread(os.path.join(TEST_DATA, TEST_INPUT_COLOR)) mask = cv2.imread(os.path.join(TEST_DATA, TEST_INPUT_BINARY), -1) @@ -1546,6 +1552,7 @@ def test_plantcv_analyze_thermal_values(): thermal_hist = pcv.analyze_thermal_values(thermal_array=img, mask=mask, histplot=True) assert thermal_hist is not None and pcv.outputs.observations['default']['median_temp']['value'] == 33.20922 + def test_plantcv_apply_mask_white(): # Test cache directory cache_dir = os.path.join(TEST_TMPDIR, "test_plantcv_apply_mask_white") @@ -2375,6 +2382,7 @@ def test_plantcv_image_subtract(): new_img = pcv.image_subtract(img1, img2) assert np.array_equal(new_img, np.zeros(np.shape(new_img), np.uint8)) + def test_plantcv_image_subtract_fail(): # read in images img1 = cv2.imread(os.path.join(TEST_DATA, TEST_INPUT_BINARY), -1) @@ -3271,6 +3279,7 @@ def test_plantcv_roi_objects_grayscale_input(): # Assert that the contours were filtered as expected assert len(kept_contours) == 1891 + def test_plantcv_rotate(): img = cv2.imread(os.path.join(TEST_DATA, TEST_INPUT_COLOR)) rotated = pcv.rotate(img=img, rotation_deg=45, crop=True) @@ -3278,6 +3287,7 @@ def test_plantcv_rotate(): rotateavg = np.average(rotated) assert rotateavg != imgavg + def test_plantcv_transform_rotate(): # Test cache directory cache_dir = os.path.join(TEST_TMPDIR, "test_plantcv_rotate_img") @@ -4116,9 +4126,9 @@ def test_plantcv_morphology_segment_insertion_angle(): pcv.params.debug = "print" _ = pcv.morphology.segment_insertion_angle(pruned, segmented_img, leaf_obj, stem_obj, 10) assert pcv.outputs.observations['default']['segment_insertion_angle']['value'][:6] == ['NA', 'NA', 'NA', - 24.956918822001636, - 50.7313343343401, - 56.427712102130734] + 24.956918822001636, + 50.7313343343401, + 56.427712102130734] def test_plantcv_morphology_segment_insertion_angle_bad_stem(): @@ -5793,8 +5803,8 @@ def test_plantcv_transform_warp_default(): pcv.params.debug = "plot" img = create_test_img((12, 10, 3)) refimg = create_test_img((12, 10, 3)) - pts = [(0, 0),(1, 0),(0, 3),(4, 4)] - refpts = [(0, 0),(1, 0),(0, 3),(4, 4)] + pts = [(0, 0), (1, 0), (0, 3), (4, 4)] + refpts = [(0, 0), (1, 0), (0, 3), (4, 4)] warped_img, mat = pcv.transform.warp(img, refimg, pts, refpts, method="default") assert mat.shape == (3, 3) @@ -5830,8 +5840,8 @@ def test_plantcv_transform_warp_ransac(): @pytest.mark.parametrize("pts, refpts", [ - [[(0,0)],[(0,0),(0,1)]], # different # of points provided for img and refimg - [[(0,0)],[(0,0)]], # not enough pairs of points provided + [[(0, 0)], [(0, 0), (0, 1)]], # different # of points provided for img and refimg + [[(0, 0)], [(0, 0)]], # not enough pairs of points provided [[(0, 0), (0, 14), (9, 14), (0, 9), (3, 3)], [(0, 0), (149, 0), (99, 149), (0, 99), (3, 3)]] # homography not able to be calculated (cannot converge) ]) @@ -5846,8 +5856,8 @@ def test_plantcv_transform_warp_err(pts, refpts): def test_plantcv_transform_warp_align(): img = create_test_img((10, 10, 3)) refimg = create_test_img((11, 11)) - mat = np.array([[ 1.00000000e+00, 1.04238500e-15, -7.69185075e-16], - [ 1.44375646e-16, 1.00000000e+00, 0.00000000e+00], + mat = np.array([[1.00000000e+00, 1.04238500e-15, -7.69185075e-16], + [1.44375646e-16, 1.00000000e+00, 0.00000000e+00], [-5.41315251e-16, 1.78930521e-15, 1.00000000e+00]]) warp_img = pcv.transform.warp_align(img=img, mat=mat, refimg=refimg) assert warp_img.shape == (11, 11, 3) @@ -6140,6 +6150,7 @@ def test_plantcv_threshold_mask_bad_nan_bad_input(): assert mask11.all() == np.zeros(sz, dtype='uint8').all() + def test_plantcv_threshold_mask_bad_input_color_img(): # Read in test data bad_img = cv2.imread(os.path.join(TEST_DATA, TEST_INPUT_COLOR)) @@ -6302,8 +6313,9 @@ def test_plantcv_visualize_colorize_masks_bad_color_input(): with pytest.raises(RuntimeError): _ = pcv.visualize.colorize_masks(masks=[mask['plant'], mask['background']], colors=['red', 1.123]) + def test_plantcv_visualize_colorize_label_img(): - label_img = np.array([[1,2,3],[4,5,6],[7,8,9]]) + label_img = np.array([[1, 2, 3], [4, 5, 6], [7, 8, 9]]) pcv.params.debug = None colored_img = pcv.visualize.colorize_label_img(label_img) assert (colored_img.shape[0:-1] == label_img.shape) and colored_img.shape[-1] == 3 @@ -6380,13 +6392,13 @@ def test_plantcv_visualize_clustered_contours(): # Reset the saved color scale (can be saved between tests) pcv.params.saved_color_scale = None _ = pcv.visualize.clustered_contours(img=img1, grouped_contour_indices=cluster, roi_objects=objs, - roi_obj_hierarchy=obj_hierarchy, bounding=False) + roi_obj_hierarchy=obj_hierarchy, bounding=False) # Test in print mode pcv.params.debug = "print" # Reset the saved color scale (can be saved between tests) pcv.params.saved_color_scale = None cluster_img = pcv.visualize.clustered_contours(img=img, grouped_contour_indices=cluster, roi_objects=objs, - roi_obj_hierarchy=obj_hierarchy, nrow=2, ncol=2, bounding=True) + roi_obj_hierarchy=obj_hierarchy, nrow=2, ncol=2, bounding=True) assert np.sum(cluster_img) > np.sum(img) From b8e7e6f4a4bf3fc16d0bed5e49fc4fac022ffb3f Mon Sep 17 00:00:00 2001 From: Dominik Schneider Date: Thu, 22 Jul 2021 12:07:00 -0700 Subject: [PATCH 03/63] acute_vertex --- plantcv/plantcv/acute_vertex.py | 47 ++++++++++++++++++--------------- tests/tests.py | 12 --------- 2 files changed, 26 insertions(+), 33 deletions(-) diff --git a/plantcv/plantcv/acute_vertex.py b/plantcv/plantcv/acute_vertex.py index 3bf5a08e2..77ca23de8 100755 --- a/plantcv/plantcv/acute_vertex.py +++ b/plantcv/plantcv/acute_vertex.py @@ -4,10 +4,9 @@ import cv2 import numpy as np import math -from plantcv.plantcv import print_image -from plantcv.plantcv import plot_image from plantcv.plantcv import params from plantcv.plantcv import outputs +from plantcv.plantcv._debug import _debug def acute_vertex(img, obj, win, thresh, sep, label="default"): @@ -50,15 +49,17 @@ def acute_vertex(img, obj, win, thresh, sep, label="default"): post_x, post_y = obj[i + win].ravel() # Angle in radians derived from Law of Cosines, converted to degrees - P12 = np.sqrt((x-pre_x)*(x-pre_x)+(y-pre_y)*(y-pre_y)) - P13 = np.sqrt((x-post_x)*(x-post_x)+(y-post_y)*(y-post_y)) - P23 = np.sqrt((pre_x-post_x)*(pre_x-post_x)+(pre_y-post_y)*(pre_y-post_y)) - if (2*P12*P13) > 0.001: - dot = (P12*P12 + P13*P13 - P23*P23)/(2*P12*P13) - elif (2*P12*P13) < 0.001: - dot = (P12*P12 + P13*P13 - P23*P23)/0.001 - - if dot < -1: # If float exceeds -1 prevent arcos error and force to equal -1 + P12 = np.sqrt((x - pre_x) * (x - pre_x) + (y - pre_y) * (y - pre_y)) + P13 = np.sqrt((x - post_x) * (x - post_x) + (y - post_y) * + (y - post_y)) + P23 = np.sqrt((pre_x - post_x) * (pre_x - post_x) + (pre_y - post_y) * + (pre_y - post_y)) + if (2 * P12 * P13) > 0.001: + dot = (P12 * P12 + P13 * P13 - P23 * P23) / (2 * P12 * P13) + elif (2 * P12 * P13) < 0.001: + dot = (P12 * P12 + P13 * P13 - P23 * P23) / 0.001 + + if dot < -1: # If float exceeds -1 prevent arcos error and force to equal -1 dot = -1 ang = math.degrees(math.acos(dot)) chain.append(ang) @@ -73,11 +74,11 @@ def acute_vertex(img, obj, win, thresh, sep, label="default"): # Sep is the number of points to evaluate the number of vertices out = [] tester = [] - for i in range(len(index)-1): + for i in range(len(index) - 1): # print str(index[i]) - if index[i+1] - index[i] < sep: + if index[i + 1] - index[i] < sep: tester.append(index[i]) - if index[i+1] - index[i] >= sep: + if index[i + 1] - index[i] >= sep: tester.append(index[i]) # print(tester) angles = ([chain[d] for d in tester]) @@ -99,14 +100,18 @@ def acute_vertex(img, obj, win, thresh, sep, label="default"): x, y = i.ravel() cv2.circle(img2, (x, y), params.line_thickness, (255, 0, 255), -1) - if params.debug == 'print': - print_image(img2, os.path.join(params.debug_outdir, str(params.device) + '_acute_vertices.png')) - elif params.debug == 'plot': - plot_image(img2) + _debug(visual=img2, + filename=os.path.join(params.debug_outdir, + str(params.device) + '_acute_vertices.png')) # Store into global measurements - outputs.add_observation(sample=label, variable='tip_coordinates', trait='tip coordinates', - method='plantcv.plantcv.acute_vertex', scale='none', datatype=list, - value=acute_points, label='none') + outputs.add_observation(sample=label, + variable='tip_coordinates', + trait='tip coordinates', + method='plantcv.plantcv.acute_vertex', + scale='none', + datatype=list, + value=acute_points, + label='none') return acute_points, img2 diff --git a/tests/tests.py b/tests/tests.py index 607681554..2234b0ab1 100755 --- a/tests/tests.py +++ b/tests/tests.py @@ -1187,22 +1187,10 @@ def test_plantcv_acute(): def test_plantcv_acute_vertex(): - # Test cache directory - cache_dir = os.path.join(TEST_TMPDIR, "test_plantcv_acute_vertex") - os.mkdir(cache_dir) - pcv.params.debug_outdir = cache_dir # Read in test data img = cv2.imread(os.path.join(TEST_DATA, TEST_VIS_SMALL)) contours_npz = np.load(os.path.join(TEST_DATA, TEST_VIS_COMP_CONTOUR), encoding="latin1") obj_contour = contours_npz['arr_0'] - # Test with debug = "print" - pcv.params.debug = "print" - _ = pcv.acute_vertex(obj=obj_contour, win=5, thresh=15, sep=5, img=img, label="prefix") - _ = pcv.acute_vertex(obj=[], win=5, thresh=15, sep=5, img=img) - _ = pcv.acute_vertex(obj=[], win=.01, thresh=.01, sep=1, img=img) - # Test with debug = "plot" - pcv.params.debug = "plot" - _ = pcv.acute_vertex(obj=obj_contour, win=5, thresh=15, sep=5, img=img) # Test with debug = None pcv.params.debug = None acute = pcv.acute_vertex(obj=obj_contour, win=5, thresh=15, sep=5, img=img) From 71fc2ef397b86f4f24337ec52fc29ab66de4b240 Mon Sep 17 00:00:00 2001 From: Dominik Schneider Date: Thu, 22 Jul 2021 12:13:15 -0700 Subject: [PATCH 04/63] analyze_bound_horizontal --- plantcv/plantcv/analyze_bound_horizontal.py | 17 +++++++---------- tests/tests.py | 12 +----------- 2 files changed, 8 insertions(+), 21 deletions(-) diff --git a/plantcv/plantcv/analyze_bound_horizontal.py b/plantcv/plantcv/analyze_bound_horizontal.py index 58f5d6516..9d33f90a0 100755 --- a/plantcv/plantcv/analyze_bound_horizontal.py +++ b/plantcv/plantcv/analyze_bound_horizontal.py @@ -3,14 +3,14 @@ import os import cv2 import numpy as np -from plantcv.plantcv import print_image -from plantcv.plantcv import plot_image +from plantcv.plantcv._debug import _debug from plantcv.plantcv import params from plantcv.plantcv import outputs def analyze_bound_horizontal(img, obj, mask, line_position, label="default"): - """User-input boundary line tool + """ + User-input boundary line tool Inputs: img = RGB or grayscale image data for plotting @@ -29,7 +29,6 @@ def analyze_bound_horizontal(img, obj, mask, line_position, label="default"): :param label: str :return analysis_images: list """ - ori_img = np.copy(img) # Draw line horizontal line through bottom of image, that is adjusted to user input height @@ -139,12 +138,10 @@ def analyze_bound_horizontal(img, obj, mask, line_position, label="default"): params.line_thickness) cv2.line(wback, (int(cmx), y_coor - 2), (int(cmx), y_coor + height_below_bound), (0, 255, 0), params.line_thickness) - if params.debug == 'print': - print_image(wback, os.path.join(params.debug_outdir, str(params.device) + '_boundary_on_white.png')) - print_image(ori_img, os.path.join(params.debug_outdir, str(params.device) + '_boundary_on_img.png')) - if params.debug == 'plot': - plot_image(wback) - plot_image(ori_img) + _debug(visual=wback, + filename=os.path.join(params.debug_outdir, str(params.device) + '_boundary_on_white.png')) + _debug(visual=ori_img, + filename=os.path.join(params.debug_outdir, str(params.device) + '_boundary_on_img.png')) outputs.add_observation(sample=label, variable='horizontal_reference_position', trait='horizontal reference position', diff --git a/tests/tests.py b/tests/tests.py index 2234b0ab1..534dde1d7 100755 --- a/tests/tests.py +++ b/tests/tests.py @@ -1210,27 +1210,17 @@ def test_plantcv_acute_vertex_bad_obj(): def test_plantcv_analyze_bound_horizontal(): # Clear previous outputs pcv.outputs.clear() - # Test cache directory - cache_dir = os.path.join(TEST_TMPDIR, "test_plantcv_analyze_bound_horizontal") - os.mkdir(cache_dir) - pcv.params.debug_outdir = cache_dir # Read in test data img = cv2.imread(os.path.join(TEST_DATA, TEST_INPUT_COLOR)) img_above_bound_only = cv2.imread(os.path.join(TEST_DATA, TEST_MASK_SMALL_PLANT)) mask = cv2.imread(os.path.join(TEST_DATA, TEST_INPUT_BINARY), -1) contours_npz = np.load(os.path.join(TEST_DATA, TEST_INPUT_CONTOURS), encoding="latin1") object_contours = contours_npz['arr_0'] - # Test with debug = "print" - pcv.params.debug = "print" + pcv.params.debug = None _ = pcv.analyze_bound_horizontal(img=img, obj=object_contours, mask=mask, line_position=300, label="prefix") pcv.outputs.clear() _ = pcv.analyze_bound_horizontal(img=img, obj=object_contours, mask=mask, line_position=100) _ = pcv.analyze_bound_horizontal(img=img_above_bound_only, obj=object_contours, mask=mask, line_position=1756) - # Test with debug = "plot" - pcv.params.debug = "plot" - _ = pcv.analyze_bound_horizontal(img=img, obj=object_contours, mask=mask, line_position=1756) - # Test with debug = None - pcv.params.debug = None _ = pcv.analyze_bound_horizontal(img=img, obj=object_contours, mask=mask, line_position=1756) assert len(pcv.outputs.observations["default"]) == 7 From 6eec5e00fa6adef25716467f2f32b55e162f5185 Mon Sep 17 00:00:00 2001 From: Dominik Schneider Date: Thu, 22 Jul 2021 12:17:22 -0700 Subject: [PATCH 05/63] analyze_bound_vertical --- plantcv/plantcv/analyze_bound_vertical.py | 22 +++++++++------------- tests/tests.py | 10 ---------- 2 files changed, 9 insertions(+), 23 deletions(-) diff --git a/plantcv/plantcv/analyze_bound_vertical.py b/plantcv/plantcv/analyze_bound_vertical.py index 021cd6566..6340abb1b 100755 --- a/plantcv/plantcv/analyze_bound_vertical.py +++ b/plantcv/plantcv/analyze_bound_vertical.py @@ -3,21 +3,19 @@ import os import cv2 import numpy as np -from plantcv.plantcv import print_image -from plantcv.plantcv import plot_image +from plantcv.plantcv._debug import _debug from plantcv.plantcv import params from plantcv.plantcv import outputs def analyze_bound_vertical(img, obj, mask, line_position, label="default"): - """User-input boundary line tool + """ + User-input boundary line tool Inputs: img = RGB or grayscale image data for plotting obj = single or grouped contour object mask = Binary mask made from selected contours - shape_header = pass shape header data to function - shape_data = pass shape data so that analyze_bound data can be appended to it line_position = position of boundary line (a value of 0 would draw the line through the left side of the image) label = optional label parameter, modifies the variable name of observations recorded @@ -92,7 +90,7 @@ def analyze_bound_vertical(img, obj, mask, line_position, label="default"): cv2.line(ori_img, point3, point4, (255, 0, 255), params.line_thickness) cv2.line(wback, point3, point4, (255, 0, 255), params.line_thickness) m = cv2.moments(mask, binaryImage=True) - cmx, cmy = (m['m10'] / m['m00'], m['m01'] / m['m00']) + _, cmy = (m['m10'] / m['m00'], m['m01'] / m['m00']) if x_coor - x <= 0: cv2.line(ori_img, (x, int(cmy)), (x + width, int(cmy)), (0, 255, 0), params.line_thickness) cv2.line(wback, (x, int(cmy)), (x + width, int(cmy)), (0, 255, 0), params.line_thickness) @@ -121,7 +119,7 @@ def analyze_bound_vertical(img, obj, mask, line_position, label="default"): cv2.line(ori_img, point3, point4, (255, 0, 255), params.line_thickness) cv2.line(wback, point3, point4, (255, 0, 255), params.line_thickness) m = cv2.moments(mask, binaryImage=True) - cmx, cmy = (m['m10'] / m['m00'], m['m01'] / m['m00']) + _, cmy = (m['m10'] / m['m00'], m['m01'] / m['m00']) if x_coor - x <= 0: cv2.line(ori_img, (x, int(cmy)), (x + width, int(cmy)), (0, 255, 0), params.line_thickness) cv2.line(wback, (x, int(cmy)), (x + width, int(cmy)), (0, 255, 0), params.line_thickness) @@ -139,12 +137,10 @@ def analyze_bound_vertical(img, obj, mask, line_position, label="default"): params.line_thickness) cv2.line(wback, (x_coor + 2, int(cmy)), (x_coor - width_right_bound, int(cmy)), (0, 255, 0), params.line_thickness) - if params.debug == 'print': - print_image(wback, os.path.join(params.debug_outdir, str(params.device) + '_boundary_on_white.png')) - print_image(ori_img, os.path.join(params.debug_outdir, str(params.device) + '_boundary_on_img.png')) - if params.debug == 'plot': - plot_image(wback) - plot_image(ori_img) + _debug(visual=wback, + filename=os.path.join(params.debug_outdir, str(params.device) + '_boundary_on_white.png')) + _debug(visual=ori_img, + filename=os.path.join(params.debug_outdir, str(params.device) + '_boundary_on_img.png')) outputs.add_observation(sample=label, variable='vertical_reference_position', trait='vertical reference position', method='plantcv.plantcv.analyze_bound_vertical', scale='none', datatype=int, diff --git a/tests/tests.py b/tests/tests.py index 534dde1d7..aeb247e7c 100755 --- a/tests/tests.py +++ b/tests/tests.py @@ -1260,21 +1260,11 @@ def test_plantcv_analyze_bound_horizontal_neg_y(): def test_plantcv_analyze_bound_vertical(): # Clear previous outputs pcv.outputs.clear() - # Test cache directory - cache_dir = os.path.join(TEST_TMPDIR, "test_plantcv_analyze_bound_vertical") - os.mkdir(cache_dir) - pcv.params.debug_outdir = cache_dir # Read in test data img = cv2.imread(os.path.join(TEST_DATA, TEST_INPUT_COLOR)) mask = cv2.imread(os.path.join(TEST_DATA, TEST_INPUT_BINARY), -1) contours_npz = np.load(os.path.join(TEST_DATA, TEST_INPUT_CONTOURS), encoding="latin1") object_contours = contours_npz['arr_0'] - # Test with debug = "print" - pcv.params.debug = "print" - _ = pcv.analyze_bound_vertical(img=img, obj=object_contours, mask=mask, line_position=1000, label="prefix") - # Test with debug = "plot" - pcv.params.debug = "plot" - _ = pcv.analyze_bound_vertical(img=img, obj=object_contours, mask=mask, line_position=1000) # Test with debug = None pcv.params.debug = None _ = pcv.analyze_bound_vertical(img=img, obj=object_contours, mask=mask, line_position=1000) From 4eff1ad1c2dabdc90c241ef4366800063b2fba41 Mon Sep 17 00:00:00 2001 From: Dominik Schneider Date: Thu, 22 Jul 2021 12:36:48 -0700 Subject: [PATCH 06/63] auto_crop --- plantcv/plantcv/auto_crop.py | 36 +++++++++++++++++++----------------- tests/tests.py | 14 ++------------ 2 files changed, 21 insertions(+), 29 deletions(-) diff --git a/plantcv/plantcv/auto_crop.py b/plantcv/plantcv/auto_crop.py index 210800173..f751769f9 100755 --- a/plantcv/plantcv/auto_crop.py +++ b/plantcv/plantcv/auto_crop.py @@ -3,14 +3,14 @@ import os import cv2 import numpy as np -from plantcv.plantcv import print_image -from plantcv.plantcv import plot_image +from plantcv.plantcv._debug import _debug from plantcv.plantcv import params from plantcv.plantcv import fatal_error def auto_crop(img, obj, padding_x=0, padding_y=0, color='black'): - """Resize image. + """ + Resize image. Inputs: img = RGB or grayscale image data @@ -59,13 +59,15 @@ def auto_crop(img, obj, padding_x=0, padding_y=0, color='black'): if color.upper() == 'BLACK': colorval = (0, 0, 0) - cropped = cv2.copyMakeBorder(crop_img, offsety_top, offsety_bottom, offsetx_left, offsetx_right, cv2.BORDER_CONSTANT, value=colorval) + cropped = cv2.copyMakeBorder(crop_img, offsety_top, offsety_bottom, offsetx_left, + offsetx_right, cv2.BORDER_CONSTANT, value=colorval) elif color.upper() == 'WHITE': colorval = (255, 255, 255) - cropped = cv2.copyMakeBorder(crop_img, offsety_top, offsety_bottom, offsetx_left, offsetx_right, cv2.BORDER_CONSTANT, value=colorval) + cropped = cv2.copyMakeBorder(crop_img, offsety_top, offsety_bottom, offsetx_left, + offsetx_right, cv2.BORDER_CONSTANT, value=colorval) elif color.upper() == 'IMAGE': # Check whether the ROI is correctly bounded inside the image - if x - offsetx_right < 0 or y - offsety_top < 0 or x + w + offsetx_right > width or y + h + offsety_bottom > height: + if x - offsetx_right < 0 or y - offsety_top < 0 or x + w + offsetx_right > width or y + h + offsety_bottom > height: cropped = img_copy2[y:y + h, x:x + w] else: # If padding is the image, crop the image with a buffer rather than cropping and adding a buffer @@ -73,16 +75,16 @@ def auto_crop(img, obj, padding_x=0, padding_y=0, color='black'): else: fatal_error('Color was provided but ' + str(color) + ' is not "white", "black", or "image"!') - - if params.debug == 'print': - print_image(img_copy, os.path.join(params.debug_outdir, str(params.device) + "_crop_area.png")) - print_image(cropped, os.path.join(params.debug_outdir, str(params.device) + "_auto_cropped.png")) - elif params.debug == 'plot': - if len(np.shape(img_copy)) == 3: - plot_image(img_copy) - plot_image(cropped) - else: - plot_image(img_copy, cmap='gray') - plot_image(cropped, cmap='gray') + if len(np.shape(img_copy)) == 3: + cmap = None + else: + cmap = 'gray' + + _debug(visual=img_copy, + filename=os.path.join(params.debug_outdir, str(params.device) + "_crop_area.png"), + cmap=cmap) + _debug(visual=cropped, + filename=os.path.join(params.debug_outdir, str(params.device) + "_auto_cropped.png"), + cmap=cmap) return cropped diff --git a/tests/tests.py b/tests/tests.py index aeb247e7c..5aaac95bc 100755 --- a/tests/tests.py +++ b/tests/tests.py @@ -1591,24 +1591,14 @@ def test_plantcv_apply_mask_bad_input(): def test_plantcv_auto_crop(): - # Test cache directory - cache_dir = os.path.join(TEST_TMPDIR, "test_plantcv_auto_crop") - os.mkdir(cache_dir) - pcv.params.debug_outdir = cache_dir # Read in test data img1 = cv2.imread(os.path.join(TEST_DATA, TEST_INPUT_MULTI), -1) contours = np.load(os.path.join(TEST_DATA, TEST_INPUT_MULTI_OBJECT), encoding="latin1") roi_contours = [contours[arr_n] for arr_n in contours] - # Test with debug = "print" - pcv.params.debug = "print" - _ = pcv.auto_crop(img=img1, obj=roi_contours[1], padding_x=(20, 10), padding_y=(20, 10), color='black') - # Test with debug = "plot" - pcv.params.debug = "plot" - _ = pcv.auto_crop(img=img1, obj=roi_contours[1], color='image') - _ = pcv.auto_crop(img=img1, obj=roi_contours[1], padding_x=2000, padding_y=2000, color='image') # Test with debug = None pcv.params.debug = None - cropped = pcv.auto_crop(img=img1, obj=roi_contours[1], padding_x=20, padding_y=20, color='black') + _ = pcv.auto_crop(img=img1, obj=roi_contours[1], padding_x=(20, 10), padding_y=(20, 10), color='black') + cropped = pcv.auto_crop(img=img1, obj=roi_contours[1], padding_x=20, padding_y=20, color='image') x, y, z = np.shape(img1) x1, y1, z1 = np.shape(cropped) assert x > x1 From c526fca599dd471b594234d722663dd2c0d6459f Mon Sep 17 00:00:00 2001 From: Dominik Schneider Date: Thu, 22 Jul 2021 13:45:40 -0700 Subject: [PATCH 07/63] background_subtraction --- plantcv/plantcv/background_subtraction.py | 15 ++++++--------- tests/tests.py | 21 --------------------- 2 files changed, 6 insertions(+), 30 deletions(-) diff --git a/plantcv/plantcv/background_subtraction.py b/plantcv/plantcv/background_subtraction.py index 6e3ec86ba..72c0c3946 100644 --- a/plantcv/plantcv/background_subtraction.py +++ b/plantcv/plantcv/background_subtraction.py @@ -4,14 +4,14 @@ import os import cv2 import numpy as np -from plantcv.plantcv import print_image -from plantcv.plantcv import plot_image +from plantcv.plantcv._debug import _debug from plantcv.plantcv import fatal_error from plantcv.plantcv import params def background_subtraction(background_image, foreground_image): - """Creates a binary image from a background subtraction of the foreground using cv2.BackgroundSubtractorMOG(). + """ + Creates a binary image from a background subtraction of the foreground using cv2.BackgroundSubtractorMOG(). The binary image returned is a mask that should contain mostly foreground pixels. The background image should be the same background as the foreground image except not containing the object of interest. @@ -31,7 +31,6 @@ def background_subtraction(background_image, foreground_image): :param foreground_image: numpy.ndarray :return fgmask: numpy.ndarray """ - params.device += 1 # Copying images to make sure not alter originals bg_img = np.copy(background_image) @@ -57,10 +56,8 @@ def background_subtraction(background_image, foreground_image): # Applying the foreground image to the background subtractor (therefore removing the background) fgmask = bgsub.apply(fg_img) - # Debug options - if params.debug == "print": - print_image(fgmask, os.path.join(params.debug_outdir, str(params.device) + "_background_subtraction.png")) - elif params.debug == "plot": - plot_image(fgmask, cmap="gray") + _debug(visual=fgmask, + filename=os.path.join(params.debug_outdir, str(params.device) + "_background_subtraction.png"), + cmap='gray') return fgmask diff --git a/tests/tests.py b/tests/tests.py index 5aaac95bc..ff67940fa 100755 --- a/tests/tests.py +++ b/tests/tests.py @@ -3681,27 +3681,6 @@ def test_plantcv_background_subtraction(): assert (all(truths)) -def test_plantcv_background_subtraction_debug(): - # Test cache directory - cache_dir = os.path.join(TEST_TMPDIR, "test_plantcv_background_subtraction_debug") - os.mkdir(cache_dir) - pcv.params.debug_outdir = cache_dir - # List to hold result of all tests. - truths = [] - fg_img = cv2.imread(os.path.join(TEST_DATA, TEST_FOREGROUND)) - bg_img = cv2.imread(os.path.join(TEST_DATA, TEST_BACKGROUND)) - # Test with debug = "print" - pcv.params.debug = "print" - fgmask = pcv.background_subtraction(background_image=bg_img, foreground_image=fg_img) - truths.append(np.sum(fgmask) > 0) - # Test with debug = "plot" - pcv.params.debug = "plot" - fgmask = pcv.background_subtraction(background_image=bg_img, foreground_image=fg_img) - truths.append(np.sum(fgmask) > 0) - # All of these should be true for the function to pass testing. - assert (all(truths)) - - def test_plantcv_background_subtraction_bad_img_type(): fg_color = cv2.imread(os.path.join(TEST_DATA, TEST_FOREGROUND)) bg_gray = cv2.imread(os.path.join(TEST_DATA, TEST_BACKGROUND), 0) From 4ad81131352fa14018478bd5a1800c63b3bf4df8 Mon Sep 17 00:00:00 2001 From: Dominik Schneider Date: Sat, 24 Jul 2021 09:24:23 -0700 Subject: [PATCH 08/63] fix cov auto_crop --- tests/tests.py | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/tests/tests.py b/tests/tests.py index ff67940fa..f249ee9e0 100755 --- a/tests/tests.py +++ b/tests/tests.py @@ -1597,7 +1597,11 @@ def test_plantcv_auto_crop(): roi_contours = [contours[arr_n] for arr_n in contours] # Test with debug = None pcv.params.debug = None + # padding as tuple _ = pcv.auto_crop(img=img1, obj=roi_contours[1], padding_x=(20, 10), padding_y=(20, 10), color='black') + # padding 0 so crop same as image + _ = pcv.auto_crop(img=img1, obj=roi_contours[1], color='image') + # padding as int cropped = pcv.auto_crop(img=img1, obj=roi_contours[1], padding_x=20, padding_y=20, color='image') x, y, z = np.shape(img1) x1, y1, z1 = np.shape(cropped) From a84945b4d44d08442902a65e7fadfc94e1bbc165 Mon Sep 17 00:00:00 2001 From: Dominik Schneider Date: Tue, 17 Aug 2021 14:43:07 -0700 Subject: [PATCH 09/63] canny edge detect --- plantcv/plantcv/canny_edge_detect.py | 15 ++++++--------- tests/tests.py | 5 ----- 2 files changed, 6 insertions(+), 14 deletions(-) diff --git a/plantcv/plantcv/canny_edge_detect.py b/plantcv/plantcv/canny_edge_detect.py index 6bf74d4af..ad14c9869 100644 --- a/plantcv/plantcv/canny_edge_detect.py +++ b/plantcv/plantcv/canny_edge_detect.py @@ -1,7 +1,6 @@ # Canny edge detection -from plantcv.plantcv import print_image -from plantcv.plantcv import plot_image +from plantcv.plantcv._debug import _debug from plantcv.plantcv import dilate from plantcv.plantcv import params from plantcv.plantcv import fatal_error @@ -13,7 +12,8 @@ def canny_edge_detect(img, mask=None, sigma=1.0, low_thresh=None, high_thresh=None, thickness=1, mask_color=None, use_quantiles=False): - """Edge filter an image using the Canny algorithm. + """ + Edge filter an image using the Canny algorithm. Inputs: img = RGB or grayscale image data @@ -52,8 +52,6 @@ def canny_edge_detect(img, mask=None, sigma=1.0, low_thresh=None, high_thresh=No Original author: Lee Kamentsky """ - params.device += 1 - # Check if the image is grayscale; if color img then make it grayscale dimensions = np.shape(img) if len(dimensions) == 3: @@ -83,9 +81,8 @@ def canny_edge_detect(img, mask=None, sigma=1.0, low_thresh=None, high_thresh=No params.debug = debug # Print or plot the binary image - if params.debug == 'print': - print_image(bin_img, os.path.join(params.debug_outdir, (str(params.device) + '_canny_edge_detect.png'))) - elif params.debug == 'plot': - plot_image(bin_img, cmap='gray') + _debug(visual=bin_img, + filename=os.path.join(params.debug_outdir, (str(params.device) + '_canny_edge_detect.png')), + cmap='gray') return bin_img diff --git a/tests/tests.py b/tests/tests.py index d91c23580..fefbe7d9a 100755 --- a/tests/tests.py +++ b/tests/tests.py @@ -1656,14 +1656,9 @@ def test_plantcv_canny_edge_detect(): rgb_img = cv2.imread(os.path.join(TEST_DATA, TEST_INPUT_COLOR)) img = cv2.imread(os.path.join(TEST_DATA, TEST_INPUT_BINARY), -1) mask = cv2.imread(os.path.join(TEST_DATA, TEST_INPUT_BINARY), -1) - # Test with debug = "print" - pcv.params.debug = "print" _ = pcv.canny_edge_detect(img=rgb_img, mask=mask, mask_color='white') _ = pcv.canny_edge_detect(img=img, mask=mask, mask_color='black') - # Test with debug = "plot" - pcv.params.debug = "plot" _ = pcv.canny_edge_detect(img=img, thickness=2) - _ = pcv.canny_edge_detect(img=img) # Test with debug = None pcv.params.debug = None edge_img = pcv.canny_edge_detect(img=img) From a3429b5f7c4a678c03a0762c70c4593119413c1b Mon Sep 17 00:00:00 2001 From: Dominik Schneider Date: Tue, 17 Aug 2021 14:48:20 -0700 Subject: [PATCH 10/63] closing --- plantcv/plantcv/closing.py | 12 ++++-------- tests/tests.py | 7 +------ 2 files changed, 5 insertions(+), 14 deletions(-) diff --git a/plantcv/plantcv/closing.py b/plantcv/plantcv/closing.py index 83b70c4c3..53197dc1e 100644 --- a/plantcv/plantcv/closing.py +++ b/plantcv/plantcv/closing.py @@ -2,8 +2,7 @@ import numpy as np from skimage import morphology from plantcv.plantcv import params -from plantcv.plantcv import print_image -from plantcv.plantcv import plot_image +from plantcv.plantcv._debug import _debug from plantcv.plantcv import fatal_error @@ -19,8 +18,6 @@ def closing(gray_img, kernel=None): :return filtered_img: ndarray """ - params.device += 1 - # Make sure the image is binary/grayscale if len(np.shape(gray_img)) != 2: fatal_error("Input image must be grayscale or binary") @@ -33,9 +30,8 @@ def closing(gray_img, kernel=None): else: filtered_img = morphology.closing(gray_img, kernel) - if params.debug == 'print': - print_image(filtered_img, os.path.join(params.debug_outdir, str(params.device) + '_opening' + '.png')) - elif params.debug == 'plot': - plot_image(filtered_img, cmap='gray') + _debug(visual=filtered_img, + filename=os.path.join(params.debug_outdir, str(params.device) + '_opening' + '.png'), + cmap='gray') return filtered_img diff --git a/tests/tests.py b/tests/tests.py index fefbe7d9a..e3d2d6a6c 100755 --- a/tests/tests.py +++ b/tests/tests.py @@ -1693,12 +1693,7 @@ def test_plantcv_closing(): bin_img = cv2.imread(os.path.join(TEST_DATA, TEST_INPUT_BINARY), -1) # Test with debug=None pcv.params.debug = None - _ = pcv.closing(gray_img) - # Test with debug='plot' - pcv.params.debug = 'plot' - _ = pcv.closing(bin_img, np.ones((4, 4), np.uint8)) - # Test with debug='print' - pcv.params.debug = 'print' + _ = pcv.closing(gray_img, np.ones((4, 4), np.uint8)) filtered_img = pcv.closing(bin_img) assert np.sum(filtered_img) == 16261860 From 66b98ddd348bd5ba8a0d271fc65185fd6f27d599 Mon Sep 17 00:00:00 2001 From: Dominik Schneider Date: Tue, 17 Aug 2021 15:00:52 -0700 Subject: [PATCH 11/63] cluster contours --- plantcv/plantcv/cluster_contours.py | 12 ++++-------- tests/tests.py | 14 +------------- 2 files changed, 5 insertions(+), 21 deletions(-) diff --git a/plantcv/plantcv/cluster_contours.py b/plantcv/plantcv/cluster_contours.py index d57fbeeaf..0d10da0ed 100755 --- a/plantcv/plantcv/cluster_contours.py +++ b/plantcv/plantcv/cluster_contours.py @@ -1,8 +1,7 @@ import os import cv2 import numpy as np -from plantcv.plantcv import print_image -from plantcv.plantcv import plot_image +from plantcv.plantcv._debug import _debug from plantcv.plantcv import color_palette from plantcv.plantcv import params @@ -37,8 +36,6 @@ def cluster_contours(img, roi_objects, roi_obj_hierarchy, nrow=1, ncol=1, show_g :return roi_obj_hierarchy: list """ - params.device += 1 - if len(np.shape(img)) == 3: iy, ix, iz = np.shape(img) else: @@ -140,9 +137,8 @@ def digitize(a, step): cv2.line(img_copy, (0, y), (ix, y), (255, 0, 0), params.line_thickness) for x in cbreaks: cv2.line(img_copy, (x, 0), (x, iy), (255, 0, 0), params.line_thickness) - if params.debug == 'print': - print_image(img_copy, os.path.join(params.debug_outdir, str(params.device) + '_clusters.png')) - elif params.debug == 'plot': - plot_image(img_copy) + + _debug(visual=img_copy, + filename=os.path.join(params.debug_outdir, str(params.device) + '_clusters.png')) return grouped_contour_indexes, contours, roi_obj_hierarchy diff --git a/tests/tests.py b/tests/tests.py index e3d2d6a6c..e8cad4edb 100755 --- a/tests/tests.py +++ b/tests/tests.py @@ -1716,15 +1716,9 @@ def test_plantcv_cluster_contours(): hierarchy = np.load(os.path.join(TEST_DATA, TEST_INPUT_MULTI_HIERARCHY), encoding="latin1") objs = [roi_objects[arr_n] for arr_n in roi_objects] obj_hierarchy = hierarchy['arr_0'] - # Test with debug = "print" - pcv.params.debug = "print" - _ = pcv.cluster_contours(img=img1, roi_objects=objs, roi_obj_hierarchy=obj_hierarchy, nrow=4, ncol=6) - _ = pcv.cluster_contours(img=img1, roi_objects=objs, roi_obj_hierarchy=obj_hierarchy, show_grid=True) - # Test with debug = "plot" - pcv.params.debug = "plot" - _ = pcv.cluster_contours(img=img1, roi_objects=objs, roi_obj_hierarchy=obj_hierarchy, nrow=4, ncol=6) # Test with debug = None pcv.params.debug = None + _ = pcv.cluster_contours(img=img1, roi_objects=objs, roi_obj_hierarchy=obj_hierarchy, show_grid=True) clusters_i, contours, hierarchy = pcv.cluster_contours(img=img1, roi_objects=objs, roi_obj_hierarchy=obj_hierarchy, nrow=4, ncol=6) lenori = len(objs) @@ -1743,12 +1737,6 @@ def test_plantcv_cluster_contours_grayscale_input(): hierachy = np.load(os.path.join(TEST_DATA, TEST_INPUT_MULTI_HIERARCHY), encoding="latin1") objs = [roi_objects[arr_n] for arr_n in roi_objects] obj_hierarchy = hierachy['arr_0'] - # Test with debug = "print" - pcv.params.debug = "print" - _ = pcv.cluster_contours(img=img1, roi_objects=objs, roi_obj_hierarchy=obj_hierarchy, nrow=4, ncol=6) - # Test with debug = "plot" - pcv.params.debug = "plot" - _ = pcv.cluster_contours(img=img1, roi_objects=objs, roi_obj_hierarchy=obj_hierarchy, nrow=4, ncol=6) # Test with debug = None pcv.params.debug = None clusters_i, contours, hierachy = pcv.cluster_contours(img=img1, roi_objects=objs, roi_obj_hierarchy=obj_hierarchy, From b1b13c31d17ba5e0cbb78e3966af47c0e6b3c03d Mon Sep 17 00:00:00 2001 From: Dominik Schneider Date: Tue, 17 Aug 2021 15:06:57 -0700 Subject: [PATCH 12/63] crop --- plantcv/plantcv/crop.py | 15 +++++---------- tests/tests.py | 12 ++---------- 2 files changed, 7 insertions(+), 20 deletions(-) diff --git a/plantcv/plantcv/crop.py b/plantcv/plantcv/crop.py index dba212402..9929a8587 100644 --- a/plantcv/plantcv/crop.py +++ b/plantcv/plantcv/crop.py @@ -3,13 +3,13 @@ import os import cv2 import numpy as np -from plantcv.plantcv import plot_image -from plantcv.plantcv import print_image +from plantcv.plantcv._debug import _debug from plantcv.plantcv import params def crop(img, x, y, h, w): - """Crop image. + """ + Crop image. Inputs: img = RGB, grayscale, or hyperspectral image data @@ -28,7 +28,6 @@ def crop(img, x, y, h, w): :param w: int :return cropped: numpy.ndarray """ - params.device += 1 # Check if the array data format if len(np.shape(img)) > 2 and np.shape(img)[-1] > 3: @@ -45,11 +44,7 @@ def crop(img, x, y, h, w): ref_img = cv2.rectangle(img=ref_img, pt1=pt1, pt2=pt2, color=(255, 0, 0), thickness=params.line_thickness) - if params.debug == "print": - # If debug is print, save the image to a file - print_image(ref_img, os.path.join(params.debug_outdir, str(params.device) + "_crop.png")) - elif params.debug == "plot": - # If debug is plot, print to the plotting device - plot_image(ref_img) + _debug(visual=ref_img, + filename=os.path.join(params.debug_outdir, str(params.device) + "_crop.png")) return cropped diff --git a/tests/tests.py b/tests/tests.py index e8cad4edb..071ed9ae6 100755 --- a/tests/tests.py +++ b/tests/tests.py @@ -1834,11 +1834,7 @@ def test_plantcv_crop(): os.mkdir(cache_dir) pcv.params.debug_outdir = cache_dir img, _, _ = pcv.readimage(os.path.join(TEST_DATA, TEST_INPUT_NIR_MASK), 'gray') - # Test with debug = "print" - pcv.params.debug = "print" - _ = pcv.crop(img=img, x=10, y=10, h=50, w=50) - # Test with debug = "plot" - pcv.params.debug = "plot" + pcv.params.debug = None cropped = pcv.crop(img=img, x=10, y=10, h=50, w=50) assert np.shape(cropped) == (50, 50) @@ -1851,11 +1847,7 @@ def test_plantcv_crop_hyperspectral(): # Read in test data img = np.ones((2056, 2454)) img_stacked = cv2.merge((img, img, img, img)) - # Test with debug = "print" - pcv.params.debug = "print" - _ = pcv.crop(img=img_stacked, x=10, y=10, h=50, w=50) - # Test with debug = "plot" - pcv.params.debug = "plot" + pcv.params.debug = None cropped = pcv.crop(img=img_stacked, x=10, y=10, h=50, w=50) assert np.shape(cropped) == (50, 50, 4) From 98fbd77c0f0fc9afd4740880ece1317703b87c00 Mon Sep 17 00:00:00 2001 From: Dominik Schneider Date: Tue, 17 Aug 2021 15:11:00 -0700 Subject: [PATCH 13/63] dilate --- plantcv/plantcv/dilate.py | 18 +++++++++--------- tests/tests.py | 6 ------ 2 files changed, 9 insertions(+), 15 deletions(-) diff --git a/plantcv/plantcv/dilate.py b/plantcv/plantcv/dilate.py index 4fd9d864f..da22f4abc 100755 --- a/plantcv/plantcv/dilate.py +++ b/plantcv/plantcv/dilate.py @@ -3,13 +3,13 @@ import cv2 import numpy as np import os -from plantcv.plantcv import print_image -from plantcv.plantcv import plot_image +from plantcv.plantcv._debug import _debug from plantcv.plantcv import params def dilate(gray_img, ksize, i): - """Performs morphological 'dilation' filtering. Adds pixel to center of kernel if conditions set in kernel are true. + """ + Performs morphological 'dilation' filtering. Adds pixel to center of kernel if conditions set in kernel are true. Inputs: gray_img = Grayscale (usually binary) image data @@ -31,10 +31,10 @@ def dilate(gray_img, ksize, i): kernel1 = int(ksize) kernel2 = np.ones((kernel1, kernel1), np.uint8) dil_img = cv2.dilate(src=gray_img, kernel=kernel2, iterations=i) - params.device += 1 - if params.debug == 'print': - print_image(dil_img, os.path.join(params.debug_outdir, - str(params.device) + '_dil_image' + str(ksize) + '_itr' + str(i) + '.png')) - elif params.debug == 'plot': - plot_image(dil_img, cmap='gray') + + _debug(visual=dil_img, + filename=os.path.join(params.debug_outdir, + str(params.device) + '_dil_image' + str(ksize) + '_itr' + str(i) + '.png'), + cmap='gray') + return dil_img diff --git a/tests/tests.py b/tests/tests.py index 071ed9ae6..8ddcc0e9c 100755 --- a/tests/tests.py +++ b/tests/tests.py @@ -1957,12 +1957,6 @@ def test_plantcv_dilate(): pcv.params.debug_outdir = cache_dir # Read in test data img = cv2.imread(os.path.join(TEST_DATA, TEST_INPUT_BINARY), -1) - # Test with debug = "print" - pcv.params.debug = "print" - _ = pcv.dilate(gray_img=img, ksize=5, i=1) - # Test with debug = "plot" - pcv.params.debug = "plot" - _ = pcv.dilate(gray_img=img, ksize=5, i=1) # Test with debug = None pcv.params.debug = None dilate_img = pcv.dilate(gray_img=img, ksize=5, i=1) From b2b6e4fa6209b0b4b9c317822f647330a3b533d4 Mon Sep 17 00:00:00 2001 From: Dominik Schneider Date: Tue, 17 Aug 2021 15:13:53 -0700 Subject: [PATCH 14/63] distance transform --- plantcv/plantcv/distance_transform.py | 11 ++++------- tests/tests.py | 6 ------ 2 files changed, 4 insertions(+), 13 deletions(-) diff --git a/plantcv/plantcv/distance_transform.py b/plantcv/plantcv/distance_transform.py index e2b6354f0..83da55423 100644 --- a/plantcv/plantcv/distance_transform.py +++ b/plantcv/plantcv/distance_transform.py @@ -2,8 +2,7 @@ import cv2 import os -from plantcv.plantcv import print_image -from plantcv.plantcv import plot_image +from plantcv.plantcv._debug import _debug from plantcv.plantcv import params @@ -29,13 +28,11 @@ def distance_transform(bin_img, distance_type, mask_size): :return norm_image: numpy.ndarray """ - params.device += 1 dist = cv2.distanceTransform(src=bin_img, distanceType=distance_type, maskSize=mask_size) norm_image = cv2.normalize(src=dist, dst=dist, alpha=0, beta=1, norm_type=cv2.NORM_MINMAX, dtype=cv2.CV_32F) - if params.debug == 'print': - print_image(norm_image, os.path.join(params.debug, str(params.device) + '_distance_transform.png')) - elif params.debug == 'plot': - plot_image(norm_image, cmap='gray') + _debug(visual=norm_image, + filename=os.path.join(params.debug, str(params.device) + '_distance_transform.png'), + cmap='gray') return norm_image diff --git a/tests/tests.py b/tests/tests.py index 8ddcc0e9c..438446b49 100755 --- a/tests/tests.py +++ b/tests/tests.py @@ -2023,12 +2023,6 @@ def test_plantcv_distance_transform(): pcv.params.debug_outdir = cache_dir # Read in test data mask = cv2.imread(os.path.join(TEST_DATA, TEST_INPUT_CROPPED_MASK), -1) - # Test with debug = "print" - pcv.params.debug = "print" - _ = pcv.distance_transform(bin_img=mask, distance_type=1, mask_size=3) - # Test with debug = "plot" - pcv.params.debug = "plot" - _ = pcv.distance_transform(bin_img=mask, distance_type=1, mask_size=3) # Test with debug = None pcv.params.debug = None distance_transform_img = pcv.distance_transform(bin_img=mask, distance_type=1, mask_size=3) From 34f473858891e5c805455312088269000bffa859 Mon Sep 17 00:00:00 2001 From: Dominik Schneider Date: Tue, 17 Aug 2021 15:16:03 -0700 Subject: [PATCH 15/63] erode --- plantcv/plantcv/erode.py | 18 +++++++++--------- tests/tests.py | 6 ------ 2 files changed, 9 insertions(+), 15 deletions(-) diff --git a/plantcv/plantcv/erode.py b/plantcv/plantcv/erode.py index 4f546b0c7..c540d2815 100755 --- a/plantcv/plantcv/erode.py +++ b/plantcv/plantcv/erode.py @@ -3,13 +3,13 @@ import cv2 import numpy as np import os -from plantcv.plantcv import print_image -from plantcv.plantcv import plot_image +from plantcv.plantcv._debug import _debug from plantcv.plantcv import params def erode(gray_img, ksize, i): - """Perform morphological 'erosion' filtering. Keeps pixel in center of the kernel if conditions set in kernel are + """ + Perform morphological 'erosion' filtering. Keeps pixel in center of the kernel if conditions set in kernel are true, otherwise removes pixel. Inputs: @@ -32,10 +32,10 @@ def erode(gray_img, ksize, i): kernel1 = int(ksize) kernel2 = np.ones((kernel1, kernel1), np.uint8) er_img = cv2.erode(src=gray_img, kernel=kernel2, iterations=i) - params.device += 1 - if params.debug == 'print': - print_image(er_img, os.path.join(params.debug_outdir, - str(params.device) + '_er_image' + str(ksize) + '_itr_' + str(i) + '.png')) - elif params.debug == 'plot': - plot_image(er_img, cmap='gray') + + _debug(er_img, + filename=os.path.join(params.debug_outdir, + str(params.device) + '_er_image' + str(ksize) + '_itr_' + str(i) + '.png'), + cmap='gray') + return er_img diff --git a/tests/tests.py b/tests/tests.py index 438446b49..ebb2f054d 100755 --- a/tests/tests.py +++ b/tests/tests.py @@ -1987,12 +1987,6 @@ def test_plantcv_erode(): pcv.params.debug_outdir = cache_dir # Read in test data img = cv2.imread(os.path.join(TEST_DATA, TEST_INPUT_BINARY), -1) - # Test with debug = "print" - pcv.params.debug = "print" - _ = pcv.erode(gray_img=img, ksize=5, i=1) - # Test with debug = "plot" - pcv.params.debug = "plot" - _ = pcv.erode(gray_img=img, ksize=5, i=1) # Test with debug = None pcv.params.debug = None erode_img = pcv.erode(gray_img=img, ksize=5, i=1) From df20d743ac8644bcf5e55f380953e99786ac2bfa Mon Sep 17 00:00:00 2001 From: Dominik Schneider Date: Tue, 17 Aug 2021 15:18:41 -0700 Subject: [PATCH 16/63] fill holes --- plantcv/plantcv/fill_holes.py | 14 ++++++-------- tests/tests.py | 5 ----- 2 files changed, 6 insertions(+), 13 deletions(-) diff --git a/plantcv/plantcv/fill_holes.py b/plantcv/plantcv/fill_holes.py index d6da70f09..1cb426fc3 100644 --- a/plantcv/plantcv/fill_holes.py +++ b/plantcv/plantcv/fill_holes.py @@ -2,15 +2,15 @@ import numpy as np import os -from plantcv.plantcv import print_image -from plantcv.plantcv import plot_image +from plantcv.plantcv._debug import _debug from plantcv.plantcv import fatal_error from plantcv.plantcv import params from scipy.ndimage.morphology import binary_fill_holes def fill_holes(bin_img): - """Flood fills holes in a binary mask + """ + Flood fills holes in a binary mask Inputs: bin_img = Binary image data @@ -21,7 +21,6 @@ def fill_holes(bin_img): :param bin_img: numpy.ndarray :return filtered_img: numpy.ndarray """ - params.device += 1 # Make sure the image is binary if len(np.shape(bin_img)) != 2 or len(np.unique(bin_img)) != 2: @@ -36,9 +35,8 @@ def fill_holes(bin_img): # Cast boolean image to binary and make a copy of the binary image for returning filtered_img = np.copy(bool_img.astype(np.uint8) * 255) - if params.debug == 'print': - print_image(filtered_img, os.path.join(params.debug_outdir, str(params.device) + '_fill_holes' + '.png')) - elif params.debug == 'plot': - plot_image(filtered_img, cmap='gray') + _debug(visual=filtered_img, + filename=os.path.join(params.debug_outdir, str(params.device) + '_fill_holes' + '.png'), + cmap='gray') return filtered_img diff --git a/tests/tests.py b/tests/tests.py index ebb2f054d..615be1da9 100755 --- a/tests/tests.py +++ b/tests/tests.py @@ -2059,11 +2059,6 @@ def test_plantcv_fill_holes(): pcv.params.debug_outdir = cache_dir # Read in test data img = cv2.imread(os.path.join(TEST_DATA, TEST_INPUT_BINARY), -1) - # Test with debug = "print" - pcv.params.debug = "print" - _ = pcv.fill_holes(bin_img=img) - pcv.params.debug = "plot" - _ = pcv.fill_holes(bin_img=img) # Test with debug = None pcv.params.debug = None fill_img = pcv.fill_holes(bin_img=img) From a0feb28908336d3cfd6c0b7a8af82553b2051573 Mon Sep 17 00:00:00 2001 From: Dominik Schneider Date: Tue, 17 Aug 2021 15:20:14 -0700 Subject: [PATCH 17/63] fill --- plantcv/plantcv/fill.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/plantcv/plantcv/fill.py b/plantcv/plantcv/fill.py index 3e585c936..7dc1dd658 100755 --- a/plantcv/plantcv/fill.py +++ b/plantcv/plantcv/fill.py @@ -9,7 +9,8 @@ def fill(bin_img, size): - """Identifies objects and fills objects that are less than size. + """ + Identifies objects and fills objects that are less than size. Inputs: bin_img = Binary image data @@ -23,7 +24,6 @@ def fill(bin_img, size): :param size: int :return filtered_img: numpy.ndarray """ - params.device += 1 # Make sure the image is binary if len(np.shape(bin_img)) != 2 or len(np.unique(bin_img)) != 2: From 7588f830c3dba62c874acd6bd4595a030b81c243 Mon Sep 17 00:00:00 2001 From: Dominik Schneider Date: Tue, 17 Aug 2021 15:25:00 -0700 Subject: [PATCH 18/63] find objects --- plantcv/plantcv/find_objects.py | 11 ++++------- tests/tests.py | 10 ++-------- 2 files changed, 6 insertions(+), 15 deletions(-) diff --git a/plantcv/plantcv/find_objects.py b/plantcv/plantcv/find_objects.py index d0250abb5..ecd6556a5 100755 --- a/plantcv/plantcv/find_objects.py +++ b/plantcv/plantcv/find_objects.py @@ -3,8 +3,7 @@ import cv2 import numpy as np import os -from plantcv.plantcv import print_image -from plantcv.plantcv import plot_image +from plantcv.plantcv._debug import _debug from plantcv.plantcv import params @@ -26,7 +25,6 @@ def find_objects(img, mask): :return hierarchy: numpy.ndarray """ - params.device += 1 mask1 = np.copy(mask) ori_img = np.copy(img) # If the reference image is grayscale convert it to color @@ -35,9 +33,8 @@ def find_objects(img, mask): objects, hierarchy = cv2.findContours(mask1, cv2.RETR_TREE, cv2.CHAIN_APPROX_NONE)[-2:] for i, cnt in enumerate(objects): cv2.drawContours(ori_img, objects, i, (255, 102, 255), -1, lineType=8, hierarchy=hierarchy) - if params.debug == 'print': - print_image(ori_img, os.path.join(params.debug_outdir, str(params.device) + '_id_objects.png')) - elif params.debug == 'plot': - plot_image(ori_img) + + _debug(visual=ori_img, + filename=os.path.join(params.debug_outdir, str(params.device) + '_id_objects.png')) return objects, hierarchy diff --git a/tests/tests.py b/tests/tests.py index 615be1da9..661dc40fe 100755 --- a/tests/tests.py +++ b/tests/tests.py @@ -2084,12 +2084,6 @@ def test_plantcv_find_objects(): # Read in test data img = cv2.imread(os.path.join(TEST_DATA, TEST_INPUT_COLOR)) mask = cv2.imread(os.path.join(TEST_DATA, TEST_INPUT_BINARY), -1) - # Test with debug = "print" - pcv.params.debug = "print" - _ = pcv.find_objects(img=img, mask=mask) - # Test with debug = "plot" - pcv.params.debug = "plot" - _ = pcv.find_objects(img=img, mask=mask) # Test with debug = None pcv.params.debug = None contours, hierarchy = pcv.find_objects(img=img, mask=mask) @@ -2105,8 +2099,8 @@ def test_plantcv_find_objects_grayscale_input(): # Read in test data img = cv2.imread(os.path.join(TEST_DATA, TEST_INPUT_COLOR), 0) mask = cv2.imread(os.path.join(TEST_DATA, TEST_INPUT_BINARY), -1) - # Test with debug = "plot" - pcv.params.debug = "plot" + # Test with debug = None + pcv.params.debug = None contours, hierarchy = pcv.find_objects(img=img, mask=mask) # Assert the correct number of contours are found assert len(contours) == 2 From 414dec3d05ac73e7dac4328c08f5eeb5ea9fe40c Mon Sep 17 00:00:00 2001 From: Dominik Schneider Date: Tue, 17 Aug 2021 15:38:11 -0700 Subject: [PATCH 19/63] fip --- plantcv/plantcv/flip.py | 22 +++++++++++----------- tests/tests.py | 8 +------- 2 files changed, 12 insertions(+), 18 deletions(-) diff --git a/plantcv/plantcv/flip.py b/plantcv/plantcv/flip.py index 81610ec2b..90c57fbfb 100755 --- a/plantcv/plantcv/flip.py +++ b/plantcv/plantcv/flip.py @@ -3,14 +3,14 @@ import cv2 import numpy as np import os -from plantcv.plantcv import print_image -from plantcv.plantcv import plot_image +from plantcv.plantcv._debug import _debug from plantcv.plantcv import fatal_error from plantcv.plantcv import params def flip(img, direction): - """Flip image. + """ + Flip image. Inputs: img = RGB or grayscale image data @@ -23,7 +23,6 @@ def flip(img, direction): :param direction: str :return vh_img: numpy.ndarray """ - params.device += 1 if direction.upper() == "VERTICAL": vh_img = cv2.flip(img, 1) elif direction.upper() == "HORIZONTAL": @@ -31,12 +30,13 @@ def flip(img, direction): else: fatal_error(str(direction) + " is not a valid direction, must be horizontal or vertical") - if params.debug == 'print': - print_image(vh_img, os.path.join(params.debug_outdir, str(params.device) + "_flipped.png")) - elif params.debug == 'plot': - if len(np.shape(vh_img)) == 3: - plot_image(vh_img) - else: - plot_image(vh_img, cmap='gray') + if len(np.shape(vh_img)) == 3: + cmap = None + else: + cmap = 'gray' + + _debug(visual=vh_img, + filename=os.path.join(params.debug_outdir, str(params.device) + "_flipped.png"), + cmap=cmap) return vh_img diff --git a/tests/tests.py b/tests/tests.py index 661dc40fe..7a91bd054 100755 --- a/tests/tests.py +++ b/tests/tests.py @@ -2114,15 +2114,9 @@ def test_plantcv_flip(): # Read in test data img = cv2.imread(os.path.join(TEST_DATA, TEST_INPUT_COLOR)) img_binary = cv2.imread(os.path.join(TEST_DATA, TEST_INPUT_BINARY), -1) - # Test with debug = "print" - pcv.params.debug = "print" - _ = pcv.flip(img=img, direction="horizontal") - # Test with debug = "plot" - pcv.params.debug = "plot" - _ = pcv.flip(img=img, direction="vertical") - _ = pcv.flip(img=img_binary, direction="vertical") # Test with debug = None pcv.params.debug = None + _ = pcv.flip(img=img_binary, direction="vertical") flipped_img = pcv.flip(img=img, direction="horizontal") assert all([i == j] for i, j in zip(np.shape(flipped_img), TEST_COLOR_DIM)) From 11cc31cf83448a3e3c15edd63ac43c2401a732e7 Mon Sep 17 00:00:00 2001 From: Dominik Schneider Date: Tue, 17 Aug 2021 15:42:54 -0700 Subject: [PATCH 20/63] gaussian blue --- plantcv/plantcv/gaussian_blur.py | 22 +++++++++++----------- tests/tests.py | 8 +------- 2 files changed, 12 insertions(+), 18 deletions(-) diff --git a/plantcv/plantcv/gaussian_blur.py b/plantcv/plantcv/gaussian_blur.py index 1e0914832..fc134ba71 100755 --- a/plantcv/plantcv/gaussian_blur.py +++ b/plantcv/plantcv/gaussian_blur.py @@ -3,13 +3,13 @@ import cv2 import os import numpy as np -from plantcv.plantcv import print_image -from plantcv.plantcv import plot_image +from plantcv.plantcv._debug import _debug from plantcv.plantcv import params def gaussian_blur(img, ksize, sigma_x=0, sigma_y=None): - """Applies a Gaussian blur filter. + """ + Applies a Gaussian blur filter. Inputs: # img = RGB or grayscale image data @@ -29,13 +29,13 @@ def gaussian_blur(img, ksize, sigma_x=0, sigma_y=None): img_gblur = cv2.GaussianBlur(img, ksize, sigma_x, sigma_y) - params.device += 1 - if params.debug == 'print': - print_image(img_gblur, os.path.join(params.debug_outdir, str(params.device) + '_gaussian_blur.png')) - elif params.debug == 'plot': - if len(np.shape(img_gblur)) == 3: - plot_image(img_gblur) - else: - plot_image(img_gblur, cmap='gray') + if len(np.shape(img_gblur)) == 3: + cmap = None + else: + cmap = 'gray' + + _debug(visual=img_gblur, + filename=os.path.join(params.debug_outdir, str(params.device) + '_gaussian_blur.png'), + cmap=cmap) return img_gblur diff --git a/tests/tests.py b/tests/tests.py index 7a91bd054..60128ee3c 100755 --- a/tests/tests.py +++ b/tests/tests.py @@ -2136,15 +2136,9 @@ def test_plantcv_gaussian_blur(): # Read in test data img = cv2.imread(os.path.join(TEST_DATA, TEST_INPUT_BINARY), -1) img_color = cv2.imread(os.path.join(TEST_DATA, TEST_INPUT_COLOR), -1) - # Test with debug = "print" - pcv.params.debug = "print" - _ = pcv.gaussian_blur(img=img, ksize=(51, 51), sigma_x=0, sigma_y=None) - # Test with debug = "plot" - pcv.params.debug = "plot" - _ = pcv.gaussian_blur(img=img, ksize=(51, 51), sigma_x=0, sigma_y=None) - _ = pcv.gaussian_blur(img=img_color, ksize=(51, 51), sigma_x=0, sigma_y=None) # Test with debug = None pcv.params.debug = None + _ = pcv.gaussian_blur(img=img_color, ksize=(51, 51), sigma_x=0, sigma_y=None) gaussian_img = pcv.gaussian_blur(img=img, ksize=(51, 51), sigma_x=0, sigma_y=None) imgavg = np.average(img) gavg = np.average(gaussian_img) From 65748398952d6a9c9b9f04d556164147b63541a3 Mon Sep 17 00:00:00 2001 From: Dominik Schneider Date: Tue, 17 Aug 2021 15:51:08 -0700 Subject: [PATCH 21/63] hist_equalization --- plantcv/plantcv/hist_equalization.py | 15 +++++++-------- tests/tests.py | 8 +------- 2 files changed, 8 insertions(+), 15 deletions(-) diff --git a/plantcv/plantcv/hist_equalization.py b/plantcv/plantcv/hist_equalization.py index 2055fa63f..77b2519c3 100755 --- a/plantcv/plantcv/hist_equalization.py +++ b/plantcv/plantcv/hist_equalization.py @@ -3,14 +3,14 @@ import cv2 import numpy as np import os -from plantcv.plantcv import print_image -from plantcv.plantcv import plot_image +from plantcv.plantcv._debug import _debug from plantcv.plantcv import fatal_error from plantcv.plantcv import params def hist_equalization(gray_img): - """Histogram equalization is a method to normalize the distribution of intensity values. If the image has low + """ + Histogram equalization is a method to normalize the distribution of intensity values. If the image has low contrast it will make it easier to threshold. Inputs: @@ -27,10 +27,9 @@ def hist_equalization(gray_img): fatal_error("Input image must be gray") img_eh = cv2.equalizeHist(gray_img) - params.device += 1 - if params.debug == 'print': - print_image(img_eh, os.path.join(params.debug_outdir, str(params.device) + '_hist_equal_img.png')) - elif params.debug == 'plot': - plot_image(img_eh, cmap='gray') + + _debug(visual=img_eh, + filename=os.path.join(params.debug_outdir, str(params.device) + '_hist_equal_img.png'), + cmap='gray') return img_eh diff --git a/tests/tests.py b/tests/tests.py index 60128ee3c..86c54491f 100755 --- a/tests/tests.py +++ b/tests/tests.py @@ -2189,12 +2189,6 @@ def test_plantcv_hist_equalization(): pcv.params.debug_outdir = cache_dir # Read in test data img = cv2.imread(os.path.join(TEST_DATA, TEST_INPUT_GRAY), -1) - # Test with debug = "print" - pcv.params.debug = "print" - _ = pcv.hist_equalization(gray_img=img) - # Test with debug = "plot" - pcv.params.debug = "plot" - _ = pcv.hist_equalization(gray_img=img) # Test with debug = None pcv.params.debug = None hist = pcv.hist_equalization(gray_img=img) @@ -2209,7 +2203,7 @@ def test_plantcv_hist_equalization_bad_input(): os.mkdir(cache_dir) pcv.params.debug_outdir = cache_dir # Read in test data - img = cv2.imread(os.path.join(TEST_DATA, TEST_INPUT_GRAY), 1) + img = cv2.imread(os.path.join(TEST_DATA, TEST_INPUT_COLOR), 1) # Test with debug = None pcv.params.debug = None with pytest.raises(RuntimeError): From c9ecac53d4e4a5252bd1e375a6cdda787746e382 Mon Sep 17 00:00:00 2001 From: Dominik Schneider Date: Tue, 17 Aug 2021 15:53:04 -0700 Subject: [PATCH 22/63] image_add --- plantcv/plantcv/image_add.py | 17 ++++++++--------- tests/tests.py | 6 ------ 2 files changed, 8 insertions(+), 15 deletions(-) diff --git a/plantcv/plantcv/image_add.py b/plantcv/plantcv/image_add.py index da0caa96e..d870bb993 100755 --- a/plantcv/plantcv/image_add.py +++ b/plantcv/plantcv/image_add.py @@ -1,14 +1,13 @@ # Image addition import os -from plantcv.plantcv import print_image -from plantcv.plantcv import plot_image +from plantcv.plantcv._debug import _debug from plantcv.plantcv import params def image_add(gray_img1, gray_img2): - - """This is a function used to add images. The numpy addition function '+' is used. This is a modulo operation + """ + This is a function used to add images. The numpy addition function '+' is used. This is a modulo operation rather than the cv2.add fxn which is a saturation operation. ddepth = -1 specifies that the dimensions of output image will be the same as the input image. @@ -25,9 +24,9 @@ def image_add(gray_img1, gray_img2): """ added_img = gray_img1 + gray_img2 - params.device += 1 - if params.debug == 'print': - print_image(added_img, os.path.join(params.debug_outdir, str(params.device) + '_added' + '.png')) - elif params.debug == 'plot': - plot_image(added_img, cmap='gray') + + _debug(visual=added_img, + filename=os.path.join(params.debug_outdir, str(params.device) + '_added' + '.png'), + cmap='gray') + return added_img diff --git a/tests/tests.py b/tests/tests.py index 86c54491f..64f34a044 100755 --- a/tests/tests.py +++ b/tests/tests.py @@ -2218,12 +2218,6 @@ def test_plantcv_image_add(): # Read in test data img1 = cv2.imread(os.path.join(TEST_DATA, TEST_INPUT_BINARY), -1) img2 = np.copy(img1) - # Test with debug = "print" - pcv.params.debug = "print" - _ = pcv.image_add(gray_img1=img1, gray_img2=img2) - # Test with debug = "plot" - pcv.params.debug = "plot" - _ = pcv.image_add(gray_img1=img1, gray_img2=img2) # Test with debug = None pcv.params.debug = None added_img = pcv.image_add(gray_img1=img1, gray_img2=img2) From 14feeb7865efdd7ce3a342a0a87b824cab3278b8 Mon Sep 17 00:00:00 2001 From: Dominik Schneider Date: Tue, 17 Aug 2021 15:56:50 -0700 Subject: [PATCH 23/63] image subtract --- plantcv/plantcv/image_subtract.py | 18 ++++++++---------- tests/tests.py | 6 ------ 2 files changed, 8 insertions(+), 16 deletions(-) diff --git a/plantcv/plantcv/image_subtract.py b/plantcv/plantcv/image_subtract.py index 32396683f..40c066cc9 100755 --- a/plantcv/plantcv/image_subtract.py +++ b/plantcv/plantcv/image_subtract.py @@ -1,7 +1,6 @@ # Image subtraction -from plantcv.plantcv import print_image -from plantcv.plantcv import plot_image +from plantcv.plantcv._debug import _debug from plantcv.plantcv import params from plantcv.plantcv import fatal_error import numpy as np @@ -9,7 +8,8 @@ def image_subtract(gray_img1, gray_img2): - """This is a function used to subtract values of one gray-scale image array from another gray-scale image array. The + """ + This is a function used to subtract values of one gray-scale image array from another gray-scale image array. The resulting gray-scale image array has a minimum element value of zero. That is all negative values resulting from the subtraction are forced to zero. @@ -25,8 +25,6 @@ def image_subtract(gray_img1, gray_img2): :return new_img: numpy.ndarray """ - params.device += 1 # increment device - # check inputs for gray-scale if len(np.shape(gray_img1)) != 2 or len(np.shape(gray_img2)) != 2: fatal_error("Input image is not gray-scale") @@ -34,9 +32,9 @@ def image_subtract(gray_img1, gray_img2): new_img = gray_img1.astype(np.float64) - gray_img2.astype(np.float64) # subtract values new_img[np.where(new_img < 0)] = 0 # force negative array values to zero new_img = new_img.astype(np.uint8) # typecast image to 8-bit image - # print-plot handling - if params.debug == 'print': - print_image(new_img, os.path.join(params.debug_outdir, str(params.device) + "_subtraction.png")) - elif params.debug == 'plot': - plot_image(new_img, cmap='gray') + + _debug(visual=new_img, + filename=os.path.join(params.debug_outdir, str(params.device) + "_subtraction.png"), + cmap='gray') + return new_img # return diff --git a/tests/tests.py b/tests/tests.py index 64f34a044..b5d91d655 100755 --- a/tests/tests.py +++ b/tests/tests.py @@ -2251,12 +2251,6 @@ def test_plantcv_image_subtract(): # read in images img1 = cv2.imread(os.path.join(TEST_DATA, TEST_INPUT_BINARY), -1) img2 = np.copy(img1) - # Test with debug = "print" - pcv.params.debug = 'print' - _ = pcv.image_subtract(img1, img2) - # Test with debug = "plot" - pcv.params.debug = 'plot' - _ = pcv.image_subtract(img1, img2) # Test with debug = None pcv.params.debug = None new_img = pcv.image_subtract(img1, img2) From 3043bc948ae12b2f61244695026e79072ab098cc Mon Sep 17 00:00:00 2001 From: Dominik Schneider Date: Tue, 17 Aug 2021 15:58:27 -0700 Subject: [PATCH 24/63] invert --- plantcv/plantcv/invert.py | 13 ++++++------- tests/tests.py | 6 ------ 2 files changed, 6 insertions(+), 13 deletions(-) diff --git a/plantcv/plantcv/invert.py b/plantcv/plantcv/invert.py index 8b111203e..d4df46014 100755 --- a/plantcv/plantcv/invert.py +++ b/plantcv/plantcv/invert.py @@ -2,8 +2,7 @@ import cv2 import os -from plantcv.plantcv import print_image -from plantcv.plantcv import plot_image +from plantcv.plantcv._debug import _debug from plantcv.plantcv import params @@ -20,10 +19,10 @@ def invert(gray_img): :return img_inv: numpy.ndarray """ - params.device += 1 img_inv = cv2.bitwise_not(gray_img) - if params.debug == 'print': - print_image(img_inv, os.path.join(params.debug_outdir, str(params.device) + '_invert.png')) - elif params.debug == 'plot': - plot_image(img_inv, cmap='gray') + + _debug(visual=img_inv, + filename=os.path.join(params.debug_outdir, str(params.device) + '_invert.png'), + cmap='gray') + return img_inv diff --git a/tests/tests.py b/tests/tests.py index b5d91d655..080e85ec8 100755 --- a/tests/tests.py +++ b/tests/tests.py @@ -2273,12 +2273,6 @@ def test_plantcv_invert(): pcv.params.debug_outdir = cache_dir # Read in test data img = cv2.imread(os.path.join(TEST_DATA, TEST_INPUT_BINARY), -1) - # Test with debug = "print" - pcv.params.debug = "print" - _ = pcv.invert(gray_img=img) - # Test with debug = "plot" - pcv.params.debug = "plot" - _ = pcv.invert(gray_img=img) # Test with debug = None pcv.params.debug = None inverted_img = pcv.invert(gray_img=img) From 62e7a662d58a7c8ed4a1800a0d48bcdb3aaff2ff Mon Sep 17 00:00:00 2001 From: Dominik Schneider Date: Tue, 17 Aug 2021 16:00:22 -0700 Subject: [PATCH 25/63] laplace filter --- plantcv/plantcv/laplace_filter.py | 16 +++++++--------- tests/tests.py | 6 ------ 2 files changed, 7 insertions(+), 15 deletions(-) diff --git a/plantcv/plantcv/laplace_filter.py b/plantcv/plantcv/laplace_filter.py index 1476e4530..77ee69632 100755 --- a/plantcv/plantcv/laplace_filter.py +++ b/plantcv/plantcv/laplace_filter.py @@ -2,8 +2,7 @@ import cv2 import os -from plantcv.plantcv import print_image -from plantcv.plantcv import plot_image +from plantcv.plantcv._debug import _debug from plantcv.plantcv import params @@ -28,11 +27,10 @@ def laplace_filter(gray_img, ksize, scale): """ lp_filtered = cv2.Laplacian(src=gray_img, ddepth=-1, ksize=ksize, scale=scale) - params.device += 1 - if params.debug == 'print': - print_image(lp_filtered, - os.path.join(params.debug_outdir, - str(params.device) + '_lp_out_k' + str(ksize) + '_scale' + str(scale) + '.png')) - elif params.debug == 'plot': - plot_image(lp_filtered, cmap='gray') + + _debug(visual=lp_filtered, + filename=os.path.join(params.debug_outdir, + str(params.device) + '_lp_out_k' + str(ksize) + '_scale' + str(scale) + '.png'), + cmap='gray') + return lp_filtered diff --git a/tests/tests.py b/tests/tests.py index 080e85ec8..9e4f74d66 100755 --- a/tests/tests.py +++ b/tests/tests.py @@ -2314,12 +2314,6 @@ def test_plantcv_laplace_filter(): pcv.params.debug_outdir = cache_dir # Read in test data img = cv2.imread(os.path.join(TEST_DATA, TEST_INPUT_GRAY), -1) - # Test with debug = "print" - pcv.params.debug = "print" - _ = pcv.laplace_filter(gray_img=img, ksize=1, scale=1) - # Test with debug = "plot" - pcv.params.debug = "plot" - _ = pcv.laplace_filter(gray_img=img, ksize=1, scale=1) # Test with debug = None pcv.params.debug = None lp_img = pcv.laplace_filter(gray_img=img, ksize=1, scale=1) From 2b6840e1282ff15d054c32d3a63f27201c41d4cb Mon Sep 17 00:00:00 2001 From: Dominik Schneider Date: Tue, 17 Aug 2021 16:01:48 -0700 Subject: [PATCH 26/63] logical and --- plantcv/plantcv/logical_and.py | 13 ++++++------- tests/tests.py | 6 ------ 2 files changed, 6 insertions(+), 13 deletions(-) diff --git a/plantcv/plantcv/logical_and.py b/plantcv/plantcv/logical_and.py index e6ff43658..c40c2b429 100755 --- a/plantcv/plantcv/logical_and.py +++ b/plantcv/plantcv/logical_and.py @@ -2,8 +2,7 @@ import cv2 import os -from plantcv.plantcv import print_image -from plantcv.plantcv import plot_image +from plantcv.plantcv._debug import _debug from plantcv.plantcv import params @@ -22,10 +21,10 @@ def logical_and(bin_img1, bin_img2): :return merged: numpy.ndarray """ - params.device += 1 merged = cv2.bitwise_and(bin_img1, bin_img2) - if params.debug == 'print': - print_image(merged, os.path.join(params.debug_outdir, str(params.device) + '_and_joined.png')) - elif params.debug == 'plot': - plot_image(merged, cmap='gray') + + _debug(visual=merged, + filename=os.path.join(params.debug_outdir, str(params.device) + '_and_joined.png'), + cmap='gray') + return merged diff --git a/tests/tests.py b/tests/tests.py index 9e4f74d66..a6dad6ee1 100755 --- a/tests/tests.py +++ b/tests/tests.py @@ -2329,12 +2329,6 @@ def test_plantcv_logical_and(): # Read in test data img1 = cv2.imread(os.path.join(TEST_DATA, TEST_INPUT_BINARY), -1) img2 = np.copy(img1) - # Test with debug = "print" - pcv.params.debug = "print" - _ = pcv.logical_and(bin_img1=img1, bin_img2=img2) - # Test with debug = "plot" - pcv.params.debug = "plot" - _ = pcv.logical_and(bin_img1=img1, bin_img2=img2) # Test with debug = None pcv.params.debug = None and_img = pcv.logical_and(bin_img1=img1, bin_img2=img2) From 1a73c3ef80556c9858443543c1dc42aed8fb6941 Mon Sep 17 00:00:00 2001 From: Dominik Schneider Date: Tue, 17 Aug 2021 16:03:35 -0700 Subject: [PATCH 27/63] logical or --- plantcv/plantcv/logical_or.py | 13 ++++++------- tests/tests.py | 6 ------ 2 files changed, 6 insertions(+), 13 deletions(-) diff --git a/plantcv/plantcv/logical_or.py b/plantcv/plantcv/logical_or.py index 06bbf0d83..c883c1d47 100755 --- a/plantcv/plantcv/logical_or.py +++ b/plantcv/plantcv/logical_or.py @@ -2,8 +2,7 @@ import cv2 import os -from plantcv.plantcv import print_image -from plantcv.plantcv import plot_image +from plantcv.plantcv._debug import _debug from plantcv.plantcv import params @@ -22,10 +21,10 @@ def logical_or(bin_img1, bin_img2): :return merged: numpy.ndarray """ - params.device += 1 merged = cv2.bitwise_or(bin_img1, bin_img2) - if params.debug == 'print': - print_image(merged, os.path.join(params.debug_outdir, str(params.device) + '_or_joined.png')) - elif params.debug == 'plot': - plot_image(merged, cmap='gray') + + _debug(visual=merged, + filename=os.path.join(params.debug_outdir, str(params.device) + '_or_joined.png'), + cmap='gray') + return merged diff --git a/tests/tests.py b/tests/tests.py index a6dad6ee1..5986d5bcf 100755 --- a/tests/tests.py +++ b/tests/tests.py @@ -2343,12 +2343,6 @@ def test_plantcv_logical_or(): # Read in test data img1 = cv2.imread(os.path.join(TEST_DATA, TEST_INPUT_BINARY), -1) img2 = np.copy(img1) - # Test with debug = "print" - pcv.params.debug = "print" - _ = pcv.logical_or(bin_img1=img1, bin_img2=img2) - # Test with debug = "plot" - pcv.params.debug = "plot" - _ = pcv.logical_or(bin_img1=img1, bin_img2=img2) # Test with debug = None pcv.params.debug = None or_img = pcv.logical_or(bin_img1=img1, bin_img2=img2) From f8b5fe8336a55037c756cb56e4a2dc36ae0d2582 Mon Sep 17 00:00:00 2001 From: Dominik Schneider Date: Tue, 17 Aug 2021 16:10:50 -0700 Subject: [PATCH 28/63] logical xor --- plantcv/plantcv/logical_xor.py | 16 ++++++++-------- tests/tests.py | 7 +------ 2 files changed, 9 insertions(+), 14 deletions(-) diff --git a/plantcv/plantcv/logical_xor.py b/plantcv/plantcv/logical_xor.py index 110baced3..2d846d8eb 100755 --- a/plantcv/plantcv/logical_xor.py +++ b/plantcv/plantcv/logical_xor.py @@ -2,13 +2,13 @@ import cv2 import os -from plantcv.plantcv import print_image -from plantcv.plantcv import plot_image +from plantcv.plantcv._debug import _debug from plantcv.plantcv import params def logical_xor(bin_img1, bin_img2): - """Join two images using the bitwise XOR operator. + """ + Join two images using the bitwise XOR operator. Inputs: bin_img1 = Binary image data to be compared to bin_img2 @@ -22,10 +22,10 @@ def logical_xor(bin_img1, bin_img2): :return merged: numpy.ndarray """ - params.device += 1 merged = cv2.bitwise_xor(bin_img1, bin_img2) - if params.debug == 'print': - print_image(merged, os.path.join(params.debug_outdir, str(params.device) + '_xor_joined.png')) - elif params.debug == 'plot': - plot_image(merged, cmap='gray') + + _debug(visual=merged, + filename=os.path.join(params.debug_outdir, str(params.device) + '_xor_joined.png'), + cmap='gray') + return merged diff --git a/tests/tests.py b/tests/tests.py index 5986d5bcf..996daf05a 100755 --- a/tests/tests.py +++ b/tests/tests.py @@ -2357,12 +2357,6 @@ def test_plantcv_logical_xor(): # Read in test data img1 = cv2.imread(os.path.join(TEST_DATA, TEST_INPUT_BINARY), -1) img2 = np.copy(img1) - # Test with debug = "print" - pcv.params.debug = "print" - _ = pcv.logical_xor(bin_img1=img1, bin_img2=img2) - # Test with debug = "plot" - pcv.params.debug = "plot" - _ = pcv.logical_xor(bin_img1=img1, bin_img2=img2) # Test with debug = None pcv.params.debug = None xor_img = pcv.logical_xor(bin_img1=img1, bin_img2=img2) @@ -2384,6 +2378,7 @@ def test_plantcv_median_blur(): _ = pcv.median_blur(gray_img=img, ksize=5) # Test with debug = None pcv.params.debug = None + _ = pcv.median_blur(gray_img=img, ksize=(5, 5)) blur_img = pcv.median_blur(gray_img=img, ksize=5) # Assert that the output image has the dimensions of the input image if all([i == j] for i, j in zip(np.shape(blur_img), TEST_BINARY_DIM)): From 33a33e73b58e19ed02f14d8666c947b9206787f5 Mon Sep 17 00:00:00 2001 From: Dominik Schneider Date: Tue, 17 Aug 2021 16:12:01 -0700 Subject: [PATCH 29/63] median_blue --- plantcv/plantcv/median_blur.py | 15 +++++++-------- tests/tests.py | 6 ------ 2 files changed, 7 insertions(+), 14 deletions(-) diff --git a/plantcv/plantcv/median_blur.py b/plantcv/plantcv/median_blur.py index b3f01d135..ff2b467a4 100755 --- a/plantcv/plantcv/median_blur.py +++ b/plantcv/plantcv/median_blur.py @@ -1,8 +1,7 @@ # Median blur device import os -from plantcv.plantcv import print_image -from plantcv.plantcv import plot_image +from plantcv.plantcv._debug import _debug from plantcv.plantcv import params from plantcv.plantcv import fatal_error from scipy.ndimage.filters import median_filter @@ -29,10 +28,10 @@ def median_blur(gray_img, ksize): fatal_error("Invalid ksize, must be integer or tuple") img_mblur = median_filter(gray_img, size=ksize) - params.device += 1 - if params.debug == 'print': - print_image(img_mblur, os.path.join(params.debug_outdir, - str(params.device) + '_median_blur' + str(ksize) + '.png')) - elif params.debug == 'plot': - plot_image(img_mblur, cmap='gray') + + _debug(img_mblur, + filename=os.path.join(params.debug_outdir, + str(params.device) + '_median_blur' + str(ksize) + '.png'), + cmap='gray') + return img_mblur diff --git a/tests/tests.py b/tests/tests.py index 996daf05a..004537b38 100755 --- a/tests/tests.py +++ b/tests/tests.py @@ -2370,12 +2370,6 @@ def test_plantcv_median_blur(): pcv.params.debug_outdir = cache_dir # Read in test data img = cv2.imread(os.path.join(TEST_DATA, TEST_INPUT_BINARY), -1) - # Test with debug = "print" - pcv.params.debug = "print" - _ = pcv.median_blur(gray_img=img, ksize=5) - # Test with debug = "plot" - pcv.params.debug = "plot" - _ = pcv.median_blur(gray_img=img, ksize=5) # Test with debug = None pcv.params.debug = None _ = pcv.median_blur(gray_img=img, ksize=(5, 5)) From 550a4b1aef086c26c116cca48c0284092729ec37 Mon Sep 17 00:00:00 2001 From: Dominik Schneider Date: Tue, 17 Aug 2021 16:17:53 -0700 Subject: [PATCH 30/63] object composition --- plantcv/plantcv/object_composition.py | 13 +++++-------- tests/tests.py | 8 +------- 2 files changed, 6 insertions(+), 15 deletions(-) diff --git a/plantcv/plantcv/object_composition.py b/plantcv/plantcv/object_composition.py index 785ef49c2..585d4a26a 100755 --- a/plantcv/plantcv/object_composition.py +++ b/plantcv/plantcv/object_composition.py @@ -3,8 +3,7 @@ import numpy as np import cv2 import os -from plantcv.plantcv import print_image -from plantcv.plantcv import plot_image +from plantcv.plantcv._debug import _debug from plantcv.plantcv import params @@ -44,7 +43,6 @@ def object_composition(img, contours, hierarchy): ids = np.where(stack == 1)[0] if len(ids) > 0: - params.device += 1 contour_list = [contours[i] for i in ids] group = np.vstack(contour_list) cv2.drawContours(mask, contours, -1, 255, -1, hierarchy=hierarchy) @@ -53,11 +51,10 @@ def object_composition(img, contours, hierarchy): cv2.drawContours(ori_img, group, -1, (255, 0, 0), params.line_thickness) for cnt in contours: cv2.drawContours(ori_img, cnt, -1, (255, 0, 0), params.line_thickness) - if params.debug == 'print': - print_image(ori_img, os.path.join(params.debug_outdir, str(params.device) + '_objcomp.png')) - print_image(ori_img, os.path.join(params.debug_outdir, str(params.device) + '_objcomp_mask.png')) - elif params.debug == 'plot': - plot_image(ori_img) + + _debug(ori_img, os.path.join(params.debug_outdir, str(params.device) + '_objcomp.png')) + _debug(ori_img, os.path.join(params.debug_outdir, str(params.device) + '_objcomp_mask.png')) + return group, mask else: print("Warning: Invalid contour.") diff --git a/tests/tests.py b/tests/tests.py index 004537b38..6d813957c 100755 --- a/tests/tests.py +++ b/tests/tests.py @@ -2443,15 +2443,9 @@ def test_plantcv_object_composition(): object_contours = [object_contours_npz[arr_n] for arr_n in object_contours_npz] object_hierarchy_npz = np.load(os.path.join(TEST_DATA, TEST_INPUT_OBJECT_HIERARCHY), encoding="latin1") object_hierarchy = object_hierarchy_npz['arr_0'] - # Test with debug = "print" - pcv.params.debug = "print" - _ = pcv.object_composition(img=img, contours=object_contours, hierarchy=object_hierarchy) - _ = pcv.object_composition(img=img, contours=[], hierarchy=object_hierarchy) - # Test with debug = "plot" - pcv.params.debug = "plot" - _ = pcv.object_composition(img=img, contours=object_contours, hierarchy=object_hierarchy) # Test with debug = None pcv.params.debug = None + _ = pcv.object_composition(img=img, contours=[], hierarchy=object_hierarchy) contours, mask = pcv.object_composition(img=img, contours=object_contours, hierarchy=object_hierarchy) # Assert that the objects have been combined contour_shape = np.shape(contours) # type: tuple From 73323c17a50b22edc8c4f5aae1c57e0f7eff233e Mon Sep 17 00:00:00 2001 From: Dominik Schneider Date: Tue, 17 Aug 2021 16:20:45 -0700 Subject: [PATCH 31/63] opening --- plantcv/plantcv/opening.py | 15 ++++++--------- tests/tests.py | 4 ---- 2 files changed, 6 insertions(+), 13 deletions(-) diff --git a/plantcv/plantcv/opening.py b/plantcv/plantcv/opening.py index 6235e9b77..f30042caa 100644 --- a/plantcv/plantcv/opening.py +++ b/plantcv/plantcv/opening.py @@ -4,13 +4,13 @@ import numpy as np from skimage import morphology from plantcv.plantcv import params -from plantcv.plantcv import print_image -from plantcv.plantcv import plot_image +from plantcv.plantcv._debug import _debug from plantcv.plantcv import fatal_error def opening(gray_img, kernel=None): - """Wrapper for scikit-image opening functions. Opening can remove small bright spots (i.e. salt). + """ + Wrapper for scikit-image opening functions. Opening can remove small bright spots (i.e. salt). Inputs: gray_img = input image (grayscale or binary) @@ -21,8 +21,6 @@ def opening(gray_img, kernel=None): :return filtered_img: ndarray """ - params.device += 1 - # Make sure the image is binary/grayscale if len(np.shape(gray_img)) != 2: fatal_error("Input image must be grayscale or binary") @@ -35,9 +33,8 @@ def opening(gray_img, kernel=None): else: filtered_img = morphology.opening(gray_img, kernel) - if params.debug == 'print': - print_image(filtered_img, os.path.join(params.debug_outdir, str(params.device) + '_opening.png')) - elif params.debug == 'plot': - plot_image(filtered_img, cmap='gray') + _debug(visual=filtered_img, + filename=os.path.join(params.debug_outdir, str(params.device) + '_opening.png'), + cmap='gray') return filtered_img diff --git a/tests/tests.py b/tests/tests.py index 6d813957c..8a351e210 100755 --- a/tests/tests.py +++ b/tests/tests.py @@ -2506,11 +2506,7 @@ def test_plantcv_opening(): # Test with debug=None pcv.params.debug = None _ = pcv.opening(gray_img) - # Test with debug='plot' - pcv.params.debug = 'plot' _ = pcv.opening(bin_img, np.ones((4, 4), np.uint8)) - # Test with debug='print' - pcv.params.debug = 'print' filtered_img = pcv.opening(bin_img) assert np.sum(filtered_img) == 16184595 From 40514e4c95dc11970e3b25e5c2ec04f8139eab16 Mon Sep 17 00:00:00 2001 From: Dominik Schneider Date: Tue, 17 Aug 2021 16:31:44 -0700 Subject: [PATCH 32/63] readbayer --- plantcv/plantcv/readbayer.py | 9 +-- tests/tests.py | 115 +++++------------------------------ 2 files changed, 17 insertions(+), 107 deletions(-) diff --git a/plantcv/plantcv/readbayer.py b/plantcv/plantcv/readbayer.py index 5de484c97..68e720907 100644 --- a/plantcv/plantcv/readbayer.py +++ b/plantcv/plantcv/readbayer.py @@ -3,8 +3,7 @@ import os import cv2 from plantcv.plantcv import fatal_error -from plantcv.plantcv import print_image -from plantcv.plantcv import plot_image +from plantcv.plantcv._debug import _debug from plantcv.plantcv import params @@ -72,9 +71,7 @@ def readbayer(filename, bayerpattern='BG', alg='default'): # Split path from filename path, img_name = os.path.split(filename) - if params.debug == "print": - print_image(img, os.path.join(params.debug_outdir, "input_image.png")) - elif params.debug == "plot": - plot_image(img) + _debug(visual=img, + filename=os.path.join(params.debug_outdir, "input_image.png")) return img, path, img_name diff --git a/tests/tests.py b/tests/tests.py index 8a351e210..30f845d9f 100755 --- a/tests/tests.py +++ b/tests/tests.py @@ -2703,117 +2703,30 @@ def test_plantcv_readimage_bad_file(): _ = pcv.readimage(filename=TEST_INPUT_COLOR) -def test_plantcv_readbayer_default_bg(): +@pytest.mark.parametrize("alg, pattern", [["default", 'BG'], + ["default", 'GB'], + ["default", 'RG'], + ["default", 'GR'], + ["edgeaware", 'BG'], + ["edgeaware", 'GB'], + ["edgeaware", 'RG'], + ["edgeaware", 'GR'], + ["variablenumbergradients", 'BG'], + ["variablenumbergradients", 'GB'], + ["variablenumbergradients", 'RG'], + ["variablenumbergradients", 'GR']]) +def test_plantcv_readbayer_default_bg(alg, pattern): # Test cache directory cache_dir = os.path.join(TEST_TMPDIR, "test_plantcv_readbayer_default_bg") os.mkdir(cache_dir) pcv.params.debug_outdir = cache_dir - # Test with debug = "print" - pcv.params.debug = "print" - _, _, _ = pcv.readbayer(filename=os.path.join(TEST_DATA, TEST_INPUT_BAYER), - bayerpattern="BG", alg="default") - # Test with debug = "plot" - pcv.params.debug = "plot" - img, path, img_name = pcv.readbayer(filename=os.path.join(TEST_DATA, TEST_INPUT_BAYER), - bayerpattern="BG", alg="default") - assert all([i == j] for i, j in zip(np.shape(img), (335, 400, 3))) - - -def test_plantcv_readbayer_default_gb(): # Test with debug = None pcv.params.debug = None img, path, img_name = pcv.readbayer(filename=os.path.join(TEST_DATA, TEST_INPUT_BAYER), - bayerpattern="GB", alg="default") + bayerpattern=pattern, alg=alg) assert all([i == j] for i, j in zip(np.shape(img), (335, 400, 3))) -def test_plantcv_readbayer_default_rg(): - # Test with debug = None - pcv.params.debug = None - img, path, img_name = pcv.readbayer(filename=os.path.join(TEST_DATA, TEST_INPUT_BAYER), - bayerpattern="RG", alg="default") - assert all([i == j] for i, j in zip(np.shape(img), (335, 400, 3))) - - -def test_plantcv_readbayer_default_gr(): - # Test with debug = None - pcv.params.debug = None - img, path, img_name = pcv.readbayer(filename=os.path.join(TEST_DATA, TEST_INPUT_BAYER), - bayerpattern="GR", alg="default") - assert all([i == j] for i, j in zip(np.shape(img), (335, 400, 3))) - - -def test_plantcv_readbayer_edgeaware_bg(): - # Test with debug = None - pcv.params.debug = None - img, path, img_name = pcv.readbayer(filename=os.path.join(TEST_DATA, TEST_INPUT_BAYER), - bayerpattern="BG", alg="edgeaware") - assert all([i == j] for i, j in zip(np.shape(img), (335, 400, 3))) - - -def test_plantcv_readbayer_edgeaware_gb(): - # Test with debug = None - pcv.params.debug = None - img, path, img_name = pcv.readbayer(filename=os.path.join(TEST_DATA, TEST_INPUT_BAYER), - bayerpattern="GB", alg="edgeaware") - assert all([i == j] for i, j in zip(np.shape(img), (335, 400, 3))) - - -def test_plantcv_readbayer_edgeaware_rg(): - # Test with debug = None - pcv.params.debug = None - img, path, img_name = pcv.readbayer(filename=os.path.join(TEST_DATA, TEST_INPUT_BAYER), - bayerpattern="RG", alg="edgeaware") - assert all([i == j] for i, j in zip(np.shape(img), (335, 400, 3))) - - -def test_plantcv_readbayer_edgeaware_gr(): - # Test with debug = None - pcv.params.debug = None - img, path, img_name = pcv.readbayer(filename=os.path.join(TEST_DATA, TEST_INPUT_BAYER), - bayerpattern="GR", alg="edgeaware") - assert all([i == j] for i, j in zip(np.shape(img), (335, 400, 3))) - - -def test_plantcv_readbayer_variablenumbergradients_bg(): - # Test with debug = None - pcv.params.debug = None - img, path, img_name = pcv.readbayer(filename=os.path.join(TEST_DATA, TEST_INPUT_BAYER), - bayerpattern="BG", alg="variablenumbergradients") - assert all([i == j] for i, j in zip(np.shape(img), (335, 400, 3))) - - -def test_plantcv_readbayer_variablenumbergradients_gb(): - # Test with debug = None - pcv.params.debug = None - img, path, img_name = pcv.readbayer(filename=os.path.join(TEST_DATA, TEST_INPUT_BAYER), - bayerpattern="GB", alg="variablenumbergradients") - assert all([i == j] for i, j in zip(np.shape(img), (335, 400, 3))) - - -def test_plantcv_readbayer_variablenumbergradients_rg(): - # Test with debug = None - pcv.params.debug = None - img, path, img_name = pcv.readbayer(filename=os.path.join(TEST_DATA, TEST_INPUT_BAYER), - bayerpattern="RG", alg="variablenumbergradients") - assert all([i == j] for i, j in zip(np.shape(img), (335, 400, 3))) - - -def test_plantcv_readbayer_variablenumbergradients_gr(): - # Test with debug = None - pcv.params.debug = None - img, path, img_name = pcv.readbayer(filename=os.path.join(TEST_DATA, TEST_INPUT_BAYER), - bayerpattern="GR", alg="variablenumbergradients") - assert all([i == j] for i, j in zip(np.shape(img), (335, 400, 3))) - - -def test_plantcv_readbayer_default_bad_input(): - # Test with debug = None - pcv.params.debug = None - with pytest.raises(RuntimeError): - _, _, _ = pcv.readbayer(filename=os.path.join(TEST_DATA, "no-image.png"), bayerpattern="GR", alg="default") - - def test_plantcv_rectangle_mask(): # Test cache directory cache_dir = os.path.join(TEST_TMPDIR, "test_plantcv_rectangle_mask") From 86c1ab52db38094b1de051d3baf9d70f6ed3e62f Mon Sep 17 00:00:00 2001 From: Dominik Schneider Date: Tue, 17 Aug 2021 16:50:31 -0700 Subject: [PATCH 33/63] rectangle maks --- plantcv/plantcv/rectangle_mask.py | 19 ++++++++++--------- tests/tests.py | 9 ++------- 2 files changed, 12 insertions(+), 16 deletions(-) diff --git a/plantcv/plantcv/rectangle_mask.py b/plantcv/plantcv/rectangle_mask.py index c7e10ab55..eab58b891 100755 --- a/plantcv/plantcv/rectangle_mask.py +++ b/plantcv/plantcv/rectangle_mask.py @@ -4,13 +4,13 @@ import numpy as np import os from plantcv.plantcv import fatal_error -from plantcv.plantcv import print_image -from plantcv.plantcv import plot_image +from plantcv.plantcv._debug import _debug from plantcv.plantcv import params def rectangle_mask(img, p1, p2, color="black"): - """Takes an input image and returns a binary image masked by a rectangular area denoted by p1 and p2. Note that + """ + Takes an input image and returns a binary image masked by a rectangular area denoted by p1 and p2. Note that p1 = (0,0) is the top left hand corner bottom right hand corner is p2 = (max-value(x), max-value(y)). Inputs: @@ -35,12 +35,12 @@ def rectangle_mask(img, p1, p2, color="black"): :return hierarchy: list """ - params.device += 1 # get the dimensions of the input image if len(np.shape(img)) == 3: ix, iy, iz = np.shape(img) else: ix, iy = np.shape(img) + # create a blank image of same size bnk = np.zeros((ix, iy), dtype=np.uint8) img1 = np.copy(img) @@ -66,9 +66,10 @@ def rectangle_mask(img, p1, p2, color="black"): else: fatal_error(str(color) + " is not a valid color, must be 'white', 'black', or 'gray'.") - if params.debug == 'print': - print_image(bnk, os.path.join(params.debug_outdir, str(params.device) + '_roi.png')) - elif params.debug == 'plot': - plot_image(img1, cmap="gray") - plot_image(bnk, cmap="gray") + _debug(visual=bnk, + filename=os.path.join(params.debug_outdir, str(params.device) + '_rectroi.png')) + _debug(visual=img1, + filename=os.path.join(params.debug_outdir, str(params.device) + '_rectmask.png'), + cmap='gray') + return img1, bnk, contour, hierarchy diff --git a/tests/tests.py b/tests/tests.py index 30f845d9f..b37249b3a 100755 --- a/tests/tests.py +++ b/tests/tests.py @@ -2735,15 +2735,10 @@ def test_plantcv_rectangle_mask(): # Read in test data img = cv2.imread(os.path.join(TEST_DATA, TEST_INPUT_GRAY), -1) img_color = cv2.imread(os.path.join(TEST_DATA, TEST_INPUT_COLOR)) - # Test with debug = "print" - pcv.params.debug = "print" - _ = pcv.rectangle_mask(img=img, p1=(0, 0), p2=(2454, 2056), color="white") - _ = pcv.rectangle_mask(img=img, p1=(0, 0), p2=(2454, 2056), color="white") - # Test with debug = "plot" - pcv.params.debug = "plot" - _ = pcv.rectangle_mask(img=img_color, p1=(0, 0), p2=(2454, 2056), color="gray") # Test with debug = None pcv.params.debug = None + _ = pcv.rectangle_mask(img=img, p1=(0, 0), p2=(2454, 2056), color="white") + _ = pcv.rectangle_mask(img=img_color, p1=(0, 0), p2=(2454, 2056), color="gray") masked, hist, contour, heir = pcv.rectangle_mask(img=img, p1=(0, 0), p2=(2454, 2056), color="black") maskedsum = np.sum(masked) imgsum = np.sum(img) From 23c4a37bb364cef3166f263d7cceb84b8612d2f0 Mon Sep 17 00:00:00 2001 From: Dominik Schneider Date: Tue, 17 Aug 2021 16:54:46 -0700 Subject: [PATCH 34/63] report size marker area --- plantcv/plantcv/report_size_marker_area.py | 9 +++------ tests/tests.py | 8 -------- 2 files changed, 3 insertions(+), 14 deletions(-) diff --git a/plantcv/plantcv/report_size_marker_area.py b/plantcv/plantcv/report_size_marker_area.py index c6f31eacb..fe83456eb 100755 --- a/plantcv/plantcv/report_size_marker_area.py +++ b/plantcv/plantcv/report_size_marker_area.py @@ -4,14 +4,13 @@ import numpy as np import os from plantcv.plantcv import fatal_error -from plantcv.plantcv import print_image -from plantcv.plantcv import plot_image from plantcv.plantcv import rgb2gray_hsv from plantcv.plantcv import find_objects from plantcv.plantcv.threshold import binary as binary_threshold from plantcv.plantcv import roi_objects from plantcv.plantcv import object_composition from plantcv.plantcv import apply_mask +from plantcv.plantcv._debug import _debug from plantcv.plantcv import params from plantcv.plantcv import outputs @@ -121,10 +120,8 @@ def report_size_marker_area(img, roi_contour, roi_hierarchy, marker='define', ob # Reset debug mode params.debug = debug - if params.debug == 'print': - print_image(ref_img, os.path.join(params.debug_outdir, str(params.device) + '_marker_shape.png')) - elif params.debug == 'plot': - plot_image(ref_img) + _debug(visual=ref_img, + filename=os.path.join(params.debug_outdir, str(params.device) + '_marker_shape.png')) outputs.add_observation(sample=label, variable='marker_area', trait='marker area', method='plantcv.plantcv.report_size_marker_area', scale='pixels', datatype=int, diff --git a/tests/tests.py b/tests/tests.py index b37249b3a..379678c2e 100755 --- a/tests/tests.py +++ b/tests/tests.py @@ -2769,14 +2769,6 @@ def test_plantcv_report_size_marker_detect(): roi_contour = [np.array([[[3550, 850]], [[3550, 1349]], [[4049, 1349]], [[4049, 850]]], dtype=np.int32)] roi_hierarchy = np.array([[[-1, -1, -1, -1]]], dtype=np.int32) - # Test with debug = "print" - pcv.params.debug = "print" - _ = pcv.report_size_marker_area(img=img, roi_contour=roi_contour, roi_hierarchy=roi_hierarchy, marker='detect', - objcolor='light', thresh_channel='s', thresh=120, label="prefix") - # Test with debug = "plot" - pcv.params.debug = "plot" - _ = pcv.report_size_marker_area(img=img, roi_contour=roi_contour, roi_hierarchy=roi_hierarchy, marker='detect', - objcolor='light', thresh_channel='s', thresh=120) # Test with debug = None pcv.params.debug = None images = pcv.report_size_marker_area(img=img, roi_contour=roi_contour, roi_hierarchy=roi_hierarchy, marker='detect', From 696875edf305c2a27e26fa3506d7ccf585820463 Mon Sep 17 00:00:00 2001 From: Dominik Schneider Date: Tue, 17 Aug 2021 16:57:42 -0700 Subject: [PATCH 35/63] rgb2gray hsv --- plantcv/plantcv/rgb2gray_hsv.py | 17 +++++++---------- tests/tests.py | 6 ------ 2 files changed, 7 insertions(+), 16 deletions(-) diff --git a/plantcv/plantcv/rgb2gray_hsv.py b/plantcv/plantcv/rgb2gray_hsv.py index 058eef577..d10f4587a 100755 --- a/plantcv/plantcv/rgb2gray_hsv.py +++ b/plantcv/plantcv/rgb2gray_hsv.py @@ -2,14 +2,14 @@ import cv2 import os -from plantcv.plantcv import print_image -from plantcv.plantcv import plot_image +from plantcv.plantcv._debug import _debug from plantcv.plantcv import fatal_error from plantcv.plantcv import params def rgb2gray_hsv(rgb_img, channel): - """Convert an RGB color image to HSV colorspace and return a gray image (one channel). + """ + Convert an RGB color image to HSV colorspace and return a gray image (one channel). Inputs: rgb_img = RGB image data @@ -22,8 +22,6 @@ def rgb2gray_hsv(rgb_img, channel): :param channel: str :return channel: numpy.ndarray """ - # Auto-increment the device counter - params.device += 1 # The allowable channel inputs are h, s or v names = {"h": "hue", "s": "saturation", "v": "value"} @@ -38,10 +36,9 @@ def rgb2gray_hsv(rgb_img, channel): # Create a channel dictionaries for lookups by a channel name index channels = {"h": h, "s": s, "v": v} - if params.debug == "print": - print_image(channels[channel], os.path.join(params.debug_outdir, - str(params.device) + "_hsv_" + names[channel] + ".png")) - elif params.debug == "plot": - plot_image(channels[channel], cmap="gray") + _debug(visual=channels[channel], + filename=os.path.join(params.debug_outdir, + str(params.device) + "_hsv_" + names[channel] + ".png"), + cmap='gray') return channels[channel] diff --git a/tests/tests.py b/tests/tests.py index 379678c2e..8a754d1fa 100755 --- a/tests/tests.py +++ b/tests/tests.py @@ -2854,12 +2854,6 @@ def test_plantcv_rgb2gray_hsv(): pcv.params.debug_outdir = cache_dir # Read in test data img = cv2.imread(os.path.join(TEST_DATA, TEST_INPUT_COLOR)) - # Test with debug = "print" - pcv.params.debug = "print" - _ = pcv.rgb2gray_hsv(rgb_img=img, channel="s") - # Test with debug = "plot" - pcv.params.debug = "plot" - _ = pcv.rgb2gray_hsv(rgb_img=img, channel="s") # Test with debug = None pcv.params.debug = None s = pcv.rgb2gray_hsv(rgb_img=img, channel="s") From caf2f45fcd28c7f0a7f000aa30034944a9155baf Mon Sep 17 00:00:00 2001 From: Dominik Schneider Date: Tue, 17 Aug 2021 17:00:04 -0700 Subject: [PATCH 36/63] rgb2gray lab --- plantcv/plantcv/rgb2gray_lab.py | 18 ++++++++---------- tests/tests.py | 6 ------ 2 files changed, 8 insertions(+), 16 deletions(-) diff --git a/plantcv/plantcv/rgb2gray_lab.py b/plantcv/plantcv/rgb2gray_lab.py index 6b766ff52..5d0d891e7 100755 --- a/plantcv/plantcv/rgb2gray_lab.py +++ b/plantcv/plantcv/rgb2gray_lab.py @@ -2,14 +2,14 @@ import cv2 import os -from plantcv.plantcv import print_image -from plantcv.plantcv import plot_image +from plantcv.plantcv._debug import _debug from plantcv.plantcv import fatal_error from plantcv.plantcv import params def rgb2gray_lab(rgb_img, channel): - """Convert image from RGB colorspace to LAB colorspace. Returns the specified subchannel as a gray image. + """ + Convert image from RGB colorspace to LAB colorspace. Returns the specified subchannel as a gray image. Inputs: rgb_img = RGB image data @@ -22,8 +22,7 @@ def rgb2gray_lab(rgb_img, channel): :param channel: str :return channel: numpy.ndarray """ - # Auto-increment the device counter - params.device += 1 + # The allowable channel inputs are l, a or b names = {"l": "lightness", "a": "green-magenta", "b": "blue-yellow"} channel = channel.lower() @@ -37,10 +36,9 @@ def rgb2gray_lab(rgb_img, channel): # Create a channel dictionaries for lookups by a channel name index channels = {"l": l, "a": a, "b": b} - if params.debug == "print": - print_image(channels[channel], os.path.join(params.debug_outdir, - str(params.device) + "_lab_" + names[channel] + ".png")) - elif params.debug == "plot": - plot_image(channels[channel], cmap="gray") + _debug(visual=channels[channel], + filename=os.path.join(params.debug_outdir, + str(params.device) + "_lab_" + names[channel] + ".png"), + cmap="gray") return channels[channel] diff --git a/tests/tests.py b/tests/tests.py index 8a754d1fa..02f5cc445 100755 --- a/tests/tests.py +++ b/tests/tests.py @@ -2875,12 +2875,6 @@ def test_plantcv_rgb2gray_lab(): pcv.params.debug_outdir = cache_dir # Read in test data img = cv2.imread(os.path.join(TEST_DATA, TEST_INPUT_COLOR)) - # Test with debug = "print" - pcv.params.debug = "print" - _ = pcv.rgb2gray_lab(rgb_img=img, channel='b') - # Test with debug = "plot" - pcv.params.debug = "plot" - _ = pcv.rgb2gray_lab(rgb_img=img, channel='b') # Test with debug = None pcv.params.debug = None b = pcv.rgb2gray_lab(rgb_img=img, channel='b') From 4b7c6bf1c85a6f83ccd67e0e061e9009d3a61952 Mon Sep 17 00:00:00 2001 From: Dominik Schneider Date: Tue, 17 Aug 2021 17:05:36 -0700 Subject: [PATCH 37/63] roi objects --- plantcv/plantcv/roi_objects.py | 15 ++++++--------- tests/tests.py | 13 +++---------- 2 files changed, 9 insertions(+), 19 deletions(-) diff --git a/plantcv/plantcv/roi_objects.py b/plantcv/plantcv/roi_objects.py index 3ac9a30ff..92973e001 100755 --- a/plantcv/plantcv/roi_objects.py +++ b/plantcv/plantcv/roi_objects.py @@ -4,8 +4,7 @@ import numpy as np import os from plantcv.plantcv import logical_and -from plantcv.plantcv import print_image -from plantcv.plantcv import plot_image +from plantcv.plantcv._debug import _debug from plantcv.plantcv import fatal_error from plantcv.plantcv import params @@ -42,7 +41,6 @@ def roi_objects(img, roi_contour, roi_hierarchy, object_contour, obj_hierarchy, debug = params.debug params.debug = None - params.device += 1 # Create an empty grayscale (black) image the same dimensions as the input image mask = np.zeros(np.shape(img)[:2], dtype=np.uint8) cv2.drawContours(mask, object_contour, -1, (255), -1, lineType=8, hierarchy=obj_hierarchy) @@ -142,11 +140,10 @@ def roi_objects(img, roi_contour, roi_hierarchy, object_contour, obj_hierarchy, # Reset debug mode params.debug = debug - if params.debug == 'print': - print_image(ori_img, os.path.join(params.debug_outdir, str(params.device) + '_obj_on_img.png')) - print_image(mask, os.path.join(params.debug_outdir, str(params.device) + '_roi_mask.png')) - elif params.debug == 'plot': - plot_image(ori_img) - plot_image(mask, cmap='gray') + _debug(ori_img, + filename=os.path.join(params.debug_outdir, str(params.device) + '_obj_on_img.png')) + _debug(mask, + filename=os.path.join(params.debug_outdir, str(params.device) + '_roi_mask.png'), + cmap='gray') return kept_cnt, kept_hierarchy, mask, obj_area diff --git a/tests/tests.py b/tests/tests.py index 02f5cc445..18e8d1a0e 100755 --- a/tests/tests.py +++ b/tests/tests.py @@ -2934,16 +2934,10 @@ def test_plantcv_roi_objects(): object_contours = [object_contours_npz[arr_n] for arr_n in object_contours_npz] object_hierarchy_npz = np.load(os.path.join(TEST_DATA, TEST_INPUT_OBJECT_HIERARCHY), encoding="latin1") object_hierarchy = object_hierarchy_npz['arr_0'] - # Test with debug = "print" - pcv.params.debug = "print" + # Test with debug = None + pcv.params.debug = None _ = pcv.roi_objects(img=img, roi_contour=roi_contour, roi_hierarchy=roi_hierarchy, object_contour=object_contours, obj_hierarchy=object_hierarchy, roi_type="largest") - # Test with debug = "plot" - pcv.params.debug = "plot" - _ = pcv.roi_objects(img=img, roi_contour=roi_contour, roi_hierarchy=roi_hierarchy, - object_contour=object_contours, obj_hierarchy=object_hierarchy, roi_type="partial") - # Test with debug = None and roi_type = cutto - pcv.params.debug = None _ = pcv.roi_objects(img=img, roi_contour=roi_contour, roi_hierarchy=roi_hierarchy, object_contour=object_contours, obj_hierarchy=object_hierarchy, roi_type="cutto") # Test with debug = None @@ -2987,8 +2981,7 @@ def test_plantcv_roi_objects_grayscale_input(): object_contours = [object_contours_npz[arr_n] for arr_n in object_contours_npz] object_hierarchy_npz = np.load(os.path.join(TEST_DATA, TEST_INPUT_OBJECT_HIERARCHY), encoding="latin1") object_hierarchy = object_hierarchy_npz['arr_0'] - # Test with debug = "plot" - pcv.params.debug = "plot" + pcv.params.debug = None kept_contours, kept_hierarchy, mask, area = pcv.roi_objects(img=img, roi_type="partial", roi_contour=roi_contour, roi_hierarchy=roi_hierarchy, object_contour=object_contours, From e51f37d12af3042cdbe93157bfc0dc5650aeae48 Mon Sep 17 00:00:00 2001 From: Dominik Schneider Date: Tue, 17 Aug 2021 17:10:10 -0700 Subject: [PATCH 38/63] scale features --- plantcv/plantcv/scale_features.py | 13 +++++-------- tests/tests.py | 7 +------ 2 files changed, 6 insertions(+), 14 deletions(-) diff --git a/plantcv/plantcv/scale_features.py b/plantcv/plantcv/scale_features.py index 6a699dbfe..43d64d35a 100755 --- a/plantcv/plantcv/scale_features.py +++ b/plantcv/plantcv/scale_features.py @@ -3,13 +3,13 @@ import os import cv2 import numpy as np -from plantcv.plantcv import plot_image -from plantcv.plantcv import print_image +from plantcv.plantcv._debug import _debug from plantcv.plantcv import params def scale_features(obj, mask, points, line_position): - """scale_features: returns feature scaled points + """ + scale_features: returns feature scaled points This is a function to transform the coordinates of landmark points onto a common scale (0 - 1.0). @@ -67,7 +67,6 @@ def scale_features(obj, mask, points, line_position): boundary_line_scaled = (blx_scaled, bly_scaled) # If debug is 'True' plot an image of the scaled points on a black background if params.debug is not None: - params.device += 1 # Make a decent size blank image scaled_img = np.zeros((1500, 1500, 3), np.uint8) plotter = np.array(rescaled) @@ -84,10 +83,8 @@ def scale_features(obj, mask, points, line_position): (0, 255, 0), -1) # Because the coordinates inc as you go down and right on the img you need to flip the object around the x-axis flipped_scaled = cv2.flip(scaled_img, 0) - if params.debug == 'print': - print_image(flipped_scaled, os.path.join(params.debug_outdir, str(params.device) + '_feature_scaled.png')) - elif params.debug == 'plot': - plot_image(flipped_scaled) + _debug(visual=flipped_scaled, + filename=os.path.join(params.debug_outdir, str(params.device) + '_feature_scaled.png')) # Return the transformed points return rescaled, centroid_scaled, boundary_line_scaled diff --git a/tests/tests.py b/tests/tests.py index 18e8d1a0e..c24fefdea 100755 --- a/tests/tests.py +++ b/tests/tests.py @@ -3041,14 +3041,9 @@ def test_plantcv_scale_features(): mask = cv2.imread(os.path.join(TEST_DATA, TEST_MASK_SMALL), -1) contours_npz = np.load(os.path.join(TEST_DATA, TEST_VIS_COMP_CONTOUR), encoding="latin1") obj_contour = contours_npz['arr_0'] - # Test with debug = "print" - pcv.params.debug = "print" - _ = pcv.scale_features(obj=obj_contour, mask=mask, points=TEST_ACUTE_RESULT, line_position=50) - # Test with debug = "plot" - pcv.params.debug = "plot" - _ = pcv.scale_features(obj=obj_contour, mask=mask, points=TEST_ACUTE_RESULT, line_position='NA') # Test with debug = None pcv.params.debug = None + _ = pcv.scale_features(obj=obj_contour, mask=mask, points=TEST_ACUTE_RESULT, line_position='NA') points_rescaled, centroid_rescaled, bottomline_rescaled = pcv.scale_features(obj=obj_contour, mask=mask, points=TEST_ACUTE_RESULT, line_position=50) From 7002fcd23fc34a43d0e7e6d38e22ae0d37d0651d Mon Sep 17 00:00:00 2001 From: Dominik Schneider Date: Tue, 17 Aug 2021 17:13:09 -0700 Subject: [PATCH 39/63] scharr filter --- plantcv/plantcv/scharr_filter.py | 19 +++++++++---------- tests/tests.py | 6 ------ 2 files changed, 9 insertions(+), 16 deletions(-) diff --git a/plantcv/plantcv/scharr_filter.py b/plantcv/plantcv/scharr_filter.py index bd24177d7..f0f095de9 100755 --- a/plantcv/plantcv/scharr_filter.py +++ b/plantcv/plantcv/scharr_filter.py @@ -2,8 +2,7 @@ import cv2 import os -from plantcv.plantcv import print_image -from plantcv.plantcv import plot_image +from plantcv.plantcv._debug import _debug from plantcv.plantcv import params @@ -14,7 +13,7 @@ def scharr_filter(img, dx, dy, scale): specifies that the dimensions of output image will be the same as the input image. Inputs: - gray_img = Grayscale image data + gray_img = grayscale image data dx = derivative of x to analyze (1-3) dy = derivative of x to analyze (1-3) scale = scaling factor applied (multiplied) to computed Scharr values (scale = 1 is unscaled) @@ -30,11 +29,11 @@ def scharr_filter(img, dx, dy, scale): """ sr_img = cv2.Scharr(src=img, ddepth=-1, dx=dx, dy=dy, scale=scale) - params.device += 1 - if params.debug == 'print': - name = os.path.join(params.debug_outdir, str(params.device)) - name += '_sr_img_dx' + str(dx) + '_dy' + str(dy) + '_scale' + str(scale) + '.png' - print_image(sr_img, name) - elif params.debug == 'plot': - plot_image(sr_img, cmap='gray') + name = os.path.join(params.debug_outdir, str(params.device)) + name += '_sr_img_dx' + str(dx) + '_dy' + str(dy) + '_scale' + str(scale) + '.png' + + _debug(visual=sr_img, + filename=name, + cmap='gray') + return sr_img diff --git a/tests/tests.py b/tests/tests.py index c24fefdea..6defe309a 100755 --- a/tests/tests.py +++ b/tests/tests.py @@ -3065,12 +3065,6 @@ def test_plantcv_scharr_filter(): pcv.params.debug_outdir = cache_dir # Read in test data img = cv2.imread(os.path.join(TEST_DATA, TEST_INPUT_GRAY), -1) - pcv.params.debug = "print" - # Test with debug = "print" - _ = pcv.scharr_filter(img=img, dx=1, dy=0, scale=1) - # Test with debug = "plot" - pcv.params.debug = "plot" - _ = pcv.scharr_filter(img=img, dx=1, dy=0, scale=1) # Test with debug = None pcv.params.debug = None scharr_img = pcv.scharr_filter(img=img, dx=1, dy=0, scale=1) From fdf148fbdadeb3d0335e6684598b003382a92af8 Mon Sep 17 00:00:00 2001 From: Dominik Schneider Date: Wed, 18 Aug 2021 10:28:16 -0700 Subject: [PATCH 40/63] shift image --- plantcv/plantcv/shift_img.py | 17 +++++++---------- tests/tests.py | 12 +----------- 2 files changed, 8 insertions(+), 21 deletions(-) diff --git a/plantcv/plantcv/shift_img.py b/plantcv/plantcv/shift_img.py index 0164f1de1..0b6b3777c 100755 --- a/plantcv/plantcv/shift_img.py +++ b/plantcv/plantcv/shift_img.py @@ -2,8 +2,7 @@ import os import numpy as np -from plantcv.plantcv import print_image -from plantcv.plantcv import plot_image +from plantcv.plantcv._debug import _debug from plantcv.plantcv import fatal_error from plantcv.plantcv import params @@ -24,7 +23,6 @@ def shift_img(img, number, side="right"): :param side: str :return newmask: numpy.ndarray """ - params.device += 1 number -= 1 @@ -35,9 +33,11 @@ def shift_img(img, number, side="right"): if len(np.shape(img)) == 3: ix, iy, iz = np.shape(img) ori_img = np.copy(img) + cmap = None else: ix, iy = np.shape(img) ori_img = np.dstack((img, img, img)) + cmap = 'gray' if side.upper() == "TOP": top = np.zeros((number, iy, 3), dtype=np.uint8) @@ -58,12 +58,9 @@ def shift_img(img, number, side="right"): if len(np.shape(img)) == 2: adjusted_img = adjusted_img[:, :, 0] - if params.debug == 'print': - print_image(adjusted_img, os.path.join(params.debug_outdir, str(params.device) + "_shifted_img.png")) - elif params.debug == 'plot': - if len(np.shape(adjusted_img)) == 3: - plot_image(adjusted_img) - else: - plot_image(adjusted_img, cmap='gray') + + _debug(visual=adjusted_img, + filename=os.path.join(params.debug_outdir, str(params.device) + "_shifted_img.png"), + cmap=cmap) return adjusted_img diff --git a/tests/tests.py b/tests/tests.py index 6defe309a..81f8aa5b5 100755 --- a/tests/tests.py +++ b/tests/tests.py @@ -3080,20 +3080,10 @@ def test_plantcv_shift_img(): # Read in test data img = cv2.imread(os.path.join(TEST_DATA, TEST_INPUT_COLOR)) mask = cv2.imread(os.path.join(TEST_DATA, TEST_INPUT_BINARY), -1) - # Test with debug = "print" - pcv.params.debug = "print" - _ = pcv.shift_img(img=img, number=300, side="top") - # Test with debug = "plot" - pcv.params.debug = "plot" - _ = pcv.shift_img(img=img, number=300, side="top") - # Test with debug = "plot" + pcv.params.debug = None _ = pcv.shift_img(img=img, number=300, side="bottom") - # Test with debug = "plot" _ = pcv.shift_img(img=img, number=300, side="right") - # Test with debug = "plot" _ = pcv.shift_img(img=mask, number=300, side="left") - # Test with debug = None - pcv.params.debug = None rotated = pcv.shift_img(img=img, number=300, side="top") imgavg = np.average(img) shiftavg = np.average(rotated) From 92e983c72240305018618a379343ece393c8b274 Mon Sep 17 00:00:00 2001 From: Dominik Schneider Date: Wed, 18 Aug 2021 10:32:11 -0700 Subject: [PATCH 41/63] sobel filter --- plantcv/plantcv/sobel_filter.py | 25 ++++++++++++------------- tests/tests.py | 6 ------ 2 files changed, 12 insertions(+), 19 deletions(-) diff --git a/plantcv/plantcv/sobel_filter.py b/plantcv/plantcv/sobel_filter.py index 6054fba8b..72affab8b 100755 --- a/plantcv/plantcv/sobel_filter.py +++ b/plantcv/plantcv/sobel_filter.py @@ -2,16 +2,16 @@ import cv2 import os -from plantcv.plantcv import print_image -from plantcv.plantcv import plot_image +from plantcv.plantcv._debug import _debug from plantcv.plantcv import params def sobel_filter(gray_img, dx, dy, ksize): - """This is a filtering method used to identify and highlight gradient edges/features using the 1st derivative. - Typically used to identify gradients along the x-axis (dx = 1, dy = 0) and y-axis (dx = 0, dy = 1) independently. - Performance is quite similar to Scharr filter. Used to detect edges / changes in pixel intensity. ddepth = -1 - specifies that the dimensions of output image will be the same as the input image. + """ + This is a filtering method used to identify and highlight gradient edges/features using the 1st derivative. + Typically used to identify gradients along the x-axis (dx = 1, dy = 0) and y-axis (dx = 0, dy = 1) independently. + Performance is quite similar to Scharr filter. Used to detect edges / changes in pixel intensity. ddepth = -1 + specifies that the dimensions of output image will be the same as the input image. Inputs: gray_img = Grayscale image data @@ -28,13 +28,12 @@ def sobel_filter(gray_img, dx, dy, ksize): :param ksize: int :return sb_img: numpy.ndarray """ - params.device += 1 + sb_img = cv2.Sobel(src=gray_img, ddepth=-1, dx=dx, dy=dy, ksize=ksize) - if params.debug == 'print': - fname = str(params.device) + '_sb_img_dx' + str(dx) + '_dy' + str(dy) + '_kernel' + str(ksize) + '.png' - name = os.path.join(params.debug_outdir, fname) - print_image(sb_img, name) - elif params.debug == 'plot': - plot_image(sb_img, cmap='gray') + fname = str(params.device) + '_sb_img_dx' + str(dx) + '_dy' + str(dy) + '_kernel' + str(ksize) + '.png' + _debug(visual=sb_img, + filename=os.path.join(params.debug_outdir, fname), + cmap='gray') + return sb_img diff --git a/tests/tests.py b/tests/tests.py index 81f8aa5b5..12ad6f9a1 100755 --- a/tests/tests.py +++ b/tests/tests.py @@ -3113,12 +3113,6 @@ def test_plantcv_sobel_filter(): pcv.params.debug_outdir = cache_dir # Read in test data img = cv2.imread(os.path.join(TEST_DATA, TEST_INPUT_GRAY), -1) - # Test with debug = "print" - pcv.params.debug = "print" - _ = pcv.sobel_filter(gray_img=img, dx=1, dy=0, ksize=1) - # Test with debug = "plot" - pcv.params.debug = "plot" - _ = pcv.sobel_filter(gray_img=img, dx=1, dy=0, ksize=1) # Test with debug = None pcv.params.debug = None sobel_img = pcv.sobel_filter(gray_img=img, dx=1, dy=0, ksize=1) From dfbb5840861f4cd66815b922ee91ed594554f11b Mon Sep 17 00:00:00 2001 From: Dominik Schneider Date: Wed, 18 Aug 2021 10:39:52 -0700 Subject: [PATCH 42/63] spatial clustering --- plantcv/plantcv/spatial_clustering.py | 16 ++++------ tests/tests.py | 43 +++++++++++---------------- 2 files changed, 22 insertions(+), 37 deletions(-) diff --git a/plantcv/plantcv/spatial_clustering.py b/plantcv/plantcv/spatial_clustering.py index 022baf792..52e18f06b 100644 --- a/plantcv/plantcv/spatial_clustering.py +++ b/plantcv/plantcv/spatial_clustering.py @@ -6,13 +6,13 @@ from sklearn.cluster import OPTICS from sklearn.preprocessing import StandardScaler from plantcv.plantcv import params -from plantcv.plantcv import print_image -from plantcv.plantcv import plot_image +from plantcv.plantcv._debug import _debug from plantcv.plantcv import color_palette def spatial_clustering(mask, algorithm="DBSCAN", min_cluster_size=5, max_distance=None): - """Counts and segments portions of an image based on distance between two pixels. + """ + Counts and segments portions of an image based on distance between two pixels. Masks showing all clusters, plus masks of individual clusters, are returned. Inputs: @@ -38,9 +38,6 @@ def spatial_clustering(mask, algorithm="DBSCAN", min_cluster_size=5, max_distanc :return clust_masks: list """ - # Increment device counter - params.device += 1 - # Uppercase algorithm name al_upper = algorithm.upper() @@ -95,10 +92,7 @@ def spatial_clustering(mask, algorithm="DBSCAN", min_cluster_size=5, max_distanc dict_of_colors[str(db.labels_[z])][1], dict_of_colors[str(db.labels_[z])][0]) - if params.debug == 'print': - print_image(clust_img, os.path.join(params.debug_outdir, f"{params.device}_{al_upper}_clusters.png")) - - elif params.debug == 'plot': - plot_image(clust_img) + _debug(visual=clust_img, + filename=os.path.join(params.debug_outdir, f"{params.device}_{al_upper}_clusters.png")) return clust_img, clust_masks diff --git a/tests/tests.py b/tests/tests.py index 12ad6f9a1..c58a69fb2 100755 --- a/tests/tests.py +++ b/tests/tests.py @@ -2704,17 +2704,17 @@ def test_plantcv_readimage_bad_file(): @pytest.mark.parametrize("alg, pattern", [["default", 'BG'], - ["default", 'GB'], - ["default", 'RG'], - ["default", 'GR'], - ["edgeaware", 'BG'], - ["edgeaware", 'GB'], - ["edgeaware", 'RG'], - ["edgeaware", 'GR'], - ["variablenumbergradients", 'BG'], - ["variablenumbergradients", 'GB'], - ["variablenumbergradients", 'RG'], - ["variablenumbergradients", 'GR']]) + ["default", 'GB'], + ["default", 'RG'], + ["default", 'GR'], + ["edgeaware", 'BG'], + ["edgeaware", 'GB'], + ["edgeaware", 'RG'], + ["edgeaware", 'GR'], + ["variablenumbergradients", 'BG'], + ["variablenumbergradients", 'GB'], + ["variablenumbergradients", 'RG'], + ["variablenumbergradients", 'GR']]) def test_plantcv_readbayer_default_bg(alg, pattern): # Test cache directory cache_dir = os.path.join(TEST_TMPDIR, "test_plantcv_readbayer_default_bg") @@ -3424,25 +3424,16 @@ def test_plantcv_background_subtraction_different_sizes(): assert np.sum(fgmask) > 0 -def test_plantcv_spatial_clustering_dbscan(): +@pytest.mark.parametrize("alg, min_size, max_size", [['DBSCAN', 10, None], + ['OPTICS', 100, 5000]] + ) +def test_plantcv_spatial_clustering(alg, min_size, max_size): cache_dir = os.path.join(TEST_TMPDIR, "test_plantcv_spatial_clustering_dbscan") os.mkdir(cache_dir) pcv.params.debug_outdir = cache_dir img = cv2.imread(os.path.join(TEST_DATA, TEST_INPUT_MULTI_MASK), -1) - pcv.params.debug = "print" - _ = pcv.spatial_clustering(img, algorithm="DBSCAN", min_cluster_size=10, max_distance=None) - pcv.params.debug = "plot" - spmask = pcv.spatial_clustering(img, algorithm="DBSCAN", min_cluster_size=10, max_distance=None) - assert len(spmask[1]) == 2 - - -def test_plantcv_spatial_clustering_optics(): - cache_dir = os.path.join(TEST_TMPDIR, "test_plantcv_spatial_clustering_optics") - os.mkdir(cache_dir) - pcv.params.debug_outdir = cache_dir - img = cv2.imread(os.path.join(TEST_DATA, TEST_INPUT_MULTI_MASK), -1) pcv.params.debug = None - spmask = pcv.spatial_clustering(img, algorithm="OPTICS", min_cluster_size=100, max_distance=5000) + spmask = pcv.spatial_clustering(img, algorithm=alg, min_cluster_size=min_size, max_distance=max_size) assert len(spmask[1]) == 2 @@ -5971,7 +5962,6 @@ def test_plantcv_visualize_colorize_masks_bad_color_input(): _ = pcv.visualize.colorize_masks(masks=[mask1, mask2], colors=['red', 1.123]) - def test_plantcv_visualize_colorize_label_img(): label_img = np.array([[1, 2, 3], [4, 5, 6], [7, 8, 9]]) pcv.params.debug = None @@ -6018,6 +6008,7 @@ def test_plantcv_visualize_histogram_multispectral_img(): fig_hist = pcv.visualize.histogram(img=img_multi) assert isinstance(fig_hist, ggplot) + def test_plantcv_visualize_histogram_no_img(): with pytest.raises(RuntimeError): _ = pcv.visualize.histogram(img=None) From 967d1de3a43a576e07e3c87aeeb67e536dd1db6b Mon Sep 17 00:00:00 2001 From: Dominik Schneider Date: Wed, 18 Aug 2021 10:43:32 -0700 Subject: [PATCH 43/63] stdev filter --- plantcv/plantcv/stdev_filter.py | 14 +++++--------- tests/tests.py | 4 +--- 2 files changed, 6 insertions(+), 12 deletions(-) diff --git a/plantcv/plantcv/stdev_filter.py b/plantcv/plantcv/stdev_filter.py index b87b7ec7f..c16e9c7b5 100644 --- a/plantcv/plantcv/stdev_filter.py +++ b/plantcv/plantcv/stdev_filter.py @@ -3,14 +3,14 @@ import os import numpy as np -from plantcv.plantcv import print_image -from plantcv.plantcv import plot_image +from plantcv.plantcv._debug import _debug from plantcv.plantcv import params from scipy.ndimage import generic_filter def stdev_filter(img, ksize, borders='nearest'): - """Creates a binary image from a grayscale image using skimage texture calculation for thresholding. + """ + Creates a binary image from a grayscale image using skimage texture calculation for thresholding. This function is quite slow. Inputs: @@ -34,11 +34,7 @@ def stdev_filter(img, ksize, borders='nearest'): # Apply the texture function over the whole image generic_filter(img, np.std, size=ksize, output=output, mode=borders) - if params.debug == "print": - # If debug is print, save the image to a file - print_image(output, os.path.join(params.debug_outdir, str(params.device) + "_variance.png")) - elif params.debug == "plot": - # If debug is plot, print to the plotting device - plot_image(output) + _debug(visual=output, + filename=os.path.join(params.debug_outdir, str(params.device) + "_variance.png")) return output diff --git a/tests/tests.py b/tests/tests.py index c58a69fb2..c8f53efb7 100755 --- a/tests/tests.py +++ b/tests/tests.py @@ -3127,9 +3127,7 @@ def test_plantcv_stdev_filter(): pcv.params.debug_outdir = cache_dir # Read in test data img = cv2.imread(os.path.join(TEST_DATA, TEST_INPUT_GRAY_SMALL), -1) - pcv.params.debug = "plot" - _ = pcv.stdev_filter(img=img, ksize=11) - pcv.params.debug = "print" + pcv.params.debug = None filter_img = pcv.stdev_filter(img=img, ksize=11) assert (np.shape(filter_img) == np.shape(img)) From de14bc4e7db7bdc16dbff0f2c45e50e8d4c1f3e9 Mon Sep 17 00:00:00 2001 From: Dominik Schneider Date: Wed, 18 Aug 2021 10:47:08 -0700 Subject: [PATCH 44/63] watershed segmentation --- plantcv/plantcv/watershed.py | 20 +++++++++----------- tests/tests.py | 10 ++-------- 2 files changed, 11 insertions(+), 19 deletions(-) diff --git a/plantcv/plantcv/watershed.py b/plantcv/plantcv/watershed.py index b73261aa3..aea014ce0 100755 --- a/plantcv/plantcv/watershed.py +++ b/plantcv/plantcv/watershed.py @@ -8,8 +8,7 @@ from scipy import ndimage as ndi from skimage.feature import peak_local_max from skimage.segmentation import watershed -from plantcv.plantcv import print_image -from plantcv.plantcv import plot_image +from plantcv.plantcv._debug import _debug from plantcv.plantcv import apply_mask from plantcv.plantcv import color_palette from plantcv.plantcv import params @@ -17,8 +16,9 @@ def watershed_segmentation(rgb_img, mask, distance=10, label="default"): - """Uses the watershed algorithm to detect boundary of objects. Needs a marker file which specifies area which is - object (white), background (grey), unknown area (black). + """ + Uses the watershed algorithm to detect boundary of objects. Needs a marker file which specifies area which is + object (white), background (grey), unknown area (black). Inputs: rgb_img = image to perform watershed on needs to be 3D (i.e. np.shape = x,y,z not np.shape = x,y) @@ -35,7 +35,6 @@ def watershed_segmentation(rgb_img, mask, distance=10, label="default"): :param label: str :return analysis_images: list """ - params.device += 1 # Store debug mode debug = params.debug @@ -63,12 +62,11 @@ def watershed_segmentation(rgb_img, mask, distance=10, label="default"): # Reset debug mode params.debug = debug - if params.debug == 'print': - print_image(dist_transform, os.path.join(params.debug_outdir, str(params.device) + '_watershed_dist_img.png')) - print_image(joined, os.path.join(params.debug_outdir, str(params.device) + '_watershed_img.png')) - elif params.debug == 'plot': - plot_image(dist_transform, cmap='gray') - plot_image(joined) + _debug(visual=dist_transform, + filename=os.path.join(params.debug_outdir, str(params.device) + '_watershed_dist_img.png'), + cmap='gray') + _debug(visual=joined, + filename=os.path.join(params.debug_outdir, str(params.device) + '_watershed_img.png')) outputs.add_observation(sample=label, variable='estimated_object_count', trait='estimated object count', method='plantcv.plantcv.watershed', scale='none', datatype=int, diff --git a/tests/tests.py b/tests/tests.py index c8f53efb7..fa7e757af 100755 --- a/tests/tests.py +++ b/tests/tests.py @@ -3142,16 +3142,10 @@ def test_plantcv_watershed_segmentation(): # Read in test data img = cv2.imread(os.path.join(TEST_DATA, TEST_INPUT_CROPPED)) mask = cv2.imread(os.path.join(TEST_DATA, TEST_INPUT_CROPPED_MASK), -1) - # Test with debug = "print" - pcv.params.debug = "print" - _ = pcv.watershed_segmentation(rgb_img=img, mask=mask, distance=10, label="prefix") - # Test with debug = "plot" - pcv.params.debug = "plot" - _ = pcv.watershed_segmentation(rgb_img=img, mask=mask, distance=10) # Test with debug = None pcv.params.debug = None - _ = pcv.watershed_segmentation(rgb_img=img, mask=mask, distance=10) - assert pcv.outputs.observations['default']['estimated_object_count']['value'] > 9 + _ = pcv.watershed_segmentation(rgb_img=img, mask=mask, distance=10, label='prefix') + assert pcv.outputs.observations['prefix']['estimated_object_count']['value'] > 9 def test_plantcv_white_balance_gray_16bit(): From 757bab0390bacd467cbd1721a2bcd417cca73c7e Mon Sep 17 00:00:00 2001 From: Dominik Schneider Date: Wed, 18 Aug 2021 11:07:20 -0700 Subject: [PATCH 45/63] white balance --- plantcv/plantcv/white_balance.py | 21 +++++------- tests/tests.py | 59 +++++++------------------------- 2 files changed, 22 insertions(+), 58 deletions(-) diff --git a/plantcv/plantcv/white_balance.py b/plantcv/plantcv/white_balance.py index 1810371c0..0a172958b 100755 --- a/plantcv/plantcv/white_balance.py +++ b/plantcv/plantcv/white_balance.py @@ -3,8 +3,7 @@ import cv2 import os import numpy as np -from plantcv.plantcv import print_image -from plantcv.plantcv import plot_image +from plantcv.plantcv._debug import _debug from plantcv.plantcv import apply_mask from plantcv.plantcv import fatal_error from plantcv.plantcv import params @@ -33,7 +32,8 @@ def _max(img, hmax, mask, x, y, h, w, data_type): def white_balance(img, mode='hist', roi=None): - """Corrects the exposure of an image based on its histogram. + """ + Corrects the exposure of an image based on its histogram. Inputs: img = An RGB image on which to perform the correction, correction is done on each channel and then reassembled, @@ -50,7 +50,6 @@ def white_balance(img, mode='hist', roi=None): :param roi: list :return finalcorrected: numpy.ndarray """ - params.device += 1 ori_img = np.copy(img) @@ -84,7 +83,6 @@ def white_balance(img, mode='hist', roi=None): y = 0 w = ix h = iy - else: x = roi[0] y = roi[1] @@ -116,12 +114,11 @@ def white_balance(img, mode='hist', roi=None): elif mode.upper() == 'MAX': finalcorrected = _max(img, hmax, mask, x, y, h, w, data_type) - if params.debug == 'print': - print_image(ori_img, os.path.join(params.debug_outdir, str(params.device) + '_whitebalance_roi.png')) - print_image(finalcorrected, os.path.join(params.debug_outdir, str(params.device) + '_whitebalance.png')) - - elif params.debug == 'plot': - plot_image(ori_img, cmap='gray') - plot_image(finalcorrected, cmap='gray') + _debug(visual=ori_img, + filename=os.path.join(params.debug_outdir, str(params.device) + '_whitebalance_roi.png'), + cmap='gray') + _debug(visual=finalcorrected, + filename=os.path.join(params.debug_outdir, str(params.device) + '_whitebalance.png'), + cmap='gray') return finalcorrected diff --git a/tests/tests.py b/tests/tests.py index fa7e757af..ebc2161f8 100755 --- a/tests/tests.py +++ b/tests/tests.py @@ -3155,17 +3155,11 @@ def test_plantcv_white_balance_gray_16bit(): pcv.params.debug_outdir = cache_dir # Read in test data img = cv2.imread(os.path.join(TEST_DATA, TEST_INPUT_NIR_MASK), -1) - # Test with debug = "print" - pcv.params.debug = "print" - _ = pcv.white_balance(img=img, mode='hist', roi=(5, 5, 80, 80)) - # Test with debug = "plot" - pcv.params.debug = "plot" - _ = pcv.white_balance(img=img, mode='max', roi=(5, 5, 80, 80)) # Test without an ROI pcv.params.debug = None - _ = pcv.white_balance(img=img, mode='hist', roi=None) + _ = pcv.white_balance(img=img, mode='max', roi=None) # Test with debug = None - white_balanced = pcv.white_balance(img=img, roi=(5, 5, 80, 80)) + white_balanced = pcv.white_balance(img=img, mode='hist', roi=(5, 5, 80, 80)) imgavg = np.average(img) balancedavg = np.average(white_balanced) assert balancedavg != imgavg @@ -3179,17 +3173,11 @@ def test_plantcv_white_balance_gray_8bit(): # Read in test data img = cv2.imread(os.path.join(TEST_DATA, TEST_INPUT_NIR_MASK)) img = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY) - # Test with debug = "print" - pcv.params.debug = "print" - _ = pcv.white_balance(img=img, mode='hist', roi=(5, 5, 80, 80)) - # Test with debug = "plot" - pcv.params.debug = "plot" - _ = pcv.white_balance(img=img, mode='max', roi=(5, 5, 80, 80)) # Test without an ROI pcv.params.debug = None - _ = pcv.white_balance(img=img, mode='hist', roi=None) + _ = pcv.white_balance(img=img, mode='max', roi=None) # Test with debug = None - white_balanced = pcv.white_balance(img=img, roi=(5, 5, 80, 80)) + white_balanced = pcv.white_balance(img=img, mode='hist', roi=(5, 5, 80, 80)) imgavg = np.average(img) balancedavg = np.average(white_balanced) assert balancedavg != imgavg @@ -3202,47 +3190,26 @@ def test_plantcv_white_balance_rgb(): pcv.params.debug_outdir = cache_dir # Read in test data img = cv2.imread(os.path.join(TEST_DATA, TEST_INPUT_MARKER)) - # Test with debug = "print" - pcv.params.debug = "print" - _ = pcv.white_balance(img=img, mode='hist', roi=(5, 5, 80, 80)) - # Test with debug = "plot" - pcv.params.debug = "plot" - _ = pcv.white_balance(img=img, mode='max', roi=(5, 5, 80, 80)) - # Test without an ROI pcv.params.debug = None - _ = pcv.white_balance(img=img, mode='hist', roi=None) + # Test without an ROI + _ = pcv.white_balance(img=img, mode='max', roi=None) # Test with debug = None - white_balanced = pcv.white_balance(img=img, roi=(5, 5, 80, 80)) + white_balanced = pcv.white_balance(img=img, mode='hist', roi=(5, 5, 80, 80)) imgavg = np.average(img) balancedavg = np.average(white_balanced) assert balancedavg != imgavg -def test_plantcv_white_balance_bad_input(): - # Read in test data - img = cv2.imread(os.path.join(TEST_DATA, TEST_INPUT_NIR_MASK), -1) - # Test with debug = None - with pytest.raises(RuntimeError): - pcv.params.debug = "plot" - _ = pcv.white_balance(img=img, mode='hist', roi=(5, 5, 5, 5, 5)) - - -def test_plantcv_white_balance_bad_mode_input(): - # Read in test data - img = cv2.imread(os.path.join(TEST_DATA, TEST_INPUT_MARKER)) - # Test with debug = None - with pytest.raises(RuntimeError): - pcv.params.debug = "plot" - _ = pcv.white_balance(img=img, mode='histogram', roi=(5, 5, 80, 80)) - - -def test_plantcv_white_balance_bad_input_int(): +@pytest.mark.parametrize("mode, roi", [['hist', (5, 5, 5, 5, 5)], # too many points + ['hist', (5., 5, 5, 5)], # not all integers + ['histogram', (5, 5, 80, 80)]]) # bad mode +def test_plantcv_white_balance_bad_input(mode, roi): # Read in test data img = cv2.imread(os.path.join(TEST_DATA, TEST_INPUT_NIR_MASK), -1) # Test with debug = None with pytest.raises(RuntimeError): - pcv.params.debug = "plot" - _ = pcv.white_balance(img=img, mode='hist', roi=(5., 5, 5, 5)) + pcv.params.debug = None + _ = pcv.white_balance(img=img, mode=mode, roi=roi) def test_plantcv_x_axis_pseudolandmarks(): From 0306be9fad3ff1d9e6918816cda55997a0fc91e2 Mon Sep 17 00:00:00 2001 From: Dominik Schneider Date: Wed, 18 Aug 2021 11:20:38 -0700 Subject: [PATCH 46/63] x axis pseudolandmarks --- plantcv/plantcv/x_axis_pseudolandmarks.py | 23 ++++++++++------------- tests/tests.py | 15 ++++----------- 2 files changed, 14 insertions(+), 24 deletions(-) diff --git a/plantcv/plantcv/x_axis_pseudolandmarks.py b/plantcv/plantcv/x_axis_pseudolandmarks.py index 36f4c57fb..1ff44ab3a 100755 --- a/plantcv/plantcv/x_axis_pseudolandmarks.py +++ b/plantcv/plantcv/x_axis_pseudolandmarks.py @@ -3,15 +3,15 @@ import cv2 import os import numpy as np -from plantcv.plantcv import plot_image -from plantcv.plantcv import print_image +from plantcv.plantcv._debug import _debug from plantcv.plantcv import params from plantcv.plantcv import outputs from plantcv.plantcv import fatal_error def x_axis_pseudolandmarks(img, obj, mask, label="default"): - """Divide up object contour into 20 equidistance segments and generate landmarks for each + """ + Divide up object contour into 20 equidistance segments and generate landmarks for each Inputs: img = This is a copy of the original plant image generated using np.copy if debug is true it will be drawn on @@ -34,7 +34,6 @@ def x_axis_pseudolandmarks(img, obj, mask, label="default"): """ # Lets get some landmarks scanning along the x-axis - params.device += 1 if not np.any(obj): return ('NA', 'NA'), ('NA', 'NA'), ('NA', 'NA') x, y, width, height = cv2.boundingRect(obj) @@ -164,11 +163,10 @@ def x_axis_pseudolandmarks(img, obj, mask, label="default"): x = i[0, 0] y = i[0, 1] cv2.circle(img2, (int(x), int(y)), params.line_thickness, (0, 79, 255), -1) - if params.debug == 'plot': - plot_image(img2) - elif params.debug == 'print': - print_image(img2, - os.path.join(params.debug_outdir, (str(params.device) + '_x_axis_pseudolandmarks.png'))) + + _debug(visual=img2, + filename=os.path.join(params.debug_outdir, (str(params.device) + '_x_axis_pseudolandmarks.png'))) + elif extent < 21: # If the width of the object is less than 20 pixels just make the object a 20 pixel rectangle x, y, width, height = cv2.boundingRect(obj) @@ -205,10 +203,9 @@ def x_axis_pseudolandmarks(img, obj, mask, label="default"): x = i[0, 0] y = i[0, 1] cv2.circle(img2, (int(x), int(y)), params.line_thickness, (0, 79, 255), -1) - if params.debug == 'plot': - plot_image(img2) - elif params.debug == 'print': - print_image(img2, os.path.join(params.debug_outdir, (str(params.device) + '_x_axis_pseudolandmarks.png'))) + + _debug(visual=img2, + filename=os.path.join(params.debug_outdir, (str(params.device) + '_x_axis_pseudolandmarks.png'))) # Store into global measurements for pt in top: diff --git a/tests/tests.py b/tests/tests.py index ebc2161f8..0d6684de8 100755 --- a/tests/tests.py +++ b/tests/tests.py @@ -3221,18 +3221,14 @@ def test_plantcv_x_axis_pseudolandmarks(): mask = cv2.imread(os.path.join(TEST_DATA, TEST_MASK_SMALL), -1) contours_npz = np.load(os.path.join(TEST_DATA, TEST_VIS_COMP_CONTOUR), encoding="latin1") obj_contour = contours_npz['arr_0'] - pcv.params.debug = "print" - _ = pcv.x_axis_pseudolandmarks(obj=obj_contour, mask=mask, img=img) - # Test with debug = "plot" - pcv.params.debug = "plot" + # Test with debug = None + pcv.params.debug = None _ = pcv.x_axis_pseudolandmarks(obj=obj_contour, mask=mask, img=img, label="prefix") _ = pcv.x_axis_pseudolandmarks(obj=np.array([[0, 0], [0, 0]]), mask=np.array([[0, 0], [0, 0]]), img=img) _ = pcv.x_axis_pseudolandmarks(obj=np.array(([[89, 222]], [[252, 39]], [[89, 207]])), mask=np.array(([[42, 161]], [[2, 47]], [[211, 222]])), img=img) _ = pcv.x_axis_pseudolandmarks(obj=(), mask=mask, img=img) - # Test with debug = None - pcv.params.debug = None top, bottom, center_v = pcv.x_axis_pseudolandmarks(obj=obj_contour, mask=mask, img=img) pcv.outputs.clear() assert all([all([i == j] for i, j in zip(np.shape(top), (20, 1, 2))), @@ -3245,12 +3241,9 @@ def test_plantcv_x_axis_pseudolandmarks_small_obj(): mask = cv2.imread(os.path.join(TEST_DATA, TEST_MASK_SMALL_PLANT), -1) contours_npz = np.load(os.path.join(TEST_DATA, TEST_VIS_COMP_CONTOUR_SMALL_PLANT), encoding="latin1") obj_contour = contours_npz['arr_0'] - # Test with debug = "print" - pcv.params.debug = "print" - _, _, _ = pcv.x_axis_pseudolandmarks(obj=[], mask=mask, img=img) + # Test with debug = None + pcv.params.debug = None _, _, _ = pcv.x_axis_pseudolandmarks(obj=obj_contour, mask=mask, img=img) - # Test with debug = "plot" - pcv.params.debug = "plot" _, _, _ = pcv.x_axis_pseudolandmarks(obj=[], mask=mask, img=img) top, bottom, center_v = pcv.x_axis_pseudolandmarks(obj=obj_contour, mask=mask, img=img) assert all([all([i == j] for i, j in zip(np.shape(top), (20, 1, 2))), From 3cfa85f3101c6db6e32ba05263f6076c4906b532 Mon Sep 17 00:00:00 2001 From: Dominik Schneider Date: Wed, 18 Aug 2021 11:25:31 -0700 Subject: [PATCH 47/63] y axis pseudolandmarks --- plantcv/plantcv/y_axis_pseudolandmarks.py | 22 +++++++++------------- tests/tests.py | 16 +++------------- 2 files changed, 12 insertions(+), 26 deletions(-) diff --git a/plantcv/plantcv/y_axis_pseudolandmarks.py b/plantcv/plantcv/y_axis_pseudolandmarks.py index e8d763a40..eaec4fda8 100755 --- a/plantcv/plantcv/y_axis_pseudolandmarks.py +++ b/plantcv/plantcv/y_axis_pseudolandmarks.py @@ -3,15 +3,15 @@ import cv2 import os import numpy as np -from plantcv.plantcv import plot_image -from plantcv.plantcv import print_image +from plantcv.plantcv._debug import _debug from plantcv.plantcv import params from plantcv.plantcv import outputs from plantcv.plantcv import fatal_error def y_axis_pseudolandmarks(img, obj, mask, label="default"): - """Divide up object contour into 19 equidistant segments and generate landmarks for each + """ + Divide up object contour into 19 equidistant segments and generate landmarks for each Inputs: img = This is a copy of the original plant image generated using np.copy if debug is true it will be drawn on @@ -38,8 +38,6 @@ def y_axis_pseudolandmarks(img, obj, mask, label="default"): x, y, width, height = cv2.boundingRect(obj) extent = height - params.device += 1 - # Outputs left = [] right = [] @@ -161,10 +159,9 @@ def y_axis_pseudolandmarks(img, obj, mask, label="default"): y = i[0, 1] cv2.circle(img2, (int(x), int(y)), params.line_thickness, (0, 79, 255), -1) - if params.debug == 'plot': - plot_image(img2) - elif params.debug == 'print': - print_image(img2, os.path.join(params.debug_outdir, (str(params.device) + '_y_axis_pseudolandmarks.png'))) + _debug(visual=img2, + filename=os.path.join(params.debug_outdir, (str(params.device) + '_y_axis_pseudolandmarks.png'))) + elif extent < 21: # If the length of the object is less than 20 pixels just make the object a 20 pixel rectangle x, y, width, height = cv2.boundingRect(obj) @@ -202,10 +199,9 @@ def y_axis_pseudolandmarks(img, obj, mask, label="default"): y = i[0, 1] cv2.circle(img2, (int(x), int(y)), params.line_thickness, (0, 79, 255), -1) # print_image(img2, (str(device) + '_y_axis_pseudolandmarks.png')) - if params.debug == 'plot': - plot_image(img2) - elif params.debug == 'print': - print_image(img2, os.path.join(params.debug_outdir, (str(params.device) + '_y_axis_pseudolandmarks.png'))) + + _debug(visual=img2, + filename=os.path.join(params.debug_outdir, (str(params.device) + '_y_axis_pseudolandmarks.png'))) # Store into global measurements for pt in left: diff --git a/tests/tests.py b/tests/tests.py index 0d6684de8..6496556fb 100755 --- a/tests/tests.py +++ b/tests/tests.py @@ -3275,20 +3275,14 @@ def test_plantcv_y_axis_pseudolandmarks(): mask = cv2.imread(os.path.join(TEST_DATA, TEST_MASK_SMALL), -1) contours_npz = np.load(os.path.join(TEST_DATA, TEST_VIS_COMP_CONTOUR), encoding="latin1") obj_contour = contours_npz['arr_0'] - pcv.params.debug = "print" - _ = pcv.y_axis_pseudolandmarks(obj=obj_contour, mask=mask, img=img, label="prefix") - # Test with debug = "plot" - pcv.params.debug = "plot" - _ = pcv.y_axis_pseudolandmarks(obj=obj_contour, mask=mask, img=img) - pcv.outputs.clear() + # Test with debug = None + pcv.params.debug = None _ = pcv.y_axis_pseudolandmarks(obj=[], mask=mask, img=img) _ = pcv.y_axis_pseudolandmarks(obj=(), mask=mask, img=img) _ = pcv.y_axis_pseudolandmarks(obj=np.array(([[89, 222]], [[252, 39]], [[89, 207]])), mask=np.array(([[42, 161]], [[2, 47]], [[211, 222]])), img=img) _ = pcv.y_axis_pseudolandmarks(obj=np.array(([[21, 11]], [[159, 155]], [[237, 11]])), mask=np.array(([[38, 54]], [[144, 169]], [[81, 137]])), img=img) - # Test with debug = None - pcv.params.debug = None left, right, center_h = pcv.y_axis_pseudolandmarks(obj=obj_contour, mask=mask, img=img) pcv.outputs.clear() assert all([all([i == j] for i, j in zip(np.shape(left), (20, 1, 2))), @@ -3303,12 +3297,8 @@ def test_plantcv_y_axis_pseudolandmarks_small_obj(): mask = cv2.imread(os.path.join(TEST_DATA, TEST_MASK_SMALL_PLANT), -1) contours_npz = np.load(os.path.join(TEST_DATA, TEST_VIS_COMP_CONTOUR_SMALL_PLANT), encoding="latin1") obj_contour = contours_npz['arr_0'] - # Test with debug = "print" - pcv.params.debug = "print" + pcv.params.debug = None _, _, _ = pcv.y_axis_pseudolandmarks(obj=[], mask=mask, img=img) - _, _, _ = pcv.y_axis_pseudolandmarks(obj=obj_contour, mask=mask, img=img) - # Test with debug = "plot" - pcv.params.debug = "plot" pcv.outputs.clear() left, right, center_h = pcv.y_axis_pseudolandmarks(obj=obj_contour, mask=mask, img=img) pcv.outputs.clear() From 12de1d77b9af2f4f698c41e215585aba9988f014 Mon Sep 17 00:00:00 2001 From: Dominik Schneider Date: Wed, 25 Aug 2021 06:48:59 -0700 Subject: [PATCH 48/63] white balance: catch bad mode. previously missed in tests? --- plantcv/plantcv/white_balance.py | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/plantcv/plantcv/white_balance.py b/plantcv/plantcv/white_balance.py index 0a172958b..cc9d32bde 100755 --- a/plantcv/plantcv/white_balance.py +++ b/plantcv/plantcv/white_balance.py @@ -53,6 +53,9 @@ def white_balance(img, mode='hist', roi=None): ori_img = np.copy(img) + if mode != 'hist' or mode != 'max': + fatal_error('Mode must be either "hist" or "max" but ' + mode + ' was input.') + if roi is not None: roiint = all(isinstance(item, (list, int)) for item in roi) @@ -102,8 +105,6 @@ def white_balance(img, mode='hist', roi=None): channel1 = _max(c1, hmax, mask, x, y, h, w, data_type) channel2 = _max(c2, hmax, mask, x, y, h, w, data_type) channel3 = _max(c3, hmax, mask, x, y, h, w, data_type) - else: - fatal_error('Mode must be either "hist" or "max" but ' + mode + ' was input.') finalcorrected = np.dstack((channel1, channel2, channel3)) From d3f82162693a10a8009637f7e490bd518369bc0c Mon Sep 17 00:00:00 2001 From: Dominik Schneider Date: Wed, 25 Aug 2021 06:53:11 -0700 Subject: [PATCH 49/63] fix debug filename --- plantcv/plantcv/distance_transform.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/plantcv/plantcv/distance_transform.py b/plantcv/plantcv/distance_transform.py index 83da55423..29fa6f537 100644 --- a/plantcv/plantcv/distance_transform.py +++ b/plantcv/plantcv/distance_transform.py @@ -32,7 +32,7 @@ def distance_transform(bin_img, distance_type, mask_size): norm_image = cv2.normalize(src=dist, dst=dist, alpha=0, beta=1, norm_type=cv2.NORM_MINMAX, dtype=cv2.CV_32F) _debug(visual=norm_image, - filename=os.path.join(params.debug, str(params.device) + '_distance_transform.png'), + filename=os.path.join(params.debug_outdir, str(params.device) + '_distance_transform.png'), cmap='gray') return norm_image From 5a60276154aef07058724db94fe147172b6c6076 Mon Sep 17 00:00:00 2001 From: Dominik Schneider Date: Wed, 25 Aug 2021 07:20:31 -0700 Subject: [PATCH 50/63] white balance logic should be 'and' --- plantcv/plantcv/white_balance.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/plantcv/plantcv/white_balance.py b/plantcv/plantcv/white_balance.py index cc9d32bde..60e1e4e5f 100755 --- a/plantcv/plantcv/white_balance.py +++ b/plantcv/plantcv/white_balance.py @@ -53,7 +53,7 @@ def white_balance(img, mode='hist', roi=None): ori_img = np.copy(img) - if mode != 'hist' or mode != 'max': + if mode != 'hist' and mode != 'max': fatal_error('Mode must be either "hist" or "max" but ' + mode + ' was input.') if roi is not None: From 9be2baebe1727e84a17ad5e5eaf10b973c5c0aa0 Mon Sep 17 00:00:00 2001 From: Dominik Schneider Date: Wed, 25 Aug 2021 07:41:09 -0700 Subject: [PATCH 51/63] _debug even if debug is not None to avoid additional testing --- plantcv/plantcv/cluster_contours.py | 7 ++++--- plantcv/plantcv/scale_features.py | 14 ++++++++++---- 2 files changed, 14 insertions(+), 7 deletions(-) diff --git a/plantcv/plantcv/cluster_contours.py b/plantcv/plantcv/cluster_contours.py index 0d10da0ed..b3a8c736f 100755 --- a/plantcv/plantcv/cluster_contours.py +++ b/plantcv/plantcv/cluster_contours.py @@ -7,7 +7,6 @@ def cluster_contours(img, roi_objects, roi_obj_hierarchy, nrow=1, ncol=1, show_grid=False): - """ This function take a image with multiple contours and clusters them based on user input of rows and columns @@ -137,8 +136,10 @@ def digitize(a, step): cv2.line(img_copy, (0, y), (ix, y), (255, 0, 0), params.line_thickness) for x in cbreaks: cv2.line(img_copy, (x, 0), (x, iy), (255, 0, 0), params.line_thickness) + else: + img_copy = img # for _debug - _debug(visual=img_copy, - filename=os.path.join(params.debug_outdir, str(params.device) + '_clusters.png')) + _debug(visual=img_copy, # keep this outside if statement to avoid additional test + filename=os.path.join(params.debug_outdir, str(params.device) + '_clusters.png')) return grouped_contour_indexes, contours, roi_obj_hierarchy diff --git a/plantcv/plantcv/scale_features.py b/plantcv/plantcv/scale_features.py index 43d64d35a..069196498 100755 --- a/plantcv/plantcv/scale_features.py +++ b/plantcv/plantcv/scale_features.py @@ -65,10 +65,12 @@ def scale_features(obj, mask, points, line_position): blx_scaled = float(blx - xmin) / float(xmax - xmin) bly_scaled = float(bly - ymin) / float(ymax - ymin) boundary_line_scaled = (blx_scaled, bly_scaled) + + # Make a decent size blank image regardless of debug + scaled_img = np.zeros((1500, 1500, 3), np.uint8) + # If debug is 'True' plot an image of the scaled points on a black background if params.debug is not None: - # Make a decent size blank image - scaled_img = np.zeros((1500, 1500, 3), np.uint8) plotter = np.array(rescaled) # Multiple the values between 0 - 1.0 by 1000 so you can plot on the black image plotter = plotter * 1000 @@ -83,8 +85,12 @@ def scale_features(obj, mask, points, line_position): (0, 255, 0), -1) # Because the coordinates inc as you go down and right on the img you need to flip the object around the x-axis flipped_scaled = cv2.flip(scaled_img, 0) - _debug(visual=flipped_scaled, - filename=os.path.join(params.debug_outdir, str(params.device) + '_feature_scaled.png')) + else: + flipped_scaled = scaled_img # for _debug + + # keep outside if statement to avoid new tests + _debug(visual=flipped_scaled, + filename=os.path.join(params.debug_outdir, str(params.device) + '_feature_scaled.png')) # Return the transformed points return rescaled, centroid_scaled, boundary_line_scaled From 898b1c9c421954bbd7cf664b1cbb8ae65d5bfe96 Mon Sep 17 00:00:00 2001 From: Dominik Schneider Date: Wed, 25 Aug 2021 08:33:19 -0700 Subject: [PATCH 52/63] undelete readbayer bad input test --- tests/tests.py | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/tests/tests.py b/tests/tests.py index 6496556fb..6686c2d40 100755 --- a/tests/tests.py +++ b/tests/tests.py @@ -2715,7 +2715,7 @@ def test_plantcv_readimage_bad_file(): ["variablenumbergradients", 'GB'], ["variablenumbergradients", 'RG'], ["variablenumbergradients", 'GR']]) -def test_plantcv_readbayer_default_bg(alg, pattern): +def test_plantcv_readbayer(alg, pattern): # Test cache directory cache_dir = os.path.join(TEST_TMPDIR, "test_plantcv_readbayer_default_bg") os.mkdir(cache_dir) @@ -2727,6 +2727,13 @@ def test_plantcv_readbayer_default_bg(alg, pattern): assert all([i == j] for i, j in zip(np.shape(img), (335, 400, 3))) +def test_plantcv_readbayer_default_bad_input(): + # Test with debug = None + pcv.params.debug = None + with pytest.raises(RuntimeError): + _, _, _ = pcv.readbayer(filename=os.path.join(TEST_DATA, "no-image.png"), bayerpattern="GR", alg="default") + + def test_plantcv_rectangle_mask(): # Test cache directory cache_dir = os.path.join(TEST_TMPDIR, "test_plantcv_rectangle_mask") From 136db97415a92d5b3f5b489a91464b5f5cbbf3ea Mon Sep 17 00:00:00 2001 From: Dominik Schneider Date: Wed, 25 Aug 2021 08:40:02 -0700 Subject: [PATCH 53/63] cover plot logic scale_features --- tests/tests.py | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/tests/tests.py b/tests/tests.py index 6686c2d40..350feaf6b 100755 --- a/tests/tests.py +++ b/tests/tests.py @@ -3048,9 +3048,11 @@ def test_plantcv_scale_features(): mask = cv2.imread(os.path.join(TEST_DATA, TEST_MASK_SMALL), -1) contours_npz = np.load(os.path.join(TEST_DATA, TEST_VIS_COMP_CONTOUR), encoding="latin1") obj_contour = contours_npz['arr_0'] + # test with debug = 'plot' to cover plotting logic + pcv.params.debug = 'plot' + _ = pcv.scale_features(obj=obj_contour, mask=mask, points=TEST_ACUTE_RESULT, line_position='NA') # Test with debug = None pcv.params.debug = None - _ = pcv.scale_features(obj=obj_contour, mask=mask, points=TEST_ACUTE_RESULT, line_position='NA') points_rescaled, centroid_rescaled, bottomline_rescaled = pcv.scale_features(obj=obj_contour, mask=mask, points=TEST_ACUTE_RESULT, line_position=50) From 0fcef7e1d3d62d1f4f2d164df22fffc018446a96 Mon Sep 17 00:00:00 2001 From: Dominik Schneider Date: Wed, 25 Aug 2021 08:46:09 -0700 Subject: [PATCH 54/63] cover plotting logic for cluster_contours --- tests/tests.py | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/tests/tests.py b/tests/tests.py index 350feaf6b..70f16093f 100755 --- a/tests/tests.py +++ b/tests/tests.py @@ -1716,9 +1716,11 @@ def test_plantcv_cluster_contours(): hierarchy = np.load(os.path.join(TEST_DATA, TEST_INPUT_MULTI_HIERARCHY), encoding="latin1") objs = [roi_objects[arr_n] for arr_n in roi_objects] obj_hierarchy = hierarchy['arr_0'] + # Test with debug = 'plot' to cover plotting logic + pcv.params.debug = 'plot' + _ = pcv.cluster_contours(img=img1, roi_objects=objs, roi_obj_hierarchy=obj_hierarchy, show_grid=True) # Test with debug = None pcv.params.debug = None - _ = pcv.cluster_contours(img=img1, roi_objects=objs, roi_obj_hierarchy=obj_hierarchy, show_grid=True) clusters_i, contours, hierarchy = pcv.cluster_contours(img=img1, roi_objects=objs, roi_obj_hierarchy=obj_hierarchy, nrow=4, ncol=6) lenori = len(objs) @@ -1737,6 +1739,9 @@ def test_plantcv_cluster_contours_grayscale_input(): hierachy = np.load(os.path.join(TEST_DATA, TEST_INPUT_MULTI_HIERARCHY), encoding="latin1") objs = [roi_objects[arr_n] for arr_n in roi_objects] obj_hierarchy = hierachy['arr_0'] + # Test with debug = 'plot' to cover plotting logic + pcv.params.debug = 'plot' + _ = pcv.cluster_contours(img=img1, roi_objects=objs, roi_obj_hierarchy=obj_hierarchy, show_grid=True) # Test with debug = None pcv.params.debug = None clusters_i, contours, hierachy = pcv.cluster_contours(img=img1, roi_objects=objs, roi_obj_hierarchy=obj_hierarchy, From eb223babaab6768efaebaa9c56d861e8baeec7d7 Mon Sep 17 00:00:00 2001 From: Dominik Schneider Date: Wed, 25 Aug 2021 09:11:55 -0700 Subject: [PATCH 55/63] apply_mask --- plantcv/plantcv/apply_mask.py | 17 +++++------------ tests/tests.py | 19 ++----------------- 2 files changed, 7 insertions(+), 29 deletions(-) diff --git a/plantcv/plantcv/apply_mask.py b/plantcv/plantcv/apply_mask.py index 00d951933..0740eb59e 100755 --- a/plantcv/plantcv/apply_mask.py +++ b/plantcv/plantcv/apply_mask.py @@ -4,8 +4,7 @@ import cv2 import numpy as np from plantcv.plantcv import params -from plantcv.plantcv import plot_image -from plantcv.plantcv import print_image +from plantcv.plantcv._debug import _debug from plantcv.plantcv import fatal_error from plantcv.plantcv.transform import rescale @@ -27,8 +26,6 @@ def apply_mask(img, mask, mask_color): :return masked_img: numpy.ndarray """ - params.device += 1 - if mask_color.upper() == "WHITE": color_val = 255 elif mask_color.upper() == "BLACK": @@ -53,14 +50,10 @@ def apply_mask(img, mask, mask_color): rescale(array_data[:, :, num_bands - 1]))) params.debug = debug - if params.debug == 'print': - print_image(pseudo_rgb, os.path.join(params.debug_outdir, str(params.device) + '_masked.png')) - elif params.debug == 'plot': - plot_image(pseudo_rgb) + _debug(visual=pseudo_rgb, + filename=os.path.join(params.debug_outdir, str(params.device) + '_masked.png')) else: - if params.debug == 'print': - print_image(array_data, os.path.join(params.debug_outdir, str(params.device) + '_masked.png')) - elif params.debug == 'plot': - plot_image(array_data) + _debug(visual=array_data, + filename=os.path.join(params.debug_outdir, str(params.device) + '_masked.png')) return array_data diff --git a/tests/tests.py b/tests/tests.py index 70f16093f..a5af25428 100755 --- a/tests/tests.py +++ b/tests/tests.py @@ -1530,12 +1530,6 @@ def test_plantcv_apply_mask_white(): # Read in test data img = cv2.imread(os.path.join(TEST_DATA, TEST_INPUT_COLOR)) mask = cv2.imread(os.path.join(TEST_DATA, TEST_INPUT_BINARY), -1) - # Test with debug = "print" - pcv.params.debug = "print" - _ = pcv.apply_mask(img=img, mask=mask, mask_color="white") - # Test with debug = "plot" - pcv.params.debug = "plot" - _ = pcv.apply_mask(img=img, mask=mask, mask_color="white") # Test with debug = None pcv.params.debug = None masked_img = pcv.apply_mask(img=img, mask=mask, mask_color="white") @@ -1550,12 +1544,6 @@ def test_plantcv_apply_mask_black(): # Read in test data img = cv2.imread(os.path.join(TEST_DATA, TEST_INPUT_COLOR)) mask = cv2.imread(os.path.join(TEST_DATA, TEST_INPUT_BINARY), -1) - # Test with debug = "print" - pcv.params.debug = "print" - _ = pcv.apply_mask(img=img, mask=mask, mask_color="black") - # Test with debug = "plot" - pcv.params.debug = "plot" - _ = pcv.apply_mask(img=img, mask=mask, mask_color="black") # Test with debug = None pcv.params.debug = None masked_img = pcv.apply_mask(img=img, mask=mask, mask_color="black") @@ -1573,11 +1561,8 @@ def test_plantcv_apply_mask_hyperspectral(): img = np.ones((2056, 2454)) img_stacked = cv2.merge((img, img, img, img)) - # Test with debug = "print" - pcv.params.debug = "print" - _ = pcv.apply_mask(img=img_stacked, mask=img, mask_color="black") - # Test with debug = "plot" - pcv.params.debug = "plot" + # Test with debug = none + pcv.params.debug = None masked_array = pcv.apply_mask(img=hyper_array.array_data, mask=img, mask_color="black") assert np.mean(masked_array) == 13.97111260224949 From e3e452cada355eef797c1bf9473ddc2378ded7ee Mon Sep 17 00:00:00 2001 From: Dominik Schneider Date: Wed, 25 Aug 2021 09:19:31 -0700 Subject: [PATCH 56/63] finish crop_position_mask --- plantcv/plantcv/crop_position_mask.py | 50 ++++++++++++--------------- 1 file changed, 22 insertions(+), 28 deletions(-) diff --git a/plantcv/plantcv/crop_position_mask.py b/plantcv/plantcv/crop_position_mask.py index 25671333c..d95975982 100755 --- a/plantcv/plantcv/crop_position_mask.py +++ b/plantcv/plantcv/crop_position_mask.py @@ -4,8 +4,7 @@ import numpy as np import math import os -from plantcv.plantcv import print_image -from plantcv.plantcv import plot_image +from plantcv.plantcv._debug import _debug from plantcv.plantcv import fatal_error from plantcv.plantcv import params @@ -33,8 +32,6 @@ def crop_position_mask(img, mask, x, y, v_pos="top", h_pos="right"): :return newmask: numpy.ndarray """ - params.device += 1 - if x < 0 or y < 0: fatal_error("x and y cannot be negative numbers or non-integers") @@ -104,10 +101,9 @@ def crop_position_mask(img, mask, x, y, v_pos="top", h_pos="right"): rows1 = np.zeros((r1, my), dtype=np.uint8) rows2 = np.zeros((r2, my), dtype=np.uint8) maskv = np.vstack((rows1, maskv, rows2)) - if params.debug == 'print': - print_image(maskv, os.path.join(params.debug_outdir, str(params.device) + "_push-top.png")) - elif params.debug == 'plot': - plot_image(maskv, cmap='gray') + _debug(visual=maskv, + filename=os.path.join(params.debug_outdir, str(params.device) + "_push-top.png"), + cmap='gray') elif v_pos.upper() == "BOTTOM": # Add rows to the bottom @@ -133,10 +129,10 @@ def crop_position_mask(img, mask, x, y, v_pos="top", h_pos="right"): rows1 = np.zeros((r1, my), dtype=np.uint8) rows2 = np.zeros((r2, my), dtype=np.uint8) maskv = np.vstack((rows1, maskv, rows2)) - if params.debug == 'print': - print_image(maskv, os.path.join(params.debug_outdir, str(params.device) + "_push-bottom.png")) - elif params.debug == 'plot': - plot_image(maskv, cmap='gray') + + _debug(visual=maskv, + filename=os.path.join(params.debug_outdir, str(params.device) + "_push-bottom.png"), + cmap='gray') else: fatal_error(str(v_pos) + ' is not valid, must be "top" or "bottom"!') @@ -166,10 +162,10 @@ def crop_position_mask(img, mask, x, y, v_pos="top", h_pos="right"): col1 = np.zeros((mx, c1), dtype=np.uint8) col2 = np.zeros((mx, c2), dtype=np.uint8) maskv = np.hstack((col1, maskv, col2)) - if params.debug == 'print': - print_image(maskv, os.path.join(params.debug_outdir, str(params.device) + "_push-left.png")) - elif params.debug == 'plot': - plot_image(maskv, cmap='gray') + + _debug(visual=maskv, + filename=os.path.join(params.debug_outdir, str(params.device) + "_push-left.png"), + cmap='gray') elif h_pos.upper() == "RIGHT": @@ -197,26 +193,24 @@ def crop_position_mask(img, mask, x, y, v_pos="top", h_pos="right"): col1 = np.zeros((mx, c1), dtype=np.uint8) col2 = np.zeros((mx, c2), dtype=np.uint8) maskv = np.hstack((col1, maskv, col2)) - if params.debug == 'print': - print_image(maskv, os.path.join(params.debug_outdir, str(params.device) + "_push-right.png")) - elif params.debug == 'plot': - plot_image(maskv, cmap='gray') + + _debug(visual=maskv, + filename=os.path.join(params.debug_outdir, str(params.device) + "_push-right.png"), + cmap='gray') else: fatal_error(str(h_pos) + ' is not valid, must be "left" or "right"!') newmask = np.array(maskv) if params.debug is not None: - if params.debug == 'print': - print_image(newmask, os.path.join(params.debug_outdir, str(params.device) + "_newmask.png")) - elif params.debug == 'plot': - plot_image(newmask, cmap='gray') + _debug(visual=newmask, + filename=os.path.join(params.debug_outdir, str(params.device) + "_newmask.png"), + cmap='gray') + objects, hierarchy = cv2.findContours(np.copy(newmask), cv2.RETR_TREE, cv2.CHAIN_APPROX_NONE)[-2:] for i, cnt in enumerate(objects): cv2.drawContours(ori_img, objects, i, (255, 102, 255), -1, lineType=8, hierarchy=hierarchy) - if params.debug == 'print': - print_image(ori_img, os.path.join(params.debug_outdir, str(params.device) + '_mask_overlay.png')) - elif params.debug == 'plot': - plot_image(ori_img) + _debug(visual=ori_img, + filename=os.path.join(params.debug_outdir, str(params.device) + '_mask_overlay.png')) return newmask From 02b25d70ba4f19b9aa4f27366f4e906ee6cd4686 Mon Sep 17 00:00:00 2001 From: Dominik Schneider Date: Wed, 25 Aug 2021 09:32:11 -0700 Subject: [PATCH 57/63] naive_bayes_classifier --- plantcv/plantcv/naive_bayes_classifier.py | 17 +++++++---------- tests/tests.py | 3 --- 2 files changed, 7 insertions(+), 13 deletions(-) diff --git a/plantcv/plantcv/naive_bayes_classifier.py b/plantcv/plantcv/naive_bayes_classifier.py index 74a67b7da..5d0064e09 100644 --- a/plantcv/plantcv/naive_bayes_classifier.py +++ b/plantcv/plantcv/naive_bayes_classifier.py @@ -4,8 +4,7 @@ import cv2 import numpy as np import os -from plantcv.plantcv import print_image -from plantcv.plantcv import plot_image +from plantcv.plantcv._debug import _debug from plantcv.plantcv import fatal_error from plantcv.plantcv import params @@ -24,7 +23,6 @@ def naive_bayes_classifier(rgb_img, pdf_file): :param pdf_file: str :return masks: dict """ - params.device += 1 # Initialize PDF dictionary pdfs = {} @@ -66,7 +64,7 @@ def naive_bayes_classifier(rgb_img, pdf_file): for class_name in pdfs.keys(): # Calculate the joint probability that this is in the class px_p[class_name][i][j] = pdfs[class_name]["hue"][h[i][j]] * pdfs[class_name]["saturation"][s[i][j]] * \ - pdfs[class_name]["value"][v[i][j]] + pdfs[class_name]["value"][v[i][j]] # Initialize empty masks masks = {} @@ -82,12 +80,11 @@ def naive_bayes_classifier(rgb_img, pdf_file): masks[class_name][np.where(px_p[class_name] > background_class)] = 255 # Print or plot the mask if debug is not None - if params.debug == "print": + if params.debug is not None: for class_name, mask in masks.items(): - print_image(mask, os.path.join(params.debug_outdir, - str(params.device) + "_naive_bayes_" + class_name + "_mask.png")) - elif params.debug == "plot": - for class_name, mask in masks.items(): - plot_image(mask, cmap="gray") + _debug(visual=mask, + filename=os.path.join(params.debug_outdir, str(params.device) + + "_naive_bayes_" + class_name + "_mask.png"), + cmap='gray') return masks diff --git a/tests/tests.py b/tests/tests.py index a5af25428..bfb170ac1 100755 --- a/tests/tests.py +++ b/tests/tests.py @@ -2393,9 +2393,6 @@ def test_plantcv_naive_bayes_classifier(): pcv.params.debug_outdir = cache_dir # Read in test data img = cv2.imread(os.path.join(TEST_DATA, TEST_INPUT_COLOR)) - # Test with debug = "print" - pcv.params.debug = "print" - _ = pcv.naive_bayes_classifier(rgb_img=img, pdf_file=os.path.join(TEST_DATA, TEST_PDFS)) # Test with debug = "plot" pcv.params.debug = "plot" _ = pcv.naive_bayes_classifier(rgb_img=img, pdf_file=os.path.join(TEST_DATA, TEST_PDFS)) From 294514eac91bb7bfbe2c6acb466efe0419271db0 Mon Sep 17 00:00:00 2001 From: Dominik Schneider Date: Wed, 25 Aug 2021 09:38:23 -0700 Subject: [PATCH 58/63] roi_methods --- plantcv/plantcv/roi/roi_methods.py | 26 ++++---------------------- 1 file changed, 4 insertions(+), 22 deletions(-) diff --git a/plantcv/plantcv/roi/roi_methods.py b/plantcv/plantcv/roi/roi_methods.py index e18327a63..5326c809a 100644 --- a/plantcv/plantcv/roi/roi_methods.py +++ b/plantcv/plantcv/roi/roi_methods.py @@ -3,8 +3,7 @@ import os import cv2 import numpy as np -from plantcv.plantcv import print_image -from plantcv.plantcv import plot_image +from plantcv.plantcv._debug import _debug from plantcv.plantcv import fatal_error from plantcv.plantcv import params @@ -26,8 +25,6 @@ def from_binary_image(img, bin_img): :return roi_contour: list :return roi_hierarchy: numpy.ndarray """ - # Autoincrement the device counter - params.device += 1 # Make sure the input bin_img is binary if len(np.unique(bin_img)) != 2: fatal_error("Input image is not binary!") @@ -63,8 +60,6 @@ def rectangle(img, x, y, h, w): :return roi_contour: list :return roi_hierarchy: numpy.ndarray """ - # Autoincrement the device counter - params.device += 1 # Get the height and width of the reference image height, width = np.shape(img)[:2] @@ -111,8 +106,6 @@ def circle(img, x, y, r): :return roi_contour: list :return roi_hierarchy: numpy.ndarray """ - # Autoincrement the device counter - params.device += 1 # Get the height and width of the reference image height, width = np.shape(img)[:2] @@ -161,8 +154,6 @@ def ellipse(img, x, y, r1, r2, angle): :return roi_contour: list :return roi_hierarchy: numpy.ndarray """ - # Autoincrement the device counter - params.device += 1 # Get the height and width of the reference image height, width = np.shape(img)[:2] @@ -201,12 +192,8 @@ def _draw_roi(img, roi_contour): ref_img = cv2.cvtColor(ref_img, cv2.COLOR_GRAY2BGR) # Draw the contour on the reference image cv2.drawContours(ref_img, roi_contour, -1, (255, 0, 0), params.line_thickness) - if params.debug == "print": - # If debug is print, save the image to a file - print_image(ref_img, os.path.join(params.debug_outdir, str(params.device) + "_roi.png")) - elif params.debug == "plot": - # If debug is plot, print to the plotting device - plot_image(ref_img) + _debug(visual=ref_img, + filename=os.path.join(params.debug_outdir, str(params.device) + "_roi.png")) def multi(img, coord, radius, spacing=None, nrows=None, ncols=None): @@ -234,9 +221,6 @@ def multi(img, coord, radius, spacing=None, nrows=None, ncols=None): :return mask: numpy.ndarray """ - # Autoincrement the device counter - params.device += 1 - # Store user debug debug = params.debug @@ -341,9 +325,7 @@ def custom(img, vertices): :param vertices: list :return roi_contour: list :return roi_hierarchy: numpy.ndarray - """ - # Autoincrement the device counter - params.device += 1 + """ # Get the height and width of the reference image height, width = np.shape(img)[:2] From 801c7ef9a7a5e845ad8a4d336a747e6929c30609 Mon Sep 17 00:00:00 2001 From: Dominik Schneider Date: Wed, 25 Aug 2021 09:40:30 -0700 Subject: [PATCH 59/63] roi2mask --- plantcv/plantcv/roi/roi2mask.py | 14 ++++++-------- tests/tests.py | 4 +--- 2 files changed, 7 insertions(+), 11 deletions(-) diff --git a/plantcv/plantcv/roi/roi2mask.py b/plantcv/plantcv/roi/roi2mask.py index c923ae07e..50868c96f 100644 --- a/plantcv/plantcv/roi/roi2mask.py +++ b/plantcv/plantcv/roi/roi2mask.py @@ -4,12 +4,12 @@ import cv2 import numpy as np from plantcv.plantcv import params -from plantcv.plantcv import plot_image -from plantcv.plantcv import print_image +from plantcv.plantcv._debug import _debug def roi2mask(img, contour): - """Create a binary mask from an ROI contour + """ + Create a binary mask from an ROI contour Inputs: img = RGB or grayscale image data contour = An ROI set of points (contour) @@ -21,7 +21,6 @@ def roi2mask(img, contour): :param contour: list :return mask: numpy.ndarray """ - params.device += 1 # create a blank image of same size shape_info = np.shape(img) @@ -29,9 +28,8 @@ def roi2mask(img, contour): mask = cv2.drawContours(bnk, contour, 0, 255, -1) - if params.debug == 'print': - print_image(mask, os.path.join(params.debug_outdir, str(params.device) + '_roi_mask.png')) - elif params.debug == 'plot': - plot_image(mask, cmap="gray") + _debug(visual=mask, + filename=os.path.join(params.debug_outdir, str(params.device) + '_roi_mask.png'), + cmap='gray') return mask diff --git a/tests/tests.py b/tests/tests.py index bfb170ac1..51430ac27 100755 --- a/tests/tests.py +++ b/tests/tests.py @@ -2906,9 +2906,7 @@ def test_plantcv_roi2mask(): img = cv2.imread(os.path.join(TEST_DATA, TEST_VIS_SMALL)) contours_npz = np.load(os.path.join(TEST_DATA, TEST_VIS_COMP_CONTOUR), encoding="latin1") obj_contour = contours_npz['arr_0'] - pcv.params.debug = "plot" - _ = pcv.roi.roi2mask(img=img, contour=obj_contour) - pcv.params.debug = "print" + pcv.params.debug = None mask = pcv.roi.roi2mask(img=img, contour=obj_contour) assert np.shape(mask)[0:2] == np.shape(img)[0:2] and np.sum(mask) == 255 From a820f085c6842e2afcd1860d5e9b980fdee26fb8 Mon Sep 17 00:00:00 2001 From: Noah Fahlgren Date: Wed, 15 Sep 2021 12:36:09 -0500 Subject: [PATCH 60/63] Remove device counter --- plantcv/plantcv/background_subtraction.py | 1 - 1 file changed, 1 deletion(-) diff --git a/plantcv/plantcv/background_subtraction.py b/plantcv/plantcv/background_subtraction.py index 72c0c3946..6454bfd3a 100644 --- a/plantcv/plantcv/background_subtraction.py +++ b/plantcv/plantcv/background_subtraction.py @@ -31,7 +31,6 @@ def background_subtraction(background_image, foreground_image): :param foreground_image: numpy.ndarray :return fgmask: numpy.ndarray """ - params.device += 1 # Copying images to make sure not alter originals bg_img = np.copy(background_image) fg_img = np.copy(foreground_image) From b95503ccf8edeb0eede1c3f82189ee0905318c25 Mon Sep 17 00:00:00 2001 From: Noah Fahlgren Date: Wed, 15 Sep 2021 12:41:00 -0500 Subject: [PATCH 61/63] Move docstring title to newline --- plantcv/plantcv/find_objects.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/plantcv/plantcv/find_objects.py b/plantcv/plantcv/find_objects.py index ecd6556a5..f8ef4a7db 100755 --- a/plantcv/plantcv/find_objects.py +++ b/plantcv/plantcv/find_objects.py @@ -8,7 +8,8 @@ def find_objects(img, mask): - """Find all objects and color them blue. + """ + Find all objects and color them blue. Inputs: img = RGB or grayscale image data for plotting From 79eb566ce5c0537f8dff196146a48b304251e346 Mon Sep 17 00:00:00 2001 From: Noah Fahlgren Date: Wed, 15 Sep 2021 12:45:13 -0500 Subject: [PATCH 62/63] Move docstring titles to newlines --- plantcv/plantcv/invert.py | 3 ++- plantcv/plantcv/laplace_filter.py | 7 ++++--- plantcv/plantcv/logical_and.py | 3 ++- plantcv/plantcv/logical_or.py | 3 ++- plantcv/plantcv/median_blur.py | 3 ++- 5 files changed, 12 insertions(+), 7 deletions(-) diff --git a/plantcv/plantcv/invert.py b/plantcv/plantcv/invert.py index d4df46014..2b2cb8ac9 100755 --- a/plantcv/plantcv/invert.py +++ b/plantcv/plantcv/invert.py @@ -7,7 +7,8 @@ def invert(gray_img): - """Inverts grayscale images. + """ + Inverts grayscale images. Inputs: gray_img = Grayscale image data diff --git a/plantcv/plantcv/laplace_filter.py b/plantcv/plantcv/laplace_filter.py index 77ee69632..4245eb808 100755 --- a/plantcv/plantcv/laplace_filter.py +++ b/plantcv/plantcv/laplace_filter.py @@ -7,9 +7,10 @@ def laplace_filter(gray_img, ksize, scale): - """This is a filtering method used to identify and highlight fine edges based on the 2nd derivative. A very - sensetive method to highlight edges but will also amplify background noise. ddepth = -1 specifies that the - dimensions of output image will be the same as the input image. + """ + This is a filtering method used to identify and highlight fine edges based on the 2nd derivative. A very + sensetive method to highlight edges but will also amplify background noise. ddepth = -1 specifies that the + dimensions of output image will be the same as the input image. Inputs: gray_img = Grayscale image data diff --git a/plantcv/plantcv/logical_and.py b/plantcv/plantcv/logical_and.py index c40c2b429..27706c072 100755 --- a/plantcv/plantcv/logical_and.py +++ b/plantcv/plantcv/logical_and.py @@ -7,7 +7,8 @@ def logical_and(bin_img1, bin_img2): - """Join two images using the bitwise AND operator. + """ + Join two images using the bitwise AND operator. Inputs: bin_img1 = Binary image data to be compared to bin_img2 diff --git a/plantcv/plantcv/logical_or.py b/plantcv/plantcv/logical_or.py index c883c1d47..b1ac7e09a 100755 --- a/plantcv/plantcv/logical_or.py +++ b/plantcv/plantcv/logical_or.py @@ -7,7 +7,8 @@ def logical_or(bin_img1, bin_img2): - """Join two images using the bitwise OR operator. + """ + Join two images using the bitwise OR operator. Inputs: bin_img1 = Binary image data to be compared to bin_img2 diff --git a/plantcv/plantcv/median_blur.py b/plantcv/plantcv/median_blur.py index ff2b467a4..697f9dafd 100755 --- a/plantcv/plantcv/median_blur.py +++ b/plantcv/plantcv/median_blur.py @@ -8,7 +8,8 @@ def median_blur(gray_img, ksize): - """Applies a median blur filter (applies median value to central pixel within a kernel size). + """ + Applies a median blur filter (applies median value to central pixel within a kernel size). Inputs: gray_img = Grayscale image data From b25234de87d300173a5c54e420abb0992ed1c348 Mon Sep 17 00:00:00 2001 From: Noah Fahlgren Date: Wed, 15 Sep 2021 12:58:02 -0500 Subject: [PATCH 63/63] Move docstring titles to newline --- plantcv/plantcv/naive_bayes_classifier.py | 3 ++- plantcv/plantcv/object_composition.py | 3 ++- plantcv/plantcv/readbayer.py | 3 ++- plantcv/plantcv/report_size_marker_area.py | 3 ++- plantcv/plantcv/roi/roi_methods.py | 21 ++++++++++++++------- plantcv/plantcv/roi_objects.py | 3 ++- plantcv/plantcv/scharr_filter.py | 9 +++++---- plantcv/plantcv/shift_img.py | 3 ++- 8 files changed, 31 insertions(+), 17 deletions(-) diff --git a/plantcv/plantcv/naive_bayes_classifier.py b/plantcv/plantcv/naive_bayes_classifier.py index 5d0064e09..68082cf68 100644 --- a/plantcv/plantcv/naive_bayes_classifier.py +++ b/plantcv/plantcv/naive_bayes_classifier.py @@ -10,7 +10,8 @@ def naive_bayes_classifier(rgb_img, pdf_file): - """Use the Naive Bayes classifier to output a plant binary mask. + """ + Use the Naive Bayes classifier to output a plant binary mask. Inputs: rgb_img = RGB image data diff --git a/plantcv/plantcv/object_composition.py b/plantcv/plantcv/object_composition.py index 585d4a26a..7ff147af8 100755 --- a/plantcv/plantcv/object_composition.py +++ b/plantcv/plantcv/object_composition.py @@ -8,7 +8,8 @@ def object_composition(img, contours, hierarchy): - """Groups objects into a single object, usually done after object filtering. + """ + Groups objects into a single object, usually done after object filtering. Inputs: img = RGB or grayscale image data for plotting diff --git a/plantcv/plantcv/readbayer.py b/plantcv/plantcv/readbayer.py index 68e720907..8315012e3 100644 --- a/plantcv/plantcv/readbayer.py +++ b/plantcv/plantcv/readbayer.py @@ -8,7 +8,8 @@ def readbayer(filename, bayerpattern='BG', alg='default'): - """Read image from file that has a Bayer mosaic. + """ + Read image from file that has a Bayer mosaic. Inputs: filename = name of image file diff --git a/plantcv/plantcv/report_size_marker_area.py b/plantcv/plantcv/report_size_marker_area.py index fe83456eb..b10802510 100755 --- a/plantcv/plantcv/report_size_marker_area.py +++ b/plantcv/plantcv/report_size_marker_area.py @@ -17,7 +17,8 @@ def report_size_marker_area(img, roi_contour, roi_hierarchy, marker='define', objcolor='dark', thresh_channel=None, thresh=None, label="default"): - """Detects a size marker in a specified region and reports its size and eccentricity + """ + Detects a size marker in a specified region and reports its size and eccentricity Inputs: img = An RGB or grayscale image to plot the marker object on diff --git a/plantcv/plantcv/roi/roi_methods.py b/plantcv/plantcv/roi/roi_methods.py index 5326c809a..76a91d098 100644 --- a/plantcv/plantcv/roi/roi_methods.py +++ b/plantcv/plantcv/roi/roi_methods.py @@ -10,7 +10,8 @@ # Create an ROI from a binary mask def from_binary_image(img, bin_img): - """Create an ROI from a binary image + """ + Create an ROI from a binary image Inputs: img = An RGB or grayscale image to plot the ROI on. @@ -39,7 +40,8 @@ def from_binary_image(img, bin_img): # Create a rectangular ROI def rectangle(img, x, y, h, w): - """Create a rectangular ROI. + """ + Create a rectangular ROI. Inputs: img = An RGB or grayscale image to plot the ROI on in debug mode. @@ -87,7 +89,8 @@ def rectangle(img, x, y, h, w): # Create a circular ROI def circle(img, x, y, r): - """Create a circular ROI. + """ + Create a circular ROI. Inputs: img = An RGB or grayscale image to plot the ROI on in debug mode. @@ -131,7 +134,8 @@ def circle(img, x, y, r): # Create an elliptical ROI def ellipse(img, x, y, r1, r2, angle): - """Create an elliptical ROI. + """ + Create an elliptical ROI. Inputs: img = An RGB or grayscale image to plot the ROI on in debug mode. @@ -180,7 +184,8 @@ def ellipse(img, x, y, r1, r2, angle): # Draw the ROI on a reference image def _draw_roi(img, roi_contour): - """Draw an ROI + """ + Draw an ROI :param img: numpy.ndarray :param roi_contour: list @@ -197,7 +202,8 @@ def _draw_roi(img, roi_contour): def multi(img, coord, radius, spacing=None, nrows=None, ncols=None): - """Create multiple circular ROIs on a single image + """ + Create multiple circular ROIs on a single image Inputs img = Input image data. coord = Two-element tuple of the center of the top left object (x,y) or a list of tuples identifying @@ -311,7 +317,8 @@ def multi(img, coord, radius, spacing=None, nrows=None, ncols=None): def custom(img, vertices): - """Create an custom polygon ROI. + """ + Create an custom polygon ROI. Inputs: img = An RGB or grayscale image to plot the ROI on in debug mode. diff --git a/plantcv/plantcv/roi_objects.py b/plantcv/plantcv/roi_objects.py index 92973e001..3d24e6431 100755 --- a/plantcv/plantcv/roi_objects.py +++ b/plantcv/plantcv/roi_objects.py @@ -10,7 +10,8 @@ def roi_objects(img, roi_contour, roi_hierarchy, object_contour, obj_hierarchy, roi_type="partial"): - """Find objects partially inside a region of interest or cut objects to the ROI. + """ + Find objects partially inside a region of interest or cut objects to the ROI. Inputs: img = RGB or grayscale image data for plotting diff --git a/plantcv/plantcv/scharr_filter.py b/plantcv/plantcv/scharr_filter.py index f0f095de9..aa6577e0a 100755 --- a/plantcv/plantcv/scharr_filter.py +++ b/plantcv/plantcv/scharr_filter.py @@ -7,10 +7,11 @@ def scharr_filter(img, dx, dy, scale): - """This is a filtering method used to identify and highlight gradient edges/features using the 1st derivative. - Typically used to identify gradients along the x-axis (dx = 1, dy = 0) and y-axis (dx = 0, dy = 1) independently. - Performance is quite similar to Sobel filter. Used to detect edges / changes in pixel intensity. ddepth = -1 - specifies that the dimensions of output image will be the same as the input image. + """ + This is a filtering method used to identify and highlight gradient edges/features using the 1st derivative. + Typically used to identify gradients along the x-axis (dx = 1, dy = 0) and y-axis (dx = 0, dy = 1) independently. + Performance is quite similar to Sobel filter. Used to detect edges / changes in pixel intensity. ddepth = -1 + specifies that the dimensions of output image will be the same as the input image. Inputs: gray_img = grayscale image data diff --git a/plantcv/plantcv/shift_img.py b/plantcv/plantcv/shift_img.py index 0b6b3777c..d24c46c33 100755 --- a/plantcv/plantcv/shift_img.py +++ b/plantcv/plantcv/shift_img.py @@ -8,7 +8,8 @@ def shift_img(img, number, side="right"): - """this function allows you to shift an image over without changing dimensions + """ + This function allows you to shift an image over without changing dimensions Inputs: img = RGB or grayscale image data