From 53f84a1f32cdfecd91d6766c614a4f90bacc4756 Mon Sep 17 00:00:00 2001 From: HaleySchuhl Date: Tue, 5 Jan 2021 13:15:52 -0600 Subject: [PATCH 001/137] add label param to analysis functions in hyperpsectral sub --- plantcv/plantcv/hyperspectral/analyze_index.py | 5 ++++- plantcv/plantcv/hyperspectral/analyze_spectral.py | 4 +++- 2 files changed, 7 insertions(+), 2 deletions(-) diff --git a/plantcv/plantcv/hyperspectral/analyze_index.py b/plantcv/plantcv/hyperspectral/analyze_index.py index b77a858d3..1bfcb48af 100644 --- a/plantcv/plantcv/hyperspectral/analyze_index.py +++ b/plantcv/plantcv/hyperspectral/analyze_index.py @@ -12,7 +12,7 @@ from plotnine import ggplot, aes, geom_line, scale_x_continuous -def analyze_index(index_array, mask, histplot=False, bins=100, min_bin=0, max_bin=1): +def analyze_index(index_array, mask, histplot=False, bins=100, min_bin=0, max_bin=1, label=None): """This extracts the hyperspectral index statistics and writes the values as observations out to the Outputs class. @@ -23,6 +23,8 @@ def analyze_index(index_array, mask, histplot=False, bins=100, min_bin=0, max_bi bins = optional, number of classes to divide spectrum into min_bin = optional, minimum bin value ("auto" or user input minimum value) max_bin = optional, maximum bin value ("auto" or user input maximum value) + label = optional label parameter, modifies the variable name of observations recorded + :param index_array: __main__.Spectral_data @@ -31,6 +33,7 @@ def analyze_index(index_array, mask, histplot=False, bins=100, min_bin=0, max_bi :param bins: int :param max_bin: float, str :param min_bin: float, str + :param label: str :return analysis_image: ggplot, None """ params.device += 1 diff --git a/plantcv/plantcv/hyperspectral/analyze_spectral.py b/plantcv/plantcv/hyperspectral/analyze_spectral.py index 3470a21ec..3d5bca6ac 100644 --- a/plantcv/plantcv/hyperspectral/analyze_spectral.py +++ b/plantcv/plantcv/hyperspectral/analyze_spectral.py @@ -8,7 +8,7 @@ from plotnine import ggplot, aes, geom_line, scale_x_continuous -def analyze_spectral(array, mask, histplot=True): +def analyze_spectral(array, mask, histplot=True, label=None): """This extracts the hyperspectral reflectance values of each pixel writes the values out to a file. It can also print out a histogram plot of pixel intensity and a pseudocolor image of the plant. @@ -17,6 +17,7 @@ def analyze_spectral(array, mask, histplot=True): array = Hyperspectral data instance mask = Binary mask made from selected contours histplot = if True plots histogram of reflectance intensity values + label = optional label parameter, modifies the variable name of observations recorded Returns: analysis_img = output image @@ -24,6 +25,7 @@ def analyze_spectral(array, mask, histplot=True): :param array: __main__.Spectral_data :param mask: numpy array :param histplot: bool + :param label: str :return analysis_img: ggplot """ params.device += 1 From 621998e67adfe63181893a567524ef733c5246ff Mon Sep 17 00:00:00 2001 From: HaleySchuhl Date: Thu, 7 Jan 2021 10:21:08 -0600 Subject: [PATCH 002/137] update hyperspectral analysis doc pages --- docs/analyze_index.md | 7 ++++--- docs/analyze_spectral.md | 3 ++- 2 files changed, 6 insertions(+), 4 deletions(-) diff --git a/docs/analyze_index.md b/docs/analyze_index.md index 9312712b2..e31d489f6 100644 --- a/docs/analyze_index.md +++ b/docs/analyze_index.md @@ -3,7 +3,7 @@ This function calculates the spectral index statistics and writes the values as observations out to the [Outputs class](outputs.md). -**plantcv.hyperspectral.analyze_index**(*index_array, mask, histplot=False, bins=100, min_bin=0, max_bin=1*) +**plantcv.hyperspectral.analyze_index**(*index_array, mask, histplot=False, bins=100, min_bin=0, max_bin=1, label=None*) **returns** None @@ -14,7 +14,8 @@ This function calculates the spectral index statistics and writes the values as - bins - Optional, number of classes to divide spectrum into (default bins=100) - min_bin - Optional, minimum bin label. Default of 0 will be used for the smallest bin label while calculating pixel frequency data unless otherwise defined. `min_bin="auto"` will set minimum bin to the smallest observed pixel value within the masked index provided. - - max_bin - Optional, maximum bin label. Default of 1 will be used for the maximum bin label unless otherwise defined. `max_bin="auto"` will set maximum bin to the largest observed pixel value within the masked index provided. + - max_bin - Optional, maximum bin label. Default of 1 will be used for the maximum bin label unless otherwise defined. `max_bin="auto"` will set maximum bin to the largest observed pixel value within the masked index provided. + - label - Optional label parameter, modifies the variable name of observations recorded - **Context:** - Calculates data about mean, median, and standard deviation of an input index within a masked region. @@ -30,7 +31,7 @@ This function calculates the spectral index statistics and writes the values as from plantcv import plantcv as pcv -pcv.hyperspectral.analyze_index(index_array=ndvi_index, mask=leaf_mask, histplot=True, bins=100, min_bin=0, max_bin="auto") +pcv.hyperspectral.analyze_index(index_array=ndvi_index, mask=leaf_mask, histplot=True, bins=100, min_bin=0, max_bin="auto", label=None) ``` diff --git a/docs/analyze_spectral.md b/docs/analyze_spectral.md index 93bddbf90..1044b12ca 100644 --- a/docs/analyze_spectral.md +++ b/docs/analyze_spectral.md @@ -11,6 +11,7 @@ the values out as observations to get saved out. Can also print out a histogram - array - A hyperspectral datacube object, an instance of the `Spectral_data` class (read in with [pcv.readimage](read_image.md) with `mode='envi'`) - mask - Binary mask made from selected contours - histplot - If True plots histogram of reflectance intensity values (default histplot = False) + - label - Optional label parameter, modifies the variable name of observations recorded. (default `label=None`) - **Example use:** - Below - **Output data stored:** Data ('max_reflectance', 'min_reflectance', 'median_reflectance', 'spectral_std', 'spectral_frequencies', 'global_mean_reflectance', 'global_median_reflectance', 'global_spectral_std') automatically gets stored to the @@ -27,7 +28,7 @@ from plantcv import plantcv as pcv pcv.params.debug = "print" # Calculates reflectance frequencies and writes the values as observations. Also provides a histogram of this data -spectral_hist = pcv.hyperspectral.analyze_spectral(array=spectral_data, mask=mask, histplot=True) +spectral_hist = pcv.hyperspectral.analyze_spectral(array=spectral_data, mask=mask, histplot=True, label=None) # Access data stored reflectance_range = max(pcv.outputs.observations['max_reflectance']['value']) - min(pcv.outputs.observations['min_reflectance']['value']) From 82acbf0628455df71fcdc8d4ab89567004db08d4 Mon Sep 17 00:00:00 2001 From: HaleySchuhl Date: Thu, 7 Jan 2021 15:58:32 -0600 Subject: [PATCH 003/137] add code to add prefix to data variable name --- .../plantcv/hyperspectral/analyze_index.py | 15 ++++++++----- .../plantcv/hyperspectral/analyze_spectral.py | 21 ++++++++++++------- 2 files changed, 23 insertions(+), 13 deletions(-) diff --git a/plantcv/plantcv/hyperspectral/analyze_index.py b/plantcv/plantcv/hyperspectral/analyze_index.py index 1bfcb48af..3de7193c1 100644 --- a/plantcv/plantcv/hyperspectral/analyze_index.py +++ b/plantcv/plantcv/hyperspectral/analyze_index.py @@ -107,22 +107,27 @@ def analyze_index(index_array, mask, histplot=False, bins=100, min_bin=0, max_bi elif params.debug == 'plot': print(fig_hist) - outputs.add_observation(variable='mean_' + index_array.array_type, + if label == None: + prefix="" + else: + prefix=label + + outputs.add_observation(variable=prefix + 'mean_' + index_array.array_type, trait='Average ' + index_array.array_type + ' reflectance', method='plantcv.plantcv.hyperspectral.analyze_index', scale='reflectance', datatype=float, value=float(index_mean), label='none') - outputs.add_observation(variable='med_' + index_array.array_type, + outputs.add_observation(variable=prefix + 'med_' + index_array.array_type, trait='Median ' + index_array.array_type + ' reflectance', method='plantcv.plantcv.hyperspectral.analyze_index', scale='reflectance', datatype=float, value=float(index_median), label='none') - outputs.add_observation(variable='std_' + index_array.array_type, + outputs.add_observation(variable=prefix + 'std_' + index_array.array_type, trait='Standard deviation ' + index_array.array_type + ' reflectance', method='plantcv.plantcv.hyperspectral.analyze_index', scale='reflectance', datatype=float, value=float(index_std), label='none') - outputs.add_observation(variable='index_frequencies_' + index_array.array_type, trait='index frequencies', + outputs.add_observation(variable=prefix + 'index_frequencies_' + index_array.array_type, trait='index frequencies', method='plantcv.plantcv.analyze_index', scale='frequency', datatype=list, value=hist_percent, label=bin_labels) @@ -130,7 +135,7 @@ def analyze_index(index_array, mask, histplot=False, bins=100, min_bin=0, max_bi plot_image(masked_array) elif params.debug == "print": print_image(img=masked_array, filename=os.path.join(params.debug_outdir, str(params.device) + - index_array.array_type + ".png")) + index_array.array_type + prefix + ".png")) # Store images outputs.images.append(analysis_image) diff --git a/plantcv/plantcv/hyperspectral/analyze_spectral.py b/plantcv/plantcv/hyperspectral/analyze_spectral.py index 3d5bca6ac..68b5c4d91 100644 --- a/plantcv/plantcv/hyperspectral/analyze_spectral.py +++ b/plantcv/plantcv/hyperspectral/analyze_spectral.py @@ -69,29 +69,34 @@ def analyze_spectral(array, mask, histplot=True, label=None): for i in array.wavelength_dict.keys(): wavelength_labels.append(i) + if label == None: + prefix="" + else: + prefix=label + # Store data into outputs class - outputs.add_observation(variable='global_mean_reflectance', trait='global mean reflectance', + outputs.add_observation(variable=prefix + 'global_mean_reflectance', trait='global mean reflectance', method='plantcv.plantcv.hyperspectral.analyze_spectral', scale='reflectance', datatype=float, value=float(avg_reflectance), label='reflectance') - outputs.add_observation(variable='global_median_reflectance', trait='global median reflectance', + outputs.add_observation(variable=prefix + 'global_median_reflectance', trait='global median reflectance', method='plantcv.plantcv.hyperspectral.analyze_spectral', scale='reflectance', datatype=float, value=float(median_reflectance), label='reflectance') - outputs.add_observation(variable='global_spectral_std', trait='pixel-wise standard deviation per band', + outputs.add_observation(variable=prefix + 'global_spectral_std', trait='pixel-wise standard deviation per band', method='plantcv.plantcv.hyperspectral.analyze_spectral', scale='None', datatype=float, value=float(std_reflectance), label='reflectance') - outputs.add_observation(variable='global_spectral_std', trait='pixel-wise standard deviation ', + outputs.add_observation(variable=prefix + 'global_spectral_std', trait='pixel-wise standard deviation ', method='plantcv.plantcv.hyperspectral.analyze_spectral', scale='None', datatype=float, value=float(std_reflectance), label='reflectance') - outputs.add_observation(variable='max_reflectance', trait='maximum reflectance per band', + outputs.add_observation(variable=prefix + 'max_reflectance', trait='maximum reflectance per band', method='plantcv.plantcv.hyperspectral.analyze_spectral', scale='reflectance', datatype=list, value=new_max_per_band, label=wavelength_labels) - outputs.add_observation(variable='min_reflectance', trait='minimum reflectance per band', + outputs.add_observation(variable=prefix + 'min_reflectance', trait='minimum reflectance per band', method='plantcv.plantcv.hyperspectral.analyze_spectral', scale='reflectance', datatype=list, value=new_min_per_band, label=wavelength_labels) - outputs.add_observation(variable='spectral_std', trait='pixel-wise standard deviation per band', + outputs.add_observation(variable=prefix + 'spectral_std', trait='pixel-wise standard deviation per band', method='plantcv.plantcv.hyperspectral.analyze_spectral', scale='None', datatype=list, value=new_std_per_band, label=wavelength_labels) - outputs.add_observation(variable='spectral_frequencies', trait='spectral frequencies', + outputs.add_observation(variable=prefix + 'spectral_frequencies', trait='spectral frequencies', method='plantcv.plantcv.hyperspectral.analyze_spectral', scale='frequency', datatype=list, value=new_freq, label=wavelength_labels) From 50d1d4723c63ef56ba6bd4f3e7e78c048b89fd09 Mon Sep 17 00:00:00 2001 From: HaleySchuhl Date: Fri, 8 Jan 2021 11:37:54 -0600 Subject: [PATCH 004/137] Update tests.py add onto testing to cover new lines of code --- tests/tests.py | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/tests/tests.py b/tests/tests.py index c1e6ad831..70a4af797 100755 --- a/tests/tests.py +++ b/tests/tests.py @@ -4547,10 +4547,10 @@ def test_plantcv_hyperspectral_analyze_spectral(): mask = cv2.imread(os.path.join(HYPERSPECTRAL_TEST_DATA, HYPERSPECTRAL_MASK), -1) array_data = pcv.hyperspectral.read_data(filename=spectral_filename) pcv.params.debug = "plot" - _ = pcv.hyperspectral.analyze_spectral(array=array_data, mask=mask, histplot=True) + _ = pcv.hyperspectral.analyze_spectral(array=array_data, mask=mask, histplot=True, label=None) pcv.params.debug = "print" - _ = pcv.hyperspectral.analyze_spectral(array=array_data, mask=mask, histplot=True) - assert len(pcv.outputs.observations['spectral_frequencies']['value']) == 978 + _ = pcv.hyperspectral.analyze_spectral(array=array_data, mask=mask, histplot=True, label="prefix") + assert len(pcv.outputs.observations['prefix_spectral_frequencies']['value']) == 978 def test_plantcv_hyperspectral_analyze_index(): @@ -4604,7 +4604,7 @@ def test_plantcv_hyperspectral_analyze_index_outside_range_warning(): mask_img = np.ones(np.shape(index_array.array_data), dtype=np.uint8) * 255 f = io.StringIO() with redirect_stdout(f): - pcv.hyperspectral.analyze_index(index_array=index_array, mask=mask_img, min_bin=.5, max_bin=.55) + pcv.hyperspectral.analyze_index(index_array=index_array, mask=mask_img, min_bin=.5, max_bin=.55, label="i") out = f.getvalue() # assert os.listdir(cache_dir) is 0 assert out[0:10] == 'WARNING!!!' From ae0c4210f5b7d342b15ff53ac0de49c9ea99bb2a Mon Sep 17 00:00:00 2001 From: HaleySchuhl Date: Fri, 8 Jan 2021 11:58:37 -0600 Subject: [PATCH 005/137] Update analyze_spectral.py --- plantcv/plantcv/hyperspectral/analyze_spectral.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/plantcv/plantcv/hyperspectral/analyze_spectral.py b/plantcv/plantcv/hyperspectral/analyze_spectral.py index 68b5c4d91..01693efb7 100644 --- a/plantcv/plantcv/hyperspectral/analyze_spectral.py +++ b/plantcv/plantcv/hyperspectral/analyze_spectral.py @@ -72,7 +72,7 @@ def analyze_spectral(array, mask, histplot=True, label=None): if label == None: prefix="" else: - prefix=label + prefix=label + "_" # Store data into outputs class outputs.add_observation(variable=prefix + 'global_mean_reflectance', trait='global mean reflectance', From 988c0e9df6375d1ed93551d30cf28517d8be6eb8 Mon Sep 17 00:00:00 2001 From: HaleySchuhl Date: Fri, 8 Jan 2021 11:58:47 -0600 Subject: [PATCH 006/137] Update analyze_index.py --- plantcv/plantcv/hyperspectral/analyze_index.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/plantcv/plantcv/hyperspectral/analyze_index.py b/plantcv/plantcv/hyperspectral/analyze_index.py index 3de7193c1..56dcd0193 100644 --- a/plantcv/plantcv/hyperspectral/analyze_index.py +++ b/plantcv/plantcv/hyperspectral/analyze_index.py @@ -110,7 +110,7 @@ def analyze_index(index_array, mask, histplot=False, bins=100, min_bin=0, max_bi if label == None: prefix="" else: - prefix=label + prefix=label + "_" outputs.add_observation(variable=prefix + 'mean_' + index_array.array_type, trait='Average ' + index_array.array_type + ' reflectance', From f47ec5c9d5cd4818d806ccbd4a4b15518b86b546 Mon Sep 17 00:00:00 2001 From: HaleySchuhl Date: Fri, 8 Jan 2021 13:57:49 -0600 Subject: [PATCH 007/137] start adding label param to morphology functions --- plantcv/plantcv/hyperspectral/analyze_index.py | 4 ++-- .../plantcv/hyperspectral/analyze_spectral.py | 4 ++-- plantcv/plantcv/morphology/analyze_stem.py | 16 ++++++++++++---- plantcv/plantcv/morphology/check_cycles.py | 13 ++++++++++--- plantcv/plantcv/morphology/fill_segments.py | 2 +- plantcv/plantcv/morphology/find_branch_pts.py | 9 ++++++++- plantcv/plantcv/morphology/find_tips.py | 10 +++++++++- 7 files changed, 44 insertions(+), 14 deletions(-) diff --git a/plantcv/plantcv/hyperspectral/analyze_index.py b/plantcv/plantcv/hyperspectral/analyze_index.py index 56dcd0193..f09ff6a6c 100644 --- a/plantcv/plantcv/hyperspectral/analyze_index.py +++ b/plantcv/plantcv/hyperspectral/analyze_index.py @@ -108,9 +108,9 @@ def analyze_index(index_array, mask, histplot=False, bins=100, min_bin=0, max_bi print(fig_hist) if label == None: - prefix="" + prefix = "" else: - prefix=label + "_" + prefix = label + "_" outputs.add_observation(variable=prefix + 'mean_' + index_array.array_type, trait='Average ' + index_array.array_type + ' reflectance', diff --git a/plantcv/plantcv/hyperspectral/analyze_spectral.py b/plantcv/plantcv/hyperspectral/analyze_spectral.py index 01693efb7..22c7cb81f 100644 --- a/plantcv/plantcv/hyperspectral/analyze_spectral.py +++ b/plantcv/plantcv/hyperspectral/analyze_spectral.py @@ -70,9 +70,9 @@ def analyze_spectral(array, mask, histplot=True, label=None): wavelength_labels.append(i) if label == None: - prefix="" + prefix = "" else: - prefix=label + "_" + prefix = label + "_" # Store data into outputs class outputs.add_observation(variable=prefix + 'global_mean_reflectance', trait='global mean reflectance', diff --git a/plantcv/plantcv/morphology/analyze_stem.py b/plantcv/plantcv/morphology/analyze_stem.py index 4d0c66b02..02717fa6c 100644 --- a/plantcv/plantcv/morphology/analyze_stem.py +++ b/plantcv/plantcv/morphology/analyze_stem.py @@ -9,12 +9,13 @@ from plantcv.plantcv import print_image -def analyze_stem(rgb_img, stem_objects): +def analyze_stem(rgb_img, stem_objects, label=None): """ Calculate angle of segments (in degrees) by fitting a linear regression line to segments. Inputs: rgb_img = RGB image to plot debug image stem_objects = List of stem segments (output from segment_sort function) + label = optional label parameter, modifies the variable name of observations recorded Returns: labeled_img = Stem analysis debugging image @@ -22,6 +23,7 @@ def analyze_stem(rgb_img, stem_objects): :param rgb_img: numpy.ndarray :param stem_objects: list + :param label: str :return labeled_img: numpy.ndarray """ params.device += 1 @@ -39,13 +41,19 @@ def analyze_stem(rgb_img, stem_objects): # Calculate stem path length stem_length = cv2.arcLength(grouped_stem, False) / 2 - outputs.add_observation(variable='stem_height', trait='vertical length of stem segments', + + if label == None: + prefix = "" + else: + prefix = label + "_" + + outputs.add_observation(variable=prefix + 'stem_height', trait='vertical length of stem segments', method='plantcv.plantcv.morphology.analyze_stem', scale='pixels', datatype=float, value=height, label=None) - outputs.add_observation(variable='stem_angle', trait='angle of combined stem object', + outputs.add_observation(variable=prefix + 'stem_angle', trait='angle of combined stem object', method='plantcv.plantcv.morphology.analyze_stem', scale='degrees', datatype=float, value=float(slope), label=None) - outputs.add_observation(variable='stem_length', trait='path length of combined stem object', + outputs.add_observation(variable=prefix + 'stem_length', trait='path length of combined stem object', method='plantcv.plantcv.morphology.analyze_stem', scale='None', datatype=float, value=stem_length, label=None) diff --git a/plantcv/plantcv/morphology/check_cycles.py b/plantcv/plantcv/morphology/check_cycles.py index 099b7e888..99d952029 100644 --- a/plantcv/plantcv/morphology/check_cycles.py +++ b/plantcv/plantcv/morphology/check_cycles.py @@ -13,15 +13,17 @@ from plantcv.plantcv import color_palette -def check_cycles(skel_img): +def check_cycles(skel_img, label=None): """ Check for cycles in a skeleton image Inputs: skel_img = Skeletonized image + label = optional label parameter, modifies the variable name of observations recorded Returns: cycle_img = Image with cycles identified :param skel_img: numpy.ndarray + :param label: str :return cycle_img: numpy.ndarray """ @@ -60,8 +62,13 @@ def check_cycles(skel_img): cv2.drawContours(cycle_img, cycle_objects, i, rand_color[i], params.line_thickness, lineType=8, hierarchy=cycle_hierarchies) + if label == None: + prefix = "" + else: + prefix = label + "_" + # Store Cycle Data - outputs.add_observation(variable='num_cycles', trait='number of cycles', + outputs.add_observation(variable=prefix + 'num_cycles', trait='number of cycles', method='plantcv.plantcv.morphology.check_cycles', scale='none', datatype=int, value=int(num_cycles), label='none') @@ -71,7 +78,7 @@ def check_cycles(skel_img): params.device += 1 if params.debug == 'print': - print_image(cycle_img, os.path.join(params.debug_outdir, str(params.device) + '_cycles.png')) + print_image(cycle_img, os.path.join(params.debug_outdir, str(params.device) + prefix + '_cycles.png')) elif params.debug == 'plot': plot_image(cycle_img) diff --git a/plantcv/plantcv/morphology/fill_segments.py b/plantcv/plantcv/morphology/fill_segments.py index d8abd411a..7717b8e84 100644 --- a/plantcv/plantcv/morphology/fill_segments.py +++ b/plantcv/plantcv/morphology/fill_segments.py @@ -11,7 +11,7 @@ from plantcv.plantcv import print_image -def fill_segments(mask, objects, stem_objects=None): +def fill_segments(mask, objects, stem_objects=None, label=None): """Fills masked segments from contours. Inputs: diff --git a/plantcv/plantcv/morphology/find_branch_pts.py b/plantcv/plantcv/morphology/find_branch_pts.py index 8718fb5c3..0834922ed 100644 --- a/plantcv/plantcv/morphology/find_branch_pts.py +++ b/plantcv/plantcv/morphology/find_branch_pts.py @@ -11,18 +11,20 @@ from plantcv.plantcv import find_objects -def find_branch_pts(skel_img, mask=None): +def find_branch_pts(skel_img, mask=None, label=None): """ The branching algorithm was inspired by Jean-Patrick Pommier: https://gist.github.com/jeanpat/5712699 Inputs: skel_img = Skeletonized image mask = (Optional) binary mask for debugging. If provided, debug image will be overlaid on the mask. + label = optional label parameter, modifies the variable name of observations recorded Returns: branch_pts_img = Image with just branch points, rest 0 :param skel_img: numpy.ndarray :param mask: np.ndarray + :param label: str :return branch_pts_img: numpy.ndarray """ @@ -94,6 +96,11 @@ def find_branch_pts(skel_img, mask=None): branch_labels.append(i) cv2.circle(branch_plot, (x, y), params.line_thickness, (255, 0, 255), -1) + if label == None: + prefix = "" + else: + prefix = label + "_" + outputs.add_observation(variable='branch_pts', trait='list of branch-point coordinates identified from a skeleton', method='plantcv.plantcv.morphology.find_branch_pts', scale='pixels', datatype=list, value=branch_list, label=branch_labels) diff --git a/plantcv/plantcv/morphology/find_tips.py b/plantcv/plantcv/morphology/find_tips.py index 7ae8e6e31..d8c421cec 100644 --- a/plantcv/plantcv/morphology/find_tips.py +++ b/plantcv/plantcv/morphology/find_tips.py @@ -11,7 +11,7 @@ from plantcv.plantcv import find_objects -def find_tips(skel_img, mask=None): +def find_tips(skel_img, mask=None, label=None): """ The endpoints algorithm was inspired by Jean-Patrick Pommier: https://gist.github.com/jeanpat/5712699 Find tips in skeletonized image. @@ -19,12 +19,14 @@ def find_tips(skel_img, mask=None): Inputs: skel_img = Skeletonized image mask = (Optional) binary mask for debugging. If provided, debug image will be overlaid on the mask. + label = optional label parameter, modifies the variable name of observations recorded Returns: tip_img = Image with just tips, rest 0 :param skel_img: numpy.ndarray :param mask: numpy.ndarray + :param label: str :return tip_img: numpy.ndarray """ @@ -77,6 +79,12 @@ def find_tips(skel_img, mask=None): tip_labels.append(i) cv2.circle(tip_plot, (x, y), params.line_thickness, (0, 255, 0), -1) + + if label == None: + prefix = "" + else: + prefix = label + "_" + outputs.add_observation(variable='tips', trait='list of tip coordinates identified from a skeleton', method='plantcv.plantcv.morphology.find_tips', scale='pixels', datatype=list, value=tip_list, label=tip_labels) From 8089a96686620a188f9ce47d2d8867bcabc6c680 Mon Sep 17 00:00:00 2001 From: HaleySchuhl Date: Fri, 8 Jan 2021 14:02:02 -0600 Subject: [PATCH 008/137] add label param to more morph functions --- plantcv/plantcv/hyperspectral/analyze_index.py | 2 +- plantcv/plantcv/morphology/analyze_stem.py | 2 +- plantcv/plantcv/morphology/find_tips.py | 4 ++-- plantcv/plantcv/morphology/segment_angle.py | 14 +++++++++++--- plantcv/plantcv/morphology/segment_curvature.py | 14 +++++++++++--- 5 files changed, 26 insertions(+), 10 deletions(-) diff --git a/plantcv/plantcv/hyperspectral/analyze_index.py b/plantcv/plantcv/hyperspectral/analyze_index.py index f09ff6a6c..c81f1e412 100644 --- a/plantcv/plantcv/hyperspectral/analyze_index.py +++ b/plantcv/plantcv/hyperspectral/analyze_index.py @@ -135,7 +135,7 @@ def analyze_index(index_array, mask, histplot=False, bins=100, min_bin=0, max_bi plot_image(masked_array) elif params.debug == "print": print_image(img=masked_array, filename=os.path.join(params.debug_outdir, str(params.device) + - index_array.array_type + prefix + ".png")) + prefix + index_array.array_type + prefix + ".png")) # Store images outputs.images.append(analysis_image) diff --git a/plantcv/plantcv/morphology/analyze_stem.py b/plantcv/plantcv/morphology/analyze_stem.py index 02717fa6c..9207000a3 100644 --- a/plantcv/plantcv/morphology/analyze_stem.py +++ b/plantcv/plantcv/morphology/analyze_stem.py @@ -70,7 +70,7 @@ def analyze_stem(rgb_img, stem_objects, label=None): else: cv2.line(labeled_img, (x_max - 1, intercept2), (x_min, intercept1), (0, 0, 255), 1) if params.debug == 'print': - print_image(labeled_img, os.path.join(params.debug_outdir, str(params.device) + '_stem_analysis.png')) + print_image(labeled_img, os.path.join(params.debug_outdir, str(params.device) + prefix + 'stem_analze.png')) elif params.debug == 'plot': plot_image(labeled_img) diff --git a/plantcv/plantcv/morphology/find_tips.py b/plantcv/plantcv/morphology/find_tips.py index d8c421cec..2c3f35eda 100644 --- a/plantcv/plantcv/morphology/find_tips.py +++ b/plantcv/plantcv/morphology/find_tips.py @@ -85,7 +85,7 @@ def find_tips(skel_img, mask=None, label=None): else: prefix = label + "_" - outputs.add_observation(variable='tips', trait='list of tip coordinates identified from a skeleton', + outputs.add_observation(variable=prefix + 'tips', trait='list of tip coordinates identified from a skeleton', method='plantcv.plantcv.morphology.find_tips', scale='pixels', datatype=list, value=tip_list, label=tip_labels) @@ -95,7 +95,7 @@ def find_tips(skel_img, mask=None, label=None): params.device += 1 if params.debug == 'print': - print_image(tip_plot, os.path.join(params.debug_outdir, str(params.device) + '_skeleton_tips.png')) + print_image(tip_plot, os.path.join(params.debug_outdir, str(params.device) + prefix + '_skeleton_tips.png')) elif params.debug == 'plot': plot_image(tip_plot) diff --git a/plantcv/plantcv/morphology/segment_angle.py b/plantcv/plantcv/morphology/segment_angle.py index e8aac9cfa..ff5ceabe9 100644 --- a/plantcv/plantcv/morphology/segment_angle.py +++ b/plantcv/plantcv/morphology/segment_angle.py @@ -11,12 +11,13 @@ from plantcv.plantcv import color_palette -def segment_angle(segmented_img, objects): +def segment_angle(segmented_img, objects, label=None): """ Calculate angle of segments (in degrees) by fitting a linear regression line to segments. Inputs: segmented_img = Segmented image to plot slope lines and angles on objects = List of contours + label = optional label parameter, modifies the variable name of observations recorded Returns: labeled_img = Segmented debugging image with angles labeled @@ -24,6 +25,7 @@ def segment_angle(segmented_img, objects): :param segmented_img: numpy.ndarray :param objects: list + :param label: str :return labeled_img: numpy.ndarray """ @@ -74,7 +76,12 @@ def segment_angle(segmented_img, objects): # segment_label = "ID" + str(i) segment_ids.append(i) - outputs.add_observation(variable='segment_angle', trait='segment angle', + if label == None: + prefix = "" + else: + prefix = label + "_" + + outputs.add_observation(variable=prefix + 'segment_angle', trait='segment angle', method='plantcv.plantcv.morphology.segment_angle', scale='degrees', datatype=list, value=segment_angles, label=segment_ids) @@ -82,7 +89,8 @@ def segment_angle(segmented_img, objects): params.device += 1 if params.debug == 'print': - print_image(labeled_img, os.path.join(params.debug_outdir, str(params.device) + '_segmented_angles.png')) + print_image(labeled_img, os.path.join(params.debug_outdir, str(params.device) + + prefix + '_segmented_angles.png')) elif params.debug == 'plot': plot_image(labeled_img) diff --git a/plantcv/plantcv/morphology/segment_curvature.py b/plantcv/plantcv/morphology/segment_curvature.py index 8d038ba6e..d9160b086 100644 --- a/plantcv/plantcv/morphology/segment_curvature.py +++ b/plantcv/plantcv/morphology/segment_curvature.py @@ -14,13 +14,14 @@ from plantcv.plantcv.morphology import segment_euclidean_length -def segment_curvature(segmented_img, objects): +def segment_curvature(segmented_img, objects, label=None): """ Calculate segment curvature as defined by the ratio between geodesic and euclidean distance. Measurement of two-dimensional tortuosity. Inputs: segmented_img = Segmented image to plot lengths on objects = List of contours + label = optional label parameter, modifies the variable name of observations recorded Returns: labeled_img = Segmented debugging image with curvature labeled @@ -28,6 +29,7 @@ def segment_curvature(segmented_img, objects): :param segmented_img: numpy.ndarray :param objects: list + :param label: str :return labeled_img: numpy.ndarray """ @@ -83,7 +85,12 @@ def segment_curvature(segmented_img, objects): # segment_label = "ID" + str(i) segment_ids.append(i) - outputs.add_observation(variable='segment_curvature', trait='segment curvature', + if label == None: + prefix = "" + else: + prefix = label + "_" + + outputs.add_observation(variable=prefix + 'segment_curvature', trait='segment curvature', method='plantcv.plantcv.morphology.segment_curvature', scale='none', datatype=list, value=curvature_measure, label=segment_ids) @@ -91,7 +98,8 @@ def segment_curvature(segmented_img, objects): params.device += 1 if params.debug == 'print': - print_image(labeled_img, os.path.join(params.debug_outdir, str(params.device) + '_segment_curvature.png')) + print_image(labeled_img, os.path.join(params.debug_outdir, str(params.device) + prefix + + '_segment_curvature.png')) elif params.debug == 'plot': plot_image(labeled_img) From 66907b0eb7fb19563715c7ca5b3a834b2db84aee Mon Sep 17 00:00:00 2001 From: HaleySchuhl Date: Fri, 8 Jan 2021 14:03:19 -0600 Subject: [PATCH 009/137] Update segment_euclidean_length.py --- .../plantcv/morphology/segment_euclidean_length.py | 14 +++++++++++--- 1 file changed, 11 insertions(+), 3 deletions(-) diff --git a/plantcv/plantcv/morphology/segment_euclidean_length.py b/plantcv/plantcv/morphology/segment_euclidean_length.py index 6ccbb8edd..67e839c70 100644 --- a/plantcv/plantcv/morphology/segment_euclidean_length.py +++ b/plantcv/plantcv/morphology/segment_euclidean_length.py @@ -14,18 +14,20 @@ from plantcv.plantcv.morphology import find_tips -def segment_euclidean_length(segmented_img, objects): +def segment_euclidean_length(segmented_img, objects, label=None): """ Use segmented skeleton image to gather euclidean length measurements per segment Inputs: segmented_img = Segmented image to plot lengths on objects = List of contours + label = optional label parameter, modifies the variable name of observations recorded Returns: labeled_img = Segmented debugging image with lengths labeled :param segmented_img: numpy.ndarray :param objects: list + :param label: str :return labeled_img: numpy.ndarray """ @@ -79,7 +81,12 @@ def segment_euclidean_length(segmented_img, objects): # segment_label = "ID" + str(c) segment_ids.append(c) - outputs.add_observation(variable='segment_eu_length', trait='segment euclidean length', + if label == None: + prefix = "" + else: + prefix = label + "_" + + outputs.add_observation(variable=prefix + 'segment_eu_length', trait='segment euclidean length', method='plantcv.plantcv.morphology.segment_euclidean_length', scale='pixels', datatype=list, value=segment_lengths, label=segment_ids) @@ -87,7 +94,8 @@ def segment_euclidean_length(segmented_img, objects): params.device += 1 if params.debug == 'print': - print_image(labeled_img, os.path.join(params.debug_outdir, str(params.device) + '_segment_eu_lengths.png')) + print_image(labeled_img, os.path.join(params.debug_outdir, str(params.device) + prefix + + '_segment_eu_lengths.png')) elif params.debug == 'plot': plot_image(labeled_img) From 05a4372ca5eb8f12215df00ee2839b6fbae65941 Mon Sep 17 00:00:00 2001 From: HaleySchuhl Date: Fri, 8 Jan 2021 14:04:40 -0600 Subject: [PATCH 010/137] Update segment_insertion_angle.py --- .../plantcv/morphology/segment_insertion_angle.py | 15 ++++++++++++--- 1 file changed, 12 insertions(+), 3 deletions(-) diff --git a/plantcv/plantcv/morphology/segment_insertion_angle.py b/plantcv/plantcv/morphology/segment_insertion_angle.py index c2d7debe9..bf42db535 100644 --- a/plantcv/plantcv/morphology/segment_insertion_angle.py +++ b/plantcv/plantcv/morphology/segment_insertion_angle.py @@ -19,7 +19,7 @@ from plantcv.plantcv.morphology.segment_tangent_angle import _slope_to_intesect_angle -def segment_insertion_angle(skel_img, segmented_img, leaf_objects, stem_objects, size): +def segment_insertion_angle(skel_img, segmented_img, leaf_objects, stem_objects, size, label=None): """ Find leaf insertion angles in degrees of skeleton segments. Fit a linear regression line to the stem. Use `size` pixels on the portion of leaf next to the stem find a linear regression line, and calculate angle between the two lines per leaf object. @@ -29,13 +29,17 @@ def segment_insertion_angle(skel_img, segmented_img, leaf_objects, stem_objects, leaf_objects = List of leaf segments stem_objects = List of stem segments size = Size of inner leaf used to calculate slope lines + label = optional label parameter, modifies the variable name of observations recorded + Returns: labeled_img = Debugging image with angles labeled + :param skel_img: numpy.ndarray :param segmented_img: numpy.ndarray :param leaf_objects: list :param stem_objects: list :param size: int + :param label: str :return labeled_img: numpy.ndarray """ @@ -182,7 +186,12 @@ def segment_insertion_angle(skel_img, segmented_img, leaf_objects, stem_objects, # segment_label = "ID" + str(i) segment_ids.append(i) - outputs.add_observation(variable='segment_insertion_angle', trait='segment insertion angle', + if label == None: + prefix = "" + else: + prefix = label + "_" + + outputs.add_observation(variable=prefix + 'segment_insertion_angle', trait='segment insertion angle', method='plantcv.plantcv.morphology.segment_insertion_angle', scale='degrees', datatype=list, value=all_intersection_angles, label=segment_ids) @@ -193,7 +202,7 @@ def segment_insertion_angle(skel_img, segmented_img, leaf_objects, stem_objects, if params.debug == 'print': print_image(labeled_img, - os.path.join(params.debug_outdir, str(params.device) + '_segment_insertion_angles.png')) + os.path.join(params.debug_outdir, str(params.device) + prefix + '_segment_insertion_angles.png')) elif params.debug == 'plot': plot_image(labeled_img) From 8b75dfd4a397f7b865acf22ba1f54a8bfada3bad Mon Sep 17 00:00:00 2001 From: HaleySchuhl Date: Fri, 8 Jan 2021 15:57:36 -0600 Subject: [PATCH 011/137] more --- plantcv/plantcv/morphology/segment_insertion_angle.py | 2 +- plantcv/plantcv/morphology/segment_path_length.py | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/plantcv/plantcv/morphology/segment_insertion_angle.py b/plantcv/plantcv/morphology/segment_insertion_angle.py index bf42db535..5b03328ca 100644 --- a/plantcv/plantcv/morphology/segment_insertion_angle.py +++ b/plantcv/plantcv/morphology/segment_insertion_angle.py @@ -39,7 +39,7 @@ def segment_insertion_angle(skel_img, segmented_img, leaf_objects, stem_objects, :param leaf_objects: list :param stem_objects: list :param size: int - :param label: str + :param label: str :return labeled_img: numpy.ndarray """ diff --git a/plantcv/plantcv/morphology/segment_path_length.py b/plantcv/plantcv/morphology/segment_path_length.py index ee45e7bbb..951abeac9 100644 --- a/plantcv/plantcv/morphology/segment_path_length.py +++ b/plantcv/plantcv/morphology/segment_path_length.py @@ -8,7 +8,7 @@ from plantcv.plantcv import print_image -def segment_path_length(segmented_img, objects): +def segment_path_length(segmented_img, objects, label=None): """ Use segments to calculate geodesic distance per segment Inputs: From 419c39674342d40dd50ecdc58ce315f8109faeb1 Mon Sep 17 00:00:00 2001 From: HaleySchuhl Date: Mon, 11 Jan 2021 12:37:13 -0600 Subject: [PATCH 012/137] Update segment_path_length.py --- plantcv/plantcv/morphology/segment_path_length.py | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/plantcv/plantcv/morphology/segment_path_length.py b/plantcv/plantcv/morphology/segment_path_length.py index 951abeac9..4ca3c0bde 100644 --- a/plantcv/plantcv/morphology/segment_path_length.py +++ b/plantcv/plantcv/morphology/segment_path_length.py @@ -14,12 +14,14 @@ def segment_path_length(segmented_img, objects, label=None): Inputs: segmented_img = Segmented image to plot lengths on objects = List of contours + label = optional label parameter, modifies the variable name of observations recorded Returns: labeled_img = Segmented debugging image with lengths labeled :param segmented_img: numpy.ndarray :param objects: list + :param label: str :return labeled_img: numpy.ndarray """ @@ -44,10 +46,14 @@ def segment_path_length(segmented_img, objects, label=None): h = label_coord_y[c] cv2.putText(img=labeled_img, text=text, org=(w, h), fontFace=cv2.FONT_HERSHEY_SIMPLEX, fontScale=params.text_size, color=(150, 150, 150), thickness=params.text_thickness) - # segment_label = "ID" + str(c) segment_ids.append(c) - outputs.add_observation(variable='segment_path_length', trait='segment path length', + if label == None: + prefix = "" + else: + prefix = label + "_" + + outputs.add_observation(variable=prefix + 'segment_path_length', trait='segment path length', method='plantcv.plantcv.morphology.segment_path_length', scale='pixels', datatype=list, value=segment_lengths, label=segment_ids) From a7b11ab2d23d1554fe00f142b27b513ec265d4e2 Mon Sep 17 00:00:00 2001 From: HaleySchuhl Date: Mon, 11 Jan 2021 12:39:38 -0600 Subject: [PATCH 013/137] Update segment_tangent_angle.py --- .../plantcv/morphology/segment_tangent_angle.py | 15 +++++++++++---- 1 file changed, 11 insertions(+), 4 deletions(-) diff --git a/plantcv/plantcv/morphology/segment_tangent_angle.py b/plantcv/plantcv/morphology/segment_tangent_angle.py index 89294cb84..6d55944b2 100644 --- a/plantcv/plantcv/morphology/segment_tangent_angle.py +++ b/plantcv/plantcv/morphology/segment_tangent_angle.py @@ -31,15 +31,16 @@ def _slope_to_intesect_angle(m1, m2): return angle -def segment_tangent_angle(segmented_img, objects, size): +def segment_tangent_angle(segmented_img, objects, size, label=None): """ Find 'tangent' angles in degrees of skeleton segments. Use `size` pixels on either end of each segment to find a linear regression line, and calculate angle between the two lines drawn per segment. Inputs: segmented_img = Segmented image to plot slope lines and intersection angles on - objects = List of contours - size = Size of ends used to calculate "tangent" lines + objects = List of contours + size = Size of ends used to calculate "tangent" lines + label = optional label parameter, modifies the variable name of observations recorded Returns: labeled_img = Segmented debugging image with angles labeled @@ -47,6 +48,7 @@ def segment_tangent_angle(segmented_img, objects, size): :param segmented_img: numpy.ndarray :param objects: list :param size: int + :param label: str :return labeled_img: numpy.ndarray """ # Store debug @@ -123,7 +125,12 @@ def segment_tangent_angle(segmented_img, objects, size): # segment_label = "ID" + str(i) segment_ids.append(i) - outputs.add_observation(variable='segment_tangent_angle', trait='segment tangent angle', + if label == None: + prefix = "" + else: + prefix = label + "_" + + outputs.add_observation(variable=prefix + 'segment_tangent_angle', trait='segment tangent angle', method='plantcv.plantcv.morphology.segment_tangent_angle', scale='degrees', datatype=list, value=intersection_angles, label=segment_ids) From 854d0ed10ffa03a8efe3928c3133c55956a8231e Mon Sep 17 00:00:00 2001 From: HaleySchuhl Date: Mon, 11 Jan 2021 12:43:50 -0600 Subject: [PATCH 014/137] Update tests.py add cases where label is not None to cover new lines of code --- tests/tests.py | 24 ++++++++++++------------ 1 file changed, 12 insertions(+), 12 deletions(-) diff --git a/tests/tests.py b/tests/tests.py index 70a4af797..9f1c19bd6 100755 --- a/tests/tests.py +++ b/tests/tests.py @@ -3578,7 +3578,7 @@ def test_plantcv_morphology_segment_curvature(): pcv.params.debug = "print" segmented_img, seg_objects = pcv.morphology.segment_skeleton(skel_img=skeleton) pcv.outputs.clear() - _ = pcv.morphology.segment_curvature(segmented_img, seg_objects) + _ = pcv.morphology.segment_curvature(segmented_img, seg_objects, label="prefix") pcv.params.debug = "plot" pcv.outputs.clear() _ = pcv.morphology.segment_curvature(segmented_img, seg_objects) @@ -3594,7 +3594,7 @@ def test_plantcv_morphology_check_cycles(): pcv.params.debug_outdir = cache_dir mask = cv2.imread(os.path.join(TEST_DATA, TEST_INPUT_BINARY), -1) pcv.params.debug = "print" - _ = pcv.morphology.check_cycles(mask) + _ = pcv.morphology.check_cycles(mask, label="prefix") pcv.params.debug = "plot" _ = pcv.morphology.check_cycles(mask) pcv.params.debug = None @@ -3613,7 +3613,7 @@ def test_plantcv_morphology_find_branch_pts(): mask = cv2.imread(os.path.join(TEST_DATA, TEST_INPUT_BINARY), -1) skeleton = cv2.imread(os.path.join(TEST_DATA, TEST_INPUT_SKELETON), -1) pcv.params.debug = "print" - _ = pcv.morphology.find_branch_pts(skel_img=skeleton, mask=mask) + _ = pcv.morphology.find_branch_pts(skel_img=skeleton, mask=mask, label="prefix") pcv.params.debug = "plot" _ = pcv.morphology.find_branch_pts(skel_img=skeleton) pcv.params.debug = None @@ -3629,7 +3629,7 @@ def test_plantcv_morphology_find_tips(): mask = cv2.imread(os.path.join(TEST_DATA, TEST_INPUT_BINARY), -1) skeleton = cv2.imread(os.path.join(TEST_DATA, TEST_INPUT_SKELETON), -1) pcv.params.debug = "print" - _ = pcv.morphology.find_tips(skel_img=skeleton, mask=mask) + _ = pcv.morphology.find_tips(skel_img=skeleton, mask=mask, label="prefix") pcv.params.debug = "plot" _ = pcv.morphology.find_tips(skel_img=skeleton) pcv.params.debug = None @@ -3646,7 +3646,7 @@ def test_plantcv_morphology_prune(): pcv.params.debug = "print" _ = pcv.morphology.prune(skel_img=skeleton, size=1) pcv.params.debug = "plot" - _ = pcv.morphology.prune(skel_img=skeleton, size=1, mask=skeleton) + _ = pcv.morphology.prune(skel_img=skeleton, size=1, mask=skeleton, label="prefix") pcv.params.debug = None pruned_img, _, _ = pcv.morphology.prune(skel_img=skeleton, size=3) assert np.sum(pruned_img) < np.sum(skeleton) @@ -3697,7 +3697,7 @@ def test_plantcv_morphology_fill_segments(): for key, val in obj_dic.items(): obj.append(val) pcv.params.debug = "print" - _ = pcv.morphology.fill_segments(mask, obj) + _ = pcv.morphology.fill_segments(mask, obj, label="prefix") pcv.params.debug = "plot" _ = pcv.morphology.fill_segments(mask, obj) pcv.print_results(os.path.join(cache_dir, "results.txt")) @@ -3736,7 +3736,7 @@ def test_plantcv_morphology_segment_angle(): skeleton = cv2.imread(os.path.join(TEST_DATA, TEST_INPUT_SKELETON_PRUNED), -1) pcv.params.debug = "print" segmented_img, segment_objects = pcv.morphology.segment_skeleton(skel_img=skeleton) - _ = pcv.morphology.segment_angle(segmented_img=segmented_img, objects=segment_objects) + _ = pcv.morphology.segment_angle(segmented_img=segmented_img, objects=segment_objects, label="prefix") pcv.params.debug = "plot" _ = pcv.morphology.segment_angle(segmented_img, segment_objects) pcv.print_results(os.path.join(cache_dir, "results.txt")) @@ -3765,7 +3765,7 @@ def test_plantcv_morphology_segment_euclidean_length(): skeleton = cv2.imread(os.path.join(TEST_DATA, TEST_INPUT_SKELETON_PRUNED), -1) pcv.params.debug = "print" segmented_img, segment_objects = pcv.morphology.segment_skeleton(skel_img=skeleton) - _ = pcv.morphology.segment_euclidean_length(segmented_img, segment_objects) + _ = pcv.morphology.segment_euclidean_length(segmented_img, segment_objects, label="prefix") pcv.params.debug = "plot" _ = pcv.morphology.segment_euclidean_length(segmented_img, segment_objects) pcv.print_results(os.path.join(cache_dir, "results.txt")) @@ -3790,7 +3790,7 @@ def test_plantcv_morphology_segment_path_length(): skeleton = cv2.imread(os.path.join(TEST_DATA, TEST_INPUT_SKELETON_PRUNED), -1) pcv.params.debug = "print" segmented_img, segment_objects = pcv.morphology.segment_skeleton(skel_img=skeleton) - _ = pcv.morphology.segment_path_length(segmented_img, segment_objects) + _ = pcv.morphology.segment_path_length(segmented_img, segment_objects, label="prefix") pcv.params.debug = "plot" _ = pcv.morphology.segment_path_length(segmented_img, segment_objects) pcv.print_results(os.path.join(cache_dir, "results.txt")) @@ -3838,7 +3838,7 @@ def test_plantcv_morphology_segment_tangent_angle(): objects = np.load(os.path.join(TEST_DATA, TEST_SKELETON_OBJECTS), encoding="latin1") objs = [objects[arr_n] for arr_n in objects] pcv.params.debug = "print" - _ = pcv.morphology.segment_tangent_angle(skel, objs, 2) + _ = pcv.morphology.segment_tangent_angle(skel, objs, 2, label="prefix") pcv.params.debug = "plot" _ = pcv.morphology.segment_tangent_angle(skel, objs, 2) pcv.print_results(os.path.join(cache_dir, "results.txt")) @@ -3871,7 +3871,7 @@ def test_plantcv_morphology_segment_insertion_angle(): segmented_img, seg_objects = pcv.morphology.segment_skeleton(skel_img=pruned) leaf_obj, stem_obj = pcv.morphology.segment_sort(pruned, seg_objects) pcv.params.debug = "plot" - _ = pcv.morphology.segment_insertion_angle(pruned, segmented_img, leaf_obj, stem_obj, 3) + _ = pcv.morphology.segment_insertion_angle(pruned, segmented_img, leaf_obj, stem_obj, 3, label="prefix") pcv.params.debug = "print" _ = pcv.morphology.segment_insertion_angle(pruned, segmented_img, leaf_obj, stem_obj, 10) pcv.print_results(os.path.join(cache_dir, "results.txt")) @@ -3935,7 +3935,7 @@ def test_plantcv_morphology_analyze_stem(): segmented_img, seg_objects = pcv.morphology.segment_skeleton(skel_img=pruned) leaf_obj, stem_obj = pcv.morphology.segment_sort(pruned, seg_objects) pcv.params.debug = "plot" - _ = pcv.morphology.analyze_stem(rgb_img=segmented_img, stem_objects=stem_obj) + _ = pcv.morphology.analyze_stem(rgb_img=segmented_img, stem_objects=stem_obj, label="prefix") pcv.params.debug = "print" _ = pcv.morphology.analyze_stem(rgb_img=segmented_img, stem_objects=stem_obj) assert pcv.outputs.observations['stem_angle']['value'] == -12.531776428222656 From 3d4df862603721fd4ff66c6de0ee69fbfc39f830 Mon Sep 17 00:00:00 2001 From: HaleySchuhl Date: Mon, 11 Jan 2021 12:59:35 -0600 Subject: [PATCH 015/137] start adding documentation for label param adding documentation for label param --- docs/analyze_spectral.md | 2 +- docs/analyze_stem.md | 12 +++++++----- docs/check_cycles.md | 5 +++-- docs/fill_segments.md | 9 +++++---- docs/find_branch_pts.md | 7 ++++--- docs/find_tips.md | 8 +++++--- docs/hyperspectral_tutorial.md | 8 ++++++-- 7 files changed, 31 insertions(+), 20 deletions(-) diff --git a/docs/analyze_spectral.md b/docs/analyze_spectral.md index 1044b12ca..802dc411b 100644 --- a/docs/analyze_spectral.md +++ b/docs/analyze_spectral.md @@ -3,7 +3,7 @@ This function calculates the reflectance frequencies associated with a hyperspectral datacube and writes the values out as observations to get saved out. Can also print out a histogram of average reflectance intensity. -**plantcv.hyperspectral.analyze_spectral**(*array, mask, histplot=False*) +**plantcv.hyperspectral.analyze_spectral**(*array, mask, histplot=False, label=None*) **returns** reflectance histogram (if `histplot=True`, otherwise returns None object) diff --git a/docs/analyze_stem.md b/docs/analyze_stem.md index 052f7ad45..7ec8b7321 100644 --- a/docs/analyze_stem.md +++ b/docs/analyze_stem.md @@ -3,13 +3,14 @@ Primary, or stem, objects identified during workflows that examine the [morphology](morphology_tutorial.md) of plants or plant organs can have specific characteristics measured about the stem segments of a skeleton. -**plantcv.morphology.analyze_stem**(*rgb_img, stem_objects*) +**plantcv.morphology.analyze_stem**(*rgb_img, stem_objects, label=None*) **returns** labeled_img - **Parameters:** - - rgb_img - RGB image data for plotting. + - rgb_img - RGB image data for plotting. - stem_objects - List of stem segments (output from [segment_sort](segment_sort.md) function) + - label - Optional label parameter, modifies the variable name of observations recorded - **Context:** - Used to output stem morphological characteristics, including height, angle, and length. - **Example use:** @@ -31,12 +32,13 @@ from plantcv import plantcv as pcv pcv.params.debug = "print" -stem_debug_img1 = pcv.morphology.analyze_stem(rgb_img=img1, stem_objects=stem_objects1) -stem_debug_img2 = pcv.morphology.analyze_stem(rgb_img=img2, stem_objects=stem_objects2) - +stem_debug_img1 = pcv.morphology.analyze_stem(rgb_img=img1, stem_objects=stem_objects1, label=None) # Access data stored out from analyze_object stem_angle = pcv.outputs.observations['stem_angle']['value'] +stem_debug_img2 = pcv.morphology.analyze_stem(rgb_img=img2, stem_objects=stem_objects2, label="rep1") +stem_angle = pcv.outputs.observations['rep1_stem_angle']['value'] + ``` **Image 1 with identified stem characteristics** diff --git a/docs/check_cycles.md b/docs/check_cycles.md index 5c642a910..94ee629ff 100644 --- a/docs/check_cycles.md +++ b/docs/check_cycles.md @@ -2,12 +2,13 @@ Check for cycles within a skeletonized image. -**plantcv.morphology.check_cycles**(*skel_img*) +**plantcv.morphology.check_cycles**(*skel_img, label=None*) **returns** debugging cycle image - **Parameters:** - skel_img - Skeleton image (output from [plantcv.morphology.skeletonize](skeletonize.md)) + - label - Optional label parameter, modifies the variable name of observations recorded. (default `label=None`) - **Context:** - Identifies cycles in a skeleton image. - **Output data stored:** Data ('num_cycles') automatically gets stored to the [`Outputs` class](outputs.md) when this function is ran. @@ -29,7 +30,7 @@ pcv.params.debug = "print" # The cycle_img created for debugging purposes allows for line thickness # adjustments with the global line thickness parameter. Try setting # pcv.params.line_thickness = 8 for thicker lines (default 5) -cycle_img = pcv.morphology.check_cycles(skel_img=skeleton) +cycle_img = pcv.morphology.check_cycles(skel_img=skeleton, label=None) # Access data stored out from check_cycles num_cycles = pcv.outputs.observations['num_cycles']['value'] diff --git a/docs/fill_segments.md b/docs/fill_segments.md index 2115eab18..91235a50d 100644 --- a/docs/fill_segments.md +++ b/docs/fill_segments.md @@ -2,16 +2,17 @@ Propagate the labels of a segmented skeleton to fill the mask. -**plantcv.morphology.fill_segments**(*mask, objects, stem_objects=None*) +**plantcv.morphology.fill_segments**(*mask, objects, stem_objects=None, label=None*) **returns** filled_img - **Parameters:** - - mask - Binary mask - - objects - Segment objects (output from either [plantcv.morphology.prune](prune.md), + - mask - Binary mask + - objects - Segment objects (output from either [plantcv.morphology.prune](prune.md), [plantcv.morphology.segment_skeleton](segment_skeleton.md), or [plantcv.morphology.segment_sort](segment_sort.md)). - stem_objects - Optional input for stem objects that will be combined into a single object before filling the mask. + - label - Optional label parameter, modifies the variable name of observations recorded. (default `label=None`) - **Context:** - Uses the watershed algorithm to fill the mask propagating the objects' labels. - **Output data stored:** Data ('segment_area') automatically gets stored to the [`Outputs` class](outputs.md) when this function is ran. @@ -32,7 +33,7 @@ from plantcv import plantcv as pcv # or "plot" (Jupyter Notebooks or X11) pcv.params.debug = "print" -filled_img = pcv.morphology.fill_segments(mask=plant_mask, objects=obj) +filled_img = pcv.morphology.fill_segments(mask=plant_mask, objects=obj, label=None) # Access data stored out from fill_segments segments_area = pcv.outputs.observations['segment_area']['value'] diff --git a/docs/find_branch_pts.md b/docs/find_branch_pts.md index a9faa06ce..b17670567 100644 --- a/docs/find_branch_pts.md +++ b/docs/find_branch_pts.md @@ -2,13 +2,14 @@ Find branch/junction points in a skeletonized image. -**plantcv.morphology.find_branch_pts**(*skel_img, mask=None*) +**plantcv.morphology.find_branch_pts**(*skel_img, mask=None, label=None*) **returns** Binary mask of branch points - **Parameters:** - skel_img - Skeleton image (output from [plantcv.morphology.skeletonize](skeletonize.md)) - - mask - Binary mask used for debugging image (optional). If provided the debug image will be overlaid on the mask. + - mask - Binary mask used for debugging image (optional). If provided the debug image will be overlaid on the mask. + - label - Optional label parameter, modifies the variable name of observations recorded. (default `label=None`) - **Context:** - Identifies branch/junction points in a skeleton image @@ -38,7 +39,7 @@ branch_points_img = pcv.morphology.find_branch_pts(skel_img=skeleton) pcv.params.line_thickness = 2 branch_points_img = pcv.morphology.find_branch_pts(skel_img=skeleton, mask=None) -branch_points_img = pcv.morphology.find_branch_pts(skel_img=skeleton, mask=plant_mask) +branch_points_img = pcv.morphology.find_branch_pts(skel_img=skeleton, mask=plant_mask, label="rep1") ``` diff --git a/docs/find_tips.md b/docs/find_tips.md index 81d1dc6a4..960f6107d 100644 --- a/docs/find_tips.md +++ b/docs/find_tips.md @@ -2,13 +2,15 @@ Find endpoints of a skeletonized image. -**plantcv.morphology.find_tips**(*skel_img, mask=None*) +**plantcv.morphology.find_tips**(*skel_img, mask=None, label=None*) **returns** Binary mask of endpoints - **Parameters:** - skel_img - Skeleton image (output from [plantcv.morphology.skeletonize](skeletonize.md)) - - mask - Binary mask used for debugging (optional). If provided the debug image will be overlaid on the mask. + - mask - Binary mask used for debugging (optional). If provided the debug image will be overlaid on the mask. + - label - Optional label parameter, modifies the variable name of observations recorded. (default `label=None`) + - **Context:** - Identifies endpoints/tips in a skeleton image @@ -36,7 +38,7 @@ pcv.params.debug = "plot" pcv.params.line_thickness = 3 tips_img = pcv.morphology.find_tips(skel_img=skeleton) -tips_img = pcv.morphology.find_tips(skel_img=skeleton, mask=plant_mask) +tips_img = pcv.morphology.find_tips(skel_img=skeleton, mask=plant_mask, label=rep1) ``` diff --git a/docs/hyperspectral_tutorial.md b/docs/hyperspectral_tutorial.md index 7226ad879..b3ff71aff 100644 --- a/docs/hyperspectral_tutorial.md +++ b/docs/hyperspectral_tutorial.md @@ -226,7 +226,9 @@ Binary mask after [filtering objects by the region of interest](roi_objects.md) # array - Hyperspectral data instance # mask - Binary mask image data # hist_plot - If True plots histogram of reflectance intensity values - analysis_img = pcv.hyperspectral.analyze_spectral(array=spectral_array, mask=kept_mask, histplot=True) + # label - Optional label parameter, modifies the variable name of observations recorded. (default `label=None`) + + analysis_img = pcv.hyperspectral.analyze_spectral(array=spectral_array, mask=kept_mask, histplot=True, label=None) ``` @@ -241,7 +243,9 @@ Binary mask after [filtering objects by the region of interest](roi_objects.md) # Inputs: # array - Hyperspectral index data instance # mask - Binary mask image data - pcv.hyperspectral.analyze_index(array=index_array_gdvi, mask=kept_mask) + # label - Optional label parameter, modifies the variable name of observations recorded. (default `label=None`) + + pcv.hyperspectral.analyze_index(array=index_array_gdvi, mask=kept_mask, label=None) ``` From de4adbe4a8373514200fc5fa3efe66f1eb0e4c72 Mon Sep 17 00:00:00 2001 From: HaleySchuhl Date: Mon, 11 Jan 2021 13:02:43 -0600 Subject: [PATCH 016/137] Update tests.py --- tests/tests.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/tests.py b/tests/tests.py index 9f1c19bd6..036eb2bb2 100755 --- a/tests/tests.py +++ b/tests/tests.py @@ -3646,7 +3646,7 @@ def test_plantcv_morphology_prune(): pcv.params.debug = "print" _ = pcv.morphology.prune(skel_img=skeleton, size=1) pcv.params.debug = "plot" - _ = pcv.morphology.prune(skel_img=skeleton, size=1, mask=skeleton, label="prefix") + _ = pcv.morphology.prune(skel_img=skeleton, size=1, mask=skeleton) pcv.params.debug = None pruned_img, _, _ = pcv.morphology.prune(skel_img=skeleton, size=3) assert np.sum(pruned_img) < np.sum(skeleton) From a8d5974edfc232504affddf89bf70e7bd322ac8e Mon Sep 17 00:00:00 2001 From: HaleySchuhl Date: Mon, 11 Jan 2021 13:02:46 -0600 Subject: [PATCH 017/137] Update morphology_tutorial.md --- docs/morphology_tutorial.md | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/docs/morphology_tutorial.md b/docs/morphology_tutorial.md index 1e5a39a00..b2aa92386 100644 --- a/docs/morphology_tutorial.md +++ b/docs/morphology_tutorial.md @@ -171,8 +171,8 @@ off. The function prunes only secondary segments; primary segments that are smal # Inputs: # skel_img = Skeletonized image # mask = (Optional) binary mask for debugging. If provided, debug image will be overlaid on the mask. - - branch_pts_mask = pcv.morphology.find_branch_pts(skel_img=skeleton, mask=cropped_mask) + # label = (Optional) label parameter, modifies the variable name of observations recorded. (default `label=None`) + branch_pts_mask = pcv.morphology.find_branch_pts(skel_img=skeleton, mask=cropped_mask, label=None) ``` @@ -193,8 +193,9 @@ to remove all barbs. # Inputs: # skel_img = Skeletonized image # mask = (Optional) binary mask for debugging. If provided, debug image will be overlaid on the mask. + # label = (Optional) label parameter, modifies the variable name of observations recorded. (default `label=None`) - tip_pts_mask = pcv.morphology.find_tips(skel_img=skeleton, mask=None) + tip_pts_mask = pcv.morphology.find_tips(skel_img=skeleton, mask=None, label=None) ``` @@ -262,9 +263,10 @@ For this tutorial we assume leaves are the objects of interest, and just pass th # Inputs: # segmented_img = Segmented image to plot lengths on # objects = List of contours + # label = (Optional) label parameter, modifies the variable name of observations recorded. (default `label=None`) labeled_img = pcv.morphology.segment_path_length(segmented_img=segmented_img, - objects=leaf_obj) + objects=leaf_obj, label=None) ``` From 60869ae20248a80f1b3c6301d16d3b6fd0a08834 Mon Sep 17 00:00:00 2001 From: HaleySchuhl Date: Tue, 12 Jan 2021 08:13:00 -0600 Subject: [PATCH 018/137] finish morph tutorial docs --- docs/morphology_tutorial.md | 15 ++++++++++----- 1 file changed, 10 insertions(+), 5 deletions(-) diff --git a/docs/morphology_tutorial.md b/docs/morphology_tutorial.md index b2aa92386..464ccbebc 100644 --- a/docs/morphology_tutorial.md +++ b/docs/morphology_tutorial.md @@ -284,9 +284,10 @@ passed into the function. # Inputs: # segmented_img = Segmented image to plot lengths on # objects = List of contours + # label = (Optional) label parameter, modifies the variable name of observations recorded. (default `label=None`) labeled_img = pcv.morphology.segment_euclidean_length(segmented_img=segmented_img, - objects=leaf_obj) + objects=leaf_obj, label=None) ``` @@ -304,9 +305,10 @@ euclidean distance of each segment passed to the function. # Inputs: # segmented_img = Segmented image to plot curvature on # objects = List of contours + # label = (Optional) label parameter, modifies the variable name of observations recorded. (default `label=None`) labeled_img = pcv.morphology.segment_curvature(segmented_img=segmented_img, - objects=leaf_obj) + objects=leaf_obj, label=None) ``` @@ -326,9 +328,10 @@ is a straight line while larger values indicate the segment has more curvature. # Inputs: # segmented_img = Segmented image to plot angles on # objects = List of contours + # label = (Optional) label parameter, modifies the variable name of observations recorded. (default `label=None`) labeled_img = pcv.morphology.segment_angle(segmented_img=segmented_img, - objects=leaf_obj) + objects=leaf_obj, label=None) ``` @@ -347,9 +350,10 @@ by fitting a linear regression line to each segment. # segmented_img = Segmented image to plot tangent angles on # objects = List of contours # size = Size of ends used to calculate "tangent" lines + # label = (Optional) label parameter, modifies the variable name of observations recorded. (default `label=None`) labeled_img = pcv.morphology.segment_tangent_angle(segmented_img=segmented_img, - objects=leaf_obj, size=15) + objects=leaf_obj, size=15, label=None) ``` @@ -372,12 +376,13 @@ leaves that are more "floppy" will have smaller angles. # leaf_objects = List of leaf contours # stem_objects = List of stem objects # size = Size of the inner portion of each leaf to find a linear regression line + # label = (Optional) label parameter, modifies the variable name of observations recorded. (default `label=None`) labeled_img = pcv.morphology.segment_insertion_angle(skel_img=skeleton, segmented_img=segmented_img, leaf_objects=leaf_obj, stem_objects=stem_obj, - size=20) + size=20, label=None) ``` From 71005d98d875b188bef5e4dc5e2e71f885f4a95d Mon Sep 17 00:00:00 2001 From: HaleySchuhl Date: Tue, 12 Jan 2021 08:29:04 -0600 Subject: [PATCH 019/137] Update segment_angle.md --- docs/segment_angle.md | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/docs/segment_angle.md b/docs/segment_angle.md index c7ee7895c..8390284e3 100644 --- a/docs/segment_angle.md +++ b/docs/segment_angle.md @@ -11,6 +11,7 @@ Measure angles of segments. or [plantcv.morphology.segment_id](segment_id.md)), used for creating the labeled image. - objects - Segment objects (output from either [plantcv.morphology.segment_skeleton](segment_skeleton.md), or [plantcv.morphology.segment_sort](segment_sort.md)). + - label - Optional label parameter, modifies the variable name of observations recorded. (default `label=None`) - **Context:** - Calculates angles of segments (in degrees) by fitting a linear regression line to each segment. Users can pass only leaf objects (returned from [plantcv.morphology.segment_sort](segment_sort.md)) to only collect angles of leaves. @@ -30,7 +31,7 @@ from plantcv import plantcv as pcv # or "plot" (Jupyter Notebooks or X11) pcv.params.debug = "print" -labeled_img = pcv.morphology.segment_angle(segmented_img=segmented_img, objects=obj) +labeled_img = pcv.morphology.segment_angle(segmented_img=segmented_img, objects=obj, label=None) # Access data stored out from segment_angle segment_angles = pcv.outputs.observations['segment_angle']['value'] From 1cb998370f3333101ee96de47c5ac38d505357de Mon Sep 17 00:00:00 2001 From: HaleySchuhl Date: Tue, 12 Jan 2021 08:30:31 -0600 Subject: [PATCH 020/137] Update segment_curvature.md --- docs/segment_curvature.md | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/docs/segment_curvature.md b/docs/segment_curvature.md index a53ed3ab8..4c329febe 100644 --- a/docs/segment_curvature.md +++ b/docs/segment_curvature.md @@ -12,6 +12,7 @@ Measure the curvature of segments. - objects - Segment objects (output from either [plantcv.morphology.prune](prune.md), [plantcv.morphology.segment_skeleton](segment_skeleton.md), or [plantcv.morphology.segment_sort](segment_sort.md)). + - label - Optional label parameter, modifies the variable name of observations recorded. (default `label=None`) - **Context:** - Calculates curvature of segments by taking the ratio of the geodesic distance ([plantcv.morphology.segment_path_length](segment_pathlength.md)) over the euclidean distance [plantcv.morphology.segment_euclidean_length](segment_euclidean_length.md)). Measurement of two-dimensional tortuosity. @@ -29,13 +30,15 @@ from plantcv import plantcv as pcv pcv.params.debug = "print" labeled_img = pcv.morphology.segment_curvature(segmented_img=segmented_img, - objects=obj) + objects=obj, label="all") # Pass just leaf objects and hierarchies (output from pcv.morphology.segment_sort) labeled_img2 = pcv.morphology.segment_curvature(segmented_img=leaf_segmented, - objects=leaf_obj) + objects=leaf_obj, label="leaf") # Access data stored out from segment_curvature -segment_curvatures = pcv.outputs.observations['segment_curvature']['value'] +all_curvatures = pcv.outputs.observations['all_segment_curvature']['value'] +leaf_curvatures = pcv.outputs.observations['leaf_segment_curvature']['value'] + ``` From 01986c744dec52d0e1a8e0a24357caad39d0c878 Mon Sep 17 00:00:00 2001 From: HaleySchuhl Date: Tue, 12 Jan 2021 08:31:30 -0600 Subject: [PATCH 021/137] update more doc pages --- docs/segment_angle.md | 2 +- docs/segment_curvature.md | 2 +- docs/segment_euclidean_length.md | 5 +++-- 3 files changed, 5 insertions(+), 4 deletions(-) diff --git a/docs/segment_angle.md b/docs/segment_angle.md index 8390284e3..92683104c 100644 --- a/docs/segment_angle.md +++ b/docs/segment_angle.md @@ -2,7 +2,7 @@ Measure angles of segments. -**plantcv.morphology.segment_angle**(*segmented_img, objects*) +**plantcv.morphology.segment_angle**(*segmented_img, objects, label=None*) **returns** labeled image diff --git a/docs/segment_curvature.md b/docs/segment_curvature.md index 4c329febe..a0d4b0b58 100644 --- a/docs/segment_curvature.md +++ b/docs/segment_curvature.md @@ -2,7 +2,7 @@ Measure the curvature of segments. -**plantcv.morphology.segment_curvature**(*segmented_img, objects*) +**plantcv.morphology.segment_curvature**(*segmented_img, objects, label=None*) **returns** labeled image diff --git a/docs/segment_euclidean_length.md b/docs/segment_euclidean_length.md index ff6598d45..4a5d9c969 100644 --- a/docs/segment_euclidean_length.md +++ b/docs/segment_euclidean_length.md @@ -2,7 +2,7 @@ Measure Euclidean distance of segments. -**plantcv.morphology.segment_euclidean_length**(*segmented_img, objects*) +**plantcv.morphology.segment_euclidean_length**(*segmented_img, objects, label=None*) **returns** labeled image @@ -12,6 +12,7 @@ Measure Euclidean distance of segments. - objects - Segment objects (output from either [plantcv.morphology.prune](prune.md), [plantcv.morphology.segment_skeleton](segment_skeleton.md), or [plantcv.morphology.segment_sort](segment_sort.md)). + - label - Optional label parameter, modifies the variable name of observations recorded. (default `label=None`) - **Context:** - Calculates the euclidean distance of each segment. Users can pass only leaf objects (returned from [plantcv.morphology.segment_sort](segment_sort.md)) to only collect lengths of leaves. @@ -32,7 +33,7 @@ from plantcv import plantcv as pcv pcv.params.debug = "print" labeled_img = pcv.morphology.segment_euclidean_length(segmented_img=segmented_img, - objects=obj) + objects=obj, label=None) # Access data stored out from segment_euclidean_length euclidean_lengths = pcv.outputs.observations['segment_eu_length']['value'] From fc55c3e6ca237958e37a54d45dd3c1e676f983eb Mon Sep 17 00:00:00 2001 From: HaleySchuhl Date: Tue, 12 Jan 2021 08:31:57 -0600 Subject: [PATCH 022/137] Update segment_insertion_angle.md --- docs/segment_insertion_angle.md | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/docs/segment_insertion_angle.md b/docs/segment_insertion_angle.md index fdf22e74a..9fa73fc22 100644 --- a/docs/segment_insertion_angle.md +++ b/docs/segment_insertion_angle.md @@ -2,7 +2,7 @@ Measure leaf insertion angles. -**plantcv.morphology.segment_insertion_angle**(*skel_img, segmented_img, leaf_objects, stem_objects, size*) +**plantcv.morphology.segment_insertion_angle**(*skel_img, segmented_img, leaf_objects, stem_objects, size, label=None*) **returns** labeled image @@ -14,6 +14,7 @@ Measure leaf insertion angles. - leaf_objects - Leaf segment objects (output from [plantcv.morphology.segment_sort](segment_sort.md)). - stem_objects - Stem segment objects (output from [plantcv.morphology.segment_sort](segment_sort.md)). - size - Size of ends (number of pixels) used to calculate insertion point "tangent" lines + - label - Optional label parameter, modifies the variable name of observations recorded. (default `label=None`) - **Context:** - Find "tangent" angles to leaf insertion points in degrees of skeleton segments compared to the stem angle. Use `size` pixels of the inner portion of each leaf to find a linear regression line, and calculate angle between insertion @@ -41,7 +42,7 @@ labeled_img = pcv.morphology.segment_insertion_angle(skel_img=skeleton, segmented_img=leaves_segment, leaf_objects=leaf_obj, stem_objects=stem_objs, - size=20) + size=20, label=None) # Access data stored out from segment_insertion_angle segment_insertion_angles = pcv.outputs.observations['segment_insertion_angle']['value'] From fbdf42b9fe5d13c64bac05766b6a6ceadb23070a Mon Sep 17 00:00:00 2001 From: HaleySchuhl Date: Tue, 12 Jan 2021 08:32:19 -0600 Subject: [PATCH 023/137] Update segment_pathlength.md --- docs/segment_pathlength.md | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/docs/segment_pathlength.md b/docs/segment_pathlength.md index 638177e42..38cd1e980 100644 --- a/docs/segment_pathlength.md +++ b/docs/segment_pathlength.md @@ -2,7 +2,7 @@ Measure the geodesic distance of segments. -**plantcv.morphology.segment_path_length**(*segmented_img, objects*) +**plantcv.morphology.segment_path_length**(*segmented_img, objects, label=None*) **returns** labeled_image @@ -12,6 +12,7 @@ Measure the geodesic distance of segments. - objects - Segment objects (output from either [plantcv.morphology.prune](prune.md), [plantcv.morphology.segment_skeleton](segment_skeleton.md), or [plantcv.morphology.segment_sort](segment_sort.md)). + - label - Optional label parameter, modifies the variable name of observations recorded. (default `label=None`) - **Context:** - Calculates the geodesic distance of each segment. Users can pass only leaf objects (returned from [plantcv.morphology.segment_sort](segment_sort.md)) to only collect lengths of leaves only. @@ -32,7 +33,7 @@ from plantcv import plantcv as pcv pcv.params.debug = "print" labeled_img = pcv.morphology.segment_path_length(segmented_img=segmented_img, - objects=obj) + objects=obj, label=None) # Access data stored out from segment_path_length path_lengths = pcv.outputs.observations['segment_path_length']['value'] From 26efa6077a21c9804a87fa546e8db51bb22b5a7d Mon Sep 17 00:00:00 2001 From: HaleySchuhl Date: Tue, 12 Jan 2021 08:32:46 -0600 Subject: [PATCH 024/137] Update segment_tangent_angle.md --- docs/segment_tangent_angle.md | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/docs/segment_tangent_angle.md b/docs/segment_tangent_angle.md index 18342b1de..e77921a37 100644 --- a/docs/segment_tangent_angle.md +++ b/docs/segment_tangent_angle.md @@ -2,7 +2,7 @@ Measure tangent angles of segments as a way to quantify leaf behavior. -**plantcv.morphology.segment_tangent_angle**(*segmented_img, objects, size*) +**plantcv.morphology.segment_tangent_angle**(*segmented_img, objects, size, label=None*) **returns** labeled image @@ -13,6 +13,7 @@ Measure tangent angles of segments as a way to quantify leaf behavior. [plantcv.morphology.segment_skeleton](segment_skeleton.md), or [plantcv.morphology.segment_sort](segment_sort.md)). - size - Size of ends (number of pixels) used to calculate "tangent" lines + - label - Optional label parameter, modifies the variable name of observations recorded. (default `label=None`) - **Context:** - Find 'tangent' angles in degrees of skeleton segments. Use `size` pixels on either end of each segment to find a linear regression line, and calculate angle between the two lines @@ -39,7 +40,7 @@ pcv.params.line_thickness = 3 labeled_img = pcv.morphology.segment_tangent_angle(segmented_img=leaves_segment, objects=leaf_obj, - size=15) + size=15, label=None) # Access data stored out from segment_tangent_angle leaf_tangent_angles = pcv.outputs.observations['segment_tangent_angle']['value'] From 3aed0ef57090bffd7e35da4b9e585a62eb182e97 Mon Sep 17 00:00:00 2001 From: HaleySchuhl Date: Tue, 12 Jan 2021 08:39:23 -0600 Subject: [PATCH 025/137] Update updating.md --- docs/updating.md | 13 ++++++++++++- 1 file changed, 12 insertions(+), 1 deletion(-) diff --git a/docs/updating.md b/docs/updating.md index c7f5721e9..7b290e80a 100644 --- a/docs/updating.md +++ b/docs/updating.md @@ -329,11 +329,13 @@ pages for more details on the input and output variable types. * pre v3.7: NA * post v3.7: **plantcv.hyperspectral.analyze_index**(*index_array, mask*) * post v3.8: index_histogram = **plantcv.hyperspectral.analyze_index**(*index_array, mask, histplot=False, bins=100, max_bin=0, min_bin=1*) +* post v3.11: index_histogram = **plantcv.hyperspectral.analyze_index**(*index_array, mask, histplot=False, bins=100, max_bin=0, min_bin=1, label=None*) #### plantcv.hyperspectral.analyze_spectral * pre v3.7: NA * post v3.7: spectral_histogram = **plantcv.hyperspectral.analyze_spectral**(*array, mask, histplot=True*) +* post v3.11: spectral_histogram =**plantcv.hyperspectral.analyze_spectral**(*array, mask, histplot=True, label=None*) #### plantcv.hyperspectral.extract_index @@ -394,21 +396,25 @@ pages for more details on the input and output variable types. * pre v3.8: NA * post v3.8: labeled_img = **plantcv.morphology.analyze_stem**(*rgb_img, stem_objects*) +* post v3.11: labeled_img = **plantcv.morphology.analyze_stem**(*rgb_img, stem_objects, label=None*) #### plantcv.morphology.check_cycles * pre v3.3: NA * post v3.3: cycle_img = **plantcv.morphology.check_cycles**(*skel_img*) +* post v3.11: cycle_img = **plantcv.morphology.check_cycles**(*skel_img, label=None*) #### plantcv.morphology.find_branch_pts * pre v3.3: NA * post v3.3: branch_pts_img = **plantcv.morphology.find_branch_pts**(*skel_img, mask=None*) +* post v3.11: branch_pts_img = **plantcv.morphology.find_branch_pts**(*skel_img, mask=None, label=None*) #### plantcv.morphology.find_tips * pre v3.3: NA * post v3.3: tip_img = **plantcv.morphology.find_tips**(*skel_img, mask=None*) +* post v3.11: tip_img = **plantcv.morphology.find_tips**(*skel_img, mask=None, label=None*) #### plantcv.morphology.prune @@ -420,16 +426,19 @@ pages for more details on the input and output variable types. * pre v3.3: NA * post v3.3: labeled_img = **plantcv.morphology.segment_angle**(*segmented_img, objects*) +* post v3.11: labeled_img = **plantcv.morphology.segment_angle**(*segmented_img, objects, label=None*) -#### plantcv.morphology.curvature +#### plantcv.morphology.segment_curvature * pre v3.3: NA * post v3.3: labeled_img = **plantcv.morphology.segment_curvature**(*segmented_img, objects*) +* post v3.11: labeled_img = **plantcv.morphology.segment_curvature**(*segmented_img, objects, label=None*) #### plantcv.morphology.segment_euclidean_length * pre v3.3: NA * post v3.3: labeled_img = **plantcv.morphology.segment_euclidean_length**(*segmented_img, objects*) +* post v3.11: labeled_img = **plantcv.morphology.segment_euclidean_length**(*segmented_img, objects, label=None*) #### plantcv.morphology.segment_id @@ -440,6 +449,7 @@ pages for more details on the input and output variable types. * pre v3.3: NA * post v3.3: labeled_img = **plantcv.morphology.segment_path_length**(*segmented_img, objects*) +* post v3.11: labeled_img = **plantcv.morphology.segment_path_length**(*segmented_img, objects, label=None*) #### plantcv.morphology.segment_skeleton @@ -455,6 +465,7 @@ pages for more details on the input and output variable types. * pre v3.3: NA * post v3.3: labeled_img = **plantcv.morphology.segment_tangent_angle**(*segmented_img, objects, size*) +* post v3.11: labeled_img = **plantcv.morphology.segment_tangent_angle**(*segmented_img, objects, size, label=None*) #### plantcv.morphology.skeletontize From fc89353c97bc1acb12e2d400386192d9ce85ac4d Mon Sep 17 00:00:00 2001 From: Haley Schuhl <44006936+HaleySchuhl@users.noreply.github.com> Date: Tue, 12 Jan 2021 15:17:03 -0600 Subject: [PATCH 026/137] Update fill_segments.py --- plantcv/plantcv/morphology/fill_segments.py | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/plantcv/plantcv/morphology/fill_segments.py b/plantcv/plantcv/morphology/fill_segments.py index 7717b8e84..fd8f40e8d 100644 --- a/plantcv/plantcv/morphology/fill_segments.py +++ b/plantcv/plantcv/morphology/fill_segments.py @@ -45,7 +45,13 @@ def fill_segments(mask, objects, stem_objects=None, label=None): # Count area in pixels of each segment ids, counts = np.unique(filled_mask, return_counts=True) - outputs.add_observation(variable='segment_area', trait='segment area', + + if label == None: + prefix = "" + else: + prefix = label + "_" + + outputs.add_observation(variable=prefix + 'segment_area', trait='segment area', method='plantcv.plantcv.morphology.fill_segments', scale='pixels', datatype=list, value=counts[1:].tolist(), From bcd167cd5bd536ebdbc484769682701e67189f06 Mon Sep 17 00:00:00 2001 From: HaleySchuhl Date: Tue, 12 Jan 2021 15:22:56 -0600 Subject: [PATCH 027/137] add prefix to image filename for print debug option --- plantcv/plantcv/morphology/fill_segments.py | 2 +- plantcv/plantcv/morphology/find_branch_pts.py | 2 +- plantcv/plantcv/morphology/segment_combine.py | 2 +- plantcv/plantcv/morphology/segment_path_length.py | 3 ++- plantcv/plantcv/morphology/segment_tangent_angle.py | 3 ++- 5 files changed, 7 insertions(+), 5 deletions(-) diff --git a/plantcv/plantcv/morphology/fill_segments.py b/plantcv/plantcv/morphology/fill_segments.py index 7717b8e84..f07d3a2d3 100644 --- a/plantcv/plantcv/morphology/fill_segments.py +++ b/plantcv/plantcv/morphology/fill_segments.py @@ -58,7 +58,7 @@ def fill_segments(mask, objects, stem_objects=None, label=None): filled_img[:,:,ch][filled_mask==l] = rgb_vals[l-1][ch] if params.debug == 'print': - print_image(filled_img, os.path.join(params.debug_outdir, str(params.device) + '_filled_img.png')) + print_image(filled_img, os.path.join(params.debug_outdir, str(params.device) + prefix + '_filled_img.png')) elif params.debug == 'plot': plot_image(filled_img) diff --git a/plantcv/plantcv/morphology/find_branch_pts.py b/plantcv/plantcv/morphology/find_branch_pts.py index 0834922ed..206f5af2d 100644 --- a/plantcv/plantcv/morphology/find_branch_pts.py +++ b/plantcv/plantcv/morphology/find_branch_pts.py @@ -111,7 +111,7 @@ def find_branch_pts(skel_img, mask=None, label=None): params.device += 1 if params.debug == 'print': - print_image(branch_plot, os.path.join(params.debug_outdir, str(params.device) + '_branch_pts.png')) + print_image(branch_plot, os.path.join(params.debug_outdir, str(params.device) + prefix + '_branch_pts.png')) elif params.debug == 'plot': plot_image(branch_plot) diff --git a/plantcv/plantcv/morphology/segment_combine.py b/plantcv/plantcv/morphology/segment_combine.py index e0ff864d4..9cfb74c92 100644 --- a/plantcv/plantcv/morphology/segment_combine.py +++ b/plantcv/plantcv/morphology/segment_combine.py @@ -101,7 +101,7 @@ def segment_combine(segment_list, objects, mask): if params.debug == 'print': print_image(labeled_img, - os.path.join(params.debug_outdir, str(params.device) + '_combined_segment_ids.png')) + os.path.join(params.debug_outdir, str(params.device) + prefix + '_combined_segment_ids.png')) elif params.debug == 'plot': plot_image(labeled_img) diff --git a/plantcv/plantcv/morphology/segment_path_length.py b/plantcv/plantcv/morphology/segment_path_length.py index 4ca3c0bde..868d13bcc 100644 --- a/plantcv/plantcv/morphology/segment_path_length.py +++ b/plantcv/plantcv/morphology/segment_path_length.py @@ -61,7 +61,8 @@ def segment_path_length(segmented_img, objects, label=None): params.device += 1 if params.debug == 'print': - print_image(labeled_img, os.path.join(params.debug_outdir, str(params.device) + '_segment_path_lengths.png')) + print_image(labeled_img, os.path.join(params.debug_outdir, str(params.device) + prefix + + '_segment_path_lengths.png')) elif params.debug == 'plot': plot_image(labeled_img) diff --git a/plantcv/plantcv/morphology/segment_tangent_angle.py b/plantcv/plantcv/morphology/segment_tangent_angle.py index 6d55944b2..a4ff21df9 100644 --- a/plantcv/plantcv/morphology/segment_tangent_angle.py +++ b/plantcv/plantcv/morphology/segment_tangent_angle.py @@ -138,7 +138,8 @@ def segment_tangent_angle(segmented_img, objects, size, label=None): params.device += 1 if params.debug == 'print': - print_image(labeled_img, os.path.join(params.debug_outdir, str(params.device) + '_segment_tangent_angles.png')) + print_image(labeled_img, os.path.join(params.debug_outdir, str(params.device) + prefix + + '_segment_tangent_angles.png')) elif params.debug == 'plot': plot_image(labeled_img) From e039955f736d28826474facc876e35215ed27c93 Mon Sep 17 00:00:00 2001 From: HaleySchuhl Date: Tue, 12 Jan 2021 15:30:34 -0600 Subject: [PATCH 028/137] Update segment_combine.py didn't mean to update this --- plantcv/plantcv/morphology/segment_combine.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/plantcv/plantcv/morphology/segment_combine.py b/plantcv/plantcv/morphology/segment_combine.py index 9cfb74c92..e0ff864d4 100644 --- a/plantcv/plantcv/morphology/segment_combine.py +++ b/plantcv/plantcv/morphology/segment_combine.py @@ -101,7 +101,7 @@ def segment_combine(segment_list, objects, mask): if params.debug == 'print': print_image(labeled_img, - os.path.join(params.debug_outdir, str(params.device) + prefix + '_combined_segment_ids.png')) + os.path.join(params.debug_outdir, str(params.device) + '_combined_segment_ids.png')) elif params.debug == 'plot': plot_image(labeled_img) From b9adc7e43a682a29adb0df1f32575958720b9760 Mon Sep 17 00:00:00 2001 From: HaleySchuhl Date: Tue, 12 Jan 2021 15:45:10 -0600 Subject: [PATCH 029/137] update sub-package functions --- .../plantcv/photosynthesis/analyze_fvfm.py | 27 ++++++++++++------- plantcv/plantcv/transform/color_correction.py | 16 ++++++++--- plantcv/plantcv/visualize/pseudocolor.py | 1 - 3 files changed, 30 insertions(+), 14 deletions(-) diff --git a/plantcv/plantcv/photosynthesis/analyze_fvfm.py b/plantcv/plantcv/photosynthesis/analyze_fvfm.py index 87b1f48fa..e20343d30 100755 --- a/plantcv/plantcv/photosynthesis/analyze_fvfm.py +++ b/plantcv/plantcv/photosynthesis/analyze_fvfm.py @@ -12,7 +12,7 @@ from plantcv.plantcv import outputs -def analyze_fvfm(fdark, fmin, fmax, mask, bins=256): +def analyze_fvfm(fdark, fmin, fmax, mask, bins=256, label=None): """Analyze PSII camera images. Inputs: fdark = grayscale fdark image @@ -20,6 +20,8 @@ def analyze_fvfm(fdark, fmin, fmax, mask, bins=256): fmax = grayscale fmax image mask = mask of plant (binary, single channel) bins = number of bins (1 to 256 for 8-bit; 1 to 65,536 for 16-bit; default is 256) + label = optional label parameter, modifies the variable name of observations recorded + Returns: analysis_images = list of images (fv image and fvfm histogram image) :param fdark: numpy.ndarray @@ -27,6 +29,7 @@ def analyze_fvfm(fdark, fmin, fmax, mask, bins=256): :param fmax: numpy.ndarray :param mask: numpy.ndarray :param bins: int + :param label: str :return analysis_images: numpy.ndarray """ @@ -86,27 +89,33 @@ def analyze_fvfm(fdark, fmin, fmax, mask, bins=256): x=.15, y=205, size=8, color='green')) analysis_images.append(fvfm_hist_fig) + if label == None: + prefix = "" + else: + prefix = label + "_" + if params.debug == 'print': - print_image(fmin_mask, os.path.join(params.debug_outdir, str(params.device) + '_fmin_mask.png')) - print_image(fmax_mask, os.path.join(params.debug_outdir, str(params.device) + '_fmax_mask.png')) - print_image(fv, os.path.join(params.debug_outdir, str(params.device) + '_fv_convert.png')) - fvfm_hist_fig.save(os.path.join(params.debug_outdir, str(params.device) + '_fv_hist.png'), verbose=False) + print_image(fmin_mask, os.path.join(params.debug_outdir, str(params.device) + prefix + '_fmin_mask.png')) + print_image(fmax_mask, os.path.join(params.debug_outdir, str(params.device) + prefix + '_fmax_mask.png')) + print_image(fv, os.path.join(params.debug_outdir, str(params.device) + prefix + '_fv_convert.png')) + fvfm_hist_fig.save(os.path.join(params.debug_outdir, str(params.device) + prefix + '_fv_hist.png'), + verbose=False) elif params.debug == 'plot': plot_image(fmin_mask, cmap='gray') plot_image(fmax_mask, cmap='gray') plot_image(fv, cmap='gray') print(fvfm_hist_fig) - outputs.add_observation(variable='fvfm_hist', trait='Fv/Fm frequencies', + outputs.add_observation(variable=prefix + 'fvfm_hist', trait='Fv/Fm frequencies', method='plantcv.plantcv.fluor_fvfm', scale='none', datatype=list, value=fvfm_hist.tolist(), label=np.around(midpoints, decimals=len(str(bins))).tolist()) - outputs.add_observation(variable='fvfm_hist_peak', trait='peak Fv/Fm value', + outputs.add_observation(variable=prefix + 'fvfm_hist_peak', trait='peak Fv/Fm value', method='plantcv.plantcv.fluor_fvfm', scale='none', datatype=float, value=float(max_bin), label='none') - outputs.add_observation(variable='fvfm_median', trait='Fv/Fm median', + outputs.add_observation(variable=prefix + 'fvfm_median', trait='Fv/Fm median', method='plantcv.plantcv.fluor_fvfm', scale='none', datatype=float, value=float(np.around(fvfm_median, decimals=4)), label='none') - outputs.add_observation(variable='fdark_passed_qc', trait='Fdark passed QC', + outputs.add_observation(variable=prefix + 'fdark_passed_qc', trait='Fdark passed QC', method='plantcv.plantcv.fluor_fvfm', scale='none', datatype=bool, value=qc_fdark, label='none') diff --git a/plantcv/plantcv/transform/color_correction.py b/plantcv/plantcv/transform/color_correction.py index 7e8b25656..7f5ac4601 100644 --- a/plantcv/plantcv/transform/color_correction.py +++ b/plantcv/plantcv/transform/color_correction.py @@ -481,7 +481,7 @@ def quick_color_check(target_matrix, source_matrix, num_chips): def find_color_card(rgb_img, threshold_type='adaptgauss', threshvalue=125, blurry=False, background='dark', - record_chip_size="median"): + record_chip_size="median", label=None): """Automatically detects a color card and output info to use in create_color_card_mask function Algorithm written by Brandon Hurr. Updated and implemented into PlantCV by Haley Schuhl. @@ -496,6 +496,7 @@ def find_color_card(rgb_img, threshold_type='adaptgauss', threshvalue=125, blurr is a dark background record_chip_size = Optional str for choosing chip size measurement to be recorded, either "median", "mean", or None + label = optional label parameter, modifies the variable name of observations recorded Returns: df = Dataframe containing information about the filtered contours @@ -508,6 +509,7 @@ def find_color_card(rgb_img, threshold_type='adaptgauss', threshvalue=125, blurr :param blurry: bool :param background: str :param record_chip_size: str + :param label: str :return df: pandas.core.frame.DataFrame :return start_coord: tuple :return spacing: tuple @@ -761,14 +763,20 @@ def find_color_card(rgb_img, threshold_type='adaptgauss', threshvalue=125, blurr chip_height = None chip_width = None # Store into global measurements - outputs.add_observation(variable='color_chip_size', trait='size of color card chips identified', + if label == None: + prefix = "" + else: + prefix = label + "_" + outputs.add_observation(variable=prefix + 'color_chip_size', trait='size of color card chips identified', method='plantcv.plantcv.transform.find_color_card', scale='none', datatype=float, value=chip_size, label=str(record_chip_size)) method = record_chip_size.lower() - outputs.add_observation(variable=f'{method}_color_chip_height', trait=f'{method} height of color card chips identified', + outputs.add_observation(variable=prefix + f'{method}_color_chip_height', + trait=f'{method} height of color card chips identified', method='plantcv.plantcv.transform.find_color_card', scale='none', datatype=float, value=chip_height, label=str(record_chip_size)) - outputs.add_observation(variable=f'{method}_color_chip_width', trait=f'{method} size of color card chips identified', + outputs.add_observation(variable=prefix + f'{method}_color_chip_width', + trait=f'{method} size of color card chips identified', method='plantcv.plantcv.transform.find_color_card', scale='none', datatype=float, value=chip_width, label=str(record_chip_size)) diff --git a/plantcv/plantcv/visualize/pseudocolor.py b/plantcv/plantcv/visualize/pseudocolor.py index 87c42b494..25de99990 100644 --- a/plantcv/plantcv/visualize/pseudocolor.py +++ b/plantcv/plantcv/visualize/pseudocolor.py @@ -5,7 +5,6 @@ import numpy as np from matplotlib import pyplot as plt from plantcv.plantcv import params -from plantcv.plantcv import plot_image from plantcv.plantcv import fatal_error From db778f509baba6110d9183ead70ad608bc017c0f Mon Sep 17 00:00:00 2001 From: HaleySchuhl Date: Thu, 14 Jan 2021 10:15:53 -0600 Subject: [PATCH 030/137] Update color_correction.py --- plantcv/plantcv/transform/color_correction.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/plantcv/plantcv/transform/color_correction.py b/plantcv/plantcv/transform/color_correction.py index 7f5ac4601..984bc46bd 100644 --- a/plantcv/plantcv/transform/color_correction.py +++ b/plantcv/plantcv/transform/color_correction.py @@ -496,7 +496,7 @@ def find_color_card(rgb_img, threshold_type='adaptgauss', threshvalue=125, blurr is a dark background record_chip_size = Optional str for choosing chip size measurement to be recorded, either "median", "mean", or None - label = optional label parameter, modifies the variable name of observations recorded + label = optional label parameter, modifies the variable name of observations recorded Returns: df = Dataframe containing information about the filtered contours From 7b77d5d201380be267d0da9f8adfc7146d3a7c9a Mon Sep 17 00:00:00 2001 From: HaleySchuhl Date: Thu, 14 Jan 2021 10:23:46 -0600 Subject: [PATCH 031/137] Update acute_vertex.py --- plantcv/plantcv/acute_vertex.py | 14 +++++++++++--- 1 file changed, 11 insertions(+), 3 deletions(-) diff --git a/plantcv/plantcv/acute_vertex.py b/plantcv/plantcv/acute_vertex.py index 6fe6941c2..0caf4a849 100755 --- a/plantcv/plantcv/acute_vertex.py +++ b/plantcv/plantcv/acute_vertex.py @@ -10,7 +10,7 @@ from plantcv.plantcv import outputs -def acute_vertex(img, obj, win, thresh, sep): +def acute_vertex(img, obj, win, thresh, sep, label=None): """acute_vertex: identify corners/acute angles of an object For each point in contour, get a point before (pre) and after (post) the point of interest, @@ -23,6 +23,8 @@ def acute_vertex(img, obj, win, thresh, sep): thresh = an threshold to set for acuteness; keep points with an angle more acute than the threshold (a value of 15 worked well for sample image) sep = the number of contour points to search within for the most acute value + label = optional label parameter, modifies the variable name of observations recorded + Returns: acute_points = list of acute points @@ -33,6 +35,7 @@ def acute_vertex(img, obj, win, thresh, sep): :param win: int :param thresh: int :param sep: int + :param label: str :return acute_points: ndarray :return img2: ndarray """ @@ -96,13 +99,18 @@ def acute_vertex(img, obj, win, thresh, sep): x, y = i.ravel() cv2.circle(img2, (x, y), params.line_thickness, (255, 0, 255), -1) + if label == None: + prefix = "" + else: + prefix = label + "_" + if params.debug == 'print': - print_image(img2, os.path.join(params.debug_outdir, str(params.device) + '_acute_vertices.png')) + print_image(img2, os.path.join(params.debug_outdir, str(params.device) + prefix + '_acute_vertices.png')) elif params.debug == 'plot': plot_image(img2) # Store into global measurements - outputs.add_observation(variable='tip_coordinates', trait='tip coordinates', + outputs.add_observation(variable=prefix + 'tip_coordinates', trait='tip coordinates', method='plantcv.plantcv.acute_vertex', scale='none', datatype=list, value=acute_points, label='none') From a1f7997bb670c5d909d7fd4681cd31dcb83f1b88 Mon Sep 17 00:00:00 2001 From: HaleySchuhl Date: Thu, 14 Jan 2021 10:28:10 -0600 Subject: [PATCH 032/137] Update analyze_bound_horizontal.py --- plantcv/plantcv/analyze_bound_horizontal.py | 23 ++++++++++++++------- 1 file changed, 15 insertions(+), 8 deletions(-) diff --git a/plantcv/plantcv/analyze_bound_horizontal.py b/plantcv/plantcv/analyze_bound_horizontal.py index f3b774bfc..3244019f0 100755 --- a/plantcv/plantcv/analyze_bound_horizontal.py +++ b/plantcv/plantcv/analyze_bound_horizontal.py @@ -9,7 +9,7 @@ from plantcv.plantcv import outputs -def analyze_bound_horizontal(img, obj, mask, line_position): +def analyze_bound_horizontal(img, obj, mask, line_position, label=None): """User-input boundary line tool Inputs: @@ -17,6 +17,7 @@ def analyze_bound_horizontal(img, obj, mask, line_position): obj = single or grouped contour object mask = Binary mask made from selected contours line_position = position of boundary line (a value of 0 would draw the line through the top of the image) + label = optional label parameter, modifies the variable name of observations recorded Returns: analysis_images = list of output images @@ -25,6 +26,7 @@ def analyze_bound_horizontal(img, obj, mask, line_position): :param obj: list :param mask: numpy.ndarray :param line_position: int + :param label: str :return analysis_images: list """ @@ -144,25 +146,30 @@ def analyze_bound_horizontal(img, obj, mask, line_position): plot_image(wback) plot_image(ori_img) - outputs.add_observation(variable='horizontal_reference_position', trait='horizontal reference position', + if label == None: + prefix = "" + else: + prefix = label + "_" + + outputs.add_observation(variable=prefix + 'horizontal_reference_position', trait='horizontal reference position', method='plantcv.plantcv.analyze_bound_horizontal', scale='none', datatype=int, value=line_position, label='none') - outputs.add_observation(variable='height_above_reference', trait='height above reference', + outputs.add_observation(variable=prefix + 'height_above_reference', trait='height above reference', method='plantcv.plantcv.analyze_bound_horizontal', scale='pixels', datatype=int, value=height_above_bound, label='pixels') - outputs.add_observation(variable='height_below_reference', trait='height_below_reference', + outputs.add_observation(variable=prefix + 'height_below_reference', trait='height_below_reference', method='plantcv.plantcv.analyze_bound_horizontal', scale='pixels', datatype=int, value=height_below_bound, label='pixels') - outputs.add_observation(variable='area_above_reference', trait='area above reference', + outputs.add_observation(variable=prefix + 'area_above_reference', trait='area above reference', method='plantcv.plantcv.analyze_bound_horizontal', scale='pixels', datatype=int, value=above_bound_area, label='pixels') - outputs.add_observation(variable='percent_area_above_reference', trait='percent area above reference', + outputs.add_observation(variable=prefix + 'percent_area_above_reference', trait='percent area above reference', method='plantcv.plantcv.analyze_bound_horizontal', scale='none', datatype=float, value=percent_bound_area_above, label='none') - outputs.add_observation(variable='area_below_reference', trait='area below reference', + outputs.add_observation(variable=prefix + 'area_below_reference', trait='area below reference', method='plantcv.plantcv.analyze_bound_horizontal', scale='pixels', datatype=int, value=below_bound_area, label='pixels') - outputs.add_observation(variable='percent_area_below_reference', trait='percent area below reference', + outputs.add_observation(variable=prefix + 'percent_area_below_reference', trait='percent area below reference', method='plantcv.plantcv.analyze_bound_horizontal', scale='none', datatype=float, value=percent_bound_area_below, label='none') From 120a35f62274b00bf43f526ccdadefea81b76436 Mon Sep 17 00:00:00 2001 From: HaleySchuhl Date: Thu, 14 Jan 2021 10:30:07 -0600 Subject: [PATCH 033/137] Update analyze_bound_vertical.py --- plantcv/plantcv/analyze_bound_vertical.py | 23 +++++++++++++++-------- 1 file changed, 15 insertions(+), 8 deletions(-) diff --git a/plantcv/plantcv/analyze_bound_vertical.py b/plantcv/plantcv/analyze_bound_vertical.py index e4868a5d7..6906cc310 100755 --- a/plantcv/plantcv/analyze_bound_vertical.py +++ b/plantcv/plantcv/analyze_bound_vertical.py @@ -9,7 +9,7 @@ from plantcv.plantcv import outputs -def analyze_bound_vertical(img, obj, mask, line_position): +def analyze_bound_vertical(img, obj, mask, line_position, label=None): """User-input boundary line tool Inputs: @@ -19,6 +19,7 @@ def analyze_bound_vertical(img, obj, mask, line_position): 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 Returns: analysis_images = output images @@ -27,6 +28,7 @@ def analyze_bound_vertical(img, obj, mask, line_position): :param obj: list :param mask: numpy.ndarray :param line_position: int + :param label: str :return analysis_images: list """ ori_img = np.copy(img) @@ -144,25 +146,30 @@ def analyze_bound_vertical(img, obj, mask, line_position): plot_image(wback) plot_image(ori_img) - outputs.add_observation(variable='vertical_reference_position', trait='vertical reference position', + if label == None: + prefix = "" + else: + prefix = label + "_" + + outputs.add_observation(variable=prefix + 'vertical_reference_position', trait='vertical reference position', method='plantcv.plantcv.analyze_bound_vertical', scale='none', datatype=int, value=line_position, label='none') - outputs.add_observation(variable='width_left_reference', trait='width left of reference', + outputs.add_observation(variable=prefix + 'width_left_reference', trait='width left of reference', method='plantcv.plantcv.analyze_bound_vertical', scale='pixels', datatype=int, value=width_left_bound, label='pixels') - outputs.add_observation(variable='width_right_reference', trait='width right of reference', + outputs.add_observation(variable=prefix + 'width_right_reference', trait='width right of reference', method='plantcv.plantcv.analyze_bound_vertical', scale='pixels', datatype=int, value=width_right_bound, label='pixels') - outputs.add_observation(variable='area_left_reference', trait='area left of reference', + outputs.add_observation(variable=prefix + 'area_left_reference', trait='area left of reference', method='plantcv.plantcv.analyze_bound_vertical', scale='pixels', datatype=int, value=left_bound_area, label='pixels') - outputs.add_observation(variable='percent_area_left_reference', trait='percent area left of reference', + outputs.add_observation(variable=prefix + 'percent_area_left_reference', trait='percent area left of reference', method='plantcv.plantcv.analyze_bound_vertical', scale='none', datatype=float, value=percent_bound_area_left, label='none') - outputs.add_observation(variable='area_right_reference', trait='area right of reference', + outputs.add_observation(variable=prefix + 'area_right_reference', trait='area right of reference', method='plantcv.plantcv.analyze_bound_vertical', scale='pixels', datatype=int, value=right_bound_area, label='pixels') - outputs.add_observation(variable='percent_area_right_reference', trait='percent area right of reference', + outputs.add_observation(variable=prefix + 'percent_area_right_reference', trait='percent area right of reference', method='plantcv.plantcv.analyze_bound_vertical', scale='none', datatype=float, value=percent_bound_area_right, label='none') From 0019a37c14d7d9ef0d73279f4554aa58e24c170d Mon Sep 17 00:00:00 2001 From: HaleySchuhl Date: Thu, 14 Jan 2021 10:32:55 -0600 Subject: [PATCH 034/137] Update analyze_color.py --- plantcv/plantcv/analyze_color.py | 34 ++++++++++++++++++++------------ 1 file changed, 21 insertions(+), 13 deletions(-) diff --git a/plantcv/plantcv/analyze_color.py b/plantcv/plantcv/analyze_color.py index df6bc819d..f9f1ae3c2 100755 --- a/plantcv/plantcv/analyze_color.py +++ b/plantcv/plantcv/analyze_color.py @@ -9,12 +9,13 @@ from plantcv.plantcv import outputs -def analyze_color(rgb_img, mask, hist_plot_type=None): +def analyze_color(rgb_img, mask, hist_plot_type=None, label=None): """Analyze the color properties of an image object Inputs: rgb_img = RGB image data mask = Binary mask made from selected contours hist_plot_type = None, 'all', 'rgb','lab' or 'hsv' + label = optional label parameter, modifies the variable name of observations recorded Returns: analysis_image = histogram output @@ -22,6 +23,7 @@ def analyze_color(rgb_img, mask, hist_plot_type=None): :param rgb_img: numpy.ndarray :param mask: numpy.ndarray :param hist_plot_type: str + :param label: str :return analysis_images: list """ if len(np.shape(rgb_img)) < 3: @@ -158,48 +160,54 @@ def analyze_color(rgb_img, mask, hist_plot_type=None): percent_values = [round((i / 255) * 100, 2) for i in range(0, 256)] # Diverging values on a -128 to 127 scale (green-magenta and blue-yellow) diverging_values = [i for i in range(-128, 128)] + + if label == None: + prefix = "" + else: + prefix = label + "_" + if hist_plot_type is not None: if hist_plot_type.upper() == 'RGB' or hist_plot_type.upper() == 'ALL': - outputs.add_observation(variable='blue_frequencies', trait='blue frequencies', + outputs.add_observation(variable=prefix + 'blue_frequencies', trait='blue frequencies', method='plantcv.plantcv.analyze_color', scale='frequency', datatype=list, value=histograms["b"]["hist"], label=rgb_values) - outputs.add_observation(variable='green_frequencies', trait='green frequencies', + outputs.add_observation(variable=prefix + 'green_frequencies', trait='green frequencies', method='plantcv.plantcv.analyze_color', scale='frequency', datatype=list, value=histograms["g"]["hist"], label=rgb_values) - outputs.add_observation(variable='red_frequencies', trait='red frequencies', + outputs.add_observation(variable=prefix + 'red_frequencies', trait='red frequencies', method='plantcv.plantcv.analyze_color', scale='frequency', datatype=list, value=histograms["r"]["hist"], label=rgb_values) if hist_plot_type.upper() == 'LAB' or hist_plot_type.upper() == 'ALL': - outputs.add_observation(variable='lightness_frequencies', trait='lightness frequencies', + outputs.add_observation(variable=prefix + 'lightness_frequencies', trait='lightness frequencies', method='plantcv.plantcv.analyze_color', scale='frequency', datatype=list, value=histograms["l"]["hist"], label=percent_values) - outputs.add_observation(variable='green-magenta_frequencies', trait='green-magenta frequencies', + outputs.add_observation(variable=prefix + 'green-magenta_frequencies', trait='green-magenta frequencies', method='plantcv.plantcv.analyze_color', scale='frequency', datatype=list, value=histograms["m"]["hist"], label=diverging_values) - outputs.add_observation(variable='blue-yellow_frequencies', trait='blue-yellow frequencies', + outputs.add_observation(variable=prefix + 'blue-yellow_frequencies', trait='blue-yellow frequencies', method='plantcv.plantcv.analyze_color', scale='frequency', datatype=list, value=histograms["y"]["hist"], label=diverging_values) if hist_plot_type.upper() == 'HSV' or hist_plot_type.upper() == 'ALL': - outputs.add_observation(variable='hue_frequencies', trait='hue frequencies', + outputs.add_observation(variable=prefix + 'hue_frequencies', trait='hue frequencies', method='plantcv.plantcv.analyze_color', scale='frequency', datatype=list, value=histograms["h"]["hist"][0:180], label=hue_values) - outputs.add_observation(variable='saturation_frequencies', trait='saturation frequencies', + outputs.add_observation(variable=prefix + 'saturation_frequencies', trait='saturation frequencies', method='plantcv.plantcv.analyze_color', scale='frequency', datatype=list, value=histograms["s"]["hist"], label=percent_values) - outputs.add_observation(variable='value_frequencies', trait='value frequencies', + outputs.add_observation(variable=prefix + 'value_frequencies', trait='value frequencies', method='plantcv.plantcv.analyze_color', scale='frequency', datatype=list, value=histograms["v"]["hist"], label=percent_values) # Always save hue stats - outputs.add_observation(variable='hue_circular_mean', trait='hue circular mean', + outputs.add_observation(variable=prefix + 'hue_circular_mean', trait='hue circular mean', method='plantcv.plantcv.analyze_color', scale='degrees', datatype=float, value=hue_circular_mean, label='degrees') - outputs.add_observation(variable='hue_circular_std', trait='hue circular standard deviation', + outputs.add_observation(variable=prefix + 'hue_circular_std', trait='hue circular standard deviation', method='plantcv.plantcv.analyze_color', scale='degrees', datatype=float, value=hue_circular_std, label='degrees') - outputs.add_observation(variable='hue_median', trait='hue median', + outputs.add_observation(variable=prefix + 'hue_median', trait='hue median', method='plantcv.plantcv.analyze_color', scale='degrees', datatype=float, value=hue_median, label='degrees') From 55bdbbe8e522691eeb90c5fa97cc505df29cbb02 Mon Sep 17 00:00:00 2001 From: HaleySchuhl Date: Thu, 14 Jan 2021 10:34:07 -0600 Subject: [PATCH 035/137] Update analyze_nir_intensity.py --- plantcv/plantcv/analyze_nir_intensity.py | 17 ++++++++++++----- 1 file changed, 12 insertions(+), 5 deletions(-) diff --git a/plantcv/plantcv/analyze_nir_intensity.py b/plantcv/plantcv/analyze_nir_intensity.py index 095cf1e78..e2a57a689 100755 --- a/plantcv/plantcv/analyze_nir_intensity.py +++ b/plantcv/plantcv/analyze_nir_intensity.py @@ -12,7 +12,7 @@ from plantcv.plantcv import outputs -def analyze_nir_intensity(gray_img, mask, bins=256, histplot=False): +def analyze_nir_intensity(gray_img, mask, bins=256, histplot=False, label=None): """This function calculates the intensity of each pixel associated with the plant and writes the values out to a file. It can also print out a histogram plot of pixel intensity and a pseudocolor image of the plant. @@ -21,6 +21,7 @@ def analyze_nir_intensity(gray_img, mask, bins=256, histplot=False): mask = Binary mask made from selected contours bins = number of classes to divide spectrum into histplot = if True plots histogram of intensity values + label = optional label parameter, modifies the variable name of observations recorded Returns: analysis_images = NIR histogram image @@ -29,6 +30,7 @@ def analyze_nir_intensity(gray_img, mask, bins=256, histplot=False): :param mask: numpy array :param bins: int :param histplot: bool + :param label: str :return analysis_images: plotnine ggplot """ # apply plant shaped mask to image @@ -91,16 +93,21 @@ def analyze_nir_intensity(gray_img, mask, bins=256, histplot=False): elif params.debug == "plot": print(fig_hist) - outputs.add_observation(variable='nir_frequencies', trait='near-infrared frequencies', + if label == None: + prefix = "" + else: + prefix = label + "_" + + outputs.add_observation(variable=prefix + 'nir_frequencies', trait='near-infrared frequencies', method='plantcv.plantcv.analyze_nir_intensity', scale='frequency', datatype=list, value=hist_nir, label=bin_labels) - outputs.add_observation(variable='nir_mean', trait='near-infrared mean', + outputs.add_observation(variable=prefix + 'nir_mean', trait='near-infrared mean', method='plantcv.plantcv.analyze_nir_intensity', scale='none', datatype=float, value=masked_nir_mean, label='none') - outputs.add_observation(variable='nir_median', trait='near-infrared median', + outputs.add_observation(variable=prefix + 'nir_median', trait='near-infrared median', method='plantcv.plantcv.analyze_nir_intensity', scale='none', datatype=float, value=masked_nir_median, label='none') - outputs.add_observation(variable='nir_stdev', trait='near-infrared standard deviation', + outputs.add_observation(variable=prefix + 'nir_stdev', trait='near-infrared standard deviation', method='plantcv.plantcv.analyze_nir_intensity', scale='none', datatype=float, value=masked_nir_std, label='none') From 207e3d7a7f724e7541443ea1d4c228e8800efd61 Mon Sep 17 00:00:00 2001 From: HaleySchuhl Date: Thu, 14 Jan 2021 10:37:02 -0600 Subject: [PATCH 036/137] Update analyze_object.py --- plantcv/plantcv/analyze_object.py | 41 ++++++++++++++++++------------- 1 file changed, 24 insertions(+), 17 deletions(-) diff --git a/plantcv/plantcv/analyze_object.py b/plantcv/plantcv/analyze_object.py index 79770bd3a..2a8c8aaf7 100755 --- a/plantcv/plantcv/analyze_object.py +++ b/plantcv/plantcv/analyze_object.py @@ -10,13 +10,14 @@ from plantcv.plantcv import within_frame -def analyze_object(img, obj, mask): +def analyze_object(img, obj, mask, label=None): """Outputs numeric properties for an input object (contour or grouped contours). Inputs: img = RGB or grayscale image data for plotting obj = single or grouped contour object mask = Binary image to use as mask + label = optional label parameter, modifies the variable name of observations recorded Returns: analysis_images = list of output images @@ -24,6 +25,7 @@ def analyze_object(img, obj, mask): :param img: numpy.ndarray :param obj: list :param mask: numpy.ndarray + :param label: str :return analysis_images: list """ # Valid objects can only be analyzed if they have >= 5 vertices @@ -156,49 +158,54 @@ def analyze_object(img, obj, mask): else: pass - outputs.add_observation(variable='area', trait='area', + if label == None: + prefix = "" + else: + prefix = label + "_" + + outputs.add_observation(variable=prefix + 'area', trait='area', method='plantcv.plantcv.analyze_object', scale='pixels', datatype=int, value=area, label='pixels') - outputs.add_observation(variable='convex_hull_area', trait='convex hull area', + outputs.add_observation(variable=prefix + 'convex_hull_area', trait='convex hull area', method='plantcv.plantcv.analyze_object', scale='pixels', datatype=int, value=hull_area, label='pixels') - outputs.add_observation(variable='solidity', trait='solidity', + outputs.add_observation(variable=prefix + 'solidity', trait='solidity', method='plantcv.plantcv.analyze_object', scale='none', datatype=float, value=solidity, label='none') - outputs.add_observation(variable='perimeter', trait='perimeter', + outputs.add_observation(variable=prefix + 'perimeter', trait='perimeter', method='plantcv.plantcv.analyze_object', scale='pixels', datatype=int, value=perimeter, label='pixels') - outputs.add_observation(variable='width', trait='width', + outputs.add_observation(variable=prefix + 'width', trait='width', method='plantcv.plantcv.analyze_object', scale='pixels', datatype=int, value=width, label='pixels') - outputs.add_observation(variable='height', trait='height', + outputs.add_observation(variable=prefix + 'height', trait='height', method='plantcv.plantcv.analyze_object', scale='pixels', datatype=int, value=height, label='pixels') - outputs.add_observation(variable='longest_path', trait='longest path', + outputs.add_observation(variable=prefix + 'longest_path', trait='longest path', method='plantcv.plantcv.analyze_object', scale='pixels', datatype=int, value=caliper_length, label='pixels') - outputs.add_observation(variable='center_of_mass', trait='center of mass', + outputs.add_observation(variable=prefix + 'center_of_mass', trait='center of mass', method='plantcv.plantcv.analyze_object', scale='none', datatype=tuple, value=(cmx, cmy), label='none') - outputs.add_observation(variable='convex_hull_vertices', trait='convex hull vertices', + outputs.add_observation(variable=prefix + 'convex_hull_vertices', trait='convex hull vertices', method='plantcv.plantcv.analyze_object', scale='none', datatype=int, value=hull_vertices, label='none') - outputs.add_observation(variable='object_in_frame', trait='object in frame', + outputs.add_observation(variable=prefix + 'object_in_frame', trait='object in frame', method='plantcv.plantcv.analyze_object', scale='none', datatype=bool, value=in_bounds, label='none') - outputs.add_observation(variable='ellipse_center', trait='ellipse center', + outputs.add_observation(variable=prefix + 'ellipse_center', trait='ellipse center', method='plantcv.plantcv.analyze_object', scale='none', datatype=tuple, value=(center[0], center[1]), label='none') - outputs.add_observation(variable='ellipse_major_axis', trait='ellipse major axis length', + outputs.add_observation(variable=prefix + 'ellipse_major_axis', trait='ellipse major axis length', method='plantcv.plantcv.analyze_object', scale='pixels', datatype=int, value=major_axis_length, label='pixels') - outputs.add_observation(variable='ellipse_minor_axis', trait='ellipse minor axis length', + outputs.add_observation(variable=prefix + 'ellipse_minor_axis', trait='ellipse minor axis length', method='plantcv.plantcv.analyze_object', scale='pixels', datatype=int, value=minor_axis_length, label='pixels') - outputs.add_observation(variable='ellipse_angle', trait='ellipse major axis angle', + outputs.add_observation(variable=prefix + 'ellipse_angle', trait='ellipse major axis angle', method='plantcv.plantcv.analyze_object', scale='degrees', datatype=float, value=float(angle), label='degrees') - outputs.add_observation(variable='ellipse_eccentricity', trait='ellipse eccentricity', + outputs.add_observation(variable=prefix + 'ellipse_eccentricity', trait='ellipse eccentricity', method='plantcv.plantcv.analyze_object', scale='none', datatype=float, value=float(eccentricity), label='none') @@ -212,7 +219,7 @@ def analyze_object(img, obj, mask): cv2.line(ori_img, (tuple(caliper_transpose[caliper_length - 1])), (tuple(caliper_transpose[0])), (255, 0, 255), params.line_thickness) if params.debug == 'print': - print_image(ori_img, os.path.join(params.debug_outdir, str(params.device) + '_shapes.png')) + print_image(ori_img, os.path.join(params.debug_outdir, str(params.device) + prefix + '_shapes.png')) elif params.debug == 'plot': if len(np.shape(img)) == 3: plot_image(ori_img) From bfddbb6bc62cefa315cf979233fbe9aca5b882fe Mon Sep 17 00:00:00 2001 From: HaleySchuhl Date: Thu, 14 Jan 2021 10:38:59 -0600 Subject: [PATCH 037/137] Update analyze_thermal_values.py --- plantcv/plantcv/analyze_thermal_values.py | 22 +++++++++++++++------- 1 file changed, 15 insertions(+), 7 deletions(-) diff --git a/plantcv/plantcv/analyze_thermal_values.py b/plantcv/plantcv/analyze_thermal_values.py index 38d15f7ab..a7137f2ec 100755 --- a/plantcv/plantcv/analyze_thermal_values.py +++ b/plantcv/plantcv/analyze_thermal_values.py @@ -10,7 +10,7 @@ from plantcv.plantcv.threshold import binary as binary_threshold -def analyze_thermal_values(thermal_array, mask, histplot=False): +def analyze_thermal_values(thermal_array, mask, histplot=False, label=None): """This extracts the thermal values of each pixel writes the values out to a file. It can also print out a histogram plot of pixel intensity and a pseudocolor image of the plant. @@ -19,6 +19,7 @@ def analyze_thermal_values(thermal_array, mask, histplot=False): array = numpy array of thermal values mask = Binary mask made from selected contours histplot = if True plots histogram of intensity values + label = optional label parameter, modifies the variable name of observations recorded Returns: analysis_img = output image @@ -26,6 +27,7 @@ def analyze_thermal_values(thermal_array, mask, histplot=False): :param thermal_array: numpy.ndarray :param mask: numpy.ndarray :param histplot: bool + :param label: str :return analysis_img: ggplot """ max_value = np.amax(thermal_array) @@ -57,20 +59,25 @@ def analyze_thermal_values(thermal_array, mask, histplot=False): avgtemp = np.average(masked_thermal) mediantemp = np.median(masked_thermal) + if label == None: + prefix = "" + else: + prefix = label + "_" + # Store data into outputs class - outputs.add_observation(variable='max_temp', trait='maximum temperature', + outputs.add_observation(variable=prefix + 'max_temp', trait='maximum temperature', method='plantcv.plantcv.analyze_thermal_values', scale='degrees', datatype=float, value=maxtemp, label='degrees') - outputs.add_observation(variable='min_temp', trait='minimum temperature', + outputs.add_observation(variable=prefix + 'min_temp', trait='minimum temperature', method='plantcv.plantcv.analyze_thermal_values', scale='degrees', datatype=float, value=mintemp, label='degrees') - outputs.add_observation(variable='mean_temp', trait='mean temperature', + outputs.add_observation(variable=prefix + 'mean_temp', trait='mean temperature', method='plantcv.plantcv.analyze_thermal_values', scale='degrees', datatype=float, value=avgtemp, label='degrees') - outputs.add_observation(variable='median_temp', trait='median temperature', + outputs.add_observation(variable=prefix + 'median_temp', trait='median temperature', method='plantcv.plantcv.analyze_thermal_values', scale='degrees', datatype=float, value=mediantemp, label='degrees') - outputs.add_observation(variable='thermal_frequencies', trait='thermal frequencies', + outputs.add_observation(variable=prefix + 'thermal_frequencies', trait='thermal frequencies', method='plantcv.plantcv.analyze_thermal_values', scale='frequency', datatype=list, value=hist_percent, label=bin_labels) analysis_img = None @@ -87,7 +94,8 @@ def analyze_thermal_values(thermal_array, mask, histplot=False): analysis_img = fig_hist if params.debug == "print": - fig_hist.save(os.path.join(params.debug_outdir, str(params.device) + '_therm_histogram.png'), verbose=False) + fig_hist.save(os.path.join(params.debug_outdir, str(params.device) + prefix + '_therm_histogram.png'), + verbose=False) elif params.debug == "plot": print(fig_hist) From aa6a85aa7023bf8456cc2a85e7c623ff5462d2c1 Mon Sep 17 00:00:00 2001 From: HaleySchuhl Date: Thu, 14 Jan 2021 10:43:56 -0600 Subject: [PATCH 038/137] Update landmark_reference_pt_dist.py --- plantcv/plantcv/landmark_reference_pt_dist.py | 24 ++++++++++++------- 1 file changed, 15 insertions(+), 9 deletions(-) diff --git a/plantcv/plantcv/landmark_reference_pt_dist.py b/plantcv/plantcv/landmark_reference_pt_dist.py index 5d8f0e4b7..c24ee4231 100755 --- a/plantcv/plantcv/landmark_reference_pt_dist.py +++ b/plantcv/plantcv/landmark_reference_pt_dist.py @@ -7,7 +7,7 @@ from plantcv.plantcv import outputs -def landmark_reference_pt_dist(points_r, centroid_r, bline_r): +def landmark_reference_pt_dist(points_r, centroid_r, bline_r, label=None): """landmark_reference_pt_dist For each point in contour, get a point before (pre) and after (post) the point of interest. @@ -17,6 +17,7 @@ def landmark_reference_pt_dist(points_r, centroid_r, bline_r): points_r = a set of rescaled points (basically the output of the acute_vertex fxn after the scale_features fxn) centroid_r = a tuple that contains the rescaled centroid coordinates bline_r = a tuple that contains the rescaled boundary line - centroid coordinates + label = optional label parameter, modifies the variable name of observations recorded :param points_r: ndarray :param centroid_r: tuple @@ -92,27 +93,32 @@ def landmark_reference_pt_dist(points_r, centroid_r, bline_r): euc_ave_b = np.mean(euc_dist_b) ang_ave_b = np.mean(angles_b) - outputs.add_observation(variable='vert_ave_c', trait='average vertical distance from centroid', + if label == None: + prefix = "" + else: + prefix = label + "_" + + outputs.add_observation(variable=prefix + 'vert_ave_c', trait='average vertical distance from centroid', method='plantcv.plantcv.landmark_reference_pt_dist', scale='pixels', datatype=float, value=vert_ave_c, label='pixels') - outputs.add_observation(variable='hori_ave_c', trait='average horizontal distance from centeroid', + outputs.add_observation(variable=prefix + 'hori_ave_c', trait='average horizontal distance from centeroid', method='plantcv.plantcv.landmark_reference_pt_dist', scale='pixels', datatype=float, value=hori_ave_c, label='pixels') - outputs.add_observation(variable='euc_ave_c', trait='average euclidean distance from centroid', + outputs.add_observation(variable=prefix + 'euc_ave_c', trait='average euclidean distance from centroid', method='plantcv.plantcv.landmark_reference_pt_dist', scale='pixels', datatype=float, value=euc_ave_c, label='pixels') - outputs.add_observation(variable='ang_ave_c', trait='average angle between landmark point and centroid', + outputs.add_observation(variable=prefix + 'ang_ave_c', trait='average angle between landmark point and centroid', method='plantcv.plantcv.landmark_reference_pt_dist', scale='degrees', datatype=float, value=ang_ave_c, label='degrees') - outputs.add_observation(variable='vert_ave_b', trait='average vertical distance from baseline', + outputs.add_observation(variable=prefix + 'vert_ave_b', trait='average vertical distance from baseline', method='plantcv.plantcv.landmark_reference_pt_dist', scale='pixels', datatype=float, value=vert_ave_b, label='pixels') - outputs.add_observation(variable='hori_ave_b', trait='average horizontal distance from baseline', + outputs.add_observation(variable=prefix + 'hori_ave_b', trait='average horizontal distance from baseline', method='plantcv.plantcv.landmark_reference_pt_dist', scale='pixels', datatype=float, value=hori_ave_b, label='pixels') - outputs.add_observation(variable='euc_ave_b', trait='average euclidean distance from baseline', + outputs.add_observation(variable=prefix + 'euc_ave_b', trait='average euclidean distance from baseline', method='plantcv.plantcv.landmark_reference_pt_dist', scale='pixels', datatype=float, value=euc_ave_b, label='pixels') - outputs.add_observation(variable='ang_ave_b', trait='average angle between landmark point and baseline', + outputs.add_observation(variable=prefix + 'ang_ave_b', trait='average angle between landmark point and baseline', method='plantcv.plantcv.landmark_reference_pt_dist', scale='degrees', datatype=float, value=ang_ave_b, label='degrees') From 5791c14dd93ca6329d9336421c7e592ea54dd6a2 Mon Sep 17 00:00:00 2001 From: HaleySchuhl Date: Thu, 14 Jan 2021 10:45:23 -0600 Subject: [PATCH 039/137] Update opening.py --- plantcv/plantcv/opening.py | 2 ++ 1 file changed, 2 insertions(+) diff --git a/plantcv/plantcv/opening.py b/plantcv/plantcv/opening.py index ecf704f70..6235e9b77 100644 --- a/plantcv/plantcv/opening.py +++ b/plantcv/plantcv/opening.py @@ -1,3 +1,5 @@ +# Remove small bright spots + import os import numpy as np from skimage import morphology From d0f08b83e9ed4fd773b0206fba45653fc223847c Mon Sep 17 00:00:00 2001 From: HaleySchuhl Date: Thu, 14 Jan 2021 10:47:17 -0600 Subject: [PATCH 040/137] Update report_size_marker_area.py --- plantcv/plantcv/report_size_marker_area.py | 19 +++++++++++++------ 1 file changed, 13 insertions(+), 6 deletions(-) diff --git a/plantcv/plantcv/report_size_marker_area.py b/plantcv/plantcv/report_size_marker_area.py index 4c24e88f0..eb6fa9e39 100755 --- a/plantcv/plantcv/report_size_marker_area.py +++ b/plantcv/plantcv/report_size_marker_area.py @@ -17,7 +17,7 @@ def report_size_marker_area(img, roi_contour, roi_hierarchy, marker='define', objcolor='dark', thresh_channel=None, - thresh=None): + thresh=None, label=None): """Detects a size marker in a specified region and reports its size and eccentricity Inputs: @@ -29,6 +29,7 @@ def report_size_marker_area(img, roi_contour, roi_hierarchy, marker='define', ob objcolor = Object color is 'dark' or 'light' (is the marker darker or lighter than the background) thresh_channel = 'h', 's', or 'v' for hue, saturation or value thresh = Binary threshold value (integer) + label = optional label parameter, modifies the variable name of observations recorded Returns: analysis_images = List of output images @@ -40,6 +41,7 @@ def report_size_marker_area(img, roi_contour, roi_hierarchy, marker='define', ob :param objcolor: str :param thresh_channel: str :param thresh: int + :param label: str :return: analysis_images: list """ # Store debug @@ -119,21 +121,26 @@ def report_size_marker_area(img, roi_contour, roi_hierarchy, marker='define', ob # Reset debug mode params.debug = debug + if label == None: + prefix = "" + else: + prefix = label + "_" + if params.debug == 'print': - print_image(ref_img, os.path.join(params.debug_outdir, str(params.device) + '_marker_shape.png')) + print_image(ref_img, os.path.join(params.debug_outdir, str(params.device) + prefix + '_marker_shape.png')) elif params.debug == 'plot': plot_image(ref_img) - outputs.add_observation(variable='marker_area', trait='marker area', + outputs.add_observation(variable=prefix + 'marker_area', trait='marker area', method='plantcv.plantcv.report_size_marker_area', scale='pixels', datatype=int, value=marker_area, label='pixels') - outputs.add_observation(variable='marker_ellipse_major_axis', trait='marker ellipse major axis length', + outputs.add_observation(variable=prefix + 'marker_ellipse_major_axis', trait='marker ellipse major axis length', method='plantcv.plantcv.report_size_marker_area', scale='pixels', datatype=int, value=major_axis_length, label='pixels') - outputs.add_observation(variable='marker_ellipse_minor_axis', trait='marker ellipse minor axis length', + outputs.add_observation(variable=prefix + 'marker_ellipse_minor_axis', trait='marker ellipse minor axis length', method='plantcv.plantcv.report_size_marker_area', scale='pixels', datatype=int, value=minor_axis_length, label='pixels') - outputs.add_observation(variable='marker_ellipse_eccentricity', trait='marker ellipse eccentricity', + outputs.add_observation(variable=prefix + 'marker_ellipse_eccentricity', trait='marker ellipse eccentricity', method='plantcv.plantcv.report_size_marker_area', scale='none', datatype=float, value=eccentricity, label='none') From 216c94bde0109c6bc7ed3031e96e340e7a98a31d Mon Sep 17 00:00:00 2001 From: HaleySchuhl Date: Thu, 14 Jan 2021 10:48:15 -0600 Subject: [PATCH 041/137] Update roi_objects.py --- plantcv/plantcv/roi_objects.py | 2 ++ 1 file changed, 2 insertions(+) diff --git a/plantcv/plantcv/roi_objects.py b/plantcv/plantcv/roi_objects.py index cfc2b22cd..2574627ab 100755 --- a/plantcv/plantcv/roi_objects.py +++ b/plantcv/plantcv/roi_objects.py @@ -1,3 +1,5 @@ +# Find objects partially inside a region of interest or cuts objects to the ROI + import cv2 import numpy as np import os From 42bc1f0a5d4b93350ba6f29c0375e541e4bff196 Mon Sep 17 00:00:00 2001 From: HaleySchuhl Date: Thu, 14 Jan 2021 10:50:37 -0600 Subject: [PATCH 042/137] update watershed --- plantcv/plantcv/roi_objects.py | 2 +- plantcv/plantcv/watershed.py | 16 ++++++++++++---- 2 files changed, 13 insertions(+), 5 deletions(-) diff --git a/plantcv/plantcv/roi_objects.py b/plantcv/plantcv/roi_objects.py index 2574627ab..3ac9a30ff 100755 --- a/plantcv/plantcv/roi_objects.py +++ b/plantcv/plantcv/roi_objects.py @@ -1,4 +1,4 @@ -# Find objects partially inside a region of interest or cuts objects to the ROI +# Find objects partially inside a region of interest or cuts objects to the ROI import cv2 import numpy as np diff --git a/plantcv/plantcv/watershed.py b/plantcv/plantcv/watershed.py index 99b02c803..7d3313bb2 100755 --- a/plantcv/plantcv/watershed.py +++ b/plantcv/plantcv/watershed.py @@ -16,7 +16,7 @@ from plantcv.plantcv import outputs -def watershed_segmentation(rgb_img, mask, distance=10): +def watershed_segmentation(rgb_img, mask, distance=10, label=None): """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). @@ -24,6 +24,7 @@ def watershed_segmentation(rgb_img, mask, distance=10): rgb_img = image to perform watershed on needs to be 3D (i.e. np.shape = x,y,z not np.shape = x,y) mask = binary image, single channel, object in white and background black distance = min_distance of local maximum + label = optional label parameter, modifies the variable name of observations recorded Returns: analysis_images = list of output images @@ -31,6 +32,7 @@ def watershed_segmentation(rgb_img, mask, distance=10): :param rgb_img: numpy.ndarray :param mask: numpy.ndarray :param distance: int + :param label: str :return analysis_images: list """ params.device += 1 @@ -59,16 +61,22 @@ def watershed_segmentation(rgb_img, mask, distance=10): estimated_object_count = len(np.unique(markers)) - 1 + if label == None: + prefix = "" + else: + prefix = label + "_" + # 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')) + print_image(dist_transform, os.path.join(params.debug_outdir, str(params.device) + prefix + + '_watershed_dist_img.png')) + print_image(joined, os.path.join(params.debug_outdir, str(params.device) + prefix + '_watershed_img.png')) elif params.debug == 'plot': plot_image(dist_transform, cmap='gray') plot_image(joined) - outputs.add_observation(variable='estimated_object_count', trait='estimated object count', + outputs.add_observation(variable=prefix + 'estimated_object_count', trait='estimated object count', method='plantcv.plantcv.watershed', scale='none', datatype=int, value=estimated_object_count, label='none') From b63b4fa7a55685570d183ed3a1c7fc361d4e0de2 Mon Sep 17 00:00:00 2001 From: HaleySchuhl Date: Thu, 14 Jan 2021 10:52:00 -0600 Subject: [PATCH 043/137] Update within_frame.py --- plantcv/plantcv/within_frame.py | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/plantcv/plantcv/within_frame.py b/plantcv/plantcv/within_frame.py index 191d9fd1b..25be246e1 100644 --- a/plantcv/plantcv/within_frame.py +++ b/plantcv/plantcv/within_frame.py @@ -5,18 +5,20 @@ from plantcv.plantcv import outputs -def within_frame(mask, border_width=1): +def within_frame(mask, border_width=1, label=None): """ This function tests whether the plant touches the edge of the image, i.e. it is completely in the field of view. Input: mask = a binary image of 0 and nonzero values border_width = distance from border of image considered out of frame (default = 1) + label = optional label parameter, modifies the variable name of observations recorded Returns: in_bounds = a boolean (True or False) confirming that the object does not touch the edge of the image :param mask: numpy.ndarray :param border_width: int + :param label: str :return in_bounds: bool """ @@ -41,7 +43,12 @@ def within_frame(mask, border_width=1): out_of_bounds = bool(np.count_nonzero(border_pxs)) in_bounds = not out_of_bounds - outputs.add_observation(variable='in_bounds', trait='whether the plant goes out of bounds ', + if label == None: + prefix = "" + else: + prefix = label + "_" + + outputs.add_observation(variable=prefix + 'in_bounds', trait='whether the plant goes out of bounds ', method='plantcv.plantcv.within_frame', scale='none', datatype=bool, value=in_bounds, label='none') From 1380acfb0aa45e6e483d6d4e6f8f94877bf0fa09 Mon Sep 17 00:00:00 2001 From: HaleySchuhl Date: Thu, 14 Jan 2021 10:59:08 -0600 Subject: [PATCH 044/137] Update x_axis_pseudolandmarks.py --- plantcv/plantcv/x_axis_pseudolandmarks.py | 15 +++++++++++---- 1 file changed, 11 insertions(+), 4 deletions(-) diff --git a/plantcv/plantcv/x_axis_pseudolandmarks.py b/plantcv/plantcv/x_axis_pseudolandmarks.py index a007f6882..3709d2b2f 100755 --- a/plantcv/plantcv/x_axis_pseudolandmarks.py +++ b/plantcv/plantcv/x_axis_pseudolandmarks.py @@ -10,13 +10,14 @@ from plantcv.plantcv import fatal_error -def x_axis_pseudolandmarks(img, obj, mask): +def x_axis_pseudolandmarks(img, obj, mask, label=None): """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 obj = a contour of the plant object (this should be output from the object_composition.py fxn) mask = this is a binary image. The object should be white and the background should be black + label = optional label parameter, modifies the variable name of observations recorded Returns: top = List of landmark points within 'top' portion @@ -26,6 +27,7 @@ def x_axis_pseudolandmarks(img, obj, mask): :param img: numpy.ndarray :param obj: list :param mask: numpy.ndarray + :param label: str :return top: list :return bottom: list :return center_v: list @@ -216,13 +218,18 @@ def x_axis_pseudolandmarks(img, obj, mask): for pt in center_v: center_v_list.append(pt[0].tolist()) - outputs.add_observation(variable='top_lmk', trait='top landmark coordinates', + if label == None: + prefix = "" + else: + prefix = label + "_" + + outputs.add_observation(variable=prefix + 'top_lmk', trait='top landmark coordinates', method='plantcv.plantcv.x_axis_pseudolandmarks', scale='none', datatype=tuple, value=tuple(top_list), label='none') - outputs.add_observation(variable='bottom_lmk', trait='bottom landmark coordinates', + outputs.add_observation(variable=prefix + 'bottom_lmk', trait='bottom landmark coordinates', method='plantcv.plantcv.x_axis_pseudolandmarks', scale='none', datatype=tuple, value=tuple(bottom_list), label='none') - outputs.add_observation(variable='center_v_lmk', trait='center vertical landmark coordinates', + outputs.add_observation(variable=prefix + 'center_v_lmk', trait='center vertical landmark coordinates', method='plantcv.plantcv.x_axis_pseudolandmarks', scale='none', datatype=tuple, value=tuple(center_v_list), label='none') From 007f0e67b0a867418457d967bff8a68e88526d08 Mon Sep 17 00:00:00 2001 From: HaleySchuhl Date: Thu, 14 Jan 2021 10:59:13 -0600 Subject: [PATCH 045/137] Update within_frame.py --- plantcv/plantcv/within_frame.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/plantcv/plantcv/within_frame.py b/plantcv/plantcv/within_frame.py index 25be246e1..116080a76 100644 --- a/plantcv/plantcv/within_frame.py +++ b/plantcv/plantcv/within_frame.py @@ -18,7 +18,7 @@ def within_frame(mask, border_width=1, label=None): :param mask: numpy.ndarray :param border_width: int - :param label: str + :param label: str :return in_bounds: bool """ From d795b2189df6c8066f9332db6b5606bd5738b57a Mon Sep 17 00:00:00 2001 From: HaleySchuhl Date: Thu, 14 Jan 2021 11:01:50 -0600 Subject: [PATCH 046/137] Update y_axis_pseudolandmarks.py --- plantcv/plantcv/y_axis_pseudolandmarks.py | 15 +++++++++++---- 1 file changed, 11 insertions(+), 4 deletions(-) diff --git a/plantcv/plantcv/y_axis_pseudolandmarks.py b/plantcv/plantcv/y_axis_pseudolandmarks.py index c08f0e146..1c3753b65 100755 --- a/plantcv/plantcv/y_axis_pseudolandmarks.py +++ b/plantcv/plantcv/y_axis_pseudolandmarks.py @@ -10,13 +10,14 @@ from plantcv.plantcv import fatal_error -def y_axis_pseudolandmarks(img, obj, mask): +def y_axis_pseudolandmarks(img, obj, mask, label=None): """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 obj = a contour of the plant object (this should be output from the object_composition.py fxn) mask = this is a binary image. The object should be white and the background should be black + label = optional label parameter, modifies the variable name of observations recorded Returns: left = List of landmarks within the left side @@ -26,6 +27,7 @@ def y_axis_pseudolandmarks(img, obj, mask): :param img: numpy.ndarray :param obj: list :param mask: numpy.ndarray + :param label: str :return left: list :return right: list :return center_h: list @@ -213,13 +215,18 @@ def y_axis_pseudolandmarks(img, obj, mask): for pt in center_h: center_h_list.append(pt[0].tolist()) - outputs.add_observation(variable='left_lmk', trait='left landmark coordinates', + if label == None: + prefix = "" + else: + prefix = label + "_" + + outputs.add_observation(variable=prefix + 'left_lmk', trait='left landmark coordinates', method='plantcv.plantcv.x_axis_pseudolandmarks', scale='none', datatype=tuple, value=tuple(left_list), label='none') - outputs.add_observation(variable='right_lmk', trait='right landmark coordinates', + outputs.add_observation(variable=prefix + 'right_lmk', trait='right landmark coordinates', method='plantcv.plantcv.x_axis_pseudolandmarks', scale='none', datatype=tuple, value=tuple(right_list), label='none') - outputs.add_observation(variable='center_h_lmk', trait='center horizontal landmark coordinates', + outputs.add_observation(variable=prefix + 'center_h_lmk', trait='center horizontal landmark coordinates', method='plantcv.plantcv.x_axis_pseudolandmarks', scale='none', datatype=tuple, value=tuple(center_h_list), label='none') From ce246a229c55c7f3f43c568fe767fce9e5c6fdb6 Mon Sep 17 00:00:00 2001 From: HaleySchuhl Date: Thu, 14 Jan 2021 11:12:14 -0600 Subject: [PATCH 047/137] Update tests.py add cases to cover new code --- tests/tests.py | 26 +++++++++++++------------- 1 file changed, 13 insertions(+), 13 deletions(-) diff --git a/tests/tests.py b/tests/tests.py index c1e6ad831..8f66a918f 100755 --- a/tests/tests.py +++ b/tests/tests.py @@ -979,7 +979,7 @@ def test_plantcv_acute_vertex(): 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) + _ = 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" @@ -1014,7 +1014,7 @@ def test_plantcv_analyze_bound_horizontal(): object_contours = contours_npz['arr_0'] # Test with debug = "print" pcv.params.debug = "print" - _ = pcv.analyze_bound_horizontal(img=img, obj=object_contours, mask=mask, line_position=300) + _ = pcv.analyze_bound_horizontal(img=img, obj=object_contours, mask=mask, line_position=300, label="prefix") _ = 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" @@ -1075,7 +1075,7 @@ def test_plantcv_analyze_bound_vertical(): 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) + _ = 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) @@ -1152,7 +1152,7 @@ def test_plantcv_analyze_color(): # Test with debug = "print" pcv.params.debug = "print" _ = pcv.analyze_color(rgb_img=img, mask=mask, hist_plot_type="all") - _ = pcv.analyze_color(rgb_img=img, mask=mask, hist_plot_type=None) + _ = pcv.analyze_color(rgb_img=img, mask=mask, hist_plot_type=None, label="prefix") # Test with debug = "plot" pcv.params.debug = "plot" @@ -1202,7 +1202,7 @@ def test_plantcv_analyze_nir(): mask = cv2.imread(os.path.join(TEST_DATA, TEST_INPUT_BINARY), -1) # Test with debug = "print" pcv.params.debug = "print" - _ = pcv.analyze_nir_intensity(gray_img=np.uint16(img), mask=mask, bins=256, histplot=True) + _ = pcv.analyze_nir_intensity(gray_img=np.uint16(img), mask=mask, bins=256, histplot=True, label="prefix") # Test with debug = "plot" pcv.params.debug = "plot" _ = pcv.analyze_nir_intensity(gray_img=img, mask=mask, bins=256, histplot=False) @@ -1230,7 +1230,7 @@ def test_plantcv_analyze_object(): # max_obj = max(obj_contour, key=len) # Test with debug = "print" pcv.params.debug = "print" - _ = pcv.analyze_object(img=img, obj=obj_contour, mask=mask) + _ = pcv.analyze_object(img=img, obj=obj_contour, mask=mask, label="prefix") # Test with debug = "plot" pcv.params.debug = "plot" _ = pcv.analyze_object(img=img, obj=obj_contour, mask=mask) @@ -1354,7 +1354,7 @@ def test_plantcv_analyze_thermal_values(): img = contours_npz['arr_0'] # Test with debug = "print" pcv.params.debug = "print" - _ = pcv.analyze_thermal_values(thermal_array=img, mask=mask, histplot=True) + _ = pcv.analyze_thermal_values(thermal_array=img, mask=mask, histplot=True, label="prefix") pcv.params.debug = "plot" thermal_hist = pcv.analyze_thermal_values(thermal_array=img, mask=mask, histplot=True) pcv.print_results(os.path.join(cache_dir, "results.txt")) @@ -2210,7 +2210,7 @@ def test_plantcv_landmark_reference_pt_dist(): (0.6458, 0.3472), (0.6389, 0.5208), (0.6458, 0.625)] centroid_rescaled = (0.4685, 0.4945) bottomline_rescaled = (0.4685, 0.2569) - _ = pcv.landmark_reference_pt_dist(points_r=[], centroid_r=('a', 'b'), bline_r=(0, 0)) + _ = pcv.landmark_reference_pt_dist(points_r=[], centroid_r=('a', 'b'), bline_r=(0, 0), label="prefix") _ = pcv.landmark_reference_pt_dist(points_r=[(10, 1000)], centroid_r=(10, 10), bline_r=(10, 10)) _ = pcv.landmark_reference_pt_dist(points_r=[], centroid_r=(0, 0), bline_r=(0, 0)) pcv.landmark_reference_pt_dist(points_r=points_rescaled, centroid_r=centroid_rescaled, bline_r=bottomline_rescaled) @@ -2426,7 +2426,7 @@ def test_plantcv_within_frame(): # Read in test data mask_ib = cv2.imread(os.path.join(TEST_DATA, TEST_INPUT_MASK), -1) mask_oob = cv2.imread(os.path.join(TEST_DATA, TEST_INPUT_MASK_OOB), -1) - in_bounds_ib = pcv.within_frame(mask=mask_ib, border_width=1) + in_bounds_ib = pcv.within_frame(mask=mask_ib, border_width=1, label="prefix") in_bounds_oob = pcv.within_frame(mask=mask_oob, border_width=1) assert (in_bounds_ib is True and in_bounds_oob is False) @@ -2794,7 +2794,7 @@ def test_plantcv_report_size_marker_detect(): # 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) + 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', @@ -3199,7 +3199,7 @@ def test_plantcv_watershed_segmentation(): 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) + _ = 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) @@ -3320,7 +3320,7 @@ def test_plantcv_x_axis_pseudolandmarks(): _ = pcv.x_axis_pseudolandmarks(obj=obj_contour, mask=mask, img=img) # Test with debug = "plot" pcv.params.debug = "plot" - _ = pcv.x_axis_pseudolandmarks(obj=obj_contour, mask=mask, img=img) + _ = 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) @@ -3379,7 +3379,7 @@ def test_plantcv_y_axis_pseudolandmarks(): 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) + _ = 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) From 516d45da27efafbb5e68a9e69f8be2b55a457a47 Mon Sep 17 00:00:00 2001 From: HaleySchuhl Date: Thu, 14 Jan 2021 12:35:26 -0600 Subject: [PATCH 048/137] Update tests.py --- tests/tests.py | 1 + 1 file changed, 1 insertion(+) diff --git a/tests/tests.py b/tests/tests.py index ee2fde4a1..13556c593 100755 --- a/tests/tests.py +++ b/tests/tests.py @@ -1082,6 +1082,7 @@ def test_plantcv_analyze_bound_horizontal(): # Test with debug = "print" pcv.params.debug = "print" _ = 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" From 938087ca920d4344e3d891cb9d08522a4e12f262 Mon Sep 17 00:00:00 2001 From: HaleySchuhl Date: Thu, 14 Jan 2021 13:03:46 -0600 Subject: [PATCH 049/137] Update tests.py --- tests/tests.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/tests/tests.py b/tests/tests.py index 13556c593..d11c49f18 100755 --- a/tests/tests.py +++ b/tests/tests.py @@ -4781,7 +4781,7 @@ def test_plantcv_photosynthesis_analyze_fvfm(): fmask = cv2.imread(os.path.join(TEST_DATA, TEST_INPUT_FMASK), -1) # Test with debug = "print" pcv.params.debug = "print" - _ = pcv.photosynthesis.analyze_fvfm(fdark=fdark, fmin=fmin, fmax=fmax, mask=fmask, bins=1000) + _ = pcv.photosynthesis.analyze_fvfm(fdark=fdark, fmin=fmin, fmax=fmax, mask=fmask, bins=1000, label="prefix") # Test with debug = "plot" pcv.params.debug = "plot" fvfm_images = pcv.photosynthesis.analyze_fvfm(fdark=fdark, fmin=fmin, fmax=fmax, mask=fmask, bins=1000) @@ -5369,7 +5369,7 @@ def test_plantcv_transform_find_color_card(): # Test with debug = "print" pcv.params.debug = "print" _ = pcv.transform.create_color_card_mask(rgb_img=rgb_img, radius=6, start_coord=start, - spacing=space, nrows=6, ncols=4, exclude=[20, 0]) + spacing=space, nrows=6, ncols=4, exclude=[20, 0], label="prefix") # Test with debug = "plot" pcv.params.debug = "plot" _ = pcv.transform.create_color_card_mask(rgb_img=rgb_img, radius=6, start_coord=start, From 3c671aac479a9b1922311a9d3e1a4d4bf7418658 Mon Sep 17 00:00:00 2001 From: HaleySchuhl Date: Thu, 14 Jan 2021 13:30:35 -0600 Subject: [PATCH 050/137] Update tests.py --- tests/tests.py | 18 +++--------------- 1 file changed, 3 insertions(+), 15 deletions(-) diff --git a/tests/tests.py b/tests/tests.py index d11c49f18..37ce8701a 100755 --- a/tests/tests.py +++ b/tests/tests.py @@ -5369,7 +5369,7 @@ def test_plantcv_transform_find_color_card(): # Test with debug = "print" pcv.params.debug = "print" _ = pcv.transform.create_color_card_mask(rgb_img=rgb_img, radius=6, start_coord=start, - spacing=space, nrows=6, ncols=4, exclude=[20, 0], label="prefix") + spacing=space, nrows=6, ncols=4, exclude=[20, 0]) # Test with debug = "plot" pcv.params.debug = "plot" _ = pcv.transform.create_color_card_mask(rgb_img=rgb_img, radius=6, start_coord=start, @@ -5392,20 +5392,8 @@ def test_plantcv_transform_find_color_card_optional_parameters(): pcv.params.debug_outdir = cache_dir # Test with threshold ='normal' df1, start1, space1 = pcv.transform.find_color_card(rgb_img=rgb_img, threshold_type='normal', blurry=True, - background='light', threshvalue=90) - _ = pcv.transform.create_color_card_mask(rgb_img=rgb_img, radius=6, start_coord=start1, - spacing=space1, nrows=6, ncols=4, exclude=[20, 0]) - # Test with threshold='otsu' - df2, start2, space2 = pcv.transform.find_color_card(rgb_img=rgb_img, threshold_type='otsu', blurry=True) - _ = pcv.transform.create_color_card_mask(rgb_img=rgb_img, radius=6, start_coord=start2, - spacing=space2, nrows=6, ncols=4, exclude=[20, 0]) - # Test with debug = None - pcv.params.debug = None - mask = pcv.transform.create_color_card_mask(rgb_img=rgb_img, radius=6, start_coord=start2, - spacing=space2, nrows=6, ncols=4, exclude=[20, 0]) - assert all([i == j] for i, j in zip(np.unique(mask), np.array([0, 10, 20, 30, 40, 50, 60, 70, 80, 90, 100, 110, - 120, 130, 140, 150, 160, 170, 180, 190, 200, 210, - 220], dtype=np.uint8))) + background='light', threshvalue=90, label="prefix") + assert pcv.outputs.observations["prefix_color_chip_size"]["value"] > 15000 def test_plantcv_transform_find_color_card_optional_size_parameters(): From 08cde48a1f012d13428ebbe3fe1a75c890ce9712 Mon Sep 17 00:00:00 2001 From: HaleySchuhl Date: Thu, 14 Jan 2021 14:09:23 -0600 Subject: [PATCH 051/137] Update tests.py --- tests/tests.py | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/tests/tests.py b/tests/tests.py index 37ce8701a..173c7b15c 100755 --- a/tests/tests.py +++ b/tests/tests.py @@ -2278,13 +2278,14 @@ def test_plantcv_landmark_reference_pt_dist(): (0.6458, 0.3472), (0.6389, 0.5208), (0.6458, 0.625)] centroid_rescaled = (0.4685, 0.4945) bottomline_rescaled = (0.4685, 0.2569) - _ = pcv.landmark_reference_pt_dist(points_r=[], centroid_r=('a', 'b'), bline_r=(0, 0), label="prefix") + _ = pcv.landmark_reference_pt_dist(points_r=[], centroid_r=('a', 'b'), bline_r=(0, 0)) _ = pcv.landmark_reference_pt_dist(points_r=[(10, 1000)], centroid_r=(10, 10), bline_r=(10, 10)) _ = pcv.landmark_reference_pt_dist(points_r=[], centroid_r=(0, 0), bline_r=(0, 0)) - pcv.landmark_reference_pt_dist(points_r=points_rescaled, centroid_r=centroid_rescaled, bline_r=bottomline_rescaled) + pcv.landmark_reference_pt_dist(points_r=points_rescaled, centroid_r=centroid_rescaled, bline_r=bottomline_rescaled, + label="prefix") pcv.print_results(os.path.join(cache_dir, "results.txt")) + assert len(pcv.outputs.observations) == 8 pcv.outputs.clear() - assert len(pcv.outputs.observations) == 0 def test_plantcv_laplace_filter(): From 921e9f555d46b85b0fd6678ce5644896c5c5fd6c Mon Sep 17 00:00:00 2001 From: HaleySchuhl Date: Thu, 14 Jan 2021 14:30:47 -0600 Subject: [PATCH 052/137] last testing update i hope --- tests/tests.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/tests.py b/tests/tests.py index 173c7b15c..59eb78aa9 100755 --- a/tests/tests.py +++ b/tests/tests.py @@ -2284,7 +2284,7 @@ def test_plantcv_landmark_reference_pt_dist(): pcv.landmark_reference_pt_dist(points_r=points_rescaled, centroid_r=centroid_rescaled, bline_r=bottomline_rescaled, label="prefix") pcv.print_results(os.path.join(cache_dir, "results.txt")) - assert len(pcv.outputs.observations) == 8 + assert len(pcv.outputs.observations) == 42 pcv.outputs.clear() From cf4c4826c8ab994bf2ad20283bc4bd0058f1d56b Mon Sep 17 00:00:00 2001 From: HaleySchuhl Date: Tue, 12 Jan 2021 15:45:10 -0600 Subject: [PATCH 053/137] update sub-package functions --- .../plantcv/photosynthesis/analyze_fvfm.py | 27 ++++++++++++------- plantcv/plantcv/transform/color_correction.py | 16 ++++++++--- plantcv/plantcv/visualize/pseudocolor.py | 1 - 3 files changed, 30 insertions(+), 14 deletions(-) diff --git a/plantcv/plantcv/photosynthesis/analyze_fvfm.py b/plantcv/plantcv/photosynthesis/analyze_fvfm.py index 87b1f48fa..e20343d30 100755 --- a/plantcv/plantcv/photosynthesis/analyze_fvfm.py +++ b/plantcv/plantcv/photosynthesis/analyze_fvfm.py @@ -12,7 +12,7 @@ from plantcv.plantcv import outputs -def analyze_fvfm(fdark, fmin, fmax, mask, bins=256): +def analyze_fvfm(fdark, fmin, fmax, mask, bins=256, label=None): """Analyze PSII camera images. Inputs: fdark = grayscale fdark image @@ -20,6 +20,8 @@ def analyze_fvfm(fdark, fmin, fmax, mask, bins=256): fmax = grayscale fmax image mask = mask of plant (binary, single channel) bins = number of bins (1 to 256 for 8-bit; 1 to 65,536 for 16-bit; default is 256) + label = optional label parameter, modifies the variable name of observations recorded + Returns: analysis_images = list of images (fv image and fvfm histogram image) :param fdark: numpy.ndarray @@ -27,6 +29,7 @@ def analyze_fvfm(fdark, fmin, fmax, mask, bins=256): :param fmax: numpy.ndarray :param mask: numpy.ndarray :param bins: int + :param label: str :return analysis_images: numpy.ndarray """ @@ -86,27 +89,33 @@ def analyze_fvfm(fdark, fmin, fmax, mask, bins=256): x=.15, y=205, size=8, color='green')) analysis_images.append(fvfm_hist_fig) + if label == None: + prefix = "" + else: + prefix = label + "_" + if params.debug == 'print': - print_image(fmin_mask, os.path.join(params.debug_outdir, str(params.device) + '_fmin_mask.png')) - print_image(fmax_mask, os.path.join(params.debug_outdir, str(params.device) + '_fmax_mask.png')) - print_image(fv, os.path.join(params.debug_outdir, str(params.device) + '_fv_convert.png')) - fvfm_hist_fig.save(os.path.join(params.debug_outdir, str(params.device) + '_fv_hist.png'), verbose=False) + print_image(fmin_mask, os.path.join(params.debug_outdir, str(params.device) + prefix + '_fmin_mask.png')) + print_image(fmax_mask, os.path.join(params.debug_outdir, str(params.device) + prefix + '_fmax_mask.png')) + print_image(fv, os.path.join(params.debug_outdir, str(params.device) + prefix + '_fv_convert.png')) + fvfm_hist_fig.save(os.path.join(params.debug_outdir, str(params.device) + prefix + '_fv_hist.png'), + verbose=False) elif params.debug == 'plot': plot_image(fmin_mask, cmap='gray') plot_image(fmax_mask, cmap='gray') plot_image(fv, cmap='gray') print(fvfm_hist_fig) - outputs.add_observation(variable='fvfm_hist', trait='Fv/Fm frequencies', + outputs.add_observation(variable=prefix + 'fvfm_hist', trait='Fv/Fm frequencies', method='plantcv.plantcv.fluor_fvfm', scale='none', datatype=list, value=fvfm_hist.tolist(), label=np.around(midpoints, decimals=len(str(bins))).tolist()) - outputs.add_observation(variable='fvfm_hist_peak', trait='peak Fv/Fm value', + outputs.add_observation(variable=prefix + 'fvfm_hist_peak', trait='peak Fv/Fm value', method='plantcv.plantcv.fluor_fvfm', scale='none', datatype=float, value=float(max_bin), label='none') - outputs.add_observation(variable='fvfm_median', trait='Fv/Fm median', + outputs.add_observation(variable=prefix + 'fvfm_median', trait='Fv/Fm median', method='plantcv.plantcv.fluor_fvfm', scale='none', datatype=float, value=float(np.around(fvfm_median, decimals=4)), label='none') - outputs.add_observation(variable='fdark_passed_qc', trait='Fdark passed QC', + outputs.add_observation(variable=prefix + 'fdark_passed_qc', trait='Fdark passed QC', method='plantcv.plantcv.fluor_fvfm', scale='none', datatype=bool, value=qc_fdark, label='none') diff --git a/plantcv/plantcv/transform/color_correction.py b/plantcv/plantcv/transform/color_correction.py index 7e8b25656..7f5ac4601 100644 --- a/plantcv/plantcv/transform/color_correction.py +++ b/plantcv/plantcv/transform/color_correction.py @@ -481,7 +481,7 @@ def quick_color_check(target_matrix, source_matrix, num_chips): def find_color_card(rgb_img, threshold_type='adaptgauss', threshvalue=125, blurry=False, background='dark', - record_chip_size="median"): + record_chip_size="median", label=None): """Automatically detects a color card and output info to use in create_color_card_mask function Algorithm written by Brandon Hurr. Updated and implemented into PlantCV by Haley Schuhl. @@ -496,6 +496,7 @@ def find_color_card(rgb_img, threshold_type='adaptgauss', threshvalue=125, blurr is a dark background record_chip_size = Optional str for choosing chip size measurement to be recorded, either "median", "mean", or None + label = optional label parameter, modifies the variable name of observations recorded Returns: df = Dataframe containing information about the filtered contours @@ -508,6 +509,7 @@ def find_color_card(rgb_img, threshold_type='adaptgauss', threshvalue=125, blurr :param blurry: bool :param background: str :param record_chip_size: str + :param label: str :return df: pandas.core.frame.DataFrame :return start_coord: tuple :return spacing: tuple @@ -761,14 +763,20 @@ def find_color_card(rgb_img, threshold_type='adaptgauss', threshvalue=125, blurr chip_height = None chip_width = None # Store into global measurements - outputs.add_observation(variable='color_chip_size', trait='size of color card chips identified', + if label == None: + prefix = "" + else: + prefix = label + "_" + outputs.add_observation(variable=prefix + 'color_chip_size', trait='size of color card chips identified', method='plantcv.plantcv.transform.find_color_card', scale='none', datatype=float, value=chip_size, label=str(record_chip_size)) method = record_chip_size.lower() - outputs.add_observation(variable=f'{method}_color_chip_height', trait=f'{method} height of color card chips identified', + outputs.add_observation(variable=prefix + f'{method}_color_chip_height', + trait=f'{method} height of color card chips identified', method='plantcv.plantcv.transform.find_color_card', scale='none', datatype=float, value=chip_height, label=str(record_chip_size)) - outputs.add_observation(variable=f'{method}_color_chip_width', trait=f'{method} size of color card chips identified', + outputs.add_observation(variable=prefix + f'{method}_color_chip_width', + trait=f'{method} size of color card chips identified', method='plantcv.plantcv.transform.find_color_card', scale='none', datatype=float, value=chip_width, label=str(record_chip_size)) diff --git a/plantcv/plantcv/visualize/pseudocolor.py b/plantcv/plantcv/visualize/pseudocolor.py index 87c42b494..25de99990 100644 --- a/plantcv/plantcv/visualize/pseudocolor.py +++ b/plantcv/plantcv/visualize/pseudocolor.py @@ -5,7 +5,6 @@ import numpy as np from matplotlib import pyplot as plt from plantcv.plantcv import params -from plantcv.plantcv import plot_image from plantcv.plantcv import fatal_error From c3e278208905577ad959a7461ed05eecdd4fe2ee Mon Sep 17 00:00:00 2001 From: HaleySchuhl Date: Thu, 14 Jan 2021 10:15:53 -0600 Subject: [PATCH 054/137] Update color_correction.py --- plantcv/plantcv/transform/color_correction.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/plantcv/plantcv/transform/color_correction.py b/plantcv/plantcv/transform/color_correction.py index 7f5ac4601..984bc46bd 100644 --- a/plantcv/plantcv/transform/color_correction.py +++ b/plantcv/plantcv/transform/color_correction.py @@ -496,7 +496,7 @@ def find_color_card(rgb_img, threshold_type='adaptgauss', threshvalue=125, blurr is a dark background record_chip_size = Optional str for choosing chip size measurement to be recorded, either "median", "mean", or None - label = optional label parameter, modifies the variable name of observations recorded + label = optional label parameter, modifies the variable name of observations recorded Returns: df = Dataframe containing information about the filtered contours From 6ded4b8d29788c420197fca0ae9552bb4b964ad7 Mon Sep 17 00:00:00 2001 From: HaleySchuhl Date: Thu, 14 Jan 2021 10:23:46 -0600 Subject: [PATCH 055/137] Update acute_vertex.py --- plantcv/plantcv/acute_vertex.py | 14 +++++++++++--- 1 file changed, 11 insertions(+), 3 deletions(-) diff --git a/plantcv/plantcv/acute_vertex.py b/plantcv/plantcv/acute_vertex.py index 6fe6941c2..0caf4a849 100755 --- a/plantcv/plantcv/acute_vertex.py +++ b/plantcv/plantcv/acute_vertex.py @@ -10,7 +10,7 @@ from plantcv.plantcv import outputs -def acute_vertex(img, obj, win, thresh, sep): +def acute_vertex(img, obj, win, thresh, sep, label=None): """acute_vertex: identify corners/acute angles of an object For each point in contour, get a point before (pre) and after (post) the point of interest, @@ -23,6 +23,8 @@ def acute_vertex(img, obj, win, thresh, sep): thresh = an threshold to set for acuteness; keep points with an angle more acute than the threshold (a value of 15 worked well for sample image) sep = the number of contour points to search within for the most acute value + label = optional label parameter, modifies the variable name of observations recorded + Returns: acute_points = list of acute points @@ -33,6 +35,7 @@ def acute_vertex(img, obj, win, thresh, sep): :param win: int :param thresh: int :param sep: int + :param label: str :return acute_points: ndarray :return img2: ndarray """ @@ -96,13 +99,18 @@ def acute_vertex(img, obj, win, thresh, sep): x, y = i.ravel() cv2.circle(img2, (x, y), params.line_thickness, (255, 0, 255), -1) + if label == None: + prefix = "" + else: + prefix = label + "_" + if params.debug == 'print': - print_image(img2, os.path.join(params.debug_outdir, str(params.device) + '_acute_vertices.png')) + print_image(img2, os.path.join(params.debug_outdir, str(params.device) + prefix + '_acute_vertices.png')) elif params.debug == 'plot': plot_image(img2) # Store into global measurements - outputs.add_observation(variable='tip_coordinates', trait='tip coordinates', + outputs.add_observation(variable=prefix + 'tip_coordinates', trait='tip coordinates', method='plantcv.plantcv.acute_vertex', scale='none', datatype=list, value=acute_points, label='none') From d0995a6630c7ff8cdd1cd68104f380112afbb569 Mon Sep 17 00:00:00 2001 From: HaleySchuhl Date: Thu, 14 Jan 2021 10:28:10 -0600 Subject: [PATCH 056/137] Update analyze_bound_horizontal.py --- plantcv/plantcv/analyze_bound_horizontal.py | 23 ++++++++++++++------- 1 file changed, 15 insertions(+), 8 deletions(-) diff --git a/plantcv/plantcv/analyze_bound_horizontal.py b/plantcv/plantcv/analyze_bound_horizontal.py index f3b774bfc..3244019f0 100755 --- a/plantcv/plantcv/analyze_bound_horizontal.py +++ b/plantcv/plantcv/analyze_bound_horizontal.py @@ -9,7 +9,7 @@ from plantcv.plantcv import outputs -def analyze_bound_horizontal(img, obj, mask, line_position): +def analyze_bound_horizontal(img, obj, mask, line_position, label=None): """User-input boundary line tool Inputs: @@ -17,6 +17,7 @@ def analyze_bound_horizontal(img, obj, mask, line_position): obj = single or grouped contour object mask = Binary mask made from selected contours line_position = position of boundary line (a value of 0 would draw the line through the top of the image) + label = optional label parameter, modifies the variable name of observations recorded Returns: analysis_images = list of output images @@ -25,6 +26,7 @@ def analyze_bound_horizontal(img, obj, mask, line_position): :param obj: list :param mask: numpy.ndarray :param line_position: int + :param label: str :return analysis_images: list """ @@ -144,25 +146,30 @@ def analyze_bound_horizontal(img, obj, mask, line_position): plot_image(wback) plot_image(ori_img) - outputs.add_observation(variable='horizontal_reference_position', trait='horizontal reference position', + if label == None: + prefix = "" + else: + prefix = label + "_" + + outputs.add_observation(variable=prefix + 'horizontal_reference_position', trait='horizontal reference position', method='plantcv.plantcv.analyze_bound_horizontal', scale='none', datatype=int, value=line_position, label='none') - outputs.add_observation(variable='height_above_reference', trait='height above reference', + outputs.add_observation(variable=prefix + 'height_above_reference', trait='height above reference', method='plantcv.plantcv.analyze_bound_horizontal', scale='pixels', datatype=int, value=height_above_bound, label='pixels') - outputs.add_observation(variable='height_below_reference', trait='height_below_reference', + outputs.add_observation(variable=prefix + 'height_below_reference', trait='height_below_reference', method='plantcv.plantcv.analyze_bound_horizontal', scale='pixels', datatype=int, value=height_below_bound, label='pixels') - outputs.add_observation(variable='area_above_reference', trait='area above reference', + outputs.add_observation(variable=prefix + 'area_above_reference', trait='area above reference', method='plantcv.plantcv.analyze_bound_horizontal', scale='pixels', datatype=int, value=above_bound_area, label='pixels') - outputs.add_observation(variable='percent_area_above_reference', trait='percent area above reference', + outputs.add_observation(variable=prefix + 'percent_area_above_reference', trait='percent area above reference', method='plantcv.plantcv.analyze_bound_horizontal', scale='none', datatype=float, value=percent_bound_area_above, label='none') - outputs.add_observation(variable='area_below_reference', trait='area below reference', + outputs.add_observation(variable=prefix + 'area_below_reference', trait='area below reference', method='plantcv.plantcv.analyze_bound_horizontal', scale='pixels', datatype=int, value=below_bound_area, label='pixels') - outputs.add_observation(variable='percent_area_below_reference', trait='percent area below reference', + outputs.add_observation(variable=prefix + 'percent_area_below_reference', trait='percent area below reference', method='plantcv.plantcv.analyze_bound_horizontal', scale='none', datatype=float, value=percent_bound_area_below, label='none') From 3647b00017eda4b78f6b5cfe3b990fea0980ae00 Mon Sep 17 00:00:00 2001 From: HaleySchuhl Date: Thu, 14 Jan 2021 10:30:07 -0600 Subject: [PATCH 057/137] Update analyze_bound_vertical.py --- plantcv/plantcv/analyze_bound_vertical.py | 23 +++++++++++++++-------- 1 file changed, 15 insertions(+), 8 deletions(-) diff --git a/plantcv/plantcv/analyze_bound_vertical.py b/plantcv/plantcv/analyze_bound_vertical.py index e4868a5d7..6906cc310 100755 --- a/plantcv/plantcv/analyze_bound_vertical.py +++ b/plantcv/plantcv/analyze_bound_vertical.py @@ -9,7 +9,7 @@ from plantcv.plantcv import outputs -def analyze_bound_vertical(img, obj, mask, line_position): +def analyze_bound_vertical(img, obj, mask, line_position, label=None): """User-input boundary line tool Inputs: @@ -19,6 +19,7 @@ def analyze_bound_vertical(img, obj, mask, line_position): 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 Returns: analysis_images = output images @@ -27,6 +28,7 @@ def analyze_bound_vertical(img, obj, mask, line_position): :param obj: list :param mask: numpy.ndarray :param line_position: int + :param label: str :return analysis_images: list """ ori_img = np.copy(img) @@ -144,25 +146,30 @@ def analyze_bound_vertical(img, obj, mask, line_position): plot_image(wback) plot_image(ori_img) - outputs.add_observation(variable='vertical_reference_position', trait='vertical reference position', + if label == None: + prefix = "" + else: + prefix = label + "_" + + outputs.add_observation(variable=prefix + 'vertical_reference_position', trait='vertical reference position', method='plantcv.plantcv.analyze_bound_vertical', scale='none', datatype=int, value=line_position, label='none') - outputs.add_observation(variable='width_left_reference', trait='width left of reference', + outputs.add_observation(variable=prefix + 'width_left_reference', trait='width left of reference', method='plantcv.plantcv.analyze_bound_vertical', scale='pixels', datatype=int, value=width_left_bound, label='pixels') - outputs.add_observation(variable='width_right_reference', trait='width right of reference', + outputs.add_observation(variable=prefix + 'width_right_reference', trait='width right of reference', method='plantcv.plantcv.analyze_bound_vertical', scale='pixels', datatype=int, value=width_right_bound, label='pixels') - outputs.add_observation(variable='area_left_reference', trait='area left of reference', + outputs.add_observation(variable=prefix + 'area_left_reference', trait='area left of reference', method='plantcv.plantcv.analyze_bound_vertical', scale='pixels', datatype=int, value=left_bound_area, label='pixels') - outputs.add_observation(variable='percent_area_left_reference', trait='percent area left of reference', + outputs.add_observation(variable=prefix + 'percent_area_left_reference', trait='percent area left of reference', method='plantcv.plantcv.analyze_bound_vertical', scale='none', datatype=float, value=percent_bound_area_left, label='none') - outputs.add_observation(variable='area_right_reference', trait='area right of reference', + outputs.add_observation(variable=prefix + 'area_right_reference', trait='area right of reference', method='plantcv.plantcv.analyze_bound_vertical', scale='pixels', datatype=int, value=right_bound_area, label='pixels') - outputs.add_observation(variable='percent_area_right_reference', trait='percent area right of reference', + outputs.add_observation(variable=prefix + 'percent_area_right_reference', trait='percent area right of reference', method='plantcv.plantcv.analyze_bound_vertical', scale='none', datatype=float, value=percent_bound_area_right, label='none') From 178e369ce86ecb9cec9414f6d695815c5e8c8a10 Mon Sep 17 00:00:00 2001 From: HaleySchuhl Date: Thu, 14 Jan 2021 10:32:55 -0600 Subject: [PATCH 058/137] Update analyze_color.py --- plantcv/plantcv/analyze_color.py | 34 ++++++++++++++++++++------------ 1 file changed, 21 insertions(+), 13 deletions(-) diff --git a/plantcv/plantcv/analyze_color.py b/plantcv/plantcv/analyze_color.py index df6bc819d..f9f1ae3c2 100755 --- a/plantcv/plantcv/analyze_color.py +++ b/plantcv/plantcv/analyze_color.py @@ -9,12 +9,13 @@ from plantcv.plantcv import outputs -def analyze_color(rgb_img, mask, hist_plot_type=None): +def analyze_color(rgb_img, mask, hist_plot_type=None, label=None): """Analyze the color properties of an image object Inputs: rgb_img = RGB image data mask = Binary mask made from selected contours hist_plot_type = None, 'all', 'rgb','lab' or 'hsv' + label = optional label parameter, modifies the variable name of observations recorded Returns: analysis_image = histogram output @@ -22,6 +23,7 @@ def analyze_color(rgb_img, mask, hist_plot_type=None): :param rgb_img: numpy.ndarray :param mask: numpy.ndarray :param hist_plot_type: str + :param label: str :return analysis_images: list """ if len(np.shape(rgb_img)) < 3: @@ -158,48 +160,54 @@ def analyze_color(rgb_img, mask, hist_plot_type=None): percent_values = [round((i / 255) * 100, 2) for i in range(0, 256)] # Diverging values on a -128 to 127 scale (green-magenta and blue-yellow) diverging_values = [i for i in range(-128, 128)] + + if label == None: + prefix = "" + else: + prefix = label + "_" + if hist_plot_type is not None: if hist_plot_type.upper() == 'RGB' or hist_plot_type.upper() == 'ALL': - outputs.add_observation(variable='blue_frequencies', trait='blue frequencies', + outputs.add_observation(variable=prefix + 'blue_frequencies', trait='blue frequencies', method='plantcv.plantcv.analyze_color', scale='frequency', datatype=list, value=histograms["b"]["hist"], label=rgb_values) - outputs.add_observation(variable='green_frequencies', trait='green frequencies', + outputs.add_observation(variable=prefix + 'green_frequencies', trait='green frequencies', method='plantcv.plantcv.analyze_color', scale='frequency', datatype=list, value=histograms["g"]["hist"], label=rgb_values) - outputs.add_observation(variable='red_frequencies', trait='red frequencies', + outputs.add_observation(variable=prefix + 'red_frequencies', trait='red frequencies', method='plantcv.plantcv.analyze_color', scale='frequency', datatype=list, value=histograms["r"]["hist"], label=rgb_values) if hist_plot_type.upper() == 'LAB' or hist_plot_type.upper() == 'ALL': - outputs.add_observation(variable='lightness_frequencies', trait='lightness frequencies', + outputs.add_observation(variable=prefix + 'lightness_frequencies', trait='lightness frequencies', method='plantcv.plantcv.analyze_color', scale='frequency', datatype=list, value=histograms["l"]["hist"], label=percent_values) - outputs.add_observation(variable='green-magenta_frequencies', trait='green-magenta frequencies', + outputs.add_observation(variable=prefix + 'green-magenta_frequencies', trait='green-magenta frequencies', method='plantcv.plantcv.analyze_color', scale='frequency', datatype=list, value=histograms["m"]["hist"], label=diverging_values) - outputs.add_observation(variable='blue-yellow_frequencies', trait='blue-yellow frequencies', + outputs.add_observation(variable=prefix + 'blue-yellow_frequencies', trait='blue-yellow frequencies', method='plantcv.plantcv.analyze_color', scale='frequency', datatype=list, value=histograms["y"]["hist"], label=diverging_values) if hist_plot_type.upper() == 'HSV' or hist_plot_type.upper() == 'ALL': - outputs.add_observation(variable='hue_frequencies', trait='hue frequencies', + outputs.add_observation(variable=prefix + 'hue_frequencies', trait='hue frequencies', method='plantcv.plantcv.analyze_color', scale='frequency', datatype=list, value=histograms["h"]["hist"][0:180], label=hue_values) - outputs.add_observation(variable='saturation_frequencies', trait='saturation frequencies', + outputs.add_observation(variable=prefix + 'saturation_frequencies', trait='saturation frequencies', method='plantcv.plantcv.analyze_color', scale='frequency', datatype=list, value=histograms["s"]["hist"], label=percent_values) - outputs.add_observation(variable='value_frequencies', trait='value frequencies', + outputs.add_observation(variable=prefix + 'value_frequencies', trait='value frequencies', method='plantcv.plantcv.analyze_color', scale='frequency', datatype=list, value=histograms["v"]["hist"], label=percent_values) # Always save hue stats - outputs.add_observation(variable='hue_circular_mean', trait='hue circular mean', + outputs.add_observation(variable=prefix + 'hue_circular_mean', trait='hue circular mean', method='plantcv.plantcv.analyze_color', scale='degrees', datatype=float, value=hue_circular_mean, label='degrees') - outputs.add_observation(variable='hue_circular_std', trait='hue circular standard deviation', + outputs.add_observation(variable=prefix + 'hue_circular_std', trait='hue circular standard deviation', method='plantcv.plantcv.analyze_color', scale='degrees', datatype=float, value=hue_circular_std, label='degrees') - outputs.add_observation(variable='hue_median', trait='hue median', + outputs.add_observation(variable=prefix + 'hue_median', trait='hue median', method='plantcv.plantcv.analyze_color', scale='degrees', datatype=float, value=hue_median, label='degrees') From a309a935b41ed249985882f64f9bc277b8576bd9 Mon Sep 17 00:00:00 2001 From: HaleySchuhl Date: Thu, 14 Jan 2021 10:34:07 -0600 Subject: [PATCH 059/137] Update analyze_nir_intensity.py --- plantcv/plantcv/analyze_nir_intensity.py | 17 ++++++++++++----- 1 file changed, 12 insertions(+), 5 deletions(-) diff --git a/plantcv/plantcv/analyze_nir_intensity.py b/plantcv/plantcv/analyze_nir_intensity.py index 095cf1e78..e2a57a689 100755 --- a/plantcv/plantcv/analyze_nir_intensity.py +++ b/plantcv/plantcv/analyze_nir_intensity.py @@ -12,7 +12,7 @@ from plantcv.plantcv import outputs -def analyze_nir_intensity(gray_img, mask, bins=256, histplot=False): +def analyze_nir_intensity(gray_img, mask, bins=256, histplot=False, label=None): """This function calculates the intensity of each pixel associated with the plant and writes the values out to a file. It can also print out a histogram plot of pixel intensity and a pseudocolor image of the plant. @@ -21,6 +21,7 @@ def analyze_nir_intensity(gray_img, mask, bins=256, histplot=False): mask = Binary mask made from selected contours bins = number of classes to divide spectrum into histplot = if True plots histogram of intensity values + label = optional label parameter, modifies the variable name of observations recorded Returns: analysis_images = NIR histogram image @@ -29,6 +30,7 @@ def analyze_nir_intensity(gray_img, mask, bins=256, histplot=False): :param mask: numpy array :param bins: int :param histplot: bool + :param label: str :return analysis_images: plotnine ggplot """ # apply plant shaped mask to image @@ -91,16 +93,21 @@ def analyze_nir_intensity(gray_img, mask, bins=256, histplot=False): elif params.debug == "plot": print(fig_hist) - outputs.add_observation(variable='nir_frequencies', trait='near-infrared frequencies', + if label == None: + prefix = "" + else: + prefix = label + "_" + + outputs.add_observation(variable=prefix + 'nir_frequencies', trait='near-infrared frequencies', method='plantcv.plantcv.analyze_nir_intensity', scale='frequency', datatype=list, value=hist_nir, label=bin_labels) - outputs.add_observation(variable='nir_mean', trait='near-infrared mean', + outputs.add_observation(variable=prefix + 'nir_mean', trait='near-infrared mean', method='plantcv.plantcv.analyze_nir_intensity', scale='none', datatype=float, value=masked_nir_mean, label='none') - outputs.add_observation(variable='nir_median', trait='near-infrared median', + outputs.add_observation(variable=prefix + 'nir_median', trait='near-infrared median', method='plantcv.plantcv.analyze_nir_intensity', scale='none', datatype=float, value=masked_nir_median, label='none') - outputs.add_observation(variable='nir_stdev', trait='near-infrared standard deviation', + outputs.add_observation(variable=prefix + 'nir_stdev', trait='near-infrared standard deviation', method='plantcv.plantcv.analyze_nir_intensity', scale='none', datatype=float, value=masked_nir_std, label='none') From 752b51d94a09c42c385488ee088203428b1e6f2b Mon Sep 17 00:00:00 2001 From: HaleySchuhl Date: Thu, 14 Jan 2021 10:37:02 -0600 Subject: [PATCH 060/137] Update analyze_object.py --- plantcv/plantcv/analyze_object.py | 41 ++++++++++++++++++------------- 1 file changed, 24 insertions(+), 17 deletions(-) diff --git a/plantcv/plantcv/analyze_object.py b/plantcv/plantcv/analyze_object.py index 79770bd3a..2a8c8aaf7 100755 --- a/plantcv/plantcv/analyze_object.py +++ b/plantcv/plantcv/analyze_object.py @@ -10,13 +10,14 @@ from plantcv.plantcv import within_frame -def analyze_object(img, obj, mask): +def analyze_object(img, obj, mask, label=None): """Outputs numeric properties for an input object (contour or grouped contours). Inputs: img = RGB or grayscale image data for plotting obj = single or grouped contour object mask = Binary image to use as mask + label = optional label parameter, modifies the variable name of observations recorded Returns: analysis_images = list of output images @@ -24,6 +25,7 @@ def analyze_object(img, obj, mask): :param img: numpy.ndarray :param obj: list :param mask: numpy.ndarray + :param label: str :return analysis_images: list """ # Valid objects can only be analyzed if they have >= 5 vertices @@ -156,49 +158,54 @@ def analyze_object(img, obj, mask): else: pass - outputs.add_observation(variable='area', trait='area', + if label == None: + prefix = "" + else: + prefix = label + "_" + + outputs.add_observation(variable=prefix + 'area', trait='area', method='plantcv.plantcv.analyze_object', scale='pixels', datatype=int, value=area, label='pixels') - outputs.add_observation(variable='convex_hull_area', trait='convex hull area', + outputs.add_observation(variable=prefix + 'convex_hull_area', trait='convex hull area', method='plantcv.plantcv.analyze_object', scale='pixels', datatype=int, value=hull_area, label='pixels') - outputs.add_observation(variable='solidity', trait='solidity', + outputs.add_observation(variable=prefix + 'solidity', trait='solidity', method='plantcv.plantcv.analyze_object', scale='none', datatype=float, value=solidity, label='none') - outputs.add_observation(variable='perimeter', trait='perimeter', + outputs.add_observation(variable=prefix + 'perimeter', trait='perimeter', method='plantcv.plantcv.analyze_object', scale='pixels', datatype=int, value=perimeter, label='pixels') - outputs.add_observation(variable='width', trait='width', + outputs.add_observation(variable=prefix + 'width', trait='width', method='plantcv.plantcv.analyze_object', scale='pixels', datatype=int, value=width, label='pixels') - outputs.add_observation(variable='height', trait='height', + outputs.add_observation(variable=prefix + 'height', trait='height', method='plantcv.plantcv.analyze_object', scale='pixels', datatype=int, value=height, label='pixels') - outputs.add_observation(variable='longest_path', trait='longest path', + outputs.add_observation(variable=prefix + 'longest_path', trait='longest path', method='plantcv.plantcv.analyze_object', scale='pixels', datatype=int, value=caliper_length, label='pixels') - outputs.add_observation(variable='center_of_mass', trait='center of mass', + outputs.add_observation(variable=prefix + 'center_of_mass', trait='center of mass', method='plantcv.plantcv.analyze_object', scale='none', datatype=tuple, value=(cmx, cmy), label='none') - outputs.add_observation(variable='convex_hull_vertices', trait='convex hull vertices', + outputs.add_observation(variable=prefix + 'convex_hull_vertices', trait='convex hull vertices', method='plantcv.plantcv.analyze_object', scale='none', datatype=int, value=hull_vertices, label='none') - outputs.add_observation(variable='object_in_frame', trait='object in frame', + outputs.add_observation(variable=prefix + 'object_in_frame', trait='object in frame', method='plantcv.plantcv.analyze_object', scale='none', datatype=bool, value=in_bounds, label='none') - outputs.add_observation(variable='ellipse_center', trait='ellipse center', + outputs.add_observation(variable=prefix + 'ellipse_center', trait='ellipse center', method='plantcv.plantcv.analyze_object', scale='none', datatype=tuple, value=(center[0], center[1]), label='none') - outputs.add_observation(variable='ellipse_major_axis', trait='ellipse major axis length', + outputs.add_observation(variable=prefix + 'ellipse_major_axis', trait='ellipse major axis length', method='plantcv.plantcv.analyze_object', scale='pixels', datatype=int, value=major_axis_length, label='pixels') - outputs.add_observation(variable='ellipse_minor_axis', trait='ellipse minor axis length', + outputs.add_observation(variable=prefix + 'ellipse_minor_axis', trait='ellipse minor axis length', method='plantcv.plantcv.analyze_object', scale='pixels', datatype=int, value=minor_axis_length, label='pixels') - outputs.add_observation(variable='ellipse_angle', trait='ellipse major axis angle', + outputs.add_observation(variable=prefix + 'ellipse_angle', trait='ellipse major axis angle', method='plantcv.plantcv.analyze_object', scale='degrees', datatype=float, value=float(angle), label='degrees') - outputs.add_observation(variable='ellipse_eccentricity', trait='ellipse eccentricity', + outputs.add_observation(variable=prefix + 'ellipse_eccentricity', trait='ellipse eccentricity', method='plantcv.plantcv.analyze_object', scale='none', datatype=float, value=float(eccentricity), label='none') @@ -212,7 +219,7 @@ def analyze_object(img, obj, mask): cv2.line(ori_img, (tuple(caliper_transpose[caliper_length - 1])), (tuple(caliper_transpose[0])), (255, 0, 255), params.line_thickness) if params.debug == 'print': - print_image(ori_img, os.path.join(params.debug_outdir, str(params.device) + '_shapes.png')) + print_image(ori_img, os.path.join(params.debug_outdir, str(params.device) + prefix + '_shapes.png')) elif params.debug == 'plot': if len(np.shape(img)) == 3: plot_image(ori_img) From 140571a26cc10794d0ef7652ede300917ac703f1 Mon Sep 17 00:00:00 2001 From: HaleySchuhl Date: Thu, 14 Jan 2021 10:38:59 -0600 Subject: [PATCH 061/137] Update analyze_thermal_values.py --- plantcv/plantcv/analyze_thermal_values.py | 22 +++++++++++++++------- 1 file changed, 15 insertions(+), 7 deletions(-) diff --git a/plantcv/plantcv/analyze_thermal_values.py b/plantcv/plantcv/analyze_thermal_values.py index 38d15f7ab..a7137f2ec 100755 --- a/plantcv/plantcv/analyze_thermal_values.py +++ b/plantcv/plantcv/analyze_thermal_values.py @@ -10,7 +10,7 @@ from plantcv.plantcv.threshold import binary as binary_threshold -def analyze_thermal_values(thermal_array, mask, histplot=False): +def analyze_thermal_values(thermal_array, mask, histplot=False, label=None): """This extracts the thermal values of each pixel writes the values out to a file. It can also print out a histogram plot of pixel intensity and a pseudocolor image of the plant. @@ -19,6 +19,7 @@ def analyze_thermal_values(thermal_array, mask, histplot=False): array = numpy array of thermal values mask = Binary mask made from selected contours histplot = if True plots histogram of intensity values + label = optional label parameter, modifies the variable name of observations recorded Returns: analysis_img = output image @@ -26,6 +27,7 @@ def analyze_thermal_values(thermal_array, mask, histplot=False): :param thermal_array: numpy.ndarray :param mask: numpy.ndarray :param histplot: bool + :param label: str :return analysis_img: ggplot """ max_value = np.amax(thermal_array) @@ -57,20 +59,25 @@ def analyze_thermal_values(thermal_array, mask, histplot=False): avgtemp = np.average(masked_thermal) mediantemp = np.median(masked_thermal) + if label == None: + prefix = "" + else: + prefix = label + "_" + # Store data into outputs class - outputs.add_observation(variable='max_temp', trait='maximum temperature', + outputs.add_observation(variable=prefix + 'max_temp', trait='maximum temperature', method='plantcv.plantcv.analyze_thermal_values', scale='degrees', datatype=float, value=maxtemp, label='degrees') - outputs.add_observation(variable='min_temp', trait='minimum temperature', + outputs.add_observation(variable=prefix + 'min_temp', trait='minimum temperature', method='plantcv.plantcv.analyze_thermal_values', scale='degrees', datatype=float, value=mintemp, label='degrees') - outputs.add_observation(variable='mean_temp', trait='mean temperature', + outputs.add_observation(variable=prefix + 'mean_temp', trait='mean temperature', method='plantcv.plantcv.analyze_thermal_values', scale='degrees', datatype=float, value=avgtemp, label='degrees') - outputs.add_observation(variable='median_temp', trait='median temperature', + outputs.add_observation(variable=prefix + 'median_temp', trait='median temperature', method='plantcv.plantcv.analyze_thermal_values', scale='degrees', datatype=float, value=mediantemp, label='degrees') - outputs.add_observation(variable='thermal_frequencies', trait='thermal frequencies', + outputs.add_observation(variable=prefix + 'thermal_frequencies', trait='thermal frequencies', method='plantcv.plantcv.analyze_thermal_values', scale='frequency', datatype=list, value=hist_percent, label=bin_labels) analysis_img = None @@ -87,7 +94,8 @@ def analyze_thermal_values(thermal_array, mask, histplot=False): analysis_img = fig_hist if params.debug == "print": - fig_hist.save(os.path.join(params.debug_outdir, str(params.device) + '_therm_histogram.png'), verbose=False) + fig_hist.save(os.path.join(params.debug_outdir, str(params.device) + prefix + '_therm_histogram.png'), + verbose=False) elif params.debug == "plot": print(fig_hist) From 0075ba6e807fe00d651b8670cce961ae2dec75c9 Mon Sep 17 00:00:00 2001 From: HaleySchuhl Date: Thu, 14 Jan 2021 10:43:56 -0600 Subject: [PATCH 062/137] Update landmark_reference_pt_dist.py --- plantcv/plantcv/landmark_reference_pt_dist.py | 24 ++++++++++++------- 1 file changed, 15 insertions(+), 9 deletions(-) diff --git a/plantcv/plantcv/landmark_reference_pt_dist.py b/plantcv/plantcv/landmark_reference_pt_dist.py index 5d8f0e4b7..c24ee4231 100755 --- a/plantcv/plantcv/landmark_reference_pt_dist.py +++ b/plantcv/plantcv/landmark_reference_pt_dist.py @@ -7,7 +7,7 @@ from plantcv.plantcv import outputs -def landmark_reference_pt_dist(points_r, centroid_r, bline_r): +def landmark_reference_pt_dist(points_r, centroid_r, bline_r, label=None): """landmark_reference_pt_dist For each point in contour, get a point before (pre) and after (post) the point of interest. @@ -17,6 +17,7 @@ def landmark_reference_pt_dist(points_r, centroid_r, bline_r): points_r = a set of rescaled points (basically the output of the acute_vertex fxn after the scale_features fxn) centroid_r = a tuple that contains the rescaled centroid coordinates bline_r = a tuple that contains the rescaled boundary line - centroid coordinates + label = optional label parameter, modifies the variable name of observations recorded :param points_r: ndarray :param centroid_r: tuple @@ -92,27 +93,32 @@ def landmark_reference_pt_dist(points_r, centroid_r, bline_r): euc_ave_b = np.mean(euc_dist_b) ang_ave_b = np.mean(angles_b) - outputs.add_observation(variable='vert_ave_c', trait='average vertical distance from centroid', + if label == None: + prefix = "" + else: + prefix = label + "_" + + outputs.add_observation(variable=prefix + 'vert_ave_c', trait='average vertical distance from centroid', method='plantcv.plantcv.landmark_reference_pt_dist', scale='pixels', datatype=float, value=vert_ave_c, label='pixels') - outputs.add_observation(variable='hori_ave_c', trait='average horizontal distance from centeroid', + outputs.add_observation(variable=prefix + 'hori_ave_c', trait='average horizontal distance from centeroid', method='plantcv.plantcv.landmark_reference_pt_dist', scale='pixels', datatype=float, value=hori_ave_c, label='pixels') - outputs.add_observation(variable='euc_ave_c', trait='average euclidean distance from centroid', + outputs.add_observation(variable=prefix + 'euc_ave_c', trait='average euclidean distance from centroid', method='plantcv.plantcv.landmark_reference_pt_dist', scale='pixels', datatype=float, value=euc_ave_c, label='pixels') - outputs.add_observation(variable='ang_ave_c', trait='average angle between landmark point and centroid', + outputs.add_observation(variable=prefix + 'ang_ave_c', trait='average angle between landmark point and centroid', method='plantcv.plantcv.landmark_reference_pt_dist', scale='degrees', datatype=float, value=ang_ave_c, label='degrees') - outputs.add_observation(variable='vert_ave_b', trait='average vertical distance from baseline', + outputs.add_observation(variable=prefix + 'vert_ave_b', trait='average vertical distance from baseline', method='plantcv.plantcv.landmark_reference_pt_dist', scale='pixels', datatype=float, value=vert_ave_b, label='pixels') - outputs.add_observation(variable='hori_ave_b', trait='average horizontal distance from baseline', + outputs.add_observation(variable=prefix + 'hori_ave_b', trait='average horizontal distance from baseline', method='plantcv.plantcv.landmark_reference_pt_dist', scale='pixels', datatype=float, value=hori_ave_b, label='pixels') - outputs.add_observation(variable='euc_ave_b', trait='average euclidean distance from baseline', + outputs.add_observation(variable=prefix + 'euc_ave_b', trait='average euclidean distance from baseline', method='plantcv.plantcv.landmark_reference_pt_dist', scale='pixels', datatype=float, value=euc_ave_b, label='pixels') - outputs.add_observation(variable='ang_ave_b', trait='average angle between landmark point and baseline', + outputs.add_observation(variable=prefix + 'ang_ave_b', trait='average angle between landmark point and baseline', method='plantcv.plantcv.landmark_reference_pt_dist', scale='degrees', datatype=float, value=ang_ave_b, label='degrees') From a41b272149a9574984d4a95d843ca85f68fae8f5 Mon Sep 17 00:00:00 2001 From: HaleySchuhl Date: Thu, 14 Jan 2021 10:45:23 -0600 Subject: [PATCH 063/137] Update opening.py --- plantcv/plantcv/opening.py | 2 ++ 1 file changed, 2 insertions(+) diff --git a/plantcv/plantcv/opening.py b/plantcv/plantcv/opening.py index ecf704f70..6235e9b77 100644 --- a/plantcv/plantcv/opening.py +++ b/plantcv/plantcv/opening.py @@ -1,3 +1,5 @@ +# Remove small bright spots + import os import numpy as np from skimage import morphology From 5691e7186d23fad25bc31c8c38b4b678202d212b Mon Sep 17 00:00:00 2001 From: HaleySchuhl Date: Thu, 14 Jan 2021 10:47:17 -0600 Subject: [PATCH 064/137] Update report_size_marker_area.py --- plantcv/plantcv/report_size_marker_area.py | 19 +++++++++++++------ 1 file changed, 13 insertions(+), 6 deletions(-) diff --git a/plantcv/plantcv/report_size_marker_area.py b/plantcv/plantcv/report_size_marker_area.py index 4c24e88f0..eb6fa9e39 100755 --- a/plantcv/plantcv/report_size_marker_area.py +++ b/plantcv/plantcv/report_size_marker_area.py @@ -17,7 +17,7 @@ def report_size_marker_area(img, roi_contour, roi_hierarchy, marker='define', objcolor='dark', thresh_channel=None, - thresh=None): + thresh=None, label=None): """Detects a size marker in a specified region and reports its size and eccentricity Inputs: @@ -29,6 +29,7 @@ def report_size_marker_area(img, roi_contour, roi_hierarchy, marker='define', ob objcolor = Object color is 'dark' or 'light' (is the marker darker or lighter than the background) thresh_channel = 'h', 's', or 'v' for hue, saturation or value thresh = Binary threshold value (integer) + label = optional label parameter, modifies the variable name of observations recorded Returns: analysis_images = List of output images @@ -40,6 +41,7 @@ def report_size_marker_area(img, roi_contour, roi_hierarchy, marker='define', ob :param objcolor: str :param thresh_channel: str :param thresh: int + :param label: str :return: analysis_images: list """ # Store debug @@ -119,21 +121,26 @@ def report_size_marker_area(img, roi_contour, roi_hierarchy, marker='define', ob # Reset debug mode params.debug = debug + if label == None: + prefix = "" + else: + prefix = label + "_" + if params.debug == 'print': - print_image(ref_img, os.path.join(params.debug_outdir, str(params.device) + '_marker_shape.png')) + print_image(ref_img, os.path.join(params.debug_outdir, str(params.device) + prefix + '_marker_shape.png')) elif params.debug == 'plot': plot_image(ref_img) - outputs.add_observation(variable='marker_area', trait='marker area', + outputs.add_observation(variable=prefix + 'marker_area', trait='marker area', method='plantcv.plantcv.report_size_marker_area', scale='pixels', datatype=int, value=marker_area, label='pixels') - outputs.add_observation(variable='marker_ellipse_major_axis', trait='marker ellipse major axis length', + outputs.add_observation(variable=prefix + 'marker_ellipse_major_axis', trait='marker ellipse major axis length', method='plantcv.plantcv.report_size_marker_area', scale='pixels', datatype=int, value=major_axis_length, label='pixels') - outputs.add_observation(variable='marker_ellipse_minor_axis', trait='marker ellipse minor axis length', + outputs.add_observation(variable=prefix + 'marker_ellipse_minor_axis', trait='marker ellipse minor axis length', method='plantcv.plantcv.report_size_marker_area', scale='pixels', datatype=int, value=minor_axis_length, label='pixels') - outputs.add_observation(variable='marker_ellipse_eccentricity', trait='marker ellipse eccentricity', + outputs.add_observation(variable=prefix + 'marker_ellipse_eccentricity', trait='marker ellipse eccentricity', method='plantcv.plantcv.report_size_marker_area', scale='none', datatype=float, value=eccentricity, label='none') From b0d902df23c7b82d6b229fa55844b91d27349fa1 Mon Sep 17 00:00:00 2001 From: HaleySchuhl Date: Thu, 14 Jan 2021 10:48:15 -0600 Subject: [PATCH 065/137] Update roi_objects.py --- plantcv/plantcv/roi_objects.py | 2 ++ 1 file changed, 2 insertions(+) diff --git a/plantcv/plantcv/roi_objects.py b/plantcv/plantcv/roi_objects.py index cfc2b22cd..2574627ab 100755 --- a/plantcv/plantcv/roi_objects.py +++ b/plantcv/plantcv/roi_objects.py @@ -1,3 +1,5 @@ +# Find objects partially inside a region of interest or cuts objects to the ROI + import cv2 import numpy as np import os From dc137f5aaba646062b71233aced08eeff5dd2703 Mon Sep 17 00:00:00 2001 From: HaleySchuhl Date: Thu, 14 Jan 2021 10:50:37 -0600 Subject: [PATCH 066/137] update watershed --- plantcv/plantcv/roi_objects.py | 2 +- plantcv/plantcv/watershed.py | 16 ++++++++++++---- 2 files changed, 13 insertions(+), 5 deletions(-) diff --git a/plantcv/plantcv/roi_objects.py b/plantcv/plantcv/roi_objects.py index 2574627ab..3ac9a30ff 100755 --- a/plantcv/plantcv/roi_objects.py +++ b/plantcv/plantcv/roi_objects.py @@ -1,4 +1,4 @@ -# Find objects partially inside a region of interest or cuts objects to the ROI +# Find objects partially inside a region of interest or cuts objects to the ROI import cv2 import numpy as np diff --git a/plantcv/plantcv/watershed.py b/plantcv/plantcv/watershed.py index 99b02c803..7d3313bb2 100755 --- a/plantcv/plantcv/watershed.py +++ b/plantcv/plantcv/watershed.py @@ -16,7 +16,7 @@ from plantcv.plantcv import outputs -def watershed_segmentation(rgb_img, mask, distance=10): +def watershed_segmentation(rgb_img, mask, distance=10, label=None): """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). @@ -24,6 +24,7 @@ def watershed_segmentation(rgb_img, mask, distance=10): rgb_img = image to perform watershed on needs to be 3D (i.e. np.shape = x,y,z not np.shape = x,y) mask = binary image, single channel, object in white and background black distance = min_distance of local maximum + label = optional label parameter, modifies the variable name of observations recorded Returns: analysis_images = list of output images @@ -31,6 +32,7 @@ def watershed_segmentation(rgb_img, mask, distance=10): :param rgb_img: numpy.ndarray :param mask: numpy.ndarray :param distance: int + :param label: str :return analysis_images: list """ params.device += 1 @@ -59,16 +61,22 @@ def watershed_segmentation(rgb_img, mask, distance=10): estimated_object_count = len(np.unique(markers)) - 1 + if label == None: + prefix = "" + else: + prefix = label + "_" + # 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')) + print_image(dist_transform, os.path.join(params.debug_outdir, str(params.device) + prefix + + '_watershed_dist_img.png')) + print_image(joined, os.path.join(params.debug_outdir, str(params.device) + prefix + '_watershed_img.png')) elif params.debug == 'plot': plot_image(dist_transform, cmap='gray') plot_image(joined) - outputs.add_observation(variable='estimated_object_count', trait='estimated object count', + outputs.add_observation(variable=prefix + 'estimated_object_count', trait='estimated object count', method='plantcv.plantcv.watershed', scale='none', datatype=int, value=estimated_object_count, label='none') From bbf64b68b2ff2a97e282e1da1296e8f64702a2b7 Mon Sep 17 00:00:00 2001 From: HaleySchuhl Date: Thu, 14 Jan 2021 10:52:00 -0600 Subject: [PATCH 067/137] Update within_frame.py --- plantcv/plantcv/within_frame.py | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/plantcv/plantcv/within_frame.py b/plantcv/plantcv/within_frame.py index 191d9fd1b..25be246e1 100644 --- a/plantcv/plantcv/within_frame.py +++ b/plantcv/plantcv/within_frame.py @@ -5,18 +5,20 @@ from plantcv.plantcv import outputs -def within_frame(mask, border_width=1): +def within_frame(mask, border_width=1, label=None): """ This function tests whether the plant touches the edge of the image, i.e. it is completely in the field of view. Input: mask = a binary image of 0 and nonzero values border_width = distance from border of image considered out of frame (default = 1) + label = optional label parameter, modifies the variable name of observations recorded Returns: in_bounds = a boolean (True or False) confirming that the object does not touch the edge of the image :param mask: numpy.ndarray :param border_width: int + :param label: str :return in_bounds: bool """ @@ -41,7 +43,12 @@ def within_frame(mask, border_width=1): out_of_bounds = bool(np.count_nonzero(border_pxs)) in_bounds = not out_of_bounds - outputs.add_observation(variable='in_bounds', trait='whether the plant goes out of bounds ', + if label == None: + prefix = "" + else: + prefix = label + "_" + + outputs.add_observation(variable=prefix + 'in_bounds', trait='whether the plant goes out of bounds ', method='plantcv.plantcv.within_frame', scale='none', datatype=bool, value=in_bounds, label='none') From 2af22347ccec7a4fe6e025155b148ba02142f196 Mon Sep 17 00:00:00 2001 From: HaleySchuhl Date: Thu, 14 Jan 2021 10:59:08 -0600 Subject: [PATCH 068/137] Update x_axis_pseudolandmarks.py --- plantcv/plantcv/x_axis_pseudolandmarks.py | 15 +++++++++++---- 1 file changed, 11 insertions(+), 4 deletions(-) diff --git a/plantcv/plantcv/x_axis_pseudolandmarks.py b/plantcv/plantcv/x_axis_pseudolandmarks.py index a007f6882..3709d2b2f 100755 --- a/plantcv/plantcv/x_axis_pseudolandmarks.py +++ b/plantcv/plantcv/x_axis_pseudolandmarks.py @@ -10,13 +10,14 @@ from plantcv.plantcv import fatal_error -def x_axis_pseudolandmarks(img, obj, mask): +def x_axis_pseudolandmarks(img, obj, mask, label=None): """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 obj = a contour of the plant object (this should be output from the object_composition.py fxn) mask = this is a binary image. The object should be white and the background should be black + label = optional label parameter, modifies the variable name of observations recorded Returns: top = List of landmark points within 'top' portion @@ -26,6 +27,7 @@ def x_axis_pseudolandmarks(img, obj, mask): :param img: numpy.ndarray :param obj: list :param mask: numpy.ndarray + :param label: str :return top: list :return bottom: list :return center_v: list @@ -216,13 +218,18 @@ def x_axis_pseudolandmarks(img, obj, mask): for pt in center_v: center_v_list.append(pt[0].tolist()) - outputs.add_observation(variable='top_lmk', trait='top landmark coordinates', + if label == None: + prefix = "" + else: + prefix = label + "_" + + outputs.add_observation(variable=prefix + 'top_lmk', trait='top landmark coordinates', method='plantcv.plantcv.x_axis_pseudolandmarks', scale='none', datatype=tuple, value=tuple(top_list), label='none') - outputs.add_observation(variable='bottom_lmk', trait='bottom landmark coordinates', + outputs.add_observation(variable=prefix + 'bottom_lmk', trait='bottom landmark coordinates', method='plantcv.plantcv.x_axis_pseudolandmarks', scale='none', datatype=tuple, value=tuple(bottom_list), label='none') - outputs.add_observation(variable='center_v_lmk', trait='center vertical landmark coordinates', + outputs.add_observation(variable=prefix + 'center_v_lmk', trait='center vertical landmark coordinates', method='plantcv.plantcv.x_axis_pseudolandmarks', scale='none', datatype=tuple, value=tuple(center_v_list), label='none') From 5eec2df280e383f2ae8c1121a14783c663b98e0a Mon Sep 17 00:00:00 2001 From: HaleySchuhl Date: Thu, 14 Jan 2021 10:59:13 -0600 Subject: [PATCH 069/137] Update within_frame.py --- plantcv/plantcv/within_frame.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/plantcv/plantcv/within_frame.py b/plantcv/plantcv/within_frame.py index 25be246e1..116080a76 100644 --- a/plantcv/plantcv/within_frame.py +++ b/plantcv/plantcv/within_frame.py @@ -18,7 +18,7 @@ def within_frame(mask, border_width=1, label=None): :param mask: numpy.ndarray :param border_width: int - :param label: str + :param label: str :return in_bounds: bool """ From d7ca299e7073dd9a19a93bd311016c5e289b0fe4 Mon Sep 17 00:00:00 2001 From: HaleySchuhl Date: Thu, 14 Jan 2021 11:01:50 -0600 Subject: [PATCH 070/137] Update y_axis_pseudolandmarks.py --- plantcv/plantcv/y_axis_pseudolandmarks.py | 15 +++++++++++---- 1 file changed, 11 insertions(+), 4 deletions(-) diff --git a/plantcv/plantcv/y_axis_pseudolandmarks.py b/plantcv/plantcv/y_axis_pseudolandmarks.py index c08f0e146..1c3753b65 100755 --- a/plantcv/plantcv/y_axis_pseudolandmarks.py +++ b/plantcv/plantcv/y_axis_pseudolandmarks.py @@ -10,13 +10,14 @@ from plantcv.plantcv import fatal_error -def y_axis_pseudolandmarks(img, obj, mask): +def y_axis_pseudolandmarks(img, obj, mask, label=None): """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 obj = a contour of the plant object (this should be output from the object_composition.py fxn) mask = this is a binary image. The object should be white and the background should be black + label = optional label parameter, modifies the variable name of observations recorded Returns: left = List of landmarks within the left side @@ -26,6 +27,7 @@ def y_axis_pseudolandmarks(img, obj, mask): :param img: numpy.ndarray :param obj: list :param mask: numpy.ndarray + :param label: str :return left: list :return right: list :return center_h: list @@ -213,13 +215,18 @@ def y_axis_pseudolandmarks(img, obj, mask): for pt in center_h: center_h_list.append(pt[0].tolist()) - outputs.add_observation(variable='left_lmk', trait='left landmark coordinates', + if label == None: + prefix = "" + else: + prefix = label + "_" + + outputs.add_observation(variable=prefix + 'left_lmk', trait='left landmark coordinates', method='plantcv.plantcv.x_axis_pseudolandmarks', scale='none', datatype=tuple, value=tuple(left_list), label='none') - outputs.add_observation(variable='right_lmk', trait='right landmark coordinates', + outputs.add_observation(variable=prefix + 'right_lmk', trait='right landmark coordinates', method='plantcv.plantcv.x_axis_pseudolandmarks', scale='none', datatype=tuple, value=tuple(right_list), label='none') - outputs.add_observation(variable='center_h_lmk', trait='center horizontal landmark coordinates', + outputs.add_observation(variable=prefix + 'center_h_lmk', trait='center horizontal landmark coordinates', method='plantcv.plantcv.x_axis_pseudolandmarks', scale='none', datatype=tuple, value=tuple(center_h_list), label='none') From e958e7b5c621b6ae7984fcb3b4e1360792427423 Mon Sep 17 00:00:00 2001 From: HaleySchuhl Date: Thu, 14 Jan 2021 11:12:14 -0600 Subject: [PATCH 071/137] Update tests.py add cases to cover new code --- tests/tests.py | 26 +++++++++++++------------- 1 file changed, 13 insertions(+), 13 deletions(-) diff --git a/tests/tests.py b/tests/tests.py index 7d89dc498..144af0f80 100755 --- a/tests/tests.py +++ b/tests/tests.py @@ -1046,7 +1046,7 @@ def test_plantcv_acute_vertex(): 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) + _ = 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" @@ -1081,7 +1081,7 @@ def test_plantcv_analyze_bound_horizontal(): object_contours = contours_npz['arr_0'] # Test with debug = "print" pcv.params.debug = "print" - _ = pcv.analyze_bound_horizontal(img=img, obj=object_contours, mask=mask, line_position=300) + _ = pcv.analyze_bound_horizontal(img=img, obj=object_contours, mask=mask, line_position=300, label="prefix") _ = 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" @@ -1142,7 +1142,7 @@ def test_plantcv_analyze_bound_vertical(): 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) + _ = 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) @@ -1219,7 +1219,7 @@ def test_plantcv_analyze_color(): # Test with debug = "print" pcv.params.debug = "print" _ = pcv.analyze_color(rgb_img=img, mask=mask, hist_plot_type="all") - _ = pcv.analyze_color(rgb_img=img, mask=mask, hist_plot_type=None) + _ = pcv.analyze_color(rgb_img=img, mask=mask, hist_plot_type=None, label="prefix") # Test with debug = "plot" pcv.params.debug = "plot" @@ -1269,7 +1269,7 @@ def test_plantcv_analyze_nir(): mask = cv2.imread(os.path.join(TEST_DATA, TEST_INPUT_BINARY), -1) # Test with debug = "print" pcv.params.debug = "print" - _ = pcv.analyze_nir_intensity(gray_img=np.uint16(img), mask=mask, bins=256, histplot=True) + _ = pcv.analyze_nir_intensity(gray_img=np.uint16(img), mask=mask, bins=256, histplot=True, label="prefix") # Test with debug = "plot" pcv.params.debug = "plot" _ = pcv.analyze_nir_intensity(gray_img=img, mask=mask, bins=256, histplot=False) @@ -1297,7 +1297,7 @@ def test_plantcv_analyze_object(): # max_obj = max(obj_contour, key=len) # Test with debug = "print" pcv.params.debug = "print" - _ = pcv.analyze_object(img=img, obj=obj_contour, mask=mask) + _ = pcv.analyze_object(img=img, obj=obj_contour, mask=mask, label="prefix") # Test with debug = "plot" pcv.params.debug = "plot" _ = pcv.analyze_object(img=img, obj=obj_contour, mask=mask) @@ -1421,7 +1421,7 @@ def test_plantcv_analyze_thermal_values(): img = contours_npz['arr_0'] # Test with debug = "print" pcv.params.debug = "print" - _ = pcv.analyze_thermal_values(thermal_array=img, mask=mask, histplot=True) + _ = pcv.analyze_thermal_values(thermal_array=img, mask=mask, histplot=True, label="prefix") pcv.params.debug = "plot" thermal_hist = pcv.analyze_thermal_values(thermal_array=img, mask=mask, histplot=True) pcv.print_results(os.path.join(cache_dir, "results.txt")) @@ -2277,7 +2277,7 @@ def test_plantcv_landmark_reference_pt_dist(): (0.6458, 0.3472), (0.6389, 0.5208), (0.6458, 0.625)] centroid_rescaled = (0.4685, 0.4945) bottomline_rescaled = (0.4685, 0.2569) - _ = pcv.landmark_reference_pt_dist(points_r=[], centroid_r=('a', 'b'), bline_r=(0, 0)) + _ = pcv.landmark_reference_pt_dist(points_r=[], centroid_r=('a', 'b'), bline_r=(0, 0), label="prefix") _ = pcv.landmark_reference_pt_dist(points_r=[(10, 1000)], centroid_r=(10, 10), bline_r=(10, 10)) _ = pcv.landmark_reference_pt_dist(points_r=[], centroid_r=(0, 0), bline_r=(0, 0)) pcv.landmark_reference_pt_dist(points_r=points_rescaled, centroid_r=centroid_rescaled, bline_r=bottomline_rescaled) @@ -2493,7 +2493,7 @@ def test_plantcv_within_frame(): # Read in test data mask_ib = cv2.imread(os.path.join(TEST_DATA, TEST_INPUT_MASK), -1) mask_oob = cv2.imread(os.path.join(TEST_DATA, TEST_INPUT_MASK_OOB), -1) - in_bounds_ib = pcv.within_frame(mask=mask_ib, border_width=1) + in_bounds_ib = pcv.within_frame(mask=mask_ib, border_width=1, label="prefix") in_bounds_oob = pcv.within_frame(mask=mask_oob, border_width=1) assert (in_bounds_ib is True and in_bounds_oob is False) @@ -2861,7 +2861,7 @@ def test_plantcv_report_size_marker_detect(): # 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) + 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', @@ -3266,7 +3266,7 @@ def test_plantcv_watershed_segmentation(): 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) + _ = 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) @@ -3387,7 +3387,7 @@ def test_plantcv_x_axis_pseudolandmarks(): _ = pcv.x_axis_pseudolandmarks(obj=obj_contour, mask=mask, img=img) # Test with debug = "plot" pcv.params.debug = "plot" - _ = pcv.x_axis_pseudolandmarks(obj=obj_contour, mask=mask, img=img) + _ = 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) @@ -3446,7 +3446,7 @@ def test_plantcv_y_axis_pseudolandmarks(): 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) + _ = 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) From aae5a68b1fa8386ccbce8fdc56da5a7d30d8ed5e Mon Sep 17 00:00:00 2001 From: HaleySchuhl Date: Thu, 14 Jan 2021 12:35:26 -0600 Subject: [PATCH 072/137] Update tests.py --- tests/tests.py | 1 + 1 file changed, 1 insertion(+) diff --git a/tests/tests.py b/tests/tests.py index 144af0f80..405d1c3a8 100755 --- a/tests/tests.py +++ b/tests/tests.py @@ -1082,6 +1082,7 @@ def test_plantcv_analyze_bound_horizontal(): # Test with debug = "print" pcv.params.debug = "print" _ = 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" From 907031bd6c5cc4dfe90e822d7c891b1ef9d20f3a Mon Sep 17 00:00:00 2001 From: HaleySchuhl Date: Thu, 14 Jan 2021 13:03:46 -0600 Subject: [PATCH 073/137] Update tests.py --- tests/tests.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/tests/tests.py b/tests/tests.py index 405d1c3a8..6695de100 100755 --- a/tests/tests.py +++ b/tests/tests.py @@ -4781,7 +4781,7 @@ def test_plantcv_photosynthesis_analyze_fvfm(): fmask = cv2.imread(os.path.join(TEST_DATA, TEST_INPUT_FMASK), -1) # Test with debug = "print" pcv.params.debug = "print" - _ = pcv.photosynthesis.analyze_fvfm(fdark=fdark, fmin=fmin, fmax=fmax, mask=fmask, bins=1000) + _ = pcv.photosynthesis.analyze_fvfm(fdark=fdark, fmin=fmin, fmax=fmax, mask=fmask, bins=1000, label="prefix") # Test with debug = "plot" pcv.params.debug = "plot" fvfm_images = pcv.photosynthesis.analyze_fvfm(fdark=fdark, fmin=fmin, fmax=fmax, mask=fmask, bins=1000) @@ -5369,7 +5369,7 @@ def test_plantcv_transform_find_color_card(): # Test with debug = "print" pcv.params.debug = "print" _ = pcv.transform.create_color_card_mask(rgb_img=rgb_img, radius=6, start_coord=start, - spacing=space, nrows=6, ncols=4, exclude=[20, 0]) + spacing=space, nrows=6, ncols=4, exclude=[20, 0], label="prefix") # Test with debug = "plot" pcv.params.debug = "plot" _ = pcv.transform.create_color_card_mask(rgb_img=rgb_img, radius=6, start_coord=start, From f00cad948d212859c176f40f52f5744a8c04e355 Mon Sep 17 00:00:00 2001 From: HaleySchuhl Date: Thu, 14 Jan 2021 13:30:35 -0600 Subject: [PATCH 074/137] Update tests.py --- tests/tests.py | 18 +++--------------- 1 file changed, 3 insertions(+), 15 deletions(-) diff --git a/tests/tests.py b/tests/tests.py index 6695de100..4898b2b2e 100755 --- a/tests/tests.py +++ b/tests/tests.py @@ -5369,7 +5369,7 @@ def test_plantcv_transform_find_color_card(): # Test with debug = "print" pcv.params.debug = "print" _ = pcv.transform.create_color_card_mask(rgb_img=rgb_img, radius=6, start_coord=start, - spacing=space, nrows=6, ncols=4, exclude=[20, 0], label="prefix") + spacing=space, nrows=6, ncols=4, exclude=[20, 0]) # Test with debug = "plot" pcv.params.debug = "plot" _ = pcv.transform.create_color_card_mask(rgb_img=rgb_img, radius=6, start_coord=start, @@ -5392,20 +5392,8 @@ def test_plantcv_transform_find_color_card_optional_parameters(): pcv.params.debug_outdir = cache_dir # Test with threshold ='normal' df1, start1, space1 = pcv.transform.find_color_card(rgb_img=rgb_img, threshold_type='normal', blurry=True, - background='light', threshvalue=90) - _ = pcv.transform.create_color_card_mask(rgb_img=rgb_img, radius=6, start_coord=start1, - spacing=space1, nrows=6, ncols=4, exclude=[20, 0]) - # Test with threshold='otsu' - df2, start2, space2 = pcv.transform.find_color_card(rgb_img=rgb_img, threshold_type='otsu', blurry=True) - _ = pcv.transform.create_color_card_mask(rgb_img=rgb_img, radius=6, start_coord=start2, - spacing=space2, nrows=6, ncols=4, exclude=[20, 0]) - # Test with debug = None - pcv.params.debug = None - mask = pcv.transform.create_color_card_mask(rgb_img=rgb_img, radius=6, start_coord=start2, - spacing=space2, nrows=6, ncols=4, exclude=[20, 0]) - assert all([i == j] for i, j in zip(np.unique(mask), np.array([0, 10, 20, 30, 40, 50, 60, 70, 80, 90, 100, 110, - 120, 130, 140, 150, 160, 170, 180, 190, 200, 210, - 220], dtype=np.uint8))) + background='light', threshvalue=90, label="prefix") + assert pcv.outputs.observations["prefix_color_chip_size"]["value"] > 15000 def test_plantcv_transform_find_color_card_optional_size_parameters(): From e53e339b1a9f317dd00b197eec097c4d8e651277 Mon Sep 17 00:00:00 2001 From: HaleySchuhl Date: Thu, 14 Jan 2021 14:09:23 -0600 Subject: [PATCH 075/137] Update tests.py --- tests/tests.py | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/tests/tests.py b/tests/tests.py index 4898b2b2e..b0911ed5b 100755 --- a/tests/tests.py +++ b/tests/tests.py @@ -2278,13 +2278,14 @@ def test_plantcv_landmark_reference_pt_dist(): (0.6458, 0.3472), (0.6389, 0.5208), (0.6458, 0.625)] centroid_rescaled = (0.4685, 0.4945) bottomline_rescaled = (0.4685, 0.2569) - _ = pcv.landmark_reference_pt_dist(points_r=[], centroid_r=('a', 'b'), bline_r=(0, 0), label="prefix") + _ = pcv.landmark_reference_pt_dist(points_r=[], centroid_r=('a', 'b'), bline_r=(0, 0)) _ = pcv.landmark_reference_pt_dist(points_r=[(10, 1000)], centroid_r=(10, 10), bline_r=(10, 10)) _ = pcv.landmark_reference_pt_dist(points_r=[], centroid_r=(0, 0), bline_r=(0, 0)) - pcv.landmark_reference_pt_dist(points_r=points_rescaled, centroid_r=centroid_rescaled, bline_r=bottomline_rescaled) + pcv.landmark_reference_pt_dist(points_r=points_rescaled, centroid_r=centroid_rescaled, bline_r=bottomline_rescaled, + label="prefix") pcv.print_results(os.path.join(cache_dir, "results.txt")) + assert len(pcv.outputs.observations) == 8 pcv.outputs.clear() - assert len(pcv.outputs.observations) == 0 def test_plantcv_laplace_filter(): From 4ce25e4e010bf77c6b46707861ec8e8b266d188f Mon Sep 17 00:00:00 2001 From: HaleySchuhl Date: Thu, 14 Jan 2021 14:30:47 -0600 Subject: [PATCH 076/137] last testing update i hope --- tests/tests.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/tests.py b/tests/tests.py index b0911ed5b..54030b504 100755 --- a/tests/tests.py +++ b/tests/tests.py @@ -2284,7 +2284,7 @@ def test_plantcv_landmark_reference_pt_dist(): pcv.landmark_reference_pt_dist(points_r=points_rescaled, centroid_r=centroid_rescaled, bline_r=bottomline_rescaled, label="prefix") pcv.print_results(os.path.join(cache_dir, "results.txt")) - assert len(pcv.outputs.observations) == 8 + assert len(pcv.outputs.observations) == 42 pcv.outputs.clear() From 375135064efa298b390f2b6b629dc178eff0b3bb Mon Sep 17 00:00:00 2001 From: HaleySchuhl Date: Thu, 14 Jan 2021 14:37:47 -0600 Subject: [PATCH 077/137] Update acute_vertex.md --- docs/acute_vertex.md | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/docs/acute_vertex.md b/docs/acute_vertex.md index 8787ff509..32bd78a4d 100644 --- a/docs/acute_vertex.md +++ b/docs/acute_vertex.md @@ -3,7 +3,7 @@ Perform a heuristic search for sharp angles given an object contour and user specified parameters. The acute (sharp) angles are often associated with object tip points. Outputs a python list of points that meet criteria specified in parameters. -**plantcv.acute_vertex**(*img, obj, window, thresh, sep*) +**plantcv.acute_vertex**(*img, obj, window, thresh, sep, label=None*) **returns** list of points that meet specified criteria, image with points selected @@ -13,6 +13,7 @@ angles are often associated with object tip points. Outputs a python list of poi - window - The pre and post point distances on which to calculate angle of focal point (a value of 30 worked well for a sample image) on which to calculate the angle - thresh - Threshold to set for acuteness; keep points with an angle more acute than the threshold (a value of 15 worked well for sample image) - sep - The number of contour points to search within for the most acute value + - label - Optional label parameter, modifies the variable name of observations recorded. (default `label=None`) - **Context:** - Used to identify tip points based upon the angle between focal pixel and reference points on contour. - **Output data stored:** Data ('tip_coordinates') automatically gets stored to the [`Outputs` class](outputs.md) when this function is ran. @@ -32,7 +33,7 @@ pcv.params.debug = "print" # Identify acute vertices (tip points) of an object # Results in set of point values that may indicate tip points -list_of_acute_points, points_img = pcv.acute_vertex(img, obj, 30, 15, 100) +list_of_acute_points, points_img = pcv.acute_vertex(img=img, obj=obj, window=30, thresh=15, sep=100, label=None) ` # Access data stored out from acute_vertex vertices = pcv.outputs.observations['tip_coordinates']['value'] From 9e8ad035453a51af604208bda2ffffb8ba09fe45 Mon Sep 17 00:00:00 2001 From: HaleySchuhl Date: Thu, 14 Jan 2021 14:39:16 -0600 Subject: [PATCH 078/137] Update analyze_bound_horizontal.md --- docs/analyze_bound_horizontal.md | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/docs/analyze_bound_horizontal.md b/docs/analyze_bound_horizontal.md index 9d3ba8f96..9ac46824c 100644 --- a/docs/analyze_bound_horizontal.md +++ b/docs/analyze_bound_horizontal.md @@ -4,7 +4,7 @@ Set boundary line with boundary tool, this allows the user to find the extent-y above and below as well as the area above and below the boundary line. This tool functions best if the pot size/position of the plant remains relatively constant. -**plantcv.analyze_bound_horizontal**(*img, obj, mask, line_position*) +**plantcv.analyze_bound_horizontal**(*img, obj, mask, line_position, label=None*) **returns** image with boundary data @@ -13,6 +13,7 @@ best if the pot size/position of the plant remains relatively constant. - obj - single or grouped contour object - mask - binary mask of selected contours - line_position - position of boundary line (a value of 0 would draw the line through the top of the image) + - label - Optional label parameter, modifies the variable name of observations recorded. (default `label=None`) - **Context:** - Used to define a boundary line for the image, to find the height above and below as well as area above and below a boundary line. - **Example use:** @@ -30,7 +31,7 @@ from plantcv import plantcv as pcv pcv.params.debug = "print" # Set Boundary Line -boundary_image = pcv.analyze_bound_horizontal(img=img, obj=obj, mask=bin_mask, line_position=300) +boundary_image = pcv.analyze_bound_horizontal(img=img, obj=obj, mask=bin_mask, line_position=300, label=None) # Access data stored out from analyze_bound_horizontal percent_area_below_reference = pcv.outputs.observations['percent_area_below_reference']['value'] From 5032ce41b05c72b02e646e4303b7ca55cde58724 Mon Sep 17 00:00:00 2001 From: HaleySchuhl Date: Thu, 14 Jan 2021 14:40:02 -0600 Subject: [PATCH 079/137] Update analyze_bound_vertical.md --- docs/analyze_bound_vertical.md | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/docs/analyze_bound_vertical.md b/docs/analyze_bound_vertical.md index 65db1569b..d8309dc8a 100644 --- a/docs/analyze_bound_vertical.md +++ b/docs/analyze_bound_vertical.md @@ -4,7 +4,7 @@ Set boundary line with boundary tool, this allows the user to find the extent-x to the right and to the left as well as the area to the right and to the left of the set boundary line. This tool functions best if the pot size/position of the plant remains relatively constant. -**plantcv.analyze_bound_vertical**(*img, obj, mask, line_position*) +**plantcv.analyze_bound_vertical**(*img, obj, mask, line_position, label=None*) **returns** image with boundary data @@ -13,6 +13,7 @@ best if the pot size/position of the plant remains relatively constant. - obj - single or grouped contour object - mask - binary mask of selected contours - line_position - position of boundary line (a value of 0 would draw the line through the left of the image) + - label - Optional label parameter, modifies the variable name of observations recorded. (default `label=None`) - **Context:** - Used to define a boundary line for the image, to find the width to the right and to the left as well as area to the right and to the left of a boundary line. - **Example use:** @@ -30,7 +31,7 @@ from plantcv import plantcv as pcv pcv.params.debug = "print" # Set Boundary Line -boundary_image = pcv.analyze_bound_vertical(img=img, obj=obj, mask=bin_mask, line_position=1000) +boundary_image = pcv.analyze_bound_vertical(img=img, obj=obj, mask=bin_mask, line_position=1000, label=None) # Access data stored out from analyze_bound_vertical area_right_reference = pcv.outputs.observations['area_right_reference']['value'] From 74063ba53e88f0b325609d01b0e2dd7f71136a78 Mon Sep 17 00:00:00 2001 From: HaleySchuhl Date: Thu, 14 Jan 2021 14:41:03 -0600 Subject: [PATCH 080/137] Update analyze_NIR_intensity.md --- docs/analyze_NIR_intensity.md | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/docs/analyze_NIR_intensity.md b/docs/analyze_NIR_intensity.md index ae1f55f04..cb32b68e0 100644 --- a/docs/analyze_NIR_intensity.md +++ b/docs/analyze_NIR_intensity.md @@ -3,7 +3,7 @@ This function calculates the intensity of each pixel associated with the plant and writes the values out to the [Outputs class](outputs.md). Can also return/plot/print out a histogram plot of pixel intensity. -**plantcv.analyze_nir_intensity**(*gray_img, mask, bins=256, histplot=False*) +**plantcv.analyze_nir_intensity**(*gray_img, mask, bins=256, histplot=False, label=None*) **returns** Histogram image (when histplot is `True`, otherwise returns `None` object) @@ -12,6 +12,7 @@ the values out to the [Outputs class](outputs.md). Can also return/plot/print ou - mask - Binary mask made from selected contours - bins - Number of NIR intensity value groups (default bins = 256) - histplot - If True plots histogram of intensity values (default histplot = False) + - label - Optional label parameter, modifies the variable name of observations recorded. (default `label=None`) - **Context:** - Near Infrared pixel frequencies within a masked area of an image. - **Example use:** @@ -33,7 +34,7 @@ from plantcv import plantcv as pcv pcv.params.debug = "print" # Caclulates the proportion of pixels that fall into a signal bin and writes the values to a file. Also provides a histogram of this data -analysis_image = pcv.analyze_nir_intensity(gray_img, mask, 256, histplot=True) +analysis_image = pcv.analyze_nir_intensity(gray_img, mask, 256, histplot=True, label=None) # Access data stored out from analyze_nir_intensity nir_frequencies = pcv.outputs.observations['nir_frequencies']['value'] From 7e8ce45c8988ad8147dd2f447d82c15cd139bd10 Mon Sep 17 00:00:00 2001 From: HaleySchuhl Date: Thu, 14 Jan 2021 14:41:06 -0600 Subject: [PATCH 081/137] Update analyze_color.md --- docs/analyze_color.md | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/docs/analyze_color.md b/docs/analyze_color.md index bdbb30761..55b200bd6 100644 --- a/docs/analyze_color.md +++ b/docs/analyze_color.md @@ -2,7 +2,7 @@ Extract color data of objects and produce pseudocolored images, can extract data for RGB (Red, Green, Blue), HSV (Hue, Saturation, Value) and LAB (Lightness, Green-Magenta, Blue Yellow) channels. -**plantcv.analyze_color**(*rgb_img, mask, hist_plot_type=None*) +**plantcv.analyze_color**(*rgb_img, mask, hist_plot_type=None, label=None*) **returns** Histogram image (if hist_plot_type is not `None`, otherwise returns `None` object) @@ -10,6 +10,7 @@ Extract color data of objects and produce pseudocolored images, can extract data - rgb_img - RGB image data - mask - binary mask of selected contours - hist_plot_type - None (default), 'all', 'rgb', 'lab', or 'hsv'. This can limit the data saved out. Hue data is still saved out when set to None. + - label - Optional label parameter, modifies the variable name of observations recorded. (default `label=None`) - **Context:** - Used to extract color data from RGB, LAB, and HSV color channels. - Generates histogram of color channel data. @@ -35,7 +36,7 @@ pcv.params.debug = "print" # Analyze Color -analysis_image = pcv.analyze_color(rgb_img=rgb_img, mask=mask, hist_plot_type='all') +analysis_image = pcv.analyze_color(rgb_img=rgb_img, mask=mask, hist_plot_type='all', label=None) # Access data stored out from analyze_color hue_circular_mean = pcv.outputs.observations['hue_circular_mean']['value'] From 71396f1866c9b6032ed004a478519f741a33fe8b Mon Sep 17 00:00:00 2001 From: HaleySchuhl Date: Thu, 14 Jan 2021 14:41:55 -0600 Subject: [PATCH 082/137] Update analyze_shape.md --- docs/analyze_shape.md | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/docs/analyze_shape.md b/docs/analyze_shape.md index 5d3110f3f..48d554930 100644 --- a/docs/analyze_shape.md +++ b/docs/analyze_shape.md @@ -2,7 +2,7 @@ Shape analysis outputs numeric properties for an input object (contour or grouped contours), works best on grouped contours. -**plantcv.analyze_object**(*img, obj, mask*) +**plantcv.analyze_object**(*img, obj, mask, label=None*) **returns** analysis_image @@ -10,6 +10,7 @@ Shape analysis outputs numeric properties for an input object (contour or groupe - img - RGB or grayscale image data for plotting. - obj - Single or grouped contour object. - mask - Binary image to use as mask for moments analysis. + - label - Optional label parameter, modifies the variable name of observations recorded. (default `label=None`) - **Context:** - Used to output shape characteristics of an image, including height, object area, convex hull, convex hull area, perimeter, extent x, extent y, longest axis, centroid x coordinate, centroid y coordinate, in bounds QC (if object @@ -38,7 +39,7 @@ pcv.params.debug = "print" # Characterize object shapes -shape_image = pcv.analyze_object(img, objects, mask) +shape_image = pcv.analyze_object(img=img, obj=objects, mask=mask, label=None) # Save returned images with more specific naming pcv.print_image(shape_image, '/home/malia/setaria_shape_img.png') From eac14cb02220f3a307e6e0860b050e78d0178d77 Mon Sep 17 00:00:00 2001 From: HaleySchuhl Date: Thu, 14 Jan 2021 14:42:34 -0600 Subject: [PATCH 083/137] Update analyze_thermal_values.md --- docs/analyze_thermal_values.md | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/docs/analyze_thermal_values.md b/docs/analyze_thermal_values.md index ed58a5b04..c61d20fb7 100644 --- a/docs/analyze_thermal_values.md +++ b/docs/analyze_thermal_values.md @@ -3,7 +3,7 @@ This function calculates the intensity of each pixel associated with the temperature and writes the values out to a file. Can optionally create a histogram of pixel intensity. -**plantcv.analyze_thermal_values**(*thermal_array, mask, histplot=False*) +**plantcv.analyze_thermal_values**(*thermal_array, mask, histplot=False, label=None*) **returns** thermal histogram (if `histplot=True`, otherwise returns None object) @@ -11,6 +11,7 @@ the values out to a file. Can optionally create a histogram of pixel intensity. - thermal_array - Numpy array of thermal image data (most likely read in with [pcv.readimage](read_image.md) with `mode='csv'`) - mask - Binary mask made from selected contours - histplot - If True plots histogram of intensity values (default histplot = False) + - label - Optional label parameter, modifies the variable name of observations recorded. (default `label=None`) - **Context:** - Data about image temperature within a masked region. - **Example use:** @@ -33,7 +34,7 @@ from plantcv import plantcv as pcv pcv.params.debug = "print" # Caclulates the proportion of pixels that fall into a signal bin and writes the values to a file. Also provides a histogram of this data -thermal_hist = pcv.analyze_thermal_values(thermal_img, mask, histplot=True) +thermal_hist = pcv.analyze_thermal_values(thermal_array=thermal_img, maks=mask, histplot=True, label=None) # Access data stored out from analyze_thermal_values temp_range = pcv.outputs.observations['max_temp']['value'] - pcv.outputs.observations['min_temp']['value'] From 91bbe4a390031c56a16aa4f64aab37208b6a9e54 Mon Sep 17 00:00:00 2001 From: HaleySchuhl Date: Thu, 14 Jan 2021 14:46:35 -0600 Subject: [PATCH 084/137] Update find_color_card.md --- docs/find_color_card.md | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/docs/find_color_card.md b/docs/find_color_card.md index 7ac9a1725..9e47d2702 100644 --- a/docs/find_color_card.md +++ b/docs/find_color_card.md @@ -2,7 +2,7 @@ Automatically detects a color card's location and size. Useful in workflows where color card positioning isn't constant in all images. -**plantcv.transform.find_color_card**(*rgb_img, threshold_type='adaptgauss', threshvalue=125, blurry=False, background='dark', record_chip_size='median'*) +**plantcv.transform.find_color_card**(*rgb_img, threshold_type='adaptgauss', threshvalue=125, blurry=False, background='dark', record_chip_size='median', label=None*) **returns** df, start_coord, spacing @@ -13,6 +13,7 @@ Automatically detects a color card's location and size. Useful in workflows wher - blurry - Optional boolean, if True then image sharpening is applied (default blurry=False) - background - Optional, type of image background, either 'dark' or 'light' (default background='dark') - record_chip_size - Optional, for choosing chip size measurement to be recorded, either "median" (default), "mean", or None + - label - Optional label parameter, modifies the variable name of observations recorded. (default `label=None`) - **Returns** - df - Dataframe of all color card chips found. - start_coord - Two-element tuple of the first chip mask starting x and y coordinate. Useful in [create a color card mask](#create-a-labeled-color-card-mask) function. @@ -32,7 +33,8 @@ rgb_img, path, filename = pcv.readimage("target_img.png") df, start, space = pcv.transform.find_color_card(rgb_img=rgb_img) # Use these outputs to create a labeled color card mask -mask = pcv.transform.create_color_card_mask(rgb_img=img, radius=10, start_coord=start, spacing=space, ncols=6, nrows=4) +mask = pcv.transform.create_color_card_mask(rgb_img=img, radius=10, start_coord=start, spacing=space, ncols=6, nrows=4, label="prefix") +avg_chip_size = pcv.outputs.observations['prefix_color_chip_size']['value'] ``` From ca7d1c3c0d3ff6cd6e046f037e800106b9d9249b Mon Sep 17 00:00:00 2001 From: HaleySchuhl Date: Thu, 14 Jan 2021 14:49:51 -0600 Subject: [PATCH 085/137] Update landmark_reference_pt_dist.md --- docs/landmark_reference_pt_dist.md | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/docs/landmark_reference_pt_dist.md b/docs/landmark_reference_pt_dist.md index feb537792..33fa2cfc6 100644 --- a/docs/landmark_reference_pt_dist.md +++ b/docs/landmark_reference_pt_dist.md @@ -4,7 +4,7 @@ This is a function to measure the distance from user defined points to the centr along the x-axis and baseline coordinate (top of pot) along the y-axis. Calculating the vertical distance between leaf tip points to the centroid of the plant object in side-view images may provide a proxy measure of turgor pressure. -**plantcv.landmark_reference_pt_dist**(*points_r, centroid_r, bline_r*) +**plantcv.landmark_reference_pt_dist**(*points_r, centroid_r, bline_r, label=None*) **returns** none @@ -12,6 +12,7 @@ to the centroid of the plant object in side-view images may provide a proxy meas - points_r - A list of tuples representing rescaled landmark points - centroid_r - A tuple representing the rescaled centroid point - bline_r - A tuple representing the rescaled baseline point + - label - Optional label parameter, modifies the variable name of observations recorded. (default `label=None`) - **Context:** - Used to estimate the distance and angles of landmark points relative to shape reference landmarks (centroid and pot height aka baseline) - **Output data stored:** Data ('vert_ave_c', 'hori_ave_c', 'euc_ave_c', 'ang_ave_c', 'vert_ave_b', 'hori_ave_b', 'euc_ave_b', @@ -31,7 +32,7 @@ pcv.params.debug = "print" # Identify acute vertices (tip points) of an object # Results in set of point values that may indicate tip points -pcv.landmark_reference_pt_dist(points_r, centroid_r, bline_r) +pcv.landmark_reference_pt_dist(points_r=points_r, centroid_r=centroid_r, bline_r=bline_r, label=None) # Access data stored out from landmark_reference_pt_dist avg_vert_distance = pcv.outputs.observations['vert_ave_c']['value'] From 9bd8eb87148b2d7bb2aa3ce7d508300af934e541 Mon Sep 17 00:00:00 2001 From: HaleySchuhl Date: Thu, 14 Jan 2021 14:49:54 -0600 Subject: [PATCH 086/137] Update photosynthesis_analyze_fvfm.md --- docs/photosynthesis_analyze_fvfm.md | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/docs/photosynthesis_analyze_fvfm.md b/docs/photosynthesis_analyze_fvfm.md index 1181077e9..a3b7966a6 100644 --- a/docs/photosynthesis_analyze_fvfm.md +++ b/docs/photosynthesis_analyze_fvfm.md @@ -2,7 +2,7 @@ Extract Fv/Fm data of objects. -**plantcv.photosynthesis.analyze_fvfm**(*fdark, fmin, fmax, mask, bins=256*) +**plantcv.photosynthesis.analyze_fvfm**(*fdark, fmin, fmax, mask, bins=256, label=None*) **returns** PSII analysis images (Fv/Fm image, Fv/Fm histogram) @@ -12,6 +12,7 @@ Extract Fv/Fm data of objects. - fmax - image object, grayscale - mask - binary mask of selected contours - bins - number of grayscale bins (0-256 for 8-bit images and 0 to 65,536), if you would like to bin data, you would alter this number (default bins=256) + - label - Optional label parameter, modifies the variable name of observations recorded. (default `label=None`) - **Context:** - Used to extract Fv/Fm or Fv'/Fm' per identified plant pixel. - Generates histogram of Fv/Fm data. @@ -41,10 +42,10 @@ from plantcv import plantcv as pcv pcv.params.debug = "print" # Analyze Fv/Fm -fvfm_images = pcv.photosynthesis.analyze_fvfm(fdark, fmin, fmax, kept_mask, 256) +fvfm_images = pcv.photosynthesis.analyze_fvfm(fdark=fdark, fmin=fmin, fmax=fmax, mask=kept_mask, bins=256, label="fluor") # Access data stored out from fluor_fvfm -fvfm_median = pcv.outputs.observations['fvfm_median']['value'] +fvfm_median = pcv.outputs.observations['fluor_fvfm_median']['value'] # Store the two images fvfm_img = fvfm_images[0] From 5c2406b87edff4c045609c8006e9076a2db042ff Mon Sep 17 00:00:00 2001 From: HaleySchuhl Date: Tue, 19 Jan 2021 10:43:06 -0600 Subject: [PATCH 087/137] Update report_size_marker.md --- docs/report_size_marker.md | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/docs/report_size_marker.md b/docs/report_size_marker.md index 452b0ee0a..f1091a480 100644 --- a/docs/report_size_marker.md +++ b/docs/report_size_marker.md @@ -3,7 +3,7 @@ Get and record the size of a size marker or set an area as a size marker. **plantcv.report_size_marker_area**(*img, roi_contour, roi_hierarchy, marker='define', objcolor='dark', thresh_channel=None, - thresh=None*) + thresh=None, label=None*) **returns** analysis_image @@ -16,6 +16,7 @@ Get and record the size of a size marker or set an area as a size marker. - objcolor = Object color is 'dark' (default) or 'light' (is the marker darker or lighter than the background) - thresh_channel = 'h', 's', or 'v' for hue, saturation or value, default set to None - thresh = Binary threshold value (integer), default set to None. + - label = Optional label parameter, modifies the variable name of observations recorded - **Context:** - Allows user to add size marker data, so that shape data can be normalized between images/cameras - **Output data stored:** Data ('marker_area', 'marker_ellipse_major_axis', 'marker_ellipse_minor_axis', 'marker_ellipse_eccentricity') @@ -37,10 +38,11 @@ from plantcv import plantcv as pcv pcv.params.debug = "print" # Define an ROI for the marker -roi_contour, roi_hierarchy = pcv.roi.rectangle(img1, 3550, 850, 500, 500) +roi_contour, roi_hierarchy = pcv.roi.rectangle(img=img1, x=3550, y=850, h=500, w=500) # Detect and Measure Size Marker -image = pcv.report_size_marker_area(img1, roi_contour, roi_hierarchy, marker='detect', objcolor='light', thresh_channel='s', thresh=120) +image = pcv.report_size_marker_area(img=img1, roi_contour=roi_contour, roi_hierarchy=roi_hierarchy, + marker='detect', objcolor='light', thresh_channel='s', thresh=120, label=None) # Access data stored out from report_size_marker_area marker_area = pcv.outputs.observations['marker_area']['value'] From ba13d45e6d5004e29d7245dfbf732f09b68ebb64 Mon Sep 17 00:00:00 2001 From: HaleySchuhl Date: Tue, 19 Jan 2021 10:44:39 -0600 Subject: [PATCH 088/137] Update watershed.md --- docs/watershed.md | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/docs/watershed.md b/docs/watershed.md index a66e50436..5180dae17 100644 --- a/docs/watershed.md +++ b/docs/watershed.md @@ -5,7 +5,7 @@ For more information see [https://github.com/lsx1980/Leaf_count](https://github. This function uses the watershed algorithm to detect boundary of objects. Needs a mask file which specifies area which is object is white, and background is black. -**plantcv.watershed_segmentation**(*rgb_img, mask, distance=10*) +**plantcv.watershed_segmentation**(*rgb_img, mask, distance=10, label=None*) **returns** analysis_image @@ -13,6 +13,7 @@ Needs a mask file which specifies area which is object is white, and background - rgb_img - RGB image data - mask - Binary image, single channel, object in white and background black - distance - Minimum distance of local maximum, lower values are more sensitive, and segments more objects (default: 10) + - label - Optional label parameter, modifies the variable name of observations recorded - **Context:** - Used to segment image into parts - Data automatically gets stored into the [Outputs class](outputs.md). Users can look at the data collected at any point during @@ -32,7 +33,7 @@ from plantcv import plantcv as pcv pcv.params.debug = "print" # Segment image with watershed function -analysis_image = pcv.watershed_segmentation(rgb_img=crop_img, mask=bin_mask, distance=10) +analysis_image = pcv.watershed_segmentation(rgb_img=crop_img, mask=bin_mask, distance=10, label=None) ``` From bd7c54ef27fdf865a64773baa831007f81c1becb Mon Sep 17 00:00:00 2001 From: HaleySchuhl Date: Tue, 19 Jan 2021 10:45:35 -0600 Subject: [PATCH 089/137] Update within_frame.md --- docs/within_frame.md | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/docs/within_frame.md b/docs/within_frame.md index 4ed31cff3..fbb87c7f0 100644 --- a/docs/within_frame.md +++ b/docs/within_frame.md @@ -3,13 +3,14 @@ This function tests whether an object (defined as nonzero pixels in a mask) falls completely within the bounds of an image, or if it touches the edge. -**plantcv.within_frame**(*mask, border_width=1*) +**plantcv.within_frame**(*mask, border_width=1, label=None*) **returns** in_bounds - **Parameters:** - mask - a single channel image (i.e. binary or greyscale) - border_width - distance from border of image considered out of frame (default = 1) + - label - Optional label parameter, modifies the variable name of observations recorded - **Context:** - This function could be used to test whether the plant has grown outside the field of view. From 1cd414c3a1a0c9293e686e8148896e3a5107c174 Mon Sep 17 00:00:00 2001 From: HaleySchuhl Date: Tue, 19 Jan 2021 10:46:20 -0600 Subject: [PATCH 090/137] Update x_axis_pseudolandmarks.md --- docs/x_axis_pseudolandmarks.md | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/docs/x_axis_pseudolandmarks.md b/docs/x_axis_pseudolandmarks.md index 8804870c2..7fd8f6a72 100644 --- a/docs/x_axis_pseudolandmarks.md +++ b/docs/x_axis_pseudolandmarks.md @@ -3,7 +3,7 @@ Divide plant object into twenty equidistant bins and assign pseudolandmark points based upon their actual (not scaled) position. Once this data is scaled this approach may provide some information regarding shape independent of size. -**plantcv.x_axis_pseudolandmarks**(*img, obj, mask*) +**plantcv.x_axis_pseudolandmarks**(*img, obj, mask, label=None*) **returns** landmarks_on_top (top), landmarks_on_bottom (bottom), landmarks_at_center_along_the_vertical_axis (center_V) @@ -11,6 +11,7 @@ Once this data is scaled this approach may provide some information regarding sh - img - A copy of the original image (RGB or grayscale) generated using np.copy - obj - A contour of the plant object (this should be output from the object_composition.py fxn) - mask - This is a binary image. The object should be white and the background should be black. + - label - Optional label parameter, modifies the variable name of observations recorded - **Context:** - Used to identify a set of sixty equidistant landmarks on the horizontal axis. Once scaled these can be used for shape analysis. - **Output data stored:** Data ('top_lmk', 'bottom_lmk', 'center_v_lmk') automatically gets stored to the [`Outputs` class](outputs.md) when this function is ran. @@ -28,7 +29,7 @@ pcv.params.debug = "plot" # Identify a set of land mark points # Results in set of point values that may indicate tip points -top, bottom, center_v = pcv.x_axis_pseudolandmarks(img, obj, mask) +top, bottom, center_v = pcv.x_axis_pseudolandmarks(img=img, obj=obj, mask=mask, label=None) # Access data stored out from x_axis_pseudolandmarks bottom_landmarks = pcv.outputs.observations['bottom_lmk']['value'] From 54505b2cd03136ff10c2dbf7dbca9b270398fc9d Mon Sep 17 00:00:00 2001 From: HaleySchuhl Date: Tue, 19 Jan 2021 10:46:49 -0600 Subject: [PATCH 091/137] Update y_axis_pseudolandmarks.md --- docs/y_axis_pseudolandmarks.md | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/docs/y_axis_pseudolandmarks.md b/docs/y_axis_pseudolandmarks.md index da548736c..94fa1829d 100644 --- a/docs/y_axis_pseudolandmarks.md +++ b/docs/y_axis_pseudolandmarks.md @@ -4,7 +4,7 @@ Divide plant object into twenty equidistant bins along the y-axis and assign pse actual (not scaled) position. Once this data is scaled this approach may provide some information regarding shape independent of size. -**plantcv.y_axis_pseudolandmarks**(*img, obj, mask*) +**plantcv.y_axis_pseudolandmarks**(*img, obj, mask, label=None*) **returns** landmarks_on_leftside (left), landmarks_on_right (right), landmarks_at_center_along_the_horizontal_axis (center_h) @@ -12,6 +12,7 @@ independent of size. - img - A copy of the original image (RGB or grayscale) generated using np.copy - obj - A contour of the plant object (this should be output from the object_composition.py fxn) - mask - This is a binary image. The object should be white and the background should be black. + - label - Optional label parameter, modifies the variable name of observations recorded - **Context:** - Used to identify a set of sixty equidistant landmarks on the vertical axis. Once scaled these can be used for shape analysis. - **Output data stored:** Data ('left_lmk', 'right_lmk', 'center_h_lmk') automatically gets stored to the [`Outputs` class](outputs.md) when this function is ran. @@ -31,7 +32,7 @@ pcv.params.debug = "plot" # Identify a set of land mark points # Results in set of point values that may indicate tip points -left, right, center_h = pcv.y_axis_pseudolandmarks(img, obj, mask) +left, right, center_h = pcv.y_axis_pseudolandmarks(img=img, obj=obj, mask=mask, label=None) # Access data stored out from y_axis_pseudolandmarks left_landmarks = pcv.outputs.observations['left_lmk']['value'] From 87bc81f60188de4949fb7b5794669deba73a645e Mon Sep 17 00:00:00 2001 From: HaleySchuhl Date: Tue, 19 Jan 2021 13:56:21 -0600 Subject: [PATCH 092/137] Update vis_tutorial.md --- docs/vis_tutorial.md | 21 ++++++++++++--------- 1 file changed, 12 insertions(+), 9 deletions(-) diff --git a/docs/vis_tutorial.md b/docs/vis_tutorial.md index efb9142f2..bfddd1d4d 100644 --- a/docs/vis_tutorial.md +++ b/docs/vis_tutorial.md @@ -380,8 +380,9 @@ The next step is to analyze the plant object for traits such as [horizontal heig # Inputs: # img - RGB or grayscale image data # obj- Single or grouped contour object - # mask - Binary image mask to use as mask for moments analysis - shape_img = pcv.analyze_object(img=img, obj=obj, mask=mask) + # mask - Binary image mask to use as mask for moments analysis + # label - Optional label parameter, modifies the variable name of observations recorded + shape_img = pcv.analyze_object(img=img, obj=obj, mask=mask, label=None) # Shape properties relative to user boundary line (optional) @@ -390,9 +391,10 @@ The next step is to analyze the plant object for traits such as [horizontal heig # obj - Single or grouped contour object # mask - Binary mask of selected contours # line_position - Position of boundary line (a value of 0 would draw a line - # through the bottom of the image) + # through the bottom of the image) + # label - Optional label parameter, modifies the variable name of observations recorded boundary_img1 = pcv.analyze_bound_horizontal(img=img, obj=obj, mask=mask, - line_position=1680) + line_position=1680, label=None) # Determine color properties: Histograms, Color Slices, output color analyzed histogram (optional) @@ -400,8 +402,9 @@ The next step is to analyze the plant object for traits such as [horizontal heig # rgb_img - RGB image data # mask - Binary mask of selected contours # hist_plot_type - None (default), 'all', 'rgb', 'lab', or 'hsv' - # This is the data to be printed to the SVG histogram file - color_histogram = pcv.analyze_color(rgb_img=img, mask=mask, hist_plot_type='all') + # This is the data to be printed to the SVG histogram file + # label - Optional label parameter, modifies the variable name of observations recorded + color_histogram = pcv.analyze_color(rgb_img=img, mask=mask, hist_plot_type='all', label=None) # Pseudocolor the grayscale image @@ -590,13 +593,13 @@ def main(): outfile = os.path.join(args.outdir, filename) # Find shape properties, output shape image (optional) - shape_imgs = pcv.analyze_object(img=img, obj=obj, mask=mask) + shape_imgs = pcv.analyze_object(img=img, obj=obj, mask=mask, label=None) # Shape properties relative to user boundary line (optional) - boundary_img1 = pcv.analyze_bound_horizontal(img=img, obj=obj, mask=mask, line_position=1680) + boundary_img1 = pcv.analyze_bound_horizontal(img=img, obj=obj, mask=mask, line_position=1680, label=None) # Determine color properties: Histograms, Color Slices, output color analyzed histogram (optional) - color_histogram = pcv.analyze_color(rgb_img=img, mask=mask, hist_plot_type='all') + color_histogram = pcv.analyze_color(rgb_img=img, mask=mask, hist_plot_type='all', label=None) # Pseudocolor the grayscale image pseudocolored_img = pcv.visualize.pseudocolor(gray_img=s, mask=mask, cmap='jet') From a48fa5ddbe448c145d60e2c97e6f0d207c907701 Mon Sep 17 00:00:00 2001 From: HaleySchuhl Date: Tue, 19 Jan 2021 13:58:39 -0600 Subject: [PATCH 093/137] Update vis_nir_tutorial.md --- docs/vis_nir_tutorial.md | 24 ++++++++++++++---------- 1 file changed, 14 insertions(+), 10 deletions(-) diff --git a/docs/vis_nir_tutorial.md b/docs/vis_nir_tutorial.md index 7fa2806c4..af9443191 100644 --- a/docs/vis_nir_tutorial.md +++ b/docs/vis_nir_tutorial.md @@ -322,7 +322,8 @@ The next step is to analyze the plant object for traits such as [horizontal heig # img - RGB or grayscale image data # obj- Single or grouped contour object # mask - Binary image mask to use as mask for moments analysis - shape_img = pcv.analyze_object(img=img, obj=obj, mask=mask) + # label - Optional label parameter, modifies the variable name of observations recorded + shape_img = pcv.analyze_object(img=img, obj=obj, mask=mask, label=None) # Shape properties relative to user boundary line (optional) @@ -332,8 +333,9 @@ The next step is to analyze the plant object for traits such as [horizontal heig # mask - Binary mask of selected contours # line_position - Position of boundary line (a value of 0 would draw a line # through the bottom of the image) + # label - Optional label parameter, modifies the variable name of observations recorded boundary_img1 = pcv.analyze_bound_horizontal(img=img, obj=obj, mask=mask, - line_position=1680) + line_position=1680, label=None) # Determine color properties: Histograms, Color Slices, output color analyzed histogram (optional) @@ -341,7 +343,8 @@ The next step is to analyze the plant object for traits such as [horizontal heig # rgb_img - RGB image data # mask - Binary mask of selected contours # hist_plot_type - None (default), 'all', 'rgb', 'lab', or 'hsv' - color_histogram = pcv.analyze_color(rgb_img=img, mask=kept_mask, hist_plot_type='all') + # label - Optional label parameter, modifies the variable name of observations recorded + color_histogram = pcv.analyze_color(rgb_img=img, mask=kept_mask, hist_plot_type='all', label=None) # Pseudocolor the grayscale image @@ -442,10 +445,11 @@ The next step is to [get the matching NIR](get_nir.md) image, [resize](transform # mask - Binary mask made from selected contours # bins - Number of classes to divide spectrum into # histplot - If True then plots histogram of intensity values, (default False) + # label - Optional label parameter, modifies the variable name of observations recorded nir_hist = pcv.analyze_nir_intensity(gray_img=nir2, mask=nir_combinedmask, - bins=256, histplot=True) + bins=256, histplot=True, label=None) - nir_shape_image = pcv.analyze_object(img=nir2, obj=nir_combined, mask=nir_combinedmask) + nir_shape_image = pcv.analyze_object(img=nir2, obj=nir_combined, mask=nir_combinedmask, label="NIR") # Save out the NIR histogram pcv.print_image(img=nir_hist, filename=os.path.join(pcv.params.debug_outdir, 'nirhist.png')) @@ -559,14 +563,14 @@ def main(): ############### Analysis ################ # Find shape properties, output shape image (optional) - shape_img = pcv.analyze_object(img=img, obj=obj, mask=mask) + shape_img = pcv.analyze_object(img=img, obj=obj, mask=mask, label=None) # Shape properties relative to user boundary line (optional) boundary_img1 = pcv.analyze_bound_horizontal(img=img, obj=obj, mask=mask, - line_position=1680) + line_position=1680, label=None) # Determine color properties: Histograms, Color Slices, output color analyzed histogram (optional) - color_histogram = pcv.analyze_color(rgb_img=img, mask=kept_mask, hist_plot_type='all') + color_histogram = pcv.analyze_color(rgb_img=img, mask=kept_mask, hist_plot_type='all', label=None) # Pseudocolor the grayscale image pseudocolored_img = pcv.visualize.pseudocolor(gray_img=s, mask=kept_mask, cmap='jet') @@ -594,8 +598,8 @@ def main(): hierarchy=nir_hierarchy) # Analyze NIR intensity and object shape - nir_hist = pcv.analyze_nir_intensity(gray_img=nir2, mask=nir_combinedmask, bins=256, histplot=True) - nir_shape_image = pcv.analyze_object(img=nir2, obj=nir_combined, mask=nir_combinedmask) + nir_hist = pcv.analyze_nir_intensity(gray_img=nir2, mask=nir_combinedmask, bins=256, histplot=True, label=None) + nir_shape_image = pcv.analyze_object(img=nir2, obj=nir_combined, mask=nir_combinedmask, label="NIR") # Save out the NIR histogram pcv.print_image(nir_imgs[0], os.path.join(pcv.params.debug_outdir, 'nirhist.png')) From eeff291e8e5db49024b296ef77007d6f9ba28d68 Mon Sep 17 00:00:00 2001 From: HaleySchuhl Date: Tue, 19 Jan 2021 14:01:00 -0600 Subject: [PATCH 094/137] Update thermal_tutorial.md --- docs/thermal_tutorial.md | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/docs/thermal_tutorial.md b/docs/thermal_tutorial.md index 87e21fa24..d77fb0684 100644 --- a/docs/thermal_tutorial.md +++ b/docs/thermal_tutorial.md @@ -217,7 +217,8 @@ Now that the plant has been separated from the background we can analyze the tem # img - Array of thermal values # mask - Binary mask made from selected contours # histplot - If True plots histogram of intensity values (default histplot = False) - analysis_img = pcv.analyze_thermal_values(thermal_array=thermal_data, mask=kept_mask, histplot=True) + # label - Optional label parameter, modifies the variable name of observations recorded + analysis_img = pcv.analyze_thermal_values(thermal_array=thermal_data, mask=kept_mask, histplot=True, label=None) ``` @@ -372,7 +373,8 @@ def main(): # img - Array of thermal values # mask - Binary mask made from selected contours # histplot - If True plots histogram of intensity values (default histplot = False) - analysis_img = pcv.analyze_thermal_values(thermal_array=thermal_data, mask=kept_mask, histplot=True) + # label - Optional label parameter, modifies the variable name of observations recorded + analysis_img = pcv.analyze_thermal_values(thermal_array=thermal_data, mask=kept_mask, histplot=True), label=None # Pseudocolor the thermal data From 39d442d9064fe63537ae42ebd0b7a2ddf8c70dc6 Mon Sep 17 00:00:00 2001 From: HaleySchuhl Date: Wed, 20 Jan 2021 09:28:30 -0600 Subject: [PATCH 095/137] Update psII_tutorial.md --- docs/psII_tutorial.md | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/docs/psII_tutorial.md b/docs/psII_tutorial.md index b75ab2e55..b6c0d069b 100644 --- a/docs/psII_tutorial.md +++ b/docs/psII_tutorial.md @@ -197,7 +197,8 @@ The next step is to analyze the plant object for traits such as [shape](analyze_ # img - RGB or grayscale image data # obj - Single or grouped contour object # mask - Binary image mask to use as mask for moments analysis - shape_img = pcv.analyze_object(img=fmax, obj=obj, mask=cleaned_mask) + # label - Optional label parameter, modifies the variable name of observations recorded. (default `label=None`) + shape_img = pcv.analyze_object(img=fmax, obj=obj, mask=cleaned_mask, label=None) # Analyze fv/fm fluorescence properties @@ -207,7 +208,8 @@ The next step is to analyze the plant object for traits such as [shape](analyze_ # fmax - Grayscale image # mask - Binary mask of selected contours # bins - Number of grayscale bins (0-256 for 8-bit img, 0-65536 for 16-bit). Default bins = 256 - fvfm_images = pcv.photosynthesis.analyze_fvfm(fdark=fdark, fmin=fmin, fmax=fmax, mask=cleaned_mask, bins=256) + # label - Optional label parameter, modifies the variable name of observations recorded. (default `label=None`) + fvfm_images = pcv.photosynthesis.analyze_fvfm(fdark=fdark, fmin=fmin, fmax=fmax, mask=cleaned_mask, bins=256, label=None) # Store the two fv_fm images fvfm_img = fvfm_images[0] @@ -305,10 +307,10 @@ def main(): obj, masked = pcv.object_composition(img=cleaned_mask, contours=id_objects, hierarchy=obj_hierarchy) # Find shape properties - shape_img = pcv.analyze_object(img=fmax, obj=obj, mask=cleaned_mask) + shape_img = pcv.analyze_object(img=fmax, obj=obj, mask=cleaned_mask, label=None) # Analyze fv/fm fluorescence properties - fvfm_images = pcv.pcv.photosynthesis.analyze_fvfm(fdark=fdark, fmin=fmin, fmax=fmax, mask=cleaned_mask, bins=256) + fvfm_images = pcv.pcv.photosynthesis.analyze_fvfm(fdark=fdark, fmin=fmin, fmax=fmax, mask=cleaned_mask, bins=256, label=None) # Store the two fv_fm images fvfm_img = fvfm_images[0] From 06bb49823b4a725ec10347c4f82f1b35f0558672 Mon Sep 17 00:00:00 2001 From: HaleySchuhl Date: Wed, 20 Jan 2021 09:32:16 -0600 Subject: [PATCH 096/137] Update nir_tutorial.md --- docs/nir_tutorial.md | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/docs/nir_tutorial.md b/docs/nir_tutorial.md index 4ae306cb2..ec2ee01f0 100644 --- a/docs/nir_tutorial.md +++ b/docs/nir_tutorial.md @@ -456,8 +456,9 @@ Now we can perform the [analysis of pixelwise signal value](analyze_NIR_intensit # mask - Binary mask made from selected contours # bins - Number of classes to divide the spectrum into # histplot - If True, plots the histogram of intensity values + # label - Optional label parameter, modifies the variable name of observations recorded. (default `label=None`) nir_hist = pcv.analyze_nir_intensity(gray_img=img, mask=kept_mask, - bins=256, histplot=True) + bins=256, histplot=True, label=None) # Pseudocolor the grayscale image to a colormap @@ -480,7 +481,8 @@ Now we can perform the [analysis of pixelwise signal value](analyze_NIR_intensit # img - RGB or grayscale image data # obj- Single or grouped contour object # mask - Binary image mask to use as mask for moments analysis - shape_imgs = pcv.analyze_object(img=rgb_img, obj=o, mask=m) + # label - Optional label parameter, modifies the variable name of observations recorded. (default `label=None`) + shape_imgs = pcv.analyze_object(img=img, obj=o, mask=m, label=None) # Write shape and nir data to results file pcv.print_results(filename=args.result) @@ -634,13 +636,13 @@ def main(): outfile = os.path.join(args.outdir, img_name) # Perform signal analysis - nir_hist = pcv.analyze_nir_intensity(gray_img=img, mask=kept_mask, bins=256, histplot=True) + nir_hist = pcv.analyze_nir_intensity(gray_img=img, mask=kept_mask, bins=256, histplot=True, label=None) # Pseudocolor the grayscale image to a colormap pseudocolored_img = pcv.visualize.pseudocolor(gray_img=img, mask=kept_mask, cmap='viridis') # Perform shape analysis - shape_imgs = pcv.analyze_object(img=rgb_img, obj=o, mask=m) + shape_imgs = pcv.analyze_object(img=img, obj=o, mask=m, label=None) # Write shape and nir data to results file pcv.print_results(filename=args.result) From 90fb4739a3074e1496d53bd61d3a39137c004e00 Mon Sep 17 00:00:00 2001 From: HaleySchuhl Date: Wed, 20 Jan 2021 09:35:38 -0600 Subject: [PATCH 097/137] Update morphology_tutorial.md add label param in script --- docs/morphology_tutorial.md | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/docs/morphology_tutorial.md b/docs/morphology_tutorial.md index 464ccbebc..6eb13082e 100644 --- a/docs/morphology_tutorial.md +++ b/docs/morphology_tutorial.md @@ -465,10 +465,10 @@ def main(): pruned, seg_img, edge_objects = pcv.morphology.prune(skel_img=skeleton, size=0, mask=cropped_mask) # Identify branch points - branch_pts_mask = pcv.morphology.find_branch_pts(skel_img=skeleton, mask=cropped_mask) + branch_pts_mask = pcv.morphology.find_branch_pts(skel_img=skeleton, mask=cropped_mask, label=None) # Identify tip points - tip_pts_mask = pcv.morphology.find_tips(skel_img=skeleton, mask=None) + tip_pts_mask = pcv.morphology.find_tips(skel_img=skeleton, mask=None, label=None) # Sort segments into leaf objects and stem objects leaf_obj, stem_obj = pcv.morphology.segment_sort(skel_img=skeleton, objects=edge_objects, @@ -480,29 +480,29 @@ def main(): # Measure path lengths of segments labeled_img2 = pcv.morphology.segment_path_length(segmented_img=segmented_img, - objects=leaf_obj) + objects=leaf_obj, label=None) # Measure euclidean distance of segments labeled_img3 = pcv.morphology.segment_euclidean_length(segmented_img=segmented_img, - objects=leaf_obj) + objects=leaf_obj, label=None) # Measure curvature of segments labeled_img4 = pcv.morphology.segment_curvature(segmented_img=segmented_img, - objects=leaf_obj) + objects=leaf_obj, label=None) # Measure the angle of segments - labeled_img5 = pcv.morphology.segment_angle(segmented_img=segmented_img, objects=leaf_obj) + labeled_img5 = pcv.morphology.segment_angle(segmented_img=segmented_img, objects=leaf_obj, label=None) # Measure the tangent angles of segments labeled_img6 = pcv.morphology.segment_tangent_angle(segmented_img=segmented_img, - objects=leaf_obj, size=15) + objects=leaf_obj, size=15, label=None) # Measure the leaf insertion angles labeled_img7 = pcv.morphology.segment_insertion_angle(skel_img=skeleton, segmented_img=segmented_img, leaf_objects=leaf_obj, stem_objects=stem_obj, - size=20) + size=20, label=None) # Write out data collected about angles and lengths From 711de2c2b15f585e642485b2a47b2b3a43a70003 Mon Sep 17 00:00:00 2001 From: HaleySchuhl Date: Wed, 20 Jan 2021 15:44:34 -0600 Subject: [PATCH 098/137] update morph tutorial and add example of fill_segments --- .../morphology/filled_img_all_segments.jpg | Bin 0 -> 23006 bytes .../morphology/filled_segments_stem.jpg | Bin 0 -> 22616 bytes docs/morphology_tutorial.md | 43 ++++++++++++++++++ 3 files changed, 43 insertions(+) create mode 100644 docs/img/tutorial_images/morphology/filled_img_all_segments.jpg create mode 100644 docs/img/tutorial_images/morphology/filled_segments_stem.jpg diff --git a/docs/img/tutorial_images/morphology/filled_img_all_segments.jpg b/docs/img/tutorial_images/morphology/filled_img_all_segments.jpg new file mode 100644 index 0000000000000000000000000000000000000000..279e2a494e1f7094f16bb0ca73bcb46687bbc4aa GIT binary patch literal 23006 zcmd42by!=^x+ol^1zIRpoB}OS++7N#Enc*^r4%df5GW)_afjkotQ1XgclYAO3GO6l zuyFI+=j^lhJ$HZ4v(NqKyKgdUCTq=1=3O)M`rQAyUj+~;$tlVKFfafB1@s4S4+BKX zf~+k802LJgI{*N{1w6nY0brp^80ZfGgBtMQZ)E^L34`Xp%9; zRKfnMcQpL1%>1_^(bTiZxfnnt_O2gZ$^r5X_`V%LjEgafafXHQ0)R=3fkljQ-wmKg zkKzHw-{5b}&=(9$EbIplad7b-Jw{ikAp&4xU}0fmV?B8A*WY0HqMrk>i64+W=aYFz zs$q)r!uct`e_ReOwRQCkjh$WHJ-vPX1A`NjQ`0lEf9B?4YwH`ETiZLkdx(?Mv-68f)F3uxL-mqONRS-06rE5 zdNE-U1Ec{c$WCrJfc5{!bpQMRfiaB#KQM-g{|Ck}`7g#$$X;djdGw*$FQ^657p~jA zEJn0)NG@*l^&ar!y$A5K*Ae zSVi2>NjOP~#+kB3&B7d)yM2CRRd1qxy++z$^DFpzZx(yZC>)h2v|%2%RiqWdC`M;n znIq}Jk|mA+dV(BRAzk+XLP1>uv%5TZVjX=)!(ohIFJc7ceujNJ193muerOnV(Cep9 z{O}0}+tdbcxieZ0I?I~#+Lou27w^>eqY1B{>lWEGt3+%72bA@FwwcZE7@4=gK0P;L zK61W%P?PyNZh)OZ&BRq74i@DHidS+LwC;UMCtRML*O$TNQArIJLK&-ZmD=p8V$5nw z?)Ly|Mfyx|<&0e2_s^}26}}?IRlyhYGQ%$A2lU#nv_n4S6aSelN&%S$X7XH!M+*Q) zEVIkv>!7Q?$s~8gmEwQiRZ70!oe94OBu6RnpKnGQIF{%tU#ShSa~w(2fJeMl3uqRR z!mD~lg5k0)13V5y2~D;^))au-yu@`%szoV91Teryc6DgyKxki#E9+zLi}t7A810## zDdG#9*%2vFQQh{5!|b{^J-gp7p)87Tu6+(5jLzGEw~sbtxtORmQ1^?%&qt8iYTRhO-ka$eB5s#K!Ufy&OpWB{fqAW ze2xczAa^8_Y{C)inIDlo*}vPixUAacFMl$6%2XK8rK;g;cX-(%P1?>1ErGz&3{ipO zkX4#{0OA^mv<$fid_MysAKn9QMJBuaK>jXXfY+c}ZY;$oscrZ)S$Rqc!7vJ%+^+z9&WRBY+@` zu3^oqs*SVL(WVf2FWg6B?kJHS>?H8jxKA2{kpRp=J%Kw!tVTT(^re<$z50<_v8DEs z*SH_xwu;di4Zv(&4+3$wTJzW&!1Ei=!Akdltf4WpYtoJ}4A&<-KP&#AY(#}F%8u0r zDJEwO@~=g5w&M{^0r}vN20_H`T8%YvwT;d$jPf-~PU7p`f5|8zAoA-Ml zWIlwe+qU+G8j9TGok9h_PLH0(5)MaP0&t}Hs16f)!0T@blQ)nKdMA?sdrQ#0<%4^` z8~%g3U{OYPt)efILbyj8Qx5ll7M9Zd+XY_=vvFGr0|Z?lYynbZ+ZfamX(cMqPgJ2% zAB4RbE!K{`*2;l^95SzEYGloJIm_nH$L<+Je4RS#2wU6PiEyP^MNMP7oq-Z7HoA?8 zLnbDJr>Yy|@p4wNhXDMh_-z1yU-f~Hl>M3mNfgX4MB?ZSxOES}y1I!1C#4EMXrz^p zS!1pfgyMP^I9U5!NtT22KBHHa4=HrfH$i^ppxlayy}Q!yK*6%JRk!;>KXo6&WdED$vpV8r$n{ZBI0dw^QSH0RdjIVEF5 zZT(x?3Wc1+sdH><V*~@B1Yy*xC_H1?YBw5Fth5f9)9Uk=VAiots zU|N@!&L~U#sT^{Ycy4V*IrRLE%sd!A`nsc+z_-<~CsoIcSuRn{Yju6RJU3CHl9kQFSlSZf-*cWel8uOITh>nqhN0td@tVG0Lbze&enD4`dY4HmNX*@<%o%Xl50Uetzwug^6B!So)e}XsJ*+iy= z+a46Ix@?;O;M`VhQ$_yj8I2u-!e`+=*;iaK0qE^6>A7!u5Act=2lTSu1A;#zR?0$9 z4@K?)l+c!+Pyy8QR<*n17D(JlHiAQvcpi#+*mgwCx05;u<-O6evIDes-eR zhQ)a4uf?rKn`Z`n#nCNkxGGHw;@&Z|ozXOOe30iF68##Fo}-A}+X{yuTFD<+>>gLX zW1t)6)^KKTiQ#PPRBs_kB>((dwDz}?Qn82ir#u8sWUPh{7hl%eFG&ND^sbWJ9M`Py zEe;;%{%v;A&_XMg5i0595@U~Md;2SszKuk(efp=Z6gJs}?r(5KsO`H*ZQUp^+BZtf zg5u;ge#fMO`hhIaZp0sIr1(kK8lyGW_$^kqyXO+lPp z3~|*irM5ewhQSE03u}4y4jyn`Z4+~o;{embt1S9{gjlbsGI!^#tH-RxblpZ$fg{E( z1p+7HlZq0&Jo`sKS-kbb?NsHDR|-!+fY^~BNi&A6))M$w=h#D#$-+Qwh4Nf9e3l}# zN@;Mzr_GH)!{6_z_c>G6iPxdqjUu;$iNqIM&`?tY90XbW|KO1ko zOqr$3^^zapHtf1cCbm4xizt$Im%)zKJN3Uy2<=C*bm6yBmRd;LhsReos%rWgL`)E? zmG4@6y}Ab!?psK*wNr|I;#0q<4=#mTu}PJ&YjEB8zzIEn{xt9z=#Jz$)ND1VNC zgbGksUXb}liR4BKT0X8s;Z2M7Z^Hv#jve5l++b=fyQx2Xx3^Tr?48=1@o=4QqfIU3q%RuWex+WN_T%m20 znldES;n4qM#rpFCEC~$yp7@X{C&KtxtwhrRQHI$v5YAd}4U8?XqQ%TNPh{v-Mz$1D zBt2{05(5Nh(IJJZAJQ%Tc*lhgq3h3VSVm%>EBpSqIy3BUG4wTPy8h(yiI+NfmFHD| zrP0s>&h_B*h!_N`;<7q$1gCkoyzFLtGF{$jJM+UM zj(zl+a5*+hWc|~}j3gS{0k^rbvg7YrCo6~Q@-GBquY!5_$o$Qh#f*m%`!}o@3&3H< zw`NFF*cjpb$Pb{5Aow+Tqi^g(Ep1?uu#Ephae4sI4TU^ex`$Aanp zRAMkJ+9w$SU=0MC7PpasmI|r~?=pYXY8eygQWyjdS0qNGoXwLXR5jUf#iWny);Be&3-^he3+mHmWF$9CrMhY!3YF9jBx6eX&v z_&(_+BsnN<7qJxWeVKZyyZL9ai!>s=DD3CPiszl-Z`9i{P`2=B1xfc-eb{um=VkuN zVy$wej@m z^N}%oRiTh(dX=G2qtq-?7O^WtdJn+82SgtwauW*AfA!a(XSp+4c&%-E%i~AsmT|w@1hY) z+#arx8R!X5w4hx_3%YHOk-0n z{N^7uF3MMlo4Jh%Q+K4f&9?86r|=c^c+rj4r2fXh#v`0)-Vy)m)<@e}ExdT69EB~& zLik$eb50cFWU8`#x5#4&E9|>J5yGPTk>F2lS_PS#=P$M&!L1=)kkq@duLzuAK0#w| zsvruori<9gnPauo6%8XhdSV|e7c)Ic`2qpu>KAvF3>$Sa)wQl;@2!OXaFmp9Joi6( zBEM}s<@~gGUrEU%O1l4=_K9sk?+>_pp60^IfYOSqrA||hHJEu~d%Pxvd~F8iGzemd ze#=H%!nUdBLI8H~QA7HEf!_nVU3SM>ZN+fXZJj=RPGUS;cOk85U!^4ieB?OWYo1+; z@#FG=z#8lV7^cb+^M9rKJ+SDzuKd#<{T_h4cvZ5291G4%Go{^?zx<5^LXOaiS$2su zIbx;LThcf|nfU9E)+SjK!qWKZN#EmU$LhxXO~|kT`_g&Fyzk3^3*#?fc&bW7x^^@0zTg@lna%HA@%Im{3q}Px*`v!3Z&};A zAsDAbggenec{?aP_=XO#pvOfL?{Svrb1X8dczqiGgvfZv^>jayv5Q)ya|QR+av2k^ z+UC`D&>ZD)Vx&v=*U@Rf?MOmojZX_gU~RN$UEh3?%hTZVK7)DP&WYVk86QqUcDmKl zhvr=< zgala#x3dVTCDnzgWiRbPp&OOLeUU}x@-5|&gu1YaDn z-{L?MEgLYEU$NbE9E1qJW`s%QS+5^q2pq6vc0XI+K?}|Z zLZZ*f%XHJ_Zc(z@++6veH*h^!O#?fQcxCANGHCrTjoiP%_QwmluZ*SMOTF0bu~#id z!Zxyd2#=Z!<$NI&7E`t#3bQxin>hx5JO?l|D)wBe4j&Jl8aX_y?EY9hm@zZT z)dQ8w9KV);*R4N^Szpi-yxCHI<;LNabQ`*L(!L0X=Wj!P--j?9kjF*HD$>`2npkvps`bG{%0{5b{C>SI_N-ww$69ary% zfnNyNAY4F-M4_73{reykdAmG7>5l7Tls}T}EWk)c+(){b`qRbNYpu$8ch18YNP2q};bvpub}t?;|K z`8sE!m}N2Dt*Abn#E%4EBV^#aHuwe9Gv7wTOP9P#Qj--MFbD}@cvdQ9&QcuvWws9# z7AN^qV*lH0!v~FC(jzYyis9}^YhF|A@ur2zm;tGYAvfM$%J^JDh_yz(Exlynr)y~31U@9LL?ar@un zvv>@=;>#988p5-VdtIZHHC__1QwjGkh9pNOMsNf?aRN&7m}U^4J9hIB&x05{JVkg9 zgN8qi4)UG&GZtyJYvyCC>#fI9grhRxz^*?qwxKB34cMCi*B@CKBgUuRJXN<7b+*#W zw_L0BupDmoQPL=C<+R5RmaVh7yURL=1{7;-@|_hr-31tit77Xs2jXScMnL)=;ol=_Gv|z57iRt?vQY zw;^Eyx2mowQ^R~}%Lxm)#v~^SXySU6_a7|#pQJO9TRtcdX=_+LQ$2(EMISqy5|bVf zP{?q1{;An@R9;l*tgRPQNi$ET6K8vCD0R)adGaVe|6??+VB!vh z)Q8T8YArpJkIG=Fy}owdaH-1mfY~W-st@Ttx)+^+nO-&g0v;QCg|C$H=?~VYDS=0l?pM~8c&)jA$EaPSP zgF9>5l6uwKGl>13yn4+T%hAt~2hS?|xdUdXoOUbV^0eh2BKbLB^`R3Wew8{Gb5T## z<4vXd+!Rr5J9rV9yHq!RCY2s=D(>Y03Fw<{;}ZXsu!$_AdU?2Qk#pT;B7-o5$z>uQ ztKF#7EBo5a;nvlg1|`a=C9=^Tjx9MTk;cU;WgA7MuIrdqR|d%EFcwI)74ab-QO=W~ z72*+!JK(^D^dGtxu*D{+p<;{FOd;_P28Bq$YoSJ4t+D<)Gx;eut~b6sTK?3BMdCxFjA6f){ghpiBj0siKNjMlut@!}-DiL5C2wIu{6nc!=>9zb=N9+JZkPC) zp2U(;rc{!_vd#R8vb+kyNM{1~qVb8jX?DJP?tSOKo)zS4MH+qq!D}t0JatFn7!hD=?Q6p{X zb0BNtI>pTZPcUNs(Zbx`^~-pJLI-IopVv8|A=hn5g9x?DD0}y6iZ8E#%K3Hg?VoA@ z2l`G^{+X5iy{sLfTvU3**ih#ZFE_Y1==7EiANLX)^Hq;-ZZYXMra~Oc@W>2KZWAeu(UKEBEpSWLMNfzQ4=#>NP8Xh4555#EUwmm;{TUuYNNji8&UZYI8 zZKC-iJZi2q!yTKfIa&)#GPgmc3#8}6wk>kG>9w~-Oe>xiC1|$X%-H|W%vt(>>i%Lw z)b`@ky*-nppGcL(QXSp7lR|2*b*vL&@6La%bZia~s%aj0(2V?s+2;T_eMsv(Ucc5t z-Aa6y-uy`rLNWqd7{FYx*(su10~@B)J#F7T&9Pva*0TC8?WubJ@ zE%q93r?ZFe0R}##>+U_YEFryGiTg5N#51q*3RW`mti5X+A9x-2NE5zYQ^T~GQKN4D zwa_x%V8K=U8N;1{m4yZSBUZ*bwzEl)!fQsHLhs88(C1IAs$VbSZI7kpMo)^xvVcJD zZjR1U3yN9Amoa_Yz3bH<>0a;qS=Y>h_TSObBXkP$OQqfzERB)Kw}Jn3B~UIUv0T2- zRQ2^5aS^&r56xp2vQYZ+WAciA?a11%#J^X&V^$}FY3=Sq)$&R#S`ZBDWG~^H{~rJ4 z$!CVZzz(vVwnwFQH9R!CN!~%tp1g`2A>rmvBC+{@Jy2jc!Pu@ZckGFMYrn=N_ZT$8 zy57|A?j5DJcABg@UuYCno78 z%7=+Hc*S7<+I8S6`l*ZUnXSz4v*Rb$!q>vdl+lmf9`W)Tw}mZCr<^Dr1Al{Yk-Df# zGwJH82XERac3=}pX}!vbc^hNosSuYR7m$lN z+~)__NH}-^2KlHWN|%KYoU`BUYeIMpeyCzU>Mk)8U3%#${3^sQdlyPmzkO%i&n!>C zp<4#(8t^URo>3hdDepTr;XpWEynMg=JF!H&*=(bA@}$zk#GcM&r2ghf;6!{l$L+qu zHi7}YP5u5Iw)FQp_x~3@+usvV?gJqj+abL7B1A*9af*H({gG5pa2a5Jl7YbDWr~@} z?$&3M?q`wRJcoJNrYMqiCihna;P=o zu;QOp&9uqE*TwXVTsyVEhbk1vq!n<+N5}f7QU(c+RxSPa7+B@zBY3>-whc zA`#x*m>g{Hqe#52Xcg^b#7b;b33$!O6sC=XlOstw344TcTrYjxWhLY`VRCYHj9f%J zyHIhGuQ*GhowN4UOQ-c#pyJJGC)-=f6H91D1C5a;lnTAeDtn&XEmEh77r#7qX(dT0 z{JQMCU*inQgfJpmMAm5pKeh5~ZN$(rk9S}K0L0@}0Y@ORL;9+G)%m0{C%y`}X?|UsupNxzcha%k!@p zc-j5PJG4?wbIeOuv%q!lDdWIG|IU&(c+4ork)zu&L1e|+81h~7Gk51F;8|~if>tUS`8ZYcF01EH zNnYb*Ji%c+osnPO^lLv5Uws0&eeh-W@WC48IS)m7q9Zr*Y{)&xPa`Pp?UsUwyC@wH z`~+>uB!ggqE_)_NMbmzelibbFFGepwqi&b8!sz=9~`r zXXG)nHVN9kX;BhlG)S<~@KpIcX($NJ^$|i$7slKQk(W_l>1v3?c@auCrM?!!_D^(w zJ{8UDJVopM0PJ!55K-MqhWM)Up`Kj4B6`$muCt2oB)=bf)42B9bU?IMekT#4 z|3(I+j3T}V(5e-6H62{H-+XcqyW5qpR97YqvM>8>1_rc4QxMWz?!48AUqGy?voF45 zr_wL3jo_sSeL0F(c{Gju&grOw3&#OP!x^i9aal5?KgyS02|OBCwU^f1PEax5`So(B zf0*yk&vu`Z%q-3W@V!oyap`2XF&FuA>9g8KIlREX1yB0uX?dMF(n~~GJ6ZL5^(ZW7N^)&WlhVcE}4lVA$wK# zy1KeIy>i=IlB`(q!>RyvJeKf_djL{9;bQ7jU$gu@AOadGZL8AyG)5jCzDTv*s5`~X z3Z=%K<&zWRELTo)Xm}GClR}I_`+k+w2uoJ?`koKx07(ZI8S*~pZiC9mkG1D7rEnro zi#GIyduZ^ECtq#`9JztRX_ov-w-)(eBSaskT3sP!v6cp~^W0`I ze@U^at_bC$Rm3(hs(KjoR6{=&t-JvKCkb-@uL4*8ji4rP;Ti1hXHP^$(c)CwdlWIU zr`dY7NqIkH<%@NMa&5;|L6la=0G7mfV*QS)sHEC?ryf7kfg{dhG^y4%U?Cg zoYxCi77oo&aC5ni${c-x_69w5GtsgD+^x+lbm*sb;i2##Z8@wj?Yj$A8t50WlmUd@46O%kNJ-~e_%*cs?Y=;cxgb)@p6R=Zd=XcS}NOM%-J}gw>DtvoK43lhGbur>5(a>-z zd^$1BV&Ut(@9TX;cExd{i}rWPBKo>50^csfcRUV%3`l(Btm+d;ee|S>tW~}5m`H)f zNo}{T+mUDtCXE3K>`p2+u$NG+uMd6r$g}uaK1r!46P?WNMBC%?*M?!FF^S7_kbWEnUGq@e2xyGdx0^ph=<>anwl_Y2AB=-;QuWxM zcEFfiLyU;)gDJ1V?nL~MH82~_Hu7UtwI#^l3R)V%f$BgE?r3jqv(&;u@V5mV2{Z~+ zRnQwwe-Cq7OgVqYu8b9dbf|eCxFdApnHwbr2Xwh)YofSkV$2@Iu&RR9b$zh4tv-2% zWT=mgUul-5GVad!dh`7fOKN&<7TJ^La_3RURNhcv*;vv7wt{{;y_1Wnj^S)DbGuX> z+`Xo!1<$qe+B3GNL4xd`VPB7|jqpk+lFxu*Y3Wle9eMB{in4ppZch7J-F!q=uInKS zL_+#40^igIOk>Q;c*Qv|nFiqyY{~H|cD#+m8XHKwD}>3Z-DP*_xlI>nxVA~z>!Oq` zPNe;Ptj8eLNGQqLF*UHs#3)VrHa+#W6D=@~j}4;N;CIY|U_2K4IR8G)Zg&3+^9lxx zgvbPw1o+VEWw%U6np75V8zM- z7i`Rb-VMx$jI%Z?L#{#6$k^+I(*%8!mQtOWhwcGGhLKOCJt=YVApJg?i0tR98BB%Y zX+@zog1NI2ZMtooUk0Gep5}LURV>h`%+yPgTNa;{oQfv2>4{zB$N7;l>12TqOoYN zh@vx_wR!A0zW@bGyem+C9Jn<`2iok((1^Mov3visQ)DwpOo=b1EX@V%xDo&Rjvgxx z=Jb10qiJsr?ik*-ntl(cL&>igb3+=14na2iiTEOEA3h`*0 zdZj+?mMLI7$$e(*FiP-NwJqrIsEj*TzwGFFtm%5Z$OB_aTC$HaWM_1AzKo!%5WZs2 z!8?SW$K8%rLc)3ErYFT_sSmVxdsx)-acEEu8I`B1HLLYJHEdsN2nwxEB}H6l5MQA2vNzq|XS8^9Phb5o}#-tA4iU zbo6V(>5}>T8_1tJ;Y*!LI_I@x1AAVH@Wh`@+7TuN;;gx?U$_6+M)S|*|INSu@6gh} z>Zm`aeYD&H?`I#XE zD?B)A{U=wsTY8xeYhmzVZ5Q{>=1Cs-^$X>=NA{9prc~HsIM@8h2zXZqI?RsVc{PUG zdf)xW`=`C6mo5v+^w$mci}*cEkWSrNnFoqEaJ8qm&N&^ay%bz!L5T`eMw9U#)sBwt zhRg9)_9Ap?`-Ows8EUjm#E>H&1b5fRscx6g;Gi6-DezN@k`^Vn^rwg2!i>C~?3D5~q!f0M2 z{Y1_c3_Q8?Z@CQpNI?gQ)!!B4e`eVfGP2SZL*8sb^Kc%#>@Q|a2xLC zryIHDHQvlyE9T%|(E*LwxH7cYi&7u^BL)44a2NBU(Nnv}@mm`9-X;(Ai5hZu+klSz zRGJ>mv+@qKqvZVg%jvas}N`{L1$os1kRs<_5kt0_0W;Tap&HWGt4Ow2lG zs!ccj%59! zXuYTLD69Bl*Olb$55vVn3;sSkEWuKdY|cf+=csX_^(YKm{i&d{V^hdPy%NHb027iO*lq$fOE){)3Z4nYv?Z%#8L*PN=cnLyKApLY+?XA1I~4_6i2!J{8_K=<^3 z?5@~-;o)Qf;&Y|Eg&B9Isjap1$r+{w4N?9bELxrnF%~MR4MpaCNHCanEa!n1EVOQI zSvzo3zQCQL`r-M_?>pdeEY5q~oX(ZElJjL?hv&VWPiK{Mzhx(G0?aLhYv=iJm0m zMe2lG1lxU(h~#Bav?v_qytZWB{QBi7I&}5$6fdszBW7#|8NdTmNP|dIi{Wi;b9gwa zZ}k|j-Z0oH1~18!@t8wN(`X{?%c-1daeZZ$ZY*F zkaP~@x;`>t)A(S*=5;{~)) zhI#g@kE`Iw>I%_tysU#Z z-%*ao%A|^u#pS8DK-;vJ1+YWSeT8ZJ!s^DVEJN$>4Ut`fAKomON9!%5Y{*f%Ne1rm zs>(v%K;Y{4fI04!HQkWxbr!$sN)+3K8J1qaAjzbShjR7fVC|3QX(Lb9aZeP9S^2ev z?*Xq)v@HsQLlp`b@ z&F3ex5Hl&3c_#C)t&ASuCc!p~X2QKBbcW6SF^z3u6drq&q|&C0-HD-K1Z8vfU^*5TDM~SLh*@c3dS5Sdf&?Sy|3h2{|>WJCxdjP&S z&S3+^LQUc9;2E*V-W?73(nBPYp^S=25&4 zM~+%onJU|=X{bq4cp1DV9RB%7SnU99TrCxo9HoV1Ad>XXU3ZJ(_9^3qeGNi7gc&&p zlhA`ryQTD9Afq&-Ce5f}4%q;~_yw4HyyA&~pAviaFe+M#hcl1(2|3!A<*x&5NaZF~t&`oor~9ctW%5!S8=!dKYA=zt#EfuDWi zon{rWV4A+uxYn`ys#p5VNWeogLib$$>^qySA5wp z$80J+Sx49yR{2bG_jPGT<^WBJK{sC=rSHTqiF!UW+O5{pPCJ|#WEIX6U2c6b>&Zmn z>|AT_18~l&B_?Q8r2Rvrp+-V_RZYXEjr0>0j?0CjtMJeh(RUA0Ljf4^ifF&lPjJsY z;1_;2h2V}9^R2#!w_}j`=Z(ojh8G-BdQ9QNZ(|KOgtb}CjTE`nz6}QYWD}t!OuX!M zV9(f-TS>#2$>1`tjh1;vg$o3erV7(wvCLp8NK-*OF1C)Aejlfkj(ohC5N6ESvHUFL z;My|6f*>m2$HLVAO}P_bpjTCNK&8*?e!9+aZ;TblJN z1H~444(Zues=?=B=}>*Nuga{M1tv`ZqUgE+lfgaG9rJd{iLZ2KJghf+s5i0#;}x0W zyZ^e_=H#}j+?7CV#vXx3Or9>IR14M)mB{TG6)oEVK5aIQ3#ZJLB84LyK4GKiV>Ou# z+{$Ur$;Ds3}=u(n#nX{Tv1el)#>BV)Q7FC%KcWJ0>@E~&Hf zzA&mdySp>02u{>3dwMXZM&mG@0q_BU2}EC%&~Ydo>r}J;nnYo9+cfufbC&LEb5(<- z=s^2UF~3J{F;?DGgJ_3EZouAoJAip;5e@u_%9vFMWT0~$s8RSOXMW;3|DZT6>DG3f2G#5kH^2nHXrE;Oxo|d zn52>m0~fiP2J1W&)cGKYs~@q3XND%td~%zH7k#U0w@>L;Lwcg5CdPV123FgM6)V}e z+{ro2BoF$tcj_Qc!B#Y8$wTRY3Y9!(lx4AAVH##Hh52%Up>^-(E17egdP!Z_GNUg& z@T37Eu8xMz#{I?G zY=X{})L7osc8_UJXaTzr*`$s%)X;0KF+d{a$i>)k`(qb6Xg3vpUVW zF$E7NuVDCms%w06g(90-_Ht`TcIIU#Qps^&3I27-n{oo_;`87dveI(?hN6K;RCcp9%ZhaQ+~_zUfxs@JndkH^=;0 zU(SMg!~C?iy<4^{PKRfjB|OXW5TTXZF|^ut9KEgB8Uy1AD-5%9$IDMp%#t%@@~n(i zse4nvB9Zw-*RJW?_V9afp6+P`EYst(%iu7np>SZ+Sa0lEH@`*j+>4KUif>9W7zwHa zt7AE?v5~IpQ37l70o73I-N#HG^BK(DuH1d{a-TOe`N8`o0Ga2(xJ*Q9TdmSgZoE`q z1u{6f9?gC@9BaAFNL)!*xkjIt@nr>JX6dJWSi>ii_|R>vy6{Eicw?*lcF}NYe?fN* zc<2wEv%LqN zmZ#gFRmLoN{)W6OZ52W$lbVbS3LaEXF30b$s8ASxp)Zz(D+2?)U#6}a1J_W6KOo(E z$LiUNlRQj`=5rSK>SeRZ)DKQrhM5`ZN#92*YM~F&o!Q>Hp25dsb-`q z&Yqs^UHG5MKzUvLm~UO6a7gewo!FR(k0~ z5Na{*CD}yCCe4OvA({dFs>LOxi2+9Rfs#*77-luPxDC&>WnMHWaoiED@;nxG4TPim zUUn6{EMsf2;z1}wBsgSW#Y;=|S*Ao9K@AK%cF=SP9P9=AZ-fZruiwU(T`OU&qDaFv zN=c2?SC;$lrnwU1C7R?gUq`x(|N5w-ka99E`uWd^oRd73tm`MZ8=sa%NOy-SiH?n; z;N+6vne9L#-XKpJ_b@8p_IbIF5c+kd-V!&!w<8WGUn3({&*g6Ht1Tu*w+@vGrhl5H z+LhmC){&PleEX^C$;qGHO&F2=NYWGz>@!G4pI4`y=lW6dLjgO0<@95c*u$M4!D{Ql z=3UPjL}|rKFgYNrj(yqm=o22F5uScfo#lx4ug(rynaHh9ZHnnz)wY8`nUUyx<61vbZ_yZJ{f zBJFR%nsQ>$-47SucR4=vXm|Z9_Yu6LN!?03I%s}VNYbb!Eq?|fKOXOUO+PGvR*<^| zaO+VE4@|8`jnd~iA}S`bnF?&@So$X>g(CQKHqB}luY4+Y3eD`#cJr=c^m(+%Wn$C% zNuCe+Q+#d-8_Du_1BSX3B}Tw`6xX7H>gB!%j1E+v=LPtN{Ftnhj@ry3jAEz9BYSNf+u(uf$?Q6d7X z%MLvDlacdREq2l+Z+ya=RdOnM92_Qom_NJBE5hhz=0fCYN7_ojxjMm*I#Xv;ZqJXL zJ0Dog7=7{syV%ytAXypond_jp;jC+Wg?QsdLz=Jb!TLQ=<=ca6`gjXuS}Isvh&eB! z3K%GVVlt>5{)-_nfKXi)JOb{%^r-To5&k_GBS>AdoBA|hU@OsWQ9P>uEzi%bHWn}w zNJI~g6Lk*7-7f|&6abC%hc};LL$SV{zIG}l|A<`_Hz=OA!HC=1MNB=uf zT%W@Q#oBAUPm`s!Jqn||4}RHQS3E1Zqd=Iw>~^Ndm$gvNti$UaVVW(mwmWk5efevM zv^|ke@uqrP74l`{9VJP1I zb$0ikQw1U4>_sR*|ErYi4r*%a_Tgd$gbRvP0V#rj^e)mAFhqzT)lfx*fOM&1KoFvV zgeD;UdWl53NEL)ARZ0TV6Hq!_N`TM_A%3}cK4$K`d2i;4f2}if_S$Ffb=Kaq>JO;8 zhWlJw^{9amuuzWM6l(JMC}*AJJyg&oS0H0yT#4cJ1%A^fG`be~))`5eub@FC@uR3Q1R`3p?V+IFTdtXE31634-jc=_H5yLWjxThvhZU|Mf&)1R=d_3}93B%ow% zPbV8Q-5a9U4SY7INjmHXO%B6h+zVU+w{kAlYvjLPcgg56c3C%9ylk3TgT(johd39W zKe@()Euz7x7p1W=9`gY(Y4gqT2~2QVu3~QIxa`u3OzZwFqdyuusScZw^n<&UH$zX* z{kMGh|4-SDQb>1r!YSk1MhAIY;ZFs$s~<06yqVk;q%{U}fR@i9i+u9V?2q2N9tm(o z-qp3dI6L;l<83n<&w7_ark@zSJKTYiU_`RoBRcZjxjXjxj7N#@TC|$+nL0k zUCgQ#gGIBA__vUEm&BRX7G^VGGcPt^%Sphl(RWTT< zjb3p{l+T(qbL*HER8dUOp@h?zF05tkE={rssJ?%i->_!>eypn^#3}zXZKTE;qs5By*~KaB!)s8TvA)6E^_<0T2bvJqfslC69%(ReD}; z4UOIySs>aK*97??@#jymr@zoC!!lmA^58%CnruZc zAtt@jvc_r70d{ggI#jumJUz(|zJ{?++?` zBU92zoz%tZ2y$mVH_!)owLyceUytFK+!xK?A4l0k3Zd1Z7Sjai5SchC!>jf>&X5;A z6K%nu^DQT;)MIb>uZrxZ>@b+wDo*)y=}?q!8g8R~WnCNb5r*?Urv_RyPpdbpRL`au zC_*7P!Z=3q?l?G2+r#1aMHv4s`;_`-x@P(+tSdiVH^6PGFo-;=^tWXe!p&>3Wwr*wZ^+jE3ndRFvpPThMz zApnDD0zmYsLw@6lgIpRftViGkd}^M=C^))>v83VGMk~GfjFvu#Bq_F3l&UsDIwJgn z6jsYhJJyZ%o}niOoG!SCS6c0DLn?N1)X0polNsjI_A>dxMYC^=m^KPzIv#;YK!U#4 z7Lev_3&FY5Y`dxuG3^yBQJX@MYN`d6Z>$6 zX=kb$e*mroEgSf6luKI#Ukr@+!wNZ^jldXjzG32+Lxf(vOAFM>yVNo*&&_L5!6cbt zBRYFr#>;BZUo^SqQOO8h1Lv>N+eiLysE7aM9ph08=Kj`qsm1t_`Kc@LW(QQ`h2elF z`jy`_Y-Zj!CSDAQC5|-Xp!N>Tc9_9+|c1EnloLQ>T=RU1Fn~9M_`p z*-$rS&`ACRgNd?pPx(Hd=n0m5kQyaP>|xB+E0YD^q;;ouiTxOLDuODm3%2-@8|$h4UVtTexs<~LTtS6Fx*D{6TAsH{q5T~K~RtTbe951$HU_6r=1_^ z*w>{7MeU0lezmSf=70axL|Lcu>nn^l4%x-A5x%DRV^?pQ-*8@^Z!bgg&bP($+Xtf# za`@!hr1(T+U!|rtbHBLB0F+j(XV_3*{Cqp!`rsYy>R6ch?o$;wxGbpkNGx z?q0Xb)g#Mf7D1Bhh;yo+M7@rYT+~D&(NW7Dq!R6^MohkYszyo)nprG+Koy{6XRSBc zneZu2MLvr|F{K$`NDSOB7HZaI~RyQ6wmI0AJ3xRV(ZDTD#@HZGS{9Litr7#N=nC&}G z3yEH+-VXfIWS!QXP}%<>#`a<01AS4352lJ)EHJ0(6IMC*)tE-8O;OL5I>(4gqZ`Pr zS)OzmW0s3VtA7V5`Nptn-C$3GSjt>N z$Hgu|9l$n#6~GvA65u1LAyGCx)U#+*}|NQUq{|5ay3jbj5km}%apQDiy zIfhYPTW)i{>BNOvNe>);^SMp7~cdS;CBtmx`ylbhCi`=KLD?{4W-3T4|j_W zuNFe{t0O_MLK5Lo&?;K4ELYR?T*6XXtjHc5ccmT`$8dqoseRIZzR;mH-`e=`WyY>M zmHbqEuxT4u9I@AEb3el%$x>$7ue)6|XC`^55xkJyqNe=x(@gALyh(oiB*M0kywp8f zvC!G~EmDLY@TXFbWMKUxsv{&m|1Hv0m>}c9`}V%m+GZ)sThrQXHrQ$&T{Ssi;>bk4 zw)Aj?6(xHUTtk5~hxc^QOb<@E#_#T1g{&H+!r37c@3s=*4xdf5&)Nq;cn|vRmQ<6^ zv$Cvk!u1LROXX=_IO84WYhwAq5bdckn6sr9a3Bdu(Yw;d99W5fcw^In$LYps_K|et zpUwYd3+}%+{`WJ9dR)`j1A+2!LEJE198+DtW8W{GV-CKgSPpU?W>lsl3`MVymIJyV znfU}>MK5pTFI~x`S~Vq5if8P{^&+L`O=<&?J&C9jq5d6zNgeP}u8_T$PfpSl zf{AOGWl7`u%8b}&{1D@-3#n4*Hke>65U ztHg*0j$VF956e0JtPyh9(9U?&_|lQ@J$k8)V=--au2OskMl0SU7 aqF<%I;)?w0w-5P$#Y8-u<5%eq!hZnASA5X` literal 0 HcmV?d00001 diff --git a/docs/img/tutorial_images/morphology/filled_segments_stem.jpg b/docs/img/tutorial_images/morphology/filled_segments_stem.jpg new file mode 100644 index 0000000000000000000000000000000000000000..69d49e9b98ee1b467199fe354ab197e1641b7ea8 GIT binary patch literal 22616 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 YSALJ-{=M(sdj5NCy{$UFSAKr`Z*vTJDgXcg literal 0 HcmV?d00001 diff --git a/docs/morphology_tutorial.md b/docs/morphology_tutorial.md index 6eb13082e..85928f84d 100644 --- a/docs/morphology_tutorial.md +++ b/docs/morphology_tutorial.md @@ -395,6 +395,45 @@ out from a stem will have larger insertion angles than those that grow upward. ![Screenshot](img/tutorial_images/morphology/insertion_angle_img.jpg) +```python + + # Fill in segments (also stores out area data) + + # Inputs: + # mask = Binary image, single channel, object = 1 and background = 0 + # objects = List of contours + # label = (Optional) label parameter, modifies the variable name of observations recorded. (default `label=None`) + filled_img = pcv.morphology.fill_segments(mask=cropped_mask, objects=edge_objects, label="all_segments") + + +``` + +**Figure 19.** Fill Segment Area + +The [plantcv.morphology.fill_segment](fill_segments.md) function aims to measure +area of segments filled in. By using watershed segmentation to flood fill the mask by +using the segments as markers. + +![Screenshot](img/tutorial_images/morphology/filled_img_all_segments.jpg) + + +```python + + # Fill in leaves (also stores out area data) + + filled_img2 = pcv.morphology.fill_segments(mask=cropped_mask, objects=leaf_obj, stem_objects=stem_obj, label="separate_leaves") + + +``` + +**Figure 20.** Fill Leaf/Stem Area + +The [plantcv.morphology.fill_segment](fill_segments.md) function can also measure segments +separately. When inputting sorted stem and leaf segments, the stem segments will be combined into +one object while the leaves remain separate. + +![Screenshot](img/tutorial_images/morphology/filled_segments_stem.jpg) + To deploy a workflow over a full image set please see tutorial on [workflow parallelization](pipeline_parallel.md). @@ -503,6 +542,10 @@ def main(): leaf_objects=leaf_obj, stem_objects=stem_obj, size=20, label=None) + + # Fill in segments (also stores out area data) + filled_img = pcv.morphology.fill_segments(mask=cropped_mask, objects=edge_objects, label="all_segments") + filled_img2 = pcv.morphology.fill_segments(mask=cropped_mask, objects=leaf_obj, stem_objects=stem_obj, label="separate_leaves") # Write out data collected about angles and lengths From 37bb0fe55e7271f5b4f2afbe31292f31dcf50443 Mon Sep 17 00:00:00 2001 From: HaleySchuhl Date: Wed, 20 Jan 2021 15:46:53 -0600 Subject: [PATCH 099/137] Update output_measurements.md --- docs/output_measurements.md | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/docs/output_measurements.md b/docs/output_measurements.md index af002db3c..1d51fcd79 100644 --- a/docs/output_measurements.md +++ b/docs/output_measurements.md @@ -150,6 +150,7 @@ Functions that automatically store data to the [`Outputs` class](outputs.md) are [morphology.segment_curvature](segment_curvature.md), [morphology.segment_euclidean_length](segment_euclidean_length.md), [morphology.segment_insertion_angle](segment_insertion_angle.md), [morphology.segment_path_length](segment_pathlength.md), [morphology.segment_tangent_angle](segment_tangent_angle.md), [report_size_marker_area](report_size_marker.md), [watershed_segmentation](watershed.md), -[within_frame](within_frame.md), [x_axis_pseudolandmarks](x_axis_pseudolandmarks.md), and [y_axis_pseudolandmarks](y_axis_pseudolandmarks.md). +[within_frame](within_frame.md), [x_axis_pseudolandmarks](x_axis_pseudolandmarks.md), and [y_axis_pseudolandmarks](y_axis_pseudolandmarks.md). All of these functions include an optional `label` parameter +that allows users to append custom prefixes to the unique variable identifier. For more detail about the traits measured by each function see the [Observation Traits Summary Table](https://docs.google.com/spreadsheets/d/1gk5VocBA-63gyF_vA6yPNvWreZ1R7-_z4vOfm37YBl8/edit?usp=sharing). From a301a67f5983ebd1b76300b38cea28b00ea7f584 Mon Sep 17 00:00:00 2001 From: HaleySchuhl Date: Mon, 25 Jan 2021 14:05:18 -0600 Subject: [PATCH 100/137] Update updating.md --- docs/updating.md | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/docs/updating.md b/docs/updating.md index 7b290e80a..6bcf12605 100644 --- a/docs/updating.md +++ b/docs/updating.md @@ -144,6 +144,7 @@ pages for more details on the input and output variable types. * pre v3.0dev2: device, acute = **plantcv.acute_vertex**(*obj, win, thresh, sep, img, device, debug=None*) * post v3.0dev2: acute = **plantcv.acute_vertex**(*obj, win, thresh, sep, img*) * post v3.2: acute, analysis_image = **plantcv.acute_vertex**(*img, obj, win, thresh, sep*) +* post v3.11: acute, analysis_image = **plantcv.acute_vertex**(**img, obj, win, thresh, sep, label=None*) #### plantcv.adaptive_threshold @@ -164,6 +165,8 @@ pages for more details on the input and output variable types. * post v3.0dev2: bound_header, bound_data, analysis_images = **plantcv.analyze_bound_horizontal**(*img, obj, mask, line_position, filename=False*) * post v3.0: bound_header, bound_data, analysis_images = **plantcv.analyze_bound_horizontal**(*img, obj, mask, line_position*) * post v3.3: analysis_image = **plantcv.analyze_bound_horizontal**(*img, obj, mask, line_position*) +* post v3.11: analysis_image = **plantcv.analyze_bound_horizontal**(*img, obj, mask, line_position, label=None*) + #### plantcv.analyze_bound_vertical @@ -171,6 +174,8 @@ pages for more details on the input and output variable types. * post v3.0dev2: bound_header, bound_data, analysis_images = **plantcv.analyze_bound_vertical**(*img, obj, mask, line_position, filename=False*) * post v3.0.5: bound_header, bound_data, analysis_images = **plantcv.analyze_bound_vertical**(*img, obj, mask, line_position*) * post v3.3: analysis_image = **plantcv.analyze_bound_vertical**(*img, obj, mask, line_position*) +* post v3.11: analysis_image = **plantcv.analyze_bound_vertical**(*img, obj, mask, line_position, label=None*) + #### plantcv.analyze_color @@ -178,6 +183,8 @@ pages for more details on the input and output variable types. * post v3.0dev2: hist_header, hist_data, analysis_images = **plantcv.analyze_color**(*rgb_img, mask, bins, hist_plot_type=None, pseudo_channel='v', pseudo_bkg='img', filename=False*) * post v3.0: hist_header, hist_data, analysis_images = **plantcv.analyze_color**(*rgb_img, mask, bins, hist_plot_type=None*) * post v3.3: analysis_image = **plantcv.analyze_color**(*rgb_img, mask, hist_plot_type=None*) +* post v3.11: analysis_image = **plantcv.analyze_color**(*rgb_img, mask, hist_plot_type=None, label=None*) + #### plantcv.analyze_nir_intensity @@ -185,6 +192,8 @@ pages for more details on the input and output variable types. * post v3.0dev2: hist_header, hist_data, analysis_img = **plantcv.analyze_nir_intensity**(*gray_img, mask, bins, histplot=False, filename=False*) * post v3.0: hist_header, hist_data, nir_hist = **plantcv.analyze_nir_intensity**(*gray_img, mask, bins, histplot=False*) * post v3.3: nir_hist = **plantcv.analyze_nir_intensity**(*gray_img, mask, bins, histplot=False*) +* post v3.11: nir_hist = **plantcv.analyze_nir_intensity**(*gray_img, mask, bins, histplot=False, label=None*) + #### plantcv.analyze_object @@ -192,11 +201,14 @@ pages for more details on the input and output variable types. * post v3.0dev2: shape_header, shape_data, analysis_images = **plantcv.analyze_object**(*img, obj, mask, filename=False*) * post v3.0: shape_header, shape_data, analysis_images = **plantcv.analyze_object**(*img, obj, mask*) * post v3.3: analysis_image = **plantcv.analyze_object**(*img, obj, mask*) +* post v3.11: analysis_image = **plantcv.analyze_object**(*img, obj, mask, label=None*) + #### plantcv.analyze_thermal_values * pre v3.5: NA * post v3.5: thermal_histogram = **plantcv.analyze_thermal_values**(*thermal_array, mask, histplot=False*) +* post v3.11: thermal_histogram = **plantcv.analyze_thermal_values**(*thermal_array, mask, histplot=False, label=None*) #### plantcv.apply_mask From c98e5c99d700bf3828f3c1f712680c1f86d95535 Mon Sep 17 00:00:00 2001 From: HaleySchuhl Date: Mon, 25 Jan 2021 14:11:12 -0600 Subject: [PATCH 101/137] Update updating.md --- docs/updating.md | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/docs/updating.md b/docs/updating.md index 6bcf12605..e116aeb7f 100644 --- a/docs/updating.md +++ b/docs/updating.md @@ -343,6 +343,7 @@ pages for more details on the input and output variable types. * post v3.8: index_histogram = **plantcv.hyperspectral.analyze_index**(*index_array, mask, histplot=False, bins=100, max_bin=0, min_bin=1*) * post v3.11: index_histogram = **plantcv.hyperspectral.analyze_index**(*index_array, mask, histplot=False, bins=100, max_bin=0, min_bin=1, label=None*) + #### plantcv.hyperspectral.analyze_spectral * pre v3.7: NA @@ -376,6 +377,8 @@ pages for more details on the input and output variable types. * post v3.0dev2: vert_ave_c, hori_ave_c, euc_ave_c, ang_ave_c, vert_ave_b, hori_ave_b, euc_ave_b, ang_ave_b = **plantcv.landmark_reference_pt_dist**(*points_r, centroid_r, bline_r*) * post v3.2: landmark_header, landmark_data = **plantcv.landmark_reference_pt_dist**(*points_r, centroid_r, bline_r*) * post v3.3: **plantcv.landmark_reference_pt_dist**(*points_r, centroid_r, bline_r*) +* post v3.11: **plantcv.landmark_reference_pt_dist**(*points_r, centroid_r, bline_r, label=None*) + #### plantcv.laplace_filter @@ -513,6 +516,7 @@ pages for more details on the input and output variable types. #### plantcv.photosynthesis.analyze_fvfm * pre v3.10: see plantcv.fluor_fvfm * post v3.10: analysis_images = **plantcv.photosynthesis.analyze_fvfm**(*fdark, fmin, fmax, mask, bins=256*) +* post v3.11: analysis_images = **plantcv.photosynthesis.analyze_fvfm**(*fdark, fmin, fmax, mask, bins=256, label=None*) #### plantcv.photosynthesis.read_cropreporter @@ -569,6 +573,7 @@ pages for more details on the input and output variable types. * post v3.0dev2: marker_header, marker_data, analysis_images = **plantcv.report_size_marker_area**(*img, roi_contour, roi_hierarchy, marker='define', objcolor='dark', thresh_channel=None, thresh=None, filename=False*) * post v3.1: marker_header, marker_data, analysis_image = **plantcv.report_size_marker_area**(*img, roi_contour, roi_hierarchy, marker='define', objcolor='dark', thresh_channel=None, thresh=None*) * post v3.3: analysis_image = **plantcv.report_size_marker_area**(*img, roi_contour, roi_hierarchy, marker='define', objcolor='dark', thresh_channel=None, thresh=None*) +* post v3.11: analysis_image = **plantcv.report_size_marker_area**(*img, roi_contour, roi_hierarchy, marker='define', objcolor='dark', thresh_channel=None, thresh=None, label=None*) #### plantcv.resize @@ -847,7 +852,7 @@ pages for more details on the input and output variable types. * post v3.0: df, start_coord, spacing = **plantcv.transform.find_color_card**(*rgb_img, threshold='adaptgauss', threshvalue=125, blurry=False, background='dark'*) * post v3.3: df, start_coord, spacing = **plantcv.transform.find_color_card**(*rgb_img, threshold_type='adaptgauss', threshvalue=125, blurry=False, background='dark'*) * post v3.9: df, start_coord, spacing = **plantcv.transform.find_color_card**(*rgb_img, threshold_type='adaptgauss', threshvalue=125, blurry=False, background='dark', record_chip_size='median'*) - +* post v3.11: df, start_coord, spacing = **plantcv.transform.find_color_card**(*rgb_img, threshold_type='adaptgauss', threshvalue=125, blurry=False, background='dark', record_chip_size='median', label=None*) #### plantcv.transform.get_color_matrix @@ -915,6 +920,7 @@ pages for more details on the input and output variable types. * post v3.0dev2: watershed_header, watershed_data, analysis_images = **plantcv.watershed_segmentation**(*rgb_img, mask, distance=10, filename=False*) * post v3.1: watershed_header, watershed_data, analysis_images = **plantcv.watershed_segmentation**(*rgb_img, mask, distance=10*) * post v3.3: analysis_image = **plantcv.watershed_segmentation**(*rgb_img, mask, distance=10*) +* post v3.11: analysis_image = **plantcv.watershed_segmentation**(*rgb_img, mask, distance=10, label=None*) #### plantcv.white_balance @@ -926,15 +932,18 @@ pages for more details on the input and output variable types. * pre v3.3: NA * post v3.3: in_bounds = **plantcv.within_frame**(*mask*) * post v3.8: in_bounds = **plantcv.within_frame**(*mask, border_width=1*) +* post v3.11: in_bounds = **plantcv.within_frame**(*mask, border_width=1, label=None*) #### plantcv.x_axis_pseudolandmarks * pre v3.0dev2: device, top, bottom, center_v = **plantcv.x_axis_pseudolandmarks**(*obj, mask, img, device, debug=None*) * post v3.0dev2: top, bottom, center_v = **plantcv.x_axis_pseudolandmarks**(*obj, mask, img*) * post v3.2: top, bottom, center_v = **plantcv.x_axis_pseudolandmarks**(*img, obj, mask*) +* post v3.11: top, bottom, center_v = **plantcv.x_axis_pseudolandmarks**(*img, obj, mask, label=None*) #### plantcv.y_axis_pseudolandmarks * pre v3.0dev2: device, left, right, center_h = **plantcv.y_axis_pseudolandmarks**(*obj, mask, img, device, debug=None*) * post v3.0dev2: left, right, center_h = **plantcv.y_axis_pseudolandmarks**(*obj, mask, img*) * post v3.2: left, right, center_h = **plantcv.y_axis_pseudolandmarks**(*img, obj, mask*) +* post v3.11: left, right, center_h = **plantcv.y_axis_pseudolandmarks**(*img, obj, mask, label=None*) From 1f641b17d8947d936898a5ba3bddb603707aa0cb Mon Sep 17 00:00:00 2001 From: HaleySchuhl Date: Mon, 8 Feb 2021 10:50:22 -0600 Subject: [PATCH 102/137] update label default to "default" in morph and spectral --- plantcv/plantcv/hyperspectral/analyze_index.py | 7 ++----- plantcv/plantcv/hyperspectral/analyze_spectral.py | 7 ++----- plantcv/plantcv/morphology/analyze_stem.py | 8 ++------ plantcv/plantcv/morphology/check_cycles.py | 7 ++----- plantcv/plantcv/morphology/fill_segments.py | 7 ++----- plantcv/plantcv/morphology/find_branch_pts.py | 7 ++----- plantcv/plantcv/morphology/find_tips.py | 7 ++----- plantcv/plantcv/morphology/segment_angle.py | 7 ++----- plantcv/plantcv/morphology/segment_curvature.py | 7 ++----- plantcv/plantcv/morphology/segment_euclidean_length.py | 7 ++----- plantcv/plantcv/morphology/segment_insertion_angle.py | 7 ++----- plantcv/plantcv/morphology/segment_path_length.py | 7 ++----- plantcv/plantcv/morphology/segment_tangent_angle.py | 7 ++----- 13 files changed, 26 insertions(+), 66 deletions(-) diff --git a/plantcv/plantcv/hyperspectral/analyze_index.py b/plantcv/plantcv/hyperspectral/analyze_index.py index c81f1e412..e6a49bf19 100644 --- a/plantcv/plantcv/hyperspectral/analyze_index.py +++ b/plantcv/plantcv/hyperspectral/analyze_index.py @@ -12,7 +12,7 @@ from plotnine import ggplot, aes, geom_line, scale_x_continuous -def analyze_index(index_array, mask, histplot=False, bins=100, min_bin=0, max_bin=1, label=None): +def analyze_index(index_array, mask, histplot=False, bins=100, min_bin=0, max_bin=1, label="default"): """This extracts the hyperspectral index statistics and writes the values as observations out to the Outputs class. @@ -107,10 +107,7 @@ def analyze_index(index_array, mask, histplot=False, bins=100, min_bin=0, max_bi elif params.debug == 'plot': print(fig_hist) - if label == None: - prefix = "" - else: - prefix = label + "_" + prefix = label + "_" outputs.add_observation(variable=prefix + 'mean_' + index_array.array_type, trait='Average ' + index_array.array_type + ' reflectance', diff --git a/plantcv/plantcv/hyperspectral/analyze_spectral.py b/plantcv/plantcv/hyperspectral/analyze_spectral.py index 22c7cb81f..b5422e42b 100644 --- a/plantcv/plantcv/hyperspectral/analyze_spectral.py +++ b/plantcv/plantcv/hyperspectral/analyze_spectral.py @@ -8,7 +8,7 @@ from plotnine import ggplot, aes, geom_line, scale_x_continuous -def analyze_spectral(array, mask, histplot=True, label=None): +def analyze_spectral(array, mask, histplot=True, label="default"): """This extracts the hyperspectral reflectance values of each pixel writes the values out to a file. It can also print out a histogram plot of pixel intensity and a pseudocolor image of the plant. @@ -69,10 +69,7 @@ def analyze_spectral(array, mask, histplot=True, label=None): for i in array.wavelength_dict.keys(): wavelength_labels.append(i) - if label == None: - prefix = "" - else: - prefix = label + "_" + prefix = label + "_" # Store data into outputs class outputs.add_observation(variable=prefix + 'global_mean_reflectance', trait='global mean reflectance', diff --git a/plantcv/plantcv/morphology/analyze_stem.py b/plantcv/plantcv/morphology/analyze_stem.py index 9207000a3..aa722f082 100644 --- a/plantcv/plantcv/morphology/analyze_stem.py +++ b/plantcv/plantcv/morphology/analyze_stem.py @@ -9,7 +9,7 @@ from plantcv.plantcv import print_image -def analyze_stem(rgb_img, stem_objects, label=None): +def analyze_stem(rgb_img, stem_objects, label="default"): """ Calculate angle of segments (in degrees) by fitting a linear regression line to segments. Inputs: @@ -41,11 +41,7 @@ def analyze_stem(rgb_img, stem_objects, label=None): # Calculate stem path length stem_length = cv2.arcLength(grouped_stem, False) / 2 - - if label == None: - prefix = "" - else: - prefix = label + "_" + prefix = label + "_" outputs.add_observation(variable=prefix + 'stem_height', trait='vertical length of stem segments', method='plantcv.plantcv.morphology.analyze_stem', scale='pixels', datatype=float, diff --git a/plantcv/plantcv/morphology/check_cycles.py b/plantcv/plantcv/morphology/check_cycles.py index 99d952029..5c8359dc6 100644 --- a/plantcv/plantcv/morphology/check_cycles.py +++ b/plantcv/plantcv/morphology/check_cycles.py @@ -13,7 +13,7 @@ from plantcv.plantcv import color_palette -def check_cycles(skel_img, label=None): +def check_cycles(skel_img, label="default"): """ Check for cycles in a skeleton image Inputs: skel_img = Skeletonized image @@ -62,10 +62,7 @@ def check_cycles(skel_img, label=None): cv2.drawContours(cycle_img, cycle_objects, i, rand_color[i], params.line_thickness, lineType=8, hierarchy=cycle_hierarchies) - if label == None: - prefix = "" - else: - prefix = label + "_" + prefix = label + "_" # Store Cycle Data outputs.add_observation(variable=prefix + 'num_cycles', trait='number of cycles', diff --git a/plantcv/plantcv/morphology/fill_segments.py b/plantcv/plantcv/morphology/fill_segments.py index 6f2010ca5..6ff7d89d3 100644 --- a/plantcv/plantcv/morphology/fill_segments.py +++ b/plantcv/plantcv/morphology/fill_segments.py @@ -11,7 +11,7 @@ from plantcv.plantcv import print_image -def fill_segments(mask, objects, stem_objects=None, label=None): +def fill_segments(mask, objects, stem_objects=None, label="default"): """Fills masked segments from contours. Inputs: @@ -46,10 +46,7 @@ def fill_segments(mask, objects, stem_objects=None, label=None): # Count area in pixels of each segment ids, counts = np.unique(filled_mask, return_counts=True) - if label == None: - prefix = "" - else: - prefix = label + "_" + prefix = label + "_" outputs.add_observation(variable=prefix + 'segment_area', trait='segment area', method='plantcv.plantcv.morphology.fill_segments', diff --git a/plantcv/plantcv/morphology/find_branch_pts.py b/plantcv/plantcv/morphology/find_branch_pts.py index 206f5af2d..09f23725a 100644 --- a/plantcv/plantcv/morphology/find_branch_pts.py +++ b/plantcv/plantcv/morphology/find_branch_pts.py @@ -11,7 +11,7 @@ from plantcv.plantcv import find_objects -def find_branch_pts(skel_img, mask=None, label=None): +def find_branch_pts(skel_img, mask=None, label="default"): """ The branching algorithm was inspired by Jean-Patrick Pommier: https://gist.github.com/jeanpat/5712699 Inputs: @@ -96,10 +96,7 @@ def find_branch_pts(skel_img, mask=None, label=None): branch_labels.append(i) cv2.circle(branch_plot, (x, y), params.line_thickness, (255, 0, 255), -1) - if label == None: - prefix = "" - else: - prefix = label + "_" + prefix = label + "_" outputs.add_observation(variable='branch_pts', trait='list of branch-point coordinates identified from a skeleton', method='plantcv.plantcv.morphology.find_branch_pts', scale='pixels', datatype=list, diff --git a/plantcv/plantcv/morphology/find_tips.py b/plantcv/plantcv/morphology/find_tips.py index 2c3f35eda..e4998bae9 100644 --- a/plantcv/plantcv/morphology/find_tips.py +++ b/plantcv/plantcv/morphology/find_tips.py @@ -11,7 +11,7 @@ from plantcv.plantcv import find_objects -def find_tips(skel_img, mask=None, label=None): +def find_tips(skel_img, mask=None, label="default"): """ The endpoints algorithm was inspired by Jean-Patrick Pommier: https://gist.github.com/jeanpat/5712699 Find tips in skeletonized image. @@ -80,10 +80,7 @@ def find_tips(skel_img, mask=None, label=None): cv2.circle(tip_plot, (x, y), params.line_thickness, (0, 255, 0), -1) - if label == None: - prefix = "" - else: - prefix = label + "_" + prefix = label + "_" outputs.add_observation(variable=prefix + 'tips', trait='list of tip coordinates identified from a skeleton', method='plantcv.plantcv.morphology.find_tips', scale='pixels', datatype=list, diff --git a/plantcv/plantcv/morphology/segment_angle.py b/plantcv/plantcv/morphology/segment_angle.py index ff5ceabe9..8f24a7154 100644 --- a/plantcv/plantcv/morphology/segment_angle.py +++ b/plantcv/plantcv/morphology/segment_angle.py @@ -11,7 +11,7 @@ from plantcv.plantcv import color_palette -def segment_angle(segmented_img, objects, label=None): +def segment_angle(segmented_img, objects, label="default"): """ Calculate angle of segments (in degrees) by fitting a linear regression line to segments. Inputs: @@ -76,10 +76,7 @@ def segment_angle(segmented_img, objects, label=None): # segment_label = "ID" + str(i) segment_ids.append(i) - if label == None: - prefix = "" - else: - prefix = label + "_" + prefix = label + "_" outputs.add_observation(variable=prefix + 'segment_angle', trait='segment angle', method='plantcv.plantcv.morphology.segment_angle', scale='degrees', datatype=list, diff --git a/plantcv/plantcv/morphology/segment_curvature.py b/plantcv/plantcv/morphology/segment_curvature.py index d9160b086..651c12024 100644 --- a/plantcv/plantcv/morphology/segment_curvature.py +++ b/plantcv/plantcv/morphology/segment_curvature.py @@ -14,7 +14,7 @@ from plantcv.plantcv.morphology import segment_euclidean_length -def segment_curvature(segmented_img, objects, label=None): +def segment_curvature(segmented_img, objects, label="default"): """ Calculate segment curvature as defined by the ratio between geodesic and euclidean distance. Measurement of two-dimensional tortuosity. @@ -85,10 +85,7 @@ def segment_curvature(segmented_img, objects, label=None): # segment_label = "ID" + str(i) segment_ids.append(i) - if label == None: - prefix = "" - else: - prefix = label + "_" + prefix = label + "_" outputs.add_observation(variable=prefix + 'segment_curvature', trait='segment curvature', method='plantcv.plantcv.morphology.segment_curvature', scale='none', datatype=list, diff --git a/plantcv/plantcv/morphology/segment_euclidean_length.py b/plantcv/plantcv/morphology/segment_euclidean_length.py index 67e839c70..d5f048033 100644 --- a/plantcv/plantcv/morphology/segment_euclidean_length.py +++ b/plantcv/plantcv/morphology/segment_euclidean_length.py @@ -14,7 +14,7 @@ from plantcv.plantcv.morphology import find_tips -def segment_euclidean_length(segmented_img, objects, label=None): +def segment_euclidean_length(segmented_img, objects, label="default"): """ Use segmented skeleton image to gather euclidean length measurements per segment Inputs: @@ -81,10 +81,7 @@ def segment_euclidean_length(segmented_img, objects, label=None): # segment_label = "ID" + str(c) segment_ids.append(c) - if label == None: - prefix = "" - else: - prefix = label + "_" + prefix = label + "_" outputs.add_observation(variable=prefix + 'segment_eu_length', trait='segment euclidean length', method='plantcv.plantcv.morphology.segment_euclidean_length', scale='pixels', datatype=list, diff --git a/plantcv/plantcv/morphology/segment_insertion_angle.py b/plantcv/plantcv/morphology/segment_insertion_angle.py index 5b03328ca..dfbd2ec91 100644 --- a/plantcv/plantcv/morphology/segment_insertion_angle.py +++ b/plantcv/plantcv/morphology/segment_insertion_angle.py @@ -19,7 +19,7 @@ from plantcv.plantcv.morphology.segment_tangent_angle import _slope_to_intesect_angle -def segment_insertion_angle(skel_img, segmented_img, leaf_objects, stem_objects, size, label=None): +def segment_insertion_angle(skel_img, segmented_img, leaf_objects, stem_objects, size, label="default"): """ Find leaf insertion angles in degrees of skeleton segments. Fit a linear regression line to the stem. Use `size` pixels on the portion of leaf next to the stem find a linear regression line, and calculate angle between the two lines per leaf object. @@ -186,10 +186,7 @@ def segment_insertion_angle(skel_img, segmented_img, leaf_objects, stem_objects, # segment_label = "ID" + str(i) segment_ids.append(i) - if label == None: - prefix = "" - else: - prefix = label + "_" + prefix = label + "_" outputs.add_observation(variable=prefix + 'segment_insertion_angle', trait='segment insertion angle', method='plantcv.plantcv.morphology.segment_insertion_angle', scale='degrees', datatype=list, diff --git a/plantcv/plantcv/morphology/segment_path_length.py b/plantcv/plantcv/morphology/segment_path_length.py index 868d13bcc..174a51ebb 100644 --- a/plantcv/plantcv/morphology/segment_path_length.py +++ b/plantcv/plantcv/morphology/segment_path_length.py @@ -8,7 +8,7 @@ from plantcv.plantcv import print_image -def segment_path_length(segmented_img, objects, label=None): +def segment_path_length(segmented_img, objects, label="default"): """ Use segments to calculate geodesic distance per segment Inputs: @@ -48,10 +48,7 @@ def segment_path_length(segmented_img, objects, label=None): fontScale=params.text_size, color=(150, 150, 150), thickness=params.text_thickness) segment_ids.append(c) - if label == None: - prefix = "" - else: - prefix = label + "_" + prefix = label + "_" outputs.add_observation(variable=prefix + 'segment_path_length', trait='segment path length', method='plantcv.plantcv.morphology.segment_path_length', scale='pixels', datatype=list, diff --git a/plantcv/plantcv/morphology/segment_tangent_angle.py b/plantcv/plantcv/morphology/segment_tangent_angle.py index a4ff21df9..64127a7c3 100644 --- a/plantcv/plantcv/morphology/segment_tangent_angle.py +++ b/plantcv/plantcv/morphology/segment_tangent_angle.py @@ -31,7 +31,7 @@ def _slope_to_intesect_angle(m1, m2): return angle -def segment_tangent_angle(segmented_img, objects, size, label=None): +def segment_tangent_angle(segmented_img, objects, size, label="default"): """ Find 'tangent' angles in degrees of skeleton segments. Use `size` pixels on either end of each segment to find a linear regression line, and calculate angle between the two lines drawn per segment. @@ -125,10 +125,7 @@ def segment_tangent_angle(segmented_img, objects, size, label=None): # segment_label = "ID" + str(i) segment_ids.append(i) - if label == None: - prefix = "" - else: - prefix = label + "_" + prefix = label + "_" outputs.add_observation(variable=prefix + 'segment_tangent_angle', trait='segment tangent angle', method='plantcv.plantcv.morphology.segment_tangent_angle', scale='degrees', datatype=list, From 8a09b3ea6342e126fe732c5ea617ca235f453b62 Mon Sep 17 00:00:00 2001 From: HaleySchuhl Date: Mon, 8 Feb 2021 11:01:46 -0600 Subject: [PATCH 103/137] update param more spots --- plantcv/plantcv/acute_vertex.py | 7 ++----- plantcv/plantcv/analyze_bound_horizontal.py | 7 ++----- plantcv/plantcv/analyze_bound_vertical.py | 7 ++----- plantcv/plantcv/analyze_color.py | 7 ++----- plantcv/plantcv/analyze_nir_intensity.py | 7 ++----- plantcv/plantcv/analyze_object.py | 7 ++----- plantcv/plantcv/analyze_thermal_values.py | 7 ++----- plantcv/plantcv/photosynthesis/analyze_fvfm.py | 7 ++----- 8 files changed, 16 insertions(+), 40 deletions(-) diff --git a/plantcv/plantcv/acute_vertex.py b/plantcv/plantcv/acute_vertex.py index 0caf4a849..e9d9dc207 100755 --- a/plantcv/plantcv/acute_vertex.py +++ b/plantcv/plantcv/acute_vertex.py @@ -10,7 +10,7 @@ from plantcv.plantcv import outputs -def acute_vertex(img, obj, win, thresh, sep, label=None): +def acute_vertex(img, obj, win, thresh, sep, label="default"): """acute_vertex: identify corners/acute angles of an object For each point in contour, get a point before (pre) and after (post) the point of interest, @@ -99,10 +99,7 @@ def acute_vertex(img, obj, win, thresh, sep, label=None): x, y = i.ravel() cv2.circle(img2, (x, y), params.line_thickness, (255, 0, 255), -1) - if label == None: - prefix = "" - else: - prefix = label + "_" + prefix = label + "_" if params.debug == 'print': print_image(img2, os.path.join(params.debug_outdir, str(params.device) + prefix + '_acute_vertices.png')) diff --git a/plantcv/plantcv/analyze_bound_horizontal.py b/plantcv/plantcv/analyze_bound_horizontal.py index 3244019f0..ed9ab1ba5 100755 --- a/plantcv/plantcv/analyze_bound_horizontal.py +++ b/plantcv/plantcv/analyze_bound_horizontal.py @@ -9,7 +9,7 @@ from plantcv.plantcv import outputs -def analyze_bound_horizontal(img, obj, mask, line_position, label=None): +def analyze_bound_horizontal(img, obj, mask, line_position, label="default"): """User-input boundary line tool Inputs: @@ -146,10 +146,7 @@ def analyze_bound_horizontal(img, obj, mask, line_position, label=None): plot_image(wback) plot_image(ori_img) - if label == None: - prefix = "" - else: - prefix = label + "_" + prefix = label + "_" outputs.add_observation(variable=prefix + 'horizontal_reference_position', trait='horizontal reference position', method='plantcv.plantcv.analyze_bound_horizontal', scale='none', datatype=int, diff --git a/plantcv/plantcv/analyze_bound_vertical.py b/plantcv/plantcv/analyze_bound_vertical.py index 6906cc310..58121577e 100755 --- a/plantcv/plantcv/analyze_bound_vertical.py +++ b/plantcv/plantcv/analyze_bound_vertical.py @@ -9,7 +9,7 @@ from plantcv.plantcv import outputs -def analyze_bound_vertical(img, obj, mask, line_position, label=None): +def analyze_bound_vertical(img, obj, mask, line_position, label="default"): """User-input boundary line tool Inputs: @@ -146,10 +146,7 @@ def analyze_bound_vertical(img, obj, mask, line_position, label=None): plot_image(wback) plot_image(ori_img) - if label == None: - prefix = "" - else: - prefix = label + "_" + prefix = label + "_" outputs.add_observation(variable=prefix + 'vertical_reference_position', trait='vertical reference position', method='plantcv.plantcv.analyze_bound_vertical', scale='none', datatype=int, diff --git a/plantcv/plantcv/analyze_color.py b/plantcv/plantcv/analyze_color.py index f9f1ae3c2..319325960 100755 --- a/plantcv/plantcv/analyze_color.py +++ b/plantcv/plantcv/analyze_color.py @@ -9,7 +9,7 @@ from plantcv.plantcv import outputs -def analyze_color(rgb_img, mask, hist_plot_type=None, label=None): +def analyze_color(rgb_img, mask, hist_plot_type=None, label="default"): """Analyze the color properties of an image object Inputs: rgb_img = RGB image data @@ -161,10 +161,7 @@ def analyze_color(rgb_img, mask, hist_plot_type=None, label=None): # Diverging values on a -128 to 127 scale (green-magenta and blue-yellow) diverging_values = [i for i in range(-128, 128)] - if label == None: - prefix = "" - else: - prefix = label + "_" + prefix = label + "_" if hist_plot_type is not None: if hist_plot_type.upper() == 'RGB' or hist_plot_type.upper() == 'ALL': diff --git a/plantcv/plantcv/analyze_nir_intensity.py b/plantcv/plantcv/analyze_nir_intensity.py index e2a57a689..6d51bc26a 100755 --- a/plantcv/plantcv/analyze_nir_intensity.py +++ b/plantcv/plantcv/analyze_nir_intensity.py @@ -12,7 +12,7 @@ from plantcv.plantcv import outputs -def analyze_nir_intensity(gray_img, mask, bins=256, histplot=False, label=None): +def analyze_nir_intensity(gray_img, mask, bins=256, histplot=False, label="default"): """This function calculates the intensity of each pixel associated with the plant and writes the values out to a file. It can also print out a histogram plot of pixel intensity and a pseudocolor image of the plant. @@ -93,10 +93,7 @@ def analyze_nir_intensity(gray_img, mask, bins=256, histplot=False, label=None): elif params.debug == "plot": print(fig_hist) - if label == None: - prefix = "" - else: - prefix = label + "_" + prefix = label + "_" outputs.add_observation(variable=prefix + 'nir_frequencies', trait='near-infrared frequencies', method='plantcv.plantcv.analyze_nir_intensity', scale='frequency', datatype=list, diff --git a/plantcv/plantcv/analyze_object.py b/plantcv/plantcv/analyze_object.py index 2a8c8aaf7..cd806f3e3 100755 --- a/plantcv/plantcv/analyze_object.py +++ b/plantcv/plantcv/analyze_object.py @@ -10,7 +10,7 @@ from plantcv.plantcv import within_frame -def analyze_object(img, obj, mask, label=None): +def analyze_object(img, obj, mask, label="default"): """Outputs numeric properties for an input object (contour or grouped contours). Inputs: @@ -158,10 +158,7 @@ def analyze_object(img, obj, mask, label=None): else: pass - if label == None: - prefix = "" - else: - prefix = label + "_" + prefix = label + "_" outputs.add_observation(variable=prefix + 'area', trait='area', method='plantcv.plantcv.analyze_object', scale='pixels', datatype=int, diff --git a/plantcv/plantcv/analyze_thermal_values.py b/plantcv/plantcv/analyze_thermal_values.py index a7137f2ec..4b049fd75 100755 --- a/plantcv/plantcv/analyze_thermal_values.py +++ b/plantcv/plantcv/analyze_thermal_values.py @@ -10,7 +10,7 @@ from plantcv.plantcv.threshold import binary as binary_threshold -def analyze_thermal_values(thermal_array, mask, histplot=False, label=None): +def analyze_thermal_values(thermal_array, mask, histplot=False, label="default"): """This extracts the thermal values of each pixel writes the values out to a file. It can also print out a histogram plot of pixel intensity and a pseudocolor image of the plant. @@ -59,10 +59,7 @@ def analyze_thermal_values(thermal_array, mask, histplot=False, label=None): avgtemp = np.average(masked_thermal) mediantemp = np.median(masked_thermal) - if label == None: - prefix = "" - else: - prefix = label + "_" + prefix = label + "_" # Store data into outputs class outputs.add_observation(variable=prefix + 'max_temp', trait='maximum temperature', diff --git a/plantcv/plantcv/photosynthesis/analyze_fvfm.py b/plantcv/plantcv/photosynthesis/analyze_fvfm.py index e20343d30..a872513a6 100755 --- a/plantcv/plantcv/photosynthesis/analyze_fvfm.py +++ b/plantcv/plantcv/photosynthesis/analyze_fvfm.py @@ -12,7 +12,7 @@ from plantcv.plantcv import outputs -def analyze_fvfm(fdark, fmin, fmax, mask, bins=256, label=None): +def analyze_fvfm(fdark, fmin, fmax, mask, bins=256, label="default"): """Analyze PSII camera images. Inputs: fdark = grayscale fdark image @@ -89,10 +89,7 @@ def analyze_fvfm(fdark, fmin, fmax, mask, bins=256, label=None): x=.15, y=205, size=8, color='green')) analysis_images.append(fvfm_hist_fig) - if label == None: - prefix = "" - else: - prefix = label + "_" + prefix = label + "_" if params.debug == 'print': print_image(fmin_mask, os.path.join(params.debug_outdir, str(params.device) + prefix + '_fmin_mask.png')) From 787acfd527a5b77a481bf2a1a79b03fef9f220ea Mon Sep 17 00:00:00 2001 From: HaleySchuhl Date: Mon, 8 Feb 2021 11:10:33 -0600 Subject: [PATCH 104/137] remaining --- plantcv/plantcv/landmark_reference_pt_dist.py | 7 ++----- plantcv/plantcv/report_size_marker_area.py | 7 ++----- plantcv/plantcv/within_frame.py | 7 ++----- plantcv/plantcv/x_axis_pseudolandmarks.py | 7 ++----- plantcv/plantcv/y_axis_pseudolandmarks.py | 7 ++----- 5 files changed, 10 insertions(+), 25 deletions(-) diff --git a/plantcv/plantcv/landmark_reference_pt_dist.py b/plantcv/plantcv/landmark_reference_pt_dist.py index c24ee4231..2fa2d586f 100755 --- a/plantcv/plantcv/landmark_reference_pt_dist.py +++ b/plantcv/plantcv/landmark_reference_pt_dist.py @@ -7,7 +7,7 @@ from plantcv.plantcv import outputs -def landmark_reference_pt_dist(points_r, centroid_r, bline_r, label=None): +def landmark_reference_pt_dist(points_r, centroid_r, bline_r, label="default"): """landmark_reference_pt_dist For each point in contour, get a point before (pre) and after (post) the point of interest. @@ -93,10 +93,7 @@ def landmark_reference_pt_dist(points_r, centroid_r, bline_r, label=None): euc_ave_b = np.mean(euc_dist_b) ang_ave_b = np.mean(angles_b) - if label == None: - prefix = "" - else: - prefix = label + "_" + prefix = label + "_" outputs.add_observation(variable=prefix + 'vert_ave_c', trait='average vertical distance from centroid', method='plantcv.plantcv.landmark_reference_pt_dist', scale='pixels', datatype=float, diff --git a/plantcv/plantcv/report_size_marker_area.py b/plantcv/plantcv/report_size_marker_area.py index eb6fa9e39..9c2218f4c 100755 --- a/plantcv/plantcv/report_size_marker_area.py +++ b/plantcv/plantcv/report_size_marker_area.py @@ -17,7 +17,7 @@ def report_size_marker_area(img, roi_contour, roi_hierarchy, marker='define', objcolor='dark', thresh_channel=None, - thresh=None, label=None): + thresh=None, label="default"): """Detects a size marker in a specified region and reports its size and eccentricity Inputs: @@ -121,10 +121,7 @@ def report_size_marker_area(img, roi_contour, roi_hierarchy, marker='define', ob # Reset debug mode params.debug = debug - if label == None: - prefix = "" - else: - prefix = label + "_" + prefix = label + "_" if params.debug == 'print': print_image(ref_img, os.path.join(params.debug_outdir, str(params.device) + prefix + '_marker_shape.png')) diff --git a/plantcv/plantcv/within_frame.py b/plantcv/plantcv/within_frame.py index 116080a76..07d4f15d2 100644 --- a/plantcv/plantcv/within_frame.py +++ b/plantcv/plantcv/within_frame.py @@ -5,7 +5,7 @@ from plantcv.plantcv import outputs -def within_frame(mask, border_width=1, label=None): +def within_frame(mask, border_width=1, label="default"): """ This function tests whether the plant touches the edge of the image, i.e. it is completely in the field of view. Input: @@ -43,10 +43,7 @@ def within_frame(mask, border_width=1, label=None): out_of_bounds = bool(np.count_nonzero(border_pxs)) in_bounds = not out_of_bounds - if label == None: - prefix = "" - else: - prefix = label + "_" + prefix = label + "_" outputs.add_observation(variable=prefix + 'in_bounds', trait='whether the plant goes out of bounds ', method='plantcv.plantcv.within_frame', scale='none', datatype=bool, diff --git a/plantcv/plantcv/x_axis_pseudolandmarks.py b/plantcv/plantcv/x_axis_pseudolandmarks.py index 3709d2b2f..7f1b1a11f 100755 --- a/plantcv/plantcv/x_axis_pseudolandmarks.py +++ b/plantcv/plantcv/x_axis_pseudolandmarks.py @@ -10,7 +10,7 @@ from plantcv.plantcv import fatal_error -def x_axis_pseudolandmarks(img, obj, mask, label=None): +def x_axis_pseudolandmarks(img, obj, mask, label="default"): """Divide up object contour into 20 equidistance segments and generate landmarks for each Inputs: @@ -218,10 +218,7 @@ def x_axis_pseudolandmarks(img, obj, mask, label=None): for pt in center_v: center_v_list.append(pt[0].tolist()) - if label == None: - prefix = "" - else: - prefix = label + "_" + prefix = label + "_" outputs.add_observation(variable=prefix + 'top_lmk', trait='top landmark coordinates', method='plantcv.plantcv.x_axis_pseudolandmarks', scale='none', datatype=tuple, diff --git a/plantcv/plantcv/y_axis_pseudolandmarks.py b/plantcv/plantcv/y_axis_pseudolandmarks.py index 1c3753b65..445a2c365 100755 --- a/plantcv/plantcv/y_axis_pseudolandmarks.py +++ b/plantcv/plantcv/y_axis_pseudolandmarks.py @@ -10,7 +10,7 @@ from plantcv.plantcv import fatal_error -def y_axis_pseudolandmarks(img, obj, mask, label=None): +def y_axis_pseudolandmarks(img, obj, mask, label="default"): """Divide up object contour into 19 equidistant segments and generate landmarks for each Inputs: @@ -215,10 +215,7 @@ def y_axis_pseudolandmarks(img, obj, mask, label=None): for pt in center_h: center_h_list.append(pt[0].tolist()) - if label == None: - prefix = "" - else: - prefix = label + "_" + prefix = label + "_" outputs.add_observation(variable=prefix + 'left_lmk', trait='left landmark coordinates', method='plantcv.plantcv.x_axis_pseudolandmarks', scale='none', datatype=tuple, From d92518be5b85696c22091173b216773c1968651b Mon Sep 17 00:00:00 2001 From: HaleySchuhl Date: Mon, 8 Feb 2021 11:19:28 -0600 Subject: [PATCH 105/137] update doc pages --- docs/acute_vertex.md | 12 ++++++------ docs/analyze_NIR_intensity.md | 8 ++++---- docs/analyze_bound_horizontal.md | 6 +++--- docs/analyze_bound_vertical.md | 6 +++--- docs/analyze_color.md | 8 ++++---- docs/analyze_index.md | 4 ++-- docs/analyze_shape.md | 8 ++++---- docs/analyze_spectral.md | 8 ++++---- docs/analyze_stem.md | 6 +++--- docs/analyze_thermal_values.md | 8 ++++---- 10 files changed, 37 insertions(+), 37 deletions(-) diff --git a/docs/acute_vertex.md b/docs/acute_vertex.md index 32bd78a4d..463beea2d 100644 --- a/docs/acute_vertex.md +++ b/docs/acute_vertex.md @@ -3,7 +3,7 @@ Perform a heuristic search for sharp angles given an object contour and user specified parameters. The acute (sharp) angles are often associated with object tip points. Outputs a python list of points that meet criteria specified in parameters. -**plantcv.acute_vertex**(*img, obj, window, thresh, sep, label=None*) +**plantcv.acute_vertex**(*img, obj, window, thresh, sep, label="default"*) **returns** list of points that meet specified criteria, image with points selected @@ -13,7 +13,7 @@ angles are often associated with object tip points. Outputs a python list of poi - window - The pre and post point distances on which to calculate angle of focal point (a value of 30 worked well for a sample image) on which to calculate the angle - thresh - Threshold to set for acuteness; keep points with an angle more acute than the threshold (a value of 15 worked well for sample image) - sep - The number of contour points to search within for the most acute value - - label - Optional label parameter, modifies the variable name of observations recorded. (default `label=None`) + - label - Optional label parameter, modifies the variable name of observations recorded. (default `label="default"`) - **Context:** - Used to identify tip points based upon the angle between focal pixel and reference points on contour. - **Output data stored:** Data ('tip_coordinates') automatically gets stored to the [`Outputs` class](outputs.md) when this function is ran. @@ -33,11 +33,11 @@ pcv.params.debug = "print" # Identify acute vertices (tip points) of an object # Results in set of point values that may indicate tip points -list_of_acute_points, points_img = pcv.acute_vertex(img=img, obj=obj, window=30, thresh=15, sep=100, label=None) -` +list_of_acute_points, points_img = pcv.acute_vertex(img=img, obj=obj, window=30, thresh=15, sep=100, label="default") + # Access data stored out from acute_vertex -vertices = pcv.outputs.observations['tip_coordinates']['value'] -` +vertices = pcv.outputs.observations['default_tip_coordinates']['value'] + ``` **Image of points selected** diff --git a/docs/analyze_NIR_intensity.md b/docs/analyze_NIR_intensity.md index cb32b68e0..12c55e6c6 100644 --- a/docs/analyze_NIR_intensity.md +++ b/docs/analyze_NIR_intensity.md @@ -3,7 +3,7 @@ This function calculates the intensity of each pixel associated with the plant and writes the values out to the [Outputs class](outputs.md). Can also return/plot/print out a histogram plot of pixel intensity. -**plantcv.analyze_nir_intensity**(*gray_img, mask, bins=256, histplot=False, label=None*) +**plantcv.analyze_nir_intensity**(*gray_img, mask, bins=256, histplot=False, label="default"*) **returns** Histogram image (when histplot is `True`, otherwise returns `None` object) @@ -12,7 +12,7 @@ the values out to the [Outputs class](outputs.md). Can also return/plot/print ou - mask - Binary mask made from selected contours - bins - Number of NIR intensity value groups (default bins = 256) - histplot - If True plots histogram of intensity values (default histplot = False) - - label - Optional label parameter, modifies the variable name of observations recorded. (default `label=None`) + - label - Optional label parameter, modifies the variable name of observations recorded. (default `label="default"`) - **Context:** - Near Infrared pixel frequencies within a masked area of an image. - **Example use:** @@ -34,10 +34,10 @@ from plantcv import plantcv as pcv pcv.params.debug = "print" # Caclulates the proportion of pixels that fall into a signal bin and writes the values to a file. Also provides a histogram of this data -analysis_image = pcv.analyze_nir_intensity(gray_img, mask, 256, histplot=True, label=None) +analysis_image = pcv.analyze_nir_intensity(gray_img, mask, 256, histplot=True, label="default") # Access data stored out from analyze_nir_intensity -nir_frequencies = pcv.outputs.observations['nir_frequencies']['value'] +nir_frequencies = pcv.outputs.observations['default_nir_frequencies']['value'] ``` diff --git a/docs/analyze_bound_horizontal.md b/docs/analyze_bound_horizontal.md index 9ac46824c..9fb80203a 100644 --- a/docs/analyze_bound_horizontal.md +++ b/docs/analyze_bound_horizontal.md @@ -4,7 +4,7 @@ Set boundary line with boundary tool, this allows the user to find the extent-y above and below as well as the area above and below the boundary line. This tool functions best if the pot size/position of the plant remains relatively constant. -**plantcv.analyze_bound_horizontal**(*img, obj, mask, line_position, label=None*) +**plantcv.analyze_bound_horizontal**(*img, obj, mask, line_position, label="default"*) **returns** image with boundary data @@ -31,10 +31,10 @@ from plantcv import plantcv as pcv pcv.params.debug = "print" # Set Boundary Line -boundary_image = pcv.analyze_bound_horizontal(img=img, obj=obj, mask=bin_mask, line_position=300, label=None) +boundary_image = pcv.analyze_bound_horizontal(img=img, obj=obj, mask=bin_mask, line_position=300, label="default") # Access data stored out from analyze_bound_horizontal -percent_area_below_reference = pcv.outputs.observations['percent_area_below_reference']['value'] +percent_area_below_reference = pcv.outputs.observations['default_percent_area_below_reference']['value'] ``` diff --git a/docs/analyze_bound_vertical.md b/docs/analyze_bound_vertical.md index d8309dc8a..ddadb9590 100644 --- a/docs/analyze_bound_vertical.md +++ b/docs/analyze_bound_vertical.md @@ -4,7 +4,7 @@ Set boundary line with boundary tool, this allows the user to find the extent-x to the right and to the left as well as the area to the right and to the left of the set boundary line. This tool functions best if the pot size/position of the plant remains relatively constant. -**plantcv.analyze_bound_vertical**(*img, obj, mask, line_position, label=None*) +**plantcv.analyze_bound_vertical**(*img, obj, mask, line_position, label="default"*) **returns** image with boundary data @@ -31,10 +31,10 @@ from plantcv import plantcv as pcv pcv.params.debug = "print" # Set Boundary Line -boundary_image = pcv.analyze_bound_vertical(img=img, obj=obj, mask=bin_mask, line_position=1000, label=None) +boundary_image = pcv.analyze_bound_vertical(img=img, obj=obj, mask=bin_mask, line_position=1000, label="default") # Access data stored out from analyze_bound_vertical -area_right_reference = pcv.outputs.observations['area_right_reference']['value'] +area_right_reference = pcv.outputs.observations['default_area_right_reference']['value'] ``` diff --git a/docs/analyze_color.md b/docs/analyze_color.md index 55b200bd6..e67456fe3 100644 --- a/docs/analyze_color.md +++ b/docs/analyze_color.md @@ -2,7 +2,7 @@ Extract color data of objects and produce pseudocolored images, can extract data for RGB (Red, Green, Blue), HSV (Hue, Saturation, Value) and LAB (Lightness, Green-Magenta, Blue Yellow) channels. -**plantcv.analyze_color**(*rgb_img, mask, hist_plot_type=None, label=None*) +**plantcv.analyze_color**(*rgb_img, mask, hist_plot_type=None, label="default"*) **returns** Histogram image (if hist_plot_type is not `None`, otherwise returns `None` object) @@ -10,7 +10,7 @@ Extract color data of objects and produce pseudocolored images, can extract data - rgb_img - RGB image data - mask - binary mask of selected contours - hist_plot_type - None (default), 'all', 'rgb', 'lab', or 'hsv'. This can limit the data saved out. Hue data is still saved out when set to None. - - label - Optional label parameter, modifies the variable name of observations recorded. (default `label=None`) + - label - Optional label parameter, modifies the variable name of observations recorded. (default `label="default"`) - **Context:** - Used to extract color data from RGB, LAB, and HSV color channels. - Generates histogram of color channel data. @@ -36,10 +36,10 @@ pcv.params.debug = "print" # Analyze Color -analysis_image = pcv.analyze_color(rgb_img=rgb_img, mask=mask, hist_plot_type='all', label=None) +analysis_image = pcv.analyze_color(rgb_img=rgb_img, mask=mask, hist_plot_type='all', label="default") # Access data stored out from analyze_color -hue_circular_mean = pcv.outputs.observations['hue_circular_mean']['value'] +hue_circular_mean = pcv.outputs.observations['default_hue_circular_mean']['value'] ``` diff --git a/docs/analyze_index.md b/docs/analyze_index.md index e31d489f6..e3bda3283 100644 --- a/docs/analyze_index.md +++ b/docs/analyze_index.md @@ -3,7 +3,7 @@ This function calculates the spectral index statistics and writes the values as observations out to the [Outputs class](outputs.md). -**plantcv.hyperspectral.analyze_index**(*index_array, mask, histplot=False, bins=100, min_bin=0, max_bin=1, label=None*) +**plantcv.hyperspectral.analyze_index**(*index_array, mask, histplot=False, bins=100, min_bin=0, max_bin=1, label="default"*) **returns** None @@ -31,7 +31,7 @@ This function calculates the spectral index statistics and writes the values as from plantcv import plantcv as pcv -pcv.hyperspectral.analyze_index(index_array=ndvi_index, mask=leaf_mask, histplot=True, bins=100, min_bin=0, max_bin="auto", label=None) +pcv.hyperspectral.analyze_index(index_array=ndvi_index, mask=leaf_mask, histplot=True, bins=100, min_bin=0, max_bin="auto", label="default") ``` diff --git a/docs/analyze_shape.md b/docs/analyze_shape.md index 48d554930..9d025ecb2 100644 --- a/docs/analyze_shape.md +++ b/docs/analyze_shape.md @@ -2,7 +2,7 @@ Shape analysis outputs numeric properties for an input object (contour or grouped contours), works best on grouped contours. -**plantcv.analyze_object**(*img, obj, mask, label=None*) +**plantcv.analyze_object**(*img, obj, mask, label="default"*) **returns** analysis_image @@ -10,7 +10,7 @@ Shape analysis outputs numeric properties for an input object (contour or groupe - img - RGB or grayscale image data for plotting. - obj - Single or grouped contour object. - mask - Binary image to use as mask for moments analysis. - - label - Optional label parameter, modifies the variable name of observations recorded. (default `label=None`) + - label - Optional label parameter, modifies the variable name of observations recorded. (default `label="default"`) - **Context:** - Used to output shape characteristics of an image, including height, object area, convex hull, convex hull area, perimeter, extent x, extent y, longest axis, centroid x coordinate, centroid y coordinate, in bounds QC (if object @@ -39,13 +39,13 @@ pcv.params.debug = "print" # Characterize object shapes -shape_image = pcv.analyze_object(img=img, obj=objects, mask=mask, label=None) +shape_image = pcv.analyze_object(img=img, obj=objects, mask=mask, label="default") # Save returned images with more specific naming pcv.print_image(shape_image, '/home/malia/setaria_shape_img.png') # Access data stored out from analyze_object -plant_solidity = pcv.outputs.observations['solidity']['value'] +plant_solidity = pcv.outputs.observations['default_solidity']['value'] ``` diff --git a/docs/analyze_spectral.md b/docs/analyze_spectral.md index 802dc411b..66dd63551 100644 --- a/docs/analyze_spectral.md +++ b/docs/analyze_spectral.md @@ -3,7 +3,7 @@ This function calculates the reflectance frequencies associated with a hyperspectral datacube and writes the values out as observations to get saved out. Can also print out a histogram of average reflectance intensity. -**plantcv.hyperspectral.analyze_spectral**(*array, mask, histplot=False, label=None*) +**plantcv.hyperspectral.analyze_spectral**(*array, mask, histplot=False, label="default"*) **returns** reflectance histogram (if `histplot=True`, otherwise returns None object) @@ -11,7 +11,7 @@ the values out as observations to get saved out. Can also print out a histogram - array - A hyperspectral datacube object, an instance of the `Spectral_data` class (read in with [pcv.readimage](read_image.md) with `mode='envi'`) - mask - Binary mask made from selected contours - histplot - If True plots histogram of reflectance intensity values (default histplot = False) - - label - Optional label parameter, modifies the variable name of observations recorded. (default `label=None`) + - label - Optional label parameter, modifies the variable name of observations recorded. (default `label="default"`) - **Example use:** - Below - **Output data stored:** Data ('max_reflectance', 'min_reflectance', 'median_reflectance', 'spectral_std', 'spectral_frequencies', 'global_mean_reflectance', 'global_median_reflectance', 'global_spectral_std') automatically gets stored to the @@ -28,10 +28,10 @@ from plantcv import plantcv as pcv pcv.params.debug = "print" # Calculates reflectance frequencies and writes the values as observations. Also provides a histogram of this data -spectral_hist = pcv.hyperspectral.analyze_spectral(array=spectral_data, mask=mask, histplot=True, label=None) +spectral_hist = pcv.hyperspectral.analyze_spectral(array=spectral_data, mask=mask, histplot=True, label="default") # Access data stored -reflectance_range = max(pcv.outputs.observations['max_reflectance']['value']) - min(pcv.outputs.observations['min_reflectance']['value']) +reflectance_range = max(pcv.outputs.observations['default_max_reflectance']['value']) - min(pcv.outputs.observations['default_min_reflectance']['value']) ``` diff --git a/docs/analyze_stem.md b/docs/analyze_stem.md index 7ec8b7321..d73c1f407 100644 --- a/docs/analyze_stem.md +++ b/docs/analyze_stem.md @@ -3,7 +3,7 @@ Primary, or stem, objects identified during workflows that examine the [morphology](morphology_tutorial.md) of plants or plant organs can have specific characteristics measured about the stem segments of a skeleton. -**plantcv.morphology.analyze_stem**(*rgb_img, stem_objects, label=None*) +**plantcv.morphology.analyze_stem**(*rgb_img, stem_objects, label="default"*) **returns** labeled_img @@ -32,9 +32,9 @@ from plantcv import plantcv as pcv pcv.params.debug = "print" -stem_debug_img1 = pcv.morphology.analyze_stem(rgb_img=img1, stem_objects=stem_objects1, label=None) +stem_debug_img1 = pcv.morphology.analyze_stem(rgb_img=img1, stem_objects=stem_objects1, label="default") # Access data stored out from analyze_object -stem_angle = pcv.outputs.observations['stem_angle']['value'] +stem_angle = pcv.outputs.observations['default_stem_angle']['value'] stem_debug_img2 = pcv.morphology.analyze_stem(rgb_img=img2, stem_objects=stem_objects2, label="rep1") stem_angle = pcv.outputs.observations['rep1_stem_angle']['value'] diff --git a/docs/analyze_thermal_values.md b/docs/analyze_thermal_values.md index c61d20fb7..7805c947b 100644 --- a/docs/analyze_thermal_values.md +++ b/docs/analyze_thermal_values.md @@ -3,7 +3,7 @@ This function calculates the intensity of each pixel associated with the temperature and writes the values out to a file. Can optionally create a histogram of pixel intensity. -**plantcv.analyze_thermal_values**(*thermal_array, mask, histplot=False, label=None*) +**plantcv.analyze_thermal_values**(*thermal_array, mask, histplot=False, label="default""default"*) **returns** thermal histogram (if `histplot=True`, otherwise returns None object) @@ -11,7 +11,7 @@ the values out to a file. Can optionally create a histogram of pixel intensity. - thermal_array - Numpy array of thermal image data (most likely read in with [pcv.readimage](read_image.md) with `mode='csv'`) - mask - Binary mask made from selected contours - histplot - If True plots histogram of intensity values (default histplot = False) - - label - Optional label parameter, modifies the variable name of observations recorded. (default `label=None`) + - label - Optional label parameter, modifies the variable name of observations recorded. (default `label="default"`) - **Context:** - Data about image temperature within a masked region. - **Example use:** @@ -34,10 +34,10 @@ from plantcv import plantcv as pcv pcv.params.debug = "print" # Caclulates the proportion of pixels that fall into a signal bin and writes the values to a file. Also provides a histogram of this data -thermal_hist = pcv.analyze_thermal_values(thermal_array=thermal_img, maks=mask, histplot=True, label=None) +thermal_hist = pcv.analyze_thermal_values(thermal_array=thermal_img, maks=mask, histplot=True, label="default") # Access data stored out from analyze_thermal_values -temp_range = pcv.outputs.observations['max_temp']['value'] - pcv.outputs.observations['min_temp']['value'] +temp_range = pcv.outputs.observations['default_max_temp']['value'] - pcv.outputs.observations['default_min_temp']['value'] ``` From 5df2b4677e627bc0b2cbdc850652b12304b262a9 Mon Sep 17 00:00:00 2001 From: HaleySchuhl Date: Mon, 8 Feb 2021 11:43:13 -0600 Subject: [PATCH 106/137] docs --- docs/check_cycles.md | 8 ++++---- docs/fill_segments.md | 8 ++++---- docs/find_branch_pts.md | 4 ++-- docs/find_color_card.md | 4 ++-- docs/find_tips.md | 4 ++-- docs/hyperspectral_tutorial.md | 8 ++++---- docs/landmark_reference_pt_dist.md | 8 ++++---- 7 files changed, 22 insertions(+), 22 deletions(-) diff --git a/docs/check_cycles.md b/docs/check_cycles.md index 94ee629ff..6cfee24a5 100644 --- a/docs/check_cycles.md +++ b/docs/check_cycles.md @@ -2,13 +2,13 @@ Check for cycles within a skeletonized image. -**plantcv.morphology.check_cycles**(*skel_img, label=None*) +**plantcv.morphology.check_cycles**(*skel_img, label="default"*) **returns** debugging cycle image - **Parameters:** - skel_img - Skeleton image (output from [plantcv.morphology.skeletonize](skeletonize.md)) - - label - Optional label parameter, modifies the variable name of observations recorded. (default `label=None`) + - label - Optional label parameter, modifies the variable name of observations recorded. (default `label="default"`) - **Context:** - Identifies cycles in a skeleton image. - **Output data stored:** Data ('num_cycles') automatically gets stored to the [`Outputs` class](outputs.md) when this function is ran. @@ -30,10 +30,10 @@ pcv.params.debug = "print" # The cycle_img created for debugging purposes allows for line thickness # adjustments with the global line thickness parameter. Try setting # pcv.params.line_thickness = 8 for thicker lines (default 5) -cycle_img = pcv.morphology.check_cycles(skel_img=skeleton, label=None) +cycle_img = pcv.morphology.check_cycles(skel_img=skeleton, label="default") # Access data stored out from check_cycles -num_cycles = pcv.outputs.observations['num_cycles']['value'] +num_cycles = pcv.outputs.observations['default_num_cycles']['value'] ``` diff --git a/docs/fill_segments.md b/docs/fill_segments.md index 91235a50d..b3f249560 100644 --- a/docs/fill_segments.md +++ b/docs/fill_segments.md @@ -2,7 +2,7 @@ Propagate the labels of a segmented skeleton to fill the mask. -**plantcv.morphology.fill_segments**(*mask, objects, stem_objects=None, label=None*) +**plantcv.morphology.fill_segments**(*mask, objects, stem_objects=None, label="default""default"*) **returns** filled_img @@ -12,7 +12,7 @@ Propagate the labels of a segmented skeleton to fill the mask. [plantcv.morphology.segment_skeleton](segment_skeleton.md), or [plantcv.morphology.segment_sort](segment_sort.md)). - stem_objects - Optional input for stem objects that will be combined into a single object before filling the mask. - - label - Optional label parameter, modifies the variable name of observations recorded. (default `label=None`) + - label - Optional label parameter, modifies the variable name of observations recorded. (default `label="default"`) - **Context:** - Uses the watershed algorithm to fill the mask propagating the objects' labels. - **Output data stored:** Data ('segment_area') automatically gets stored to the [`Outputs` class](outputs.md) when this function is ran. @@ -33,10 +33,10 @@ from plantcv import plantcv as pcv # or "plot" (Jupyter Notebooks or X11) pcv.params.debug = "print" -filled_img = pcv.morphology.fill_segments(mask=plant_mask, objects=obj, label=None) +filled_img = pcv.morphology.fill_segments(mask=plant_mask, objects=obj, label="default") # Access data stored out from fill_segments -segments_area = pcv.outputs.observations['segment_area']['value'] +segments_area = pcv.outputs.observations['default_segment_area']['value'] ``` diff --git a/docs/find_branch_pts.md b/docs/find_branch_pts.md index b17670567..bc758ab27 100644 --- a/docs/find_branch_pts.md +++ b/docs/find_branch_pts.md @@ -2,14 +2,14 @@ Find branch/junction points in a skeletonized image. -**plantcv.morphology.find_branch_pts**(*skel_img, mask=None, label=None*) +**plantcv.morphology.find_branch_pts**(*skel_img, mask=None, label="default"*) **returns** Binary mask of branch points - **Parameters:** - skel_img - Skeleton image (output from [plantcv.morphology.skeletonize](skeletonize.md)) - mask - Binary mask used for debugging image (optional). If provided the debug image will be overlaid on the mask. - - label - Optional label parameter, modifies the variable name of observations recorded. (default `label=None`) + - label - Optional label parameter, modifies the variable name of observations recorded. (default `label="default"`) - **Context:** - Identifies branch/junction points in a skeleton image diff --git a/docs/find_color_card.md b/docs/find_color_card.md index 9e47d2702..8fcbf29d6 100644 --- a/docs/find_color_card.md +++ b/docs/find_color_card.md @@ -2,7 +2,7 @@ Automatically detects a color card's location and size. Useful in workflows where color card positioning isn't constant in all images. -**plantcv.transform.find_color_card**(*rgb_img, threshold_type='adaptgauss', threshvalue=125, blurry=False, background='dark', record_chip_size='median', label=None*) +**plantcv.transform.find_color_card**(*rgb_img, threshold_type='adaptgauss', threshvalue=125, blurry=False, background='dark', record_chip_size='median', label="default"*) **returns** df, start_coord, spacing @@ -13,7 +13,7 @@ Automatically detects a color card's location and size. Useful in workflows wher - blurry - Optional boolean, if True then image sharpening is applied (default blurry=False) - background - Optional, type of image background, either 'dark' or 'light' (default background='dark') - record_chip_size - Optional, for choosing chip size measurement to be recorded, either "median" (default), "mean", or None - - label - Optional label parameter, modifies the variable name of observations recorded. (default `label=None`) + - label - Optional label parameter, modifies the variable name of observations recorded. (default `label="default"`) - **Returns** - df - Dataframe of all color card chips found. - start_coord - Two-element tuple of the first chip mask starting x and y coordinate. Useful in [create a color card mask](#create-a-labeled-color-card-mask) function. diff --git a/docs/find_tips.md b/docs/find_tips.md index 960f6107d..2f26013ea 100644 --- a/docs/find_tips.md +++ b/docs/find_tips.md @@ -2,14 +2,14 @@ Find endpoints of a skeletonized image. -**plantcv.morphology.find_tips**(*skel_img, mask=None, label=None*) +**plantcv.morphology.find_tips**(*skel_img, mask=None, label="default"*) **returns** Binary mask of endpoints - **Parameters:** - skel_img - Skeleton image (output from [plantcv.morphology.skeletonize](skeletonize.md)) - mask - Binary mask used for debugging (optional). If provided the debug image will be overlaid on the mask. - - label - Optional label parameter, modifies the variable name of observations recorded. (default `label=None`) + - label - Optional label parameter, modifies the variable name of observations recorded. (default `label="default"`) - **Context:** - Identifies endpoints/tips in a skeleton image diff --git a/docs/hyperspectral_tutorial.md b/docs/hyperspectral_tutorial.md index b3ff71aff..3989afc1d 100644 --- a/docs/hyperspectral_tutorial.md +++ b/docs/hyperspectral_tutorial.md @@ -226,9 +226,9 @@ Binary mask after [filtering objects by the region of interest](roi_objects.md) # array - Hyperspectral data instance # mask - Binary mask image data # hist_plot - If True plots histogram of reflectance intensity values - # label - Optional label parameter, modifies the variable name of observations recorded. (default `label=None`) + # label - Optional label parameter, modifies the variable name of observations recorded. (default `label="default"`) - analysis_img = pcv.hyperspectral.analyze_spectral(array=spectral_array, mask=kept_mask, histplot=True, label=None) + analysis_img = pcv.hyperspectral.analyze_spectral(array=spectral_array, mask=kept_mask, histplot=True, label="default") ``` @@ -243,9 +243,9 @@ Binary mask after [filtering objects by the region of interest](roi_objects.md) # Inputs: # array - Hyperspectral index data instance # mask - Binary mask image data - # label - Optional label parameter, modifies the variable name of observations recorded. (default `label=None`) + # label - Optional label parameter, modifies the variable name of observations recorded. (default `label="default"`) - pcv.hyperspectral.analyze_index(array=index_array_gdvi, mask=kept_mask, label=None) + pcv.hyperspectral.analyze_index(array=index_array_gdvi, mask=kept_mask, label="default") ``` diff --git a/docs/landmark_reference_pt_dist.md b/docs/landmark_reference_pt_dist.md index 33fa2cfc6..c6f0fabf2 100644 --- a/docs/landmark_reference_pt_dist.md +++ b/docs/landmark_reference_pt_dist.md @@ -4,7 +4,7 @@ This is a function to measure the distance from user defined points to the centr along the x-axis and baseline coordinate (top of pot) along the y-axis. Calculating the vertical distance between leaf tip points to the centroid of the plant object in side-view images may provide a proxy measure of turgor pressure. -**plantcv.landmark_reference_pt_dist**(*points_r, centroid_r, bline_r, label=None*) +**plantcv.landmark_reference_pt_dist**(*points_r, centroid_r, bline_r, label="default"*) **returns** none @@ -12,7 +12,7 @@ to the centroid of the plant object in side-view images may provide a proxy meas - points_r - A list of tuples representing rescaled landmark points - centroid_r - A tuple representing the rescaled centroid point - bline_r - A tuple representing the rescaled baseline point - - label - Optional label parameter, modifies the variable name of observations recorded. (default `label=None`) + - label - Optional label parameter, modifies the variable name of observations recorded. (default `label="default"`) - **Context:** - Used to estimate the distance and angles of landmark points relative to shape reference landmarks (centroid and pot height aka baseline) - **Output data stored:** Data ('vert_ave_c', 'hori_ave_c', 'euc_ave_c', 'ang_ave_c', 'vert_ave_b', 'hori_ave_b', 'euc_ave_b', @@ -32,10 +32,10 @@ pcv.params.debug = "print" # Identify acute vertices (tip points) of an object # Results in set of point values that may indicate tip points -pcv.landmark_reference_pt_dist(points_r=points_r, centroid_r=centroid_r, bline_r=bline_r, label=None) +pcv.landmark_reference_pt_dist(points_r=points_r, centroid_r=centroid_r, bline_r=bline_r, label="default") # Access data stored out from landmark_reference_pt_dist -avg_vert_distance = pcv.outputs.observations['vert_ave_c']['value'] +avg_vert_distance = pcv.outputs.observations['default_vert_ave_c']['value'] ``` From b2049f9ce055ace4ec9bd79fbde3e18b6f7946f9 Mon Sep 17 00:00:00 2001 From: HaleySchuhl Date: Mon, 8 Feb 2021 11:47:46 -0600 Subject: [PATCH 107/137] Update morphology_tutorial.md --- docs/morphology_tutorial.md | 50 ++++++++++++++++++------------------- 1 file changed, 25 insertions(+), 25 deletions(-) diff --git a/docs/morphology_tutorial.md b/docs/morphology_tutorial.md index 85928f84d..fb0b41eff 100644 --- a/docs/morphology_tutorial.md +++ b/docs/morphology_tutorial.md @@ -171,8 +171,8 @@ off. The function prunes only secondary segments; primary segments that are smal # Inputs: # skel_img = Skeletonized image # mask = (Optional) binary mask for debugging. If provided, debug image will be overlaid on the mask. - # label = (Optional) label parameter, modifies the variable name of observations recorded. (default `label=None`) - branch_pts_mask = pcv.morphology.find_branch_pts(skel_img=skeleton, mask=cropped_mask, label=None) + # label = (Optional) label parameter, modifies the variable name of observations recorded. (default `label="default"`) + branch_pts_mask = pcv.morphology.find_branch_pts(skel_img=skeleton, mask=cropped_mask, label="default") ``` @@ -193,9 +193,9 @@ to remove all barbs. # Inputs: # skel_img = Skeletonized image # mask = (Optional) binary mask for debugging. If provided, debug image will be overlaid on the mask. - # label = (Optional) label parameter, modifies the variable name of observations recorded. (default `label=None`) + # label = (Optional) label parameter, modifies the variable name of observations recorded. (default `label="default"`) - tip_pts_mask = pcv.morphology.find_tips(skel_img=skeleton, mask=None, label=None) + tip_pts_mask = pcv.morphology.find_tips(skel_img=skeleton, mask=None, label="default") ``` @@ -263,10 +263,10 @@ For this tutorial we assume leaves are the objects of interest, and just pass th # Inputs: # segmented_img = Segmented image to plot lengths on # objects = List of contours - # label = (Optional) label parameter, modifies the variable name of observations recorded. (default `label=None`) + # label = (Optional) label parameter, modifies the variable name of observations recorded. (default `label="default"`) labeled_img = pcv.morphology.segment_path_length(segmented_img=segmented_img, - objects=leaf_obj, label=None) + objects=leaf_obj, label="default") ``` @@ -284,10 +284,10 @@ passed into the function. # Inputs: # segmented_img = Segmented image to plot lengths on # objects = List of contours - # label = (Optional) label parameter, modifies the variable name of observations recorded. (default `label=None`) + # label = (Optional) label parameter, modifies the variable name of observations recorded. (default `label="default"`) labeled_img = pcv.morphology.segment_euclidean_length(segmented_img=segmented_img, - objects=leaf_obj, label=None) + objects=leaf_obj, label="default") ``` @@ -305,10 +305,10 @@ euclidean distance of each segment passed to the function. # Inputs: # segmented_img = Segmented image to plot curvature on # objects = List of contours - # label = (Optional) label parameter, modifies the variable name of observations recorded. (default `label=None`) + # label = (Optional) label parameter, modifies the variable name of observations recorded. (default `label="default"`) labeled_img = pcv.morphology.segment_curvature(segmented_img=segmented_img, - objects=leaf_obj, label=None) + objects=leaf_obj, label="default") ``` @@ -328,10 +328,10 @@ is a straight line while larger values indicate the segment has more curvature. # Inputs: # segmented_img = Segmented image to plot angles on # objects = List of contours - # label = (Optional) label parameter, modifies the variable name of observations recorded. (default `label=None`) + # label = (Optional) label parameter, modifies the variable name of observations recorded. (default `label="default"`) labeled_img = pcv.morphology.segment_angle(segmented_img=segmented_img, - objects=leaf_obj, label=None) + objects=leaf_obj, label="default") ``` @@ -350,10 +350,10 @@ by fitting a linear regression line to each segment. # segmented_img = Segmented image to plot tangent angles on # objects = List of contours # size = Size of ends used to calculate "tangent" lines - # label = (Optional) label parameter, modifies the variable name of observations recorded. (default `label=None`) + # label = (Optional) label parameter, modifies the variable name of observations recorded. (default `label="default"`) labeled_img = pcv.morphology.segment_tangent_angle(segmented_img=segmented_img, - objects=leaf_obj, size=15, label=None) + objects=leaf_obj, size=15, label="default") ``` @@ -376,13 +376,13 @@ leaves that are more "floppy" will have smaller angles. # leaf_objects = List of leaf contours # stem_objects = List of stem objects # size = Size of the inner portion of each leaf to find a linear regression line - # label = (Optional) label parameter, modifies the variable name of observations recorded. (default `label=None`) + # label = (Optional) label parameter, modifies the variable name of observations recorded. (default `label="default"`) labeled_img = pcv.morphology.segment_insertion_angle(skel_img=skeleton, segmented_img=segmented_img, leaf_objects=leaf_obj, stem_objects=stem_obj, - size=20, label=None) + size=20, label="default") ``` @@ -402,7 +402,7 @@ out from a stem will have larger insertion angles than those that grow upward. # Inputs: # mask = Binary image, single channel, object = 1 and background = 0 # objects = List of contours - # label = (Optional) label parameter, modifies the variable name of observations recorded. (default `label=None`) + # label = (Optional) label parameter, modifies the variable name of observations recorded. (default `label="default"`) filled_img = pcv.morphology.fill_segments(mask=cropped_mask, objects=edge_objects, label="all_segments") @@ -504,10 +504,10 @@ def main(): pruned, seg_img, edge_objects = pcv.morphology.prune(skel_img=skeleton, size=0, mask=cropped_mask) # Identify branch points - branch_pts_mask = pcv.morphology.find_branch_pts(skel_img=skeleton, mask=cropped_mask, label=None) + branch_pts_mask = pcv.morphology.find_branch_pts(skel_img=skeleton, mask=cropped_mask, label="default") # Identify tip points - tip_pts_mask = pcv.morphology.find_tips(skel_img=skeleton, mask=None, label=None) + tip_pts_mask = pcv.morphology.find_tips(skel_img=skeleton, mask=None, label="default") # Sort segments into leaf objects and stem objects leaf_obj, stem_obj = pcv.morphology.segment_sort(skel_img=skeleton, objects=edge_objects, @@ -519,29 +519,29 @@ def main(): # Measure path lengths of segments labeled_img2 = pcv.morphology.segment_path_length(segmented_img=segmented_img, - objects=leaf_obj, label=None) + objects=leaf_obj, label="default") # Measure euclidean distance of segments labeled_img3 = pcv.morphology.segment_euclidean_length(segmented_img=segmented_img, - objects=leaf_obj, label=None) + objects=leaf_obj, label="default") # Measure curvature of segments labeled_img4 = pcv.morphology.segment_curvature(segmented_img=segmented_img, - objects=leaf_obj, label=None) + objects=leaf_obj, label="default") # Measure the angle of segments - labeled_img5 = pcv.morphology.segment_angle(segmented_img=segmented_img, objects=leaf_obj, label=None) + labeled_img5 = pcv.morphology.segment_angle(segmented_img=segmented_img, objects=leaf_obj, label="default") # Measure the tangent angles of segments labeled_img6 = pcv.morphology.segment_tangent_angle(segmented_img=segmented_img, - objects=leaf_obj, size=15, label=None) + objects=leaf_obj, size=15, label="default") # Measure the leaf insertion angles labeled_img7 = pcv.morphology.segment_insertion_angle(skel_img=skeleton, segmented_img=segmented_img, leaf_objects=leaf_obj, stem_objects=stem_obj, - size=20, label=None) + size=20, label="default") # Fill in segments (also stores out area data) filled_img = pcv.morphology.fill_segments(mask=cropped_mask, objects=edge_objects, label="all_segments") From 3542dc4f673506e2fe48f0ade8e5f9accbbb4fdd Mon Sep 17 00:00:00 2001 From: HaleySchuhl Date: Mon, 8 Feb 2021 11:49:23 -0600 Subject: [PATCH 108/137] Update nir_tutorial.md --- docs/nir_tutorial.md | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/docs/nir_tutorial.md b/docs/nir_tutorial.md index ec2ee01f0..13e88d217 100644 --- a/docs/nir_tutorial.md +++ b/docs/nir_tutorial.md @@ -456,9 +456,9 @@ Now we can perform the [analysis of pixelwise signal value](analyze_NIR_intensit # mask - Binary mask made from selected contours # bins - Number of classes to divide the spectrum into # histplot - If True, plots the histogram of intensity values - # label - Optional label parameter, modifies the variable name of observations recorded. (default `label=None`) + # label - Optional label parameter, modifies the variable name of observations recorded. (default `label="default"`) nir_hist = pcv.analyze_nir_intensity(gray_img=img, mask=kept_mask, - bins=256, histplot=True, label=None) + bins=256, histplot=True, label="default") # Pseudocolor the grayscale image to a colormap @@ -481,8 +481,8 @@ Now we can perform the [analysis of pixelwise signal value](analyze_NIR_intensit # img - RGB or grayscale image data # obj- Single or grouped contour object # mask - Binary image mask to use as mask for moments analysis - # label - Optional label parameter, modifies the variable name of observations recorded. (default `label=None`) - shape_imgs = pcv.analyze_object(img=img, obj=o, mask=m, label=None) + # label - Optional label parameter, modifies the variable name of observations recorded. (default `label="default"`) + shape_imgs = pcv.analyze_object(img=img, obj=o, mask=m, label="default") # Write shape and nir data to results file pcv.print_results(filename=args.result) @@ -636,13 +636,13 @@ def main(): outfile = os.path.join(args.outdir, img_name) # Perform signal analysis - nir_hist = pcv.analyze_nir_intensity(gray_img=img, mask=kept_mask, bins=256, histplot=True, label=None) + nir_hist = pcv.analyze_nir_intensity(gray_img=img, mask=kept_mask, bins=256, histplot=True, label="default") # Pseudocolor the grayscale image to a colormap pseudocolored_img = pcv.visualize.pseudocolor(gray_img=img, mask=kept_mask, cmap='viridis') # Perform shape analysis - shape_imgs = pcv.analyze_object(img=img, obj=o, mask=m, label=None) + shape_imgs = pcv.analyze_object(img=img, obj=o, mask=m, label="default") # Write shape and nir data to results file pcv.print_results(filename=args.result) From b671ef152905f63abaf83ee4abf15ddacd6a2c29 Mon Sep 17 00:00:00 2001 From: HaleySchuhl Date: Mon, 8 Feb 2021 12:17:10 -0600 Subject: [PATCH 109/137] Update outputs.md --- docs/outputs.md | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/docs/outputs.md b/docs/outputs.md index 8c534590d..c11761dd4 100644 --- a/docs/outputs.md +++ b/docs/outputs.md @@ -28,7 +28,7 @@ functions: * `watershed` An instance of `Outputs` is created on import automatically as `plantcv.outputs`. The function -[pcv.print_results](print_results.md) will print out all the stored measurments data to a text file. +[pcv.print_results](print_results.md) will print out all the stored measurment data to a text file. ### Methods @@ -63,10 +63,10 @@ from plantcv import plantcv as pcv ######## workflow steps here ######## # Find shape properties, output shape image (optional) -shape_img = pcv.analyze_object(img, obj, mask) +shape_img = pcv.analyze_object(img, obj, mask, label="default") # Look at object area data without writing to a file -plant_area = pcv.outputs.observations['pixel_area']['value'] +plant_area = pcv.outputs.observations['default_pixel_area']['value'] # Write shape data to results file pcv.print_results(filename=args.result) @@ -76,8 +76,8 @@ pcv.outputs.clear() ######## More workflow steps here ######## -nir_imgs = pcv.analyze_nir_intensity(nir2, nir_combinedmask, 256) -shape_img = pcv.analyze_object(nir2, nir_combined, nir_combinedmask) +nir_imgs = pcv.analyze_nir_intensity(nir2, nir_combinedmask, 256, label="default") +shape_img = pcv.analyze_object(nir2, nir_combined, nir_combinedmask, label="default") # Write the NIR and shape data to a file pcv.print_results(filename=args.coresult) From c40ea4f4ed777bea7f4a90f6c6ff9f93749c3b1d Mon Sep 17 00:00:00 2001 From: HaleySchuhl Date: Mon, 8 Feb 2021 12:17:50 -0600 Subject: [PATCH 110/137] Update photosynthesis_analyze_fvfm.md --- docs/photosynthesis_analyze_fvfm.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/docs/photosynthesis_analyze_fvfm.md b/docs/photosynthesis_analyze_fvfm.md index a3b7966a6..d61e8409c 100644 --- a/docs/photosynthesis_analyze_fvfm.md +++ b/docs/photosynthesis_analyze_fvfm.md @@ -2,7 +2,7 @@ Extract Fv/Fm data of objects. -**plantcv.photosynthesis.analyze_fvfm**(*fdark, fmin, fmax, mask, bins=256, label=None*) +**plantcv.photosynthesis.analyze_fvfm**(*fdark, fmin, fmax, mask, bins=256, label="default"*) **returns** PSII analysis images (Fv/Fm image, Fv/Fm histogram) @@ -12,7 +12,7 @@ Extract Fv/Fm data of objects. - fmax - image object, grayscale - mask - binary mask of selected contours - bins - number of grayscale bins (0-256 for 8-bit images and 0 to 65,536), if you would like to bin data, you would alter this number (default bins=256) - - label - Optional label parameter, modifies the variable name of observations recorded. (default `label=None`) + - label - Optional label parameter, modifies the variable name of observations recorded. (default `label="default"`) - **Context:** - Used to extract Fv/Fm or Fv'/Fm' per identified plant pixel. - Generates histogram of Fv/Fm data. From 2eda1f0e8ce5902dde2f910ff5482b9cfcca676b Mon Sep 17 00:00:00 2001 From: HaleySchuhl Date: Mon, 8 Feb 2021 12:21:47 -0600 Subject: [PATCH 111/137] Update psII_tutorial.md --- docs/psII_tutorial.md | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/docs/psII_tutorial.md b/docs/psII_tutorial.md index b6c0d069b..d03498855 100644 --- a/docs/psII_tutorial.md +++ b/docs/psII_tutorial.md @@ -197,8 +197,8 @@ The next step is to analyze the plant object for traits such as [shape](analyze_ # img - RGB or grayscale image data # obj - Single or grouped contour object # mask - Binary image mask to use as mask for moments analysis - # label - Optional label parameter, modifies the variable name of observations recorded. (default `label=None`) - shape_img = pcv.analyze_object(img=fmax, obj=obj, mask=cleaned_mask, label=None) + # label - Optional label parameter, modifies the variable name of observations recorded. (default `label="default"`) + shape_img = pcv.analyze_object(img=fmax, obj=obj, mask=cleaned_mask, label="default") # Analyze fv/fm fluorescence properties @@ -208,8 +208,8 @@ The next step is to analyze the plant object for traits such as [shape](analyze_ # fmax - Grayscale image # mask - Binary mask of selected contours # bins - Number of grayscale bins (0-256 for 8-bit img, 0-65536 for 16-bit). Default bins = 256 - # label - Optional label parameter, modifies the variable name of observations recorded. (default `label=None`) - fvfm_images = pcv.photosynthesis.analyze_fvfm(fdark=fdark, fmin=fmin, fmax=fmax, mask=cleaned_mask, bins=256, label=None) + # label - Optional label parameter, modifies the variable name of observations recorded. (default `label="default"`) + fvfm_images = pcv.photosynthesis.analyze_fvfm(fdark=fdark, fmin=fmin, fmax=fmax, mask=cleaned_mask, bins=256, label="default") # Store the two fv_fm images fvfm_img = fvfm_images[0] @@ -307,10 +307,10 @@ def main(): obj, masked = pcv.object_composition(img=cleaned_mask, contours=id_objects, hierarchy=obj_hierarchy) # Find shape properties - shape_img = pcv.analyze_object(img=fmax, obj=obj, mask=cleaned_mask, label=None) + shape_img = pcv.analyze_object(img=fmax, obj=obj, mask=cleaned_mask, label="default") # Analyze fv/fm fluorescence properties - fvfm_images = pcv.pcv.photosynthesis.analyze_fvfm(fdark=fdark, fmin=fmin, fmax=fmax, mask=cleaned_mask, bins=256, label=None) + fvfm_images = pcv.pcv.photosynthesis.analyze_fvfm(fdark=fdark, fmin=fmin, fmax=fmax, mask=cleaned_mask, bins=256, label="default") # Store the two fv_fm images fvfm_img = fvfm_images[0] From b0c41b26b54bd462307c87118d178d4f10ea421e Mon Sep 17 00:00:00 2001 From: HaleySchuhl Date: Mon, 8 Feb 2021 12:21:51 -0600 Subject: [PATCH 112/137] Update report_size_marker.md --- docs/report_size_marker.md | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/docs/report_size_marker.md b/docs/report_size_marker.md index f1091a480..82bfebca1 100644 --- a/docs/report_size_marker.md +++ b/docs/report_size_marker.md @@ -3,7 +3,7 @@ Get and record the size of a size marker or set an area as a size marker. **plantcv.report_size_marker_area**(*img, roi_contour, roi_hierarchy, marker='define', objcolor='dark', thresh_channel=None, - thresh=None, label=None*) + thresh=None, label="default"*) **returns** analysis_image @@ -42,10 +42,10 @@ roi_contour, roi_hierarchy = pcv.roi.rectangle(img=img1, x=3550, y=850, h=500, w # Detect and Measure Size Marker image = pcv.report_size_marker_area(img=img1, roi_contour=roi_contour, roi_hierarchy=roi_hierarchy, - marker='detect', objcolor='light', thresh_channel='s', thresh=120, label=None) + marker='detect', objcolor='light', thresh_channel='s', thresh=120, label="default") # Access data stored out from report_size_marker_area -marker_area = pcv.outputs.observations['marker_area']['value'] +marker_area = pcv.outputs.observations['default_marker_area']['value'] ``` From 47e4a7710d8ee81bcea358fa5357b1c9db27078a Mon Sep 17 00:00:00 2001 From: HaleySchuhl Date: Mon, 8 Feb 2021 12:26:28 -0600 Subject: [PATCH 113/137] morph doc pages --- docs/segment_angle.md | 8 ++++---- docs/segment_curvature.md | 4 ++-- docs/segment_euclidean_length.md | 4 ++-- docs/segment_insertion_angle.md | 8 ++++---- docs/segment_pathlength.md | 8 ++++---- docs/segment_tangent_angle.md | 8 ++++---- 6 files changed, 20 insertions(+), 20 deletions(-) diff --git a/docs/segment_angle.md b/docs/segment_angle.md index 92683104c..f1398d1d9 100644 --- a/docs/segment_angle.md +++ b/docs/segment_angle.md @@ -2,7 +2,7 @@ Measure angles of segments. -**plantcv.morphology.segment_angle**(*segmented_img, objects, label=None*) +**plantcv.morphology.segment_angle**(*segmented_img, objects, label="default"*) **returns** labeled image @@ -11,7 +11,7 @@ Measure angles of segments. or [plantcv.morphology.segment_id](segment_id.md)), used for creating the labeled image. - objects - Segment objects (output from either [plantcv.morphology.segment_skeleton](segment_skeleton.md), or [plantcv.morphology.segment_sort](segment_sort.md)). - - label - Optional label parameter, modifies the variable name of observations recorded. (default `label=None`) + - label - Optional label parameter, modifies the variable name of observations recorded. (default `label="default"`) - **Context:** - Calculates angles of segments (in degrees) by fitting a linear regression line to each segment. Users can pass only leaf objects (returned from [plantcv.morphology.segment_sort](segment_sort.md)) to only collect angles of leaves. @@ -31,10 +31,10 @@ from plantcv import plantcv as pcv # or "plot" (Jupyter Notebooks or X11) pcv.params.debug = "print" -labeled_img = pcv.morphology.segment_angle(segmented_img=segmented_img, objects=obj, label=None) +labeled_img = pcv.morphology.segment_angle(segmented_img=segmented_img, objects=obj, label="default") # Access data stored out from segment_angle -segment_angles = pcv.outputs.observations['segment_angle']['value'] +segment_angles = pcv.outputs.observations['default_segment_angle']['value'] ``` diff --git a/docs/segment_curvature.md b/docs/segment_curvature.md index a0d4b0b58..0261119a8 100644 --- a/docs/segment_curvature.md +++ b/docs/segment_curvature.md @@ -2,7 +2,7 @@ Measure the curvature of segments. -**plantcv.morphology.segment_curvature**(*segmented_img, objects, label=None*) +**plantcv.morphology.segment_curvature**(*segmented_img, objects, label="default"*) **returns** labeled image @@ -12,7 +12,7 @@ Measure the curvature of segments. - objects - Segment objects (output from either [plantcv.morphology.prune](prune.md), [plantcv.morphology.segment_skeleton](segment_skeleton.md), or [plantcv.morphology.segment_sort](segment_sort.md)). - - label - Optional label parameter, modifies the variable name of observations recorded. (default `label=None`) + - label - Optional label parameter, modifies the variable name of observations recorded. (default `label="default"`) - **Context:** - Calculates curvature of segments by taking the ratio of the geodesic distance ([plantcv.morphology.segment_path_length](segment_pathlength.md)) over the euclidean distance [plantcv.morphology.segment_euclidean_length](segment_euclidean_length.md)). Measurement of two-dimensional tortuosity. diff --git a/docs/segment_euclidean_length.md b/docs/segment_euclidean_length.md index 4a5d9c969..8df4e187f 100644 --- a/docs/segment_euclidean_length.md +++ b/docs/segment_euclidean_length.md @@ -2,7 +2,7 @@ Measure Euclidean distance of segments. -**plantcv.morphology.segment_euclidean_length**(*segmented_img, objects, label=None*) +**plantcv.morphology.segment_euclidean_length**(*segmented_img, objects, label="default"*) **returns** labeled image @@ -12,7 +12,7 @@ Measure Euclidean distance of segments. - objects - Segment objects (output from either [plantcv.morphology.prune](prune.md), [plantcv.morphology.segment_skeleton](segment_skeleton.md), or [plantcv.morphology.segment_sort](segment_sort.md)). - - label - Optional label parameter, modifies the variable name of observations recorded. (default `label=None`) + - label - Optional label parameter, modifies the variable name of observations recorded. (default `label="default"`) - **Context:** - Calculates the euclidean distance of each segment. Users can pass only leaf objects (returned from [plantcv.morphology.segment_sort](segment_sort.md)) to only collect lengths of leaves. diff --git a/docs/segment_insertion_angle.md b/docs/segment_insertion_angle.md index 9fa73fc22..0f9526e16 100644 --- a/docs/segment_insertion_angle.md +++ b/docs/segment_insertion_angle.md @@ -2,7 +2,7 @@ Measure leaf insertion angles. -**plantcv.morphology.segment_insertion_angle**(*skel_img, segmented_img, leaf_objects, stem_objects, size, label=None*) +**plantcv.morphology.segment_insertion_angle**(*skel_img, segmented_img, leaf_objects, stem_objects, size, label="default"*) **returns** labeled image @@ -14,7 +14,7 @@ Measure leaf insertion angles. - leaf_objects - Leaf segment objects (output from [plantcv.morphology.segment_sort](segment_sort.md)). - stem_objects - Stem segment objects (output from [plantcv.morphology.segment_sort](segment_sort.md)). - size - Size of ends (number of pixels) used to calculate insertion point "tangent" lines - - label - Optional label parameter, modifies the variable name of observations recorded. (default `label=None`) + - label - Optional label parameter, modifies the variable name of observations recorded. (default `label="default"`) - **Context:** - Find "tangent" angles to leaf insertion points in degrees of skeleton segments compared to the stem angle. Use `size` pixels of the inner portion of each leaf to find a linear regression line, and calculate angle between insertion @@ -42,10 +42,10 @@ labeled_img = pcv.morphology.segment_insertion_angle(skel_img=skeleton, segmented_img=leaves_segment, leaf_objects=leaf_obj, stem_objects=stem_objs, - size=20, label=None) + size=20, label="default") # Access data stored out from segment_insertion_angle -segment_insertion_angles = pcv.outputs.observations['segment_insertion_angle']['value'] +segment_insertion_angles = pcv.outputs.observations['default_segment_insertion_angle']['value'] ``` diff --git a/docs/segment_pathlength.md b/docs/segment_pathlength.md index 38cd1e980..b6b432b64 100644 --- a/docs/segment_pathlength.md +++ b/docs/segment_pathlength.md @@ -2,7 +2,7 @@ Measure the geodesic distance of segments. -**plantcv.morphology.segment_path_length**(*segmented_img, objects, label=None*) +**plantcv.morphology.segment_path_length**(*segmented_img, objects, label="default"*) **returns** labeled_image @@ -12,7 +12,7 @@ Measure the geodesic distance of segments. - objects - Segment objects (output from either [plantcv.morphology.prune](prune.md), [plantcv.morphology.segment_skeleton](segment_skeleton.md), or [plantcv.morphology.segment_sort](segment_sort.md)). - - label - Optional label parameter, modifies the variable name of observations recorded. (default `label=None`) + - label - Optional label parameter, modifies the variable name of observations recorded. (default `label="default"`) - **Context:** - Calculates the geodesic distance of each segment. Users can pass only leaf objects (returned from [plantcv.morphology.segment_sort](segment_sort.md)) to only collect lengths of leaves only. @@ -33,10 +33,10 @@ from plantcv import plantcv as pcv pcv.params.debug = "print" labeled_img = pcv.morphology.segment_path_length(segmented_img=segmented_img, - objects=obj, label=None) + objects=obj, label="default") # Access data stored out from segment_path_length -path_lengths = pcv.outputs.observations['segment_path_length']['value'] +path_lengths = pcv.outputs.observations['default_segment_path_length']['value'] ``` diff --git a/docs/segment_tangent_angle.md b/docs/segment_tangent_angle.md index e77921a37..84fddb33a 100644 --- a/docs/segment_tangent_angle.md +++ b/docs/segment_tangent_angle.md @@ -2,7 +2,7 @@ Measure tangent angles of segments as a way to quantify leaf behavior. -**plantcv.morphology.segment_tangent_angle**(*segmented_img, objects, size, label=None*) +**plantcv.morphology.segment_tangent_angle**(*segmented_img, objects, size, label="default"*) **returns** labeled image @@ -13,7 +13,7 @@ Measure tangent angles of segments as a way to quantify leaf behavior. [plantcv.morphology.segment_skeleton](segment_skeleton.md), or [plantcv.morphology.segment_sort](segment_sort.md)). - size - Size of ends (number of pixels) used to calculate "tangent" lines - - label - Optional label parameter, modifies the variable name of observations recorded. (default `label=None`) + - label - Optional label parameter, modifies the variable name of observations recorded. (default `label="default"`) - **Context:** - Find 'tangent' angles in degrees of skeleton segments. Use `size` pixels on either end of each segment to find a linear regression line, and calculate angle between the two lines @@ -40,10 +40,10 @@ pcv.params.line_thickness = 3 labeled_img = pcv.morphology.segment_tangent_angle(segmented_img=leaves_segment, objects=leaf_obj, - size=15, label=None) + size=15, label="default") # Access data stored out from segment_tangent_angle -leaf_tangent_angles = pcv.outputs.observations['segment_tangent_angle']['value'] +leaf_tangent_angles = pcv.outputs.observations['default_segment_tangent_angle']['value'] ``` From 49a33d2b30b314b1524552ad1270315cc608308e Mon Sep 17 00:00:00 2001 From: HaleySchuhl Date: Mon, 8 Feb 2021 12:28:00 -0600 Subject: [PATCH 114/137] Update thermal_tutorial.md --- docs/thermal_tutorial.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/docs/thermal_tutorial.md b/docs/thermal_tutorial.md index d77fb0684..f1dc10760 100644 --- a/docs/thermal_tutorial.md +++ b/docs/thermal_tutorial.md @@ -218,7 +218,7 @@ Now that the plant has been separated from the background we can analyze the tem # mask - Binary mask made from selected contours # histplot - If True plots histogram of intensity values (default histplot = False) # label - Optional label parameter, modifies the variable name of observations recorded - analysis_img = pcv.analyze_thermal_values(thermal_array=thermal_data, mask=kept_mask, histplot=True, label=None) + analysis_img = pcv.analyze_thermal_values(thermal_array=thermal_data, mask=kept_mask, histplot=True, label="default") ``` @@ -374,7 +374,7 @@ def main(): # mask - Binary mask made from selected contours # histplot - If True plots histogram of intensity values (default histplot = False) # label - Optional label parameter, modifies the variable name of observations recorded - analysis_img = pcv.analyze_thermal_values(thermal_array=thermal_data, mask=kept_mask, histplot=True), label=None + analysis_img = pcv.analyze_thermal_values(thermal_array=thermal_data, mask=kept_mask, histplot=True, label="default") # Pseudocolor the thermal data From 0eee0be157bb83497c46bd4d43fd5b11c885c4f0 Mon Sep 17 00:00:00 2001 From: HaleySchuhl Date: Mon, 8 Feb 2021 12:36:06 -0600 Subject: [PATCH 115/137] Update updating.md --- docs/updating.md | 54 ++++++++++++++++++++++++------------------------ 1 file changed, 27 insertions(+), 27 deletions(-) diff --git a/docs/updating.md b/docs/updating.md index e116aeb7f..de15d1a77 100644 --- a/docs/updating.md +++ b/docs/updating.md @@ -144,7 +144,7 @@ pages for more details on the input and output variable types. * pre v3.0dev2: device, acute = **plantcv.acute_vertex**(*obj, win, thresh, sep, img, device, debug=None*) * post v3.0dev2: acute = **plantcv.acute_vertex**(*obj, win, thresh, sep, img*) * post v3.2: acute, analysis_image = **plantcv.acute_vertex**(*img, obj, win, thresh, sep*) -* post v3.11: acute, analysis_image = **plantcv.acute_vertex**(**img, obj, win, thresh, sep, label=None*) +* post v3.11: acute, analysis_image = **plantcv.acute_vertex**(**img, obj, win, thresh, sep, label="default"*) #### plantcv.adaptive_threshold @@ -157,7 +157,7 @@ pages for more details on the input and output variable types. * pre v3.0dev2: device, bound_header, bound_data, analysis_images = **plantcv.analyze_bound**(*img, imgname, obj, mask, line_position, device, debug=None, filename=False*) * post v3.0dev2: Deprecated, see: - * analysis_images = **plantcv.analyze_bound_horizontal**(*img, obj, mask, line_position, filename=False*) + * analysis_images = **plantcv.analyze_bound_horizontal**(*img, obj, mask, line_position, filename=False, label="default"*) #### plantcv.analyze_bound_horizontal @@ -165,7 +165,7 @@ pages for more details on the input and output variable types. * post v3.0dev2: bound_header, bound_data, analysis_images = **plantcv.analyze_bound_horizontal**(*img, obj, mask, line_position, filename=False*) * post v3.0: bound_header, bound_data, analysis_images = **plantcv.analyze_bound_horizontal**(*img, obj, mask, line_position*) * post v3.3: analysis_image = **plantcv.analyze_bound_horizontal**(*img, obj, mask, line_position*) -* post v3.11: analysis_image = **plantcv.analyze_bound_horizontal**(*img, obj, mask, line_position, label=None*) +* post v3.11: analysis_image = **plantcv.analyze_bound_horizontal**(*img, obj, mask, line_position, label="default"*) #### plantcv.analyze_bound_vertical @@ -174,7 +174,7 @@ pages for more details on the input and output variable types. * post v3.0dev2: bound_header, bound_data, analysis_images = **plantcv.analyze_bound_vertical**(*img, obj, mask, line_position, filename=False*) * post v3.0.5: bound_header, bound_data, analysis_images = **plantcv.analyze_bound_vertical**(*img, obj, mask, line_position*) * post v3.3: analysis_image = **plantcv.analyze_bound_vertical**(*img, obj, mask, line_position*) -* post v3.11: analysis_image = **plantcv.analyze_bound_vertical**(*img, obj, mask, line_position, label=None*) +* post v3.11: analysis_image = **plantcv.analyze_bound_vertical**(*img, obj, mask, line_position, label="default"*) #### plantcv.analyze_color @@ -183,7 +183,7 @@ pages for more details on the input and output variable types. * post v3.0dev2: hist_header, hist_data, analysis_images = **plantcv.analyze_color**(*rgb_img, mask, bins, hist_plot_type=None, pseudo_channel='v', pseudo_bkg='img', filename=False*) * post v3.0: hist_header, hist_data, analysis_images = **plantcv.analyze_color**(*rgb_img, mask, bins, hist_plot_type=None*) * post v3.3: analysis_image = **plantcv.analyze_color**(*rgb_img, mask, hist_plot_type=None*) -* post v3.11: analysis_image = **plantcv.analyze_color**(*rgb_img, mask, hist_plot_type=None, label=None*) +* post v3.11: analysis_image = **plantcv.analyze_color**(*rgb_img, mask, hist_plot_type=None, label="default"*) #### plantcv.analyze_nir_intensity @@ -192,7 +192,7 @@ pages for more details on the input and output variable types. * post v3.0dev2: hist_header, hist_data, analysis_img = **plantcv.analyze_nir_intensity**(*gray_img, mask, bins, histplot=False, filename=False*) * post v3.0: hist_header, hist_data, nir_hist = **plantcv.analyze_nir_intensity**(*gray_img, mask, bins, histplot=False*) * post v3.3: nir_hist = **plantcv.analyze_nir_intensity**(*gray_img, mask, bins, histplot=False*) -* post v3.11: nir_hist = **plantcv.analyze_nir_intensity**(*gray_img, mask, bins, histplot=False, label=None*) +* post v3.11: nir_hist = **plantcv.analyze_nir_intensity**(*gray_img, mask, bins, histplot=False, label="default"*) #### plantcv.analyze_object @@ -201,14 +201,14 @@ pages for more details on the input and output variable types. * post v3.0dev2: shape_header, shape_data, analysis_images = **plantcv.analyze_object**(*img, obj, mask, filename=False*) * post v3.0: shape_header, shape_data, analysis_images = **plantcv.analyze_object**(*img, obj, mask*) * post v3.3: analysis_image = **plantcv.analyze_object**(*img, obj, mask*) -* post v3.11: analysis_image = **plantcv.analyze_object**(*img, obj, mask, label=None*) +* post v3.11: analysis_image = **plantcv.analyze_object**(*img, obj, mask, label="default"*) #### plantcv.analyze_thermal_values * pre v3.5: NA * post v3.5: thermal_histogram = **plantcv.analyze_thermal_values**(*thermal_array, mask, histplot=False*) -* post v3.11: thermal_histogram = **plantcv.analyze_thermal_values**(*thermal_array, mask, histplot=False, label=None*) +* post v3.11: thermal_histogram = **plantcv.analyze_thermal_values**(*thermal_array, mask, histplot=False, label="default"*) #### plantcv.apply_mask @@ -341,14 +341,14 @@ pages for more details on the input and output variable types. * pre v3.7: NA * post v3.7: **plantcv.hyperspectral.analyze_index**(*index_array, mask*) * post v3.8: index_histogram = **plantcv.hyperspectral.analyze_index**(*index_array, mask, histplot=False, bins=100, max_bin=0, min_bin=1*) -* post v3.11: index_histogram = **plantcv.hyperspectral.analyze_index**(*index_array, mask, histplot=False, bins=100, max_bin=0, min_bin=1, label=None*) +* post v3.11: index_histogram = **plantcv.hyperspectral.analyze_index**(*index_array, mask, histplot=False, bins=100, max_bin=0, min_bin=1, label="default"*) #### plantcv.hyperspectral.analyze_spectral * pre v3.7: NA * post v3.7: spectral_histogram = **plantcv.hyperspectral.analyze_spectral**(*array, mask, histplot=True*) -* post v3.11: spectral_histogram =**plantcv.hyperspectral.analyze_spectral**(*array, mask, histplot=True, label=None*) +* post v3.11: spectral_histogram =**plantcv.hyperspectral.analyze_spectral**(*array, mask, histplot=True, label="default"*) #### plantcv.hyperspectral.extract_index @@ -377,7 +377,7 @@ pages for more details on the input and output variable types. * post v3.0dev2: vert_ave_c, hori_ave_c, euc_ave_c, ang_ave_c, vert_ave_b, hori_ave_b, euc_ave_b, ang_ave_b = **plantcv.landmark_reference_pt_dist**(*points_r, centroid_r, bline_r*) * post v3.2: landmark_header, landmark_data = **plantcv.landmark_reference_pt_dist**(*points_r, centroid_r, bline_r*) * post v3.3: **plantcv.landmark_reference_pt_dist**(*points_r, centroid_r, bline_r*) -* post v3.11: **plantcv.landmark_reference_pt_dist**(*points_r, centroid_r, bline_r, label=None*) +* post v3.11: **plantcv.landmark_reference_pt_dist**(*points_r, centroid_r, bline_r, label="default"*) #### plantcv.laplace_filter @@ -411,25 +411,25 @@ pages for more details on the input and output variable types. * pre v3.8: NA * post v3.8: labeled_img = **plantcv.morphology.analyze_stem**(*rgb_img, stem_objects*) -* post v3.11: labeled_img = **plantcv.morphology.analyze_stem**(*rgb_img, stem_objects, label=None*) +* post v3.11: labeled_img = **plantcv.morphology.analyze_stem**(*rgb_img, stem_objects, label="default"*) #### plantcv.morphology.check_cycles * pre v3.3: NA * post v3.3: cycle_img = **plantcv.morphology.check_cycles**(*skel_img*) -* post v3.11: cycle_img = **plantcv.morphology.check_cycles**(*skel_img, label=None*) +* post v3.11: cycle_img = **plantcv.morphology.check_cycles**(*skel_img, label="default"*) #### plantcv.morphology.find_branch_pts * pre v3.3: NA * post v3.3: branch_pts_img = **plantcv.morphology.find_branch_pts**(*skel_img, mask=None*) -* post v3.11: branch_pts_img = **plantcv.morphology.find_branch_pts**(*skel_img, mask=None, label=None*) +* post v3.11: branch_pts_img = **plantcv.morphology.find_branch_pts**(*skel_img, mask=None, label="default"*) #### plantcv.morphology.find_tips * pre v3.3: NA * post v3.3: tip_img = **plantcv.morphology.find_tips**(*skel_img, mask=None*) -* post v3.11: tip_img = **plantcv.morphology.find_tips**(*skel_img, mask=None, label=None*) +* post v3.11: tip_img = **plantcv.morphology.find_tips**(*skel_img, mask=None, label="default"*) #### plantcv.morphology.prune @@ -441,19 +441,19 @@ pages for more details on the input and output variable types. * pre v3.3: NA * post v3.3: labeled_img = **plantcv.morphology.segment_angle**(*segmented_img, objects*) -* post v3.11: labeled_img = **plantcv.morphology.segment_angle**(*segmented_img, objects, label=None*) +* post v3.11: labeled_img = **plantcv.morphology.segment_angle**(*segmented_img, objects, label="default"*) #### plantcv.morphology.segment_curvature * pre v3.3: NA * post v3.3: labeled_img = **plantcv.morphology.segment_curvature**(*segmented_img, objects*) -* post v3.11: labeled_img = **plantcv.morphology.segment_curvature**(*segmented_img, objects, label=None*) +* post v3.11: labeled_img = **plantcv.morphology.segment_curvature**(*segmented_img, objects, label="default"*) #### plantcv.morphology.segment_euclidean_length * pre v3.3: NA * post v3.3: labeled_img = **plantcv.morphology.segment_euclidean_length**(*segmented_img, objects*) -* post v3.11: labeled_img = **plantcv.morphology.segment_euclidean_length**(*segmented_img, objects, label=None*) +* post v3.11: labeled_img = **plantcv.morphology.segment_euclidean_length**(*segmented_img, objects, label="default"*) #### plantcv.morphology.segment_id @@ -464,7 +464,7 @@ pages for more details on the input and output variable types. * pre v3.3: NA * post v3.3: labeled_img = **plantcv.morphology.segment_path_length**(*segmented_img, objects*) -* post v3.11: labeled_img = **plantcv.morphology.segment_path_length**(*segmented_img, objects, label=None*) +* post v3.11: labeled_img = **plantcv.morphology.segment_path_length**(*segmented_img, objects, label="default"*) #### plantcv.morphology.segment_skeleton @@ -480,7 +480,7 @@ pages for more details on the input and output variable types. * pre v3.3: NA * post v3.3: labeled_img = **plantcv.morphology.segment_tangent_angle**(*segmented_img, objects, size*) -* post v3.11: labeled_img = **plantcv.morphology.segment_tangent_angle**(*segmented_img, objects, size, label=None*) +* post v3.11: labeled_img = **plantcv.morphology.segment_tangent_angle**(*segmented_img, objects, size, label="default"*) #### plantcv.morphology.skeletontize @@ -516,7 +516,7 @@ pages for more details on the input and output variable types. #### plantcv.photosynthesis.analyze_fvfm * pre v3.10: see plantcv.fluor_fvfm * post v3.10: analysis_images = **plantcv.photosynthesis.analyze_fvfm**(*fdark, fmin, fmax, mask, bins=256*) -* post v3.11: analysis_images = **plantcv.photosynthesis.analyze_fvfm**(*fdark, fmin, fmax, mask, bins=256, label=None*) +* post v3.11: analysis_images = **plantcv.photosynthesis.analyze_fvfm**(*fdark, fmin, fmax, mask, bins=256, label="default"*) #### plantcv.photosynthesis.read_cropreporter @@ -573,7 +573,7 @@ pages for more details on the input and output variable types. * post v3.0dev2: marker_header, marker_data, analysis_images = **plantcv.report_size_marker_area**(*img, roi_contour, roi_hierarchy, marker='define', objcolor='dark', thresh_channel=None, thresh=None, filename=False*) * post v3.1: marker_header, marker_data, analysis_image = **plantcv.report_size_marker_area**(*img, roi_contour, roi_hierarchy, marker='define', objcolor='dark', thresh_channel=None, thresh=None*) * post v3.3: analysis_image = **plantcv.report_size_marker_area**(*img, roi_contour, roi_hierarchy, marker='define', objcolor='dark', thresh_channel=None, thresh=None*) -* post v3.11: analysis_image = **plantcv.report_size_marker_area**(*img, roi_contour, roi_hierarchy, marker='define', objcolor='dark', thresh_channel=None, thresh=None, label=None*) +* post v3.11: analysis_image = **plantcv.report_size_marker_area**(*img, roi_contour, roi_hierarchy, marker='define', objcolor='dark', thresh_channel=None, thresh=None, label="default"*) #### plantcv.resize @@ -852,7 +852,7 @@ pages for more details on the input and output variable types. * post v3.0: df, start_coord, spacing = **plantcv.transform.find_color_card**(*rgb_img, threshold='adaptgauss', threshvalue=125, blurry=False, background='dark'*) * post v3.3: df, start_coord, spacing = **plantcv.transform.find_color_card**(*rgb_img, threshold_type='adaptgauss', threshvalue=125, blurry=False, background='dark'*) * post v3.9: df, start_coord, spacing = **plantcv.transform.find_color_card**(*rgb_img, threshold_type='adaptgauss', threshvalue=125, blurry=False, background='dark', record_chip_size='median'*) -* post v3.11: df, start_coord, spacing = **plantcv.transform.find_color_card**(*rgb_img, threshold_type='adaptgauss', threshvalue=125, blurry=False, background='dark', record_chip_size='median', label=None*) +* post v3.11: df, start_coord, spacing = **plantcv.transform.find_color_card**(*rgb_img, threshold_type='adaptgauss', threshvalue=125, blurry=False, background='dark', record_chip_size='median', label="default"*) #### plantcv.transform.get_color_matrix @@ -920,7 +920,7 @@ pages for more details on the input and output variable types. * post v3.0dev2: watershed_header, watershed_data, analysis_images = **plantcv.watershed_segmentation**(*rgb_img, mask, distance=10, filename=False*) * post v3.1: watershed_header, watershed_data, analysis_images = **plantcv.watershed_segmentation**(*rgb_img, mask, distance=10*) * post v3.3: analysis_image = **plantcv.watershed_segmentation**(*rgb_img, mask, distance=10*) -* post v3.11: analysis_image = **plantcv.watershed_segmentation**(*rgb_img, mask, distance=10, label=None*) +* post v3.11: analysis_image = **plantcv.watershed_segmentation**(*rgb_img, mask, distance=10, label="default"*) #### plantcv.white_balance @@ -932,18 +932,18 @@ pages for more details on the input and output variable types. * pre v3.3: NA * post v3.3: in_bounds = **plantcv.within_frame**(*mask*) * post v3.8: in_bounds = **plantcv.within_frame**(*mask, border_width=1*) -* post v3.11: in_bounds = **plantcv.within_frame**(*mask, border_width=1, label=None*) +* post v3.11: in_bounds = **plantcv.within_frame**(*mask, border_width=1, label="default"*) #### plantcv.x_axis_pseudolandmarks * pre v3.0dev2: device, top, bottom, center_v = **plantcv.x_axis_pseudolandmarks**(*obj, mask, img, device, debug=None*) * post v3.0dev2: top, bottom, center_v = **plantcv.x_axis_pseudolandmarks**(*obj, mask, img*) * post v3.2: top, bottom, center_v = **plantcv.x_axis_pseudolandmarks**(*img, obj, mask*) -* post v3.11: top, bottom, center_v = **plantcv.x_axis_pseudolandmarks**(*img, obj, mask, label=None*) +* post v3.11: top, bottom, center_v = **plantcv.x_axis_pseudolandmarks**(*img, obj, mask, label="default"*) #### plantcv.y_axis_pseudolandmarks * pre v3.0dev2: device, left, right, center_h = **plantcv.y_axis_pseudolandmarks**(*obj, mask, img, device, debug=None*) * post v3.0dev2: left, right, center_h = **plantcv.y_axis_pseudolandmarks**(*obj, mask, img*) * post v3.2: left, right, center_h = **plantcv.y_axis_pseudolandmarks**(*img, obj, mask*) -* post v3.11: left, right, center_h = **plantcv.y_axis_pseudolandmarks**(*img, obj, mask, label=None*) +* post v3.11: left, right, center_h = **plantcv.y_axis_pseudolandmarks**(*img, obj, mask, label="default"*) From 5de7ea95229d36d731f2b8a987c9a8422de8fb0c Mon Sep 17 00:00:00 2001 From: HaleySchuhl Date: Mon, 8 Feb 2021 12:39:12 -0600 Subject: [PATCH 116/137] update remaining doc files --- docs/vis_nir_tutorial.md | 16 ++++++++-------- docs/vis_tutorial.md | 12 ++++++------ docs/watershed.md | 4 ++-- docs/within_frame.md | 2 +- docs/x_axis_pseudolandmarks.md | 6 +++--- 5 files changed, 20 insertions(+), 20 deletions(-) diff --git a/docs/vis_nir_tutorial.md b/docs/vis_nir_tutorial.md index af9443191..27ab3c89a 100644 --- a/docs/vis_nir_tutorial.md +++ b/docs/vis_nir_tutorial.md @@ -323,7 +323,7 @@ The next step is to analyze the plant object for traits such as [horizontal heig # obj- Single or grouped contour object # mask - Binary image mask to use as mask for moments analysis # label - Optional label parameter, modifies the variable name of observations recorded - shape_img = pcv.analyze_object(img=img, obj=obj, mask=mask, label=None) + shape_img = pcv.analyze_object(img=img, obj=obj, mask=mask, label="default") # Shape properties relative to user boundary line (optional) @@ -335,7 +335,7 @@ The next step is to analyze the plant object for traits such as [horizontal heig # through the bottom of the image) # label - Optional label parameter, modifies the variable name of observations recorded boundary_img1 = pcv.analyze_bound_horizontal(img=img, obj=obj, mask=mask, - line_position=1680, label=None) + line_position=1680, label="default") # Determine color properties: Histograms, Color Slices, output color analyzed histogram (optional) @@ -344,7 +344,7 @@ The next step is to analyze the plant object for traits such as [horizontal heig # mask - Binary mask of selected contours # hist_plot_type - None (default), 'all', 'rgb', 'lab', or 'hsv' # label - Optional label parameter, modifies the variable name of observations recorded - color_histogram = pcv.analyze_color(rgb_img=img, mask=kept_mask, hist_plot_type='all', label=None) + color_histogram = pcv.analyze_color(rgb_img=img, mask=kept_mask, hist_plot_type='all', label="default") # Pseudocolor the grayscale image @@ -447,7 +447,7 @@ The next step is to [get the matching NIR](get_nir.md) image, [resize](transform # histplot - If True then plots histogram of intensity values, (default False) # label - Optional label parameter, modifies the variable name of observations recorded nir_hist = pcv.analyze_nir_intensity(gray_img=nir2, mask=nir_combinedmask, - bins=256, histplot=True, label=None) + bins=256, histplot=True, label="default") nir_shape_image = pcv.analyze_object(img=nir2, obj=nir_combined, mask=nir_combinedmask, label="NIR") @@ -563,14 +563,14 @@ def main(): ############### Analysis ################ # Find shape properties, output shape image (optional) - shape_img = pcv.analyze_object(img=img, obj=obj, mask=mask, label=None) + shape_img = pcv.analyze_object(img=img, obj=obj, mask=mask, label="default") # Shape properties relative to user boundary line (optional) boundary_img1 = pcv.analyze_bound_horizontal(img=img, obj=obj, mask=mask, - line_position=1680, label=None) + line_position=1680, label="default") # Determine color properties: Histograms, Color Slices, output color analyzed histogram (optional) - color_histogram = pcv.analyze_color(rgb_img=img, mask=kept_mask, hist_plot_type='all', label=None) + color_histogram = pcv.analyze_color(rgb_img=img, mask=kept_mask, hist_plot_type='all', label="default") # Pseudocolor the grayscale image pseudocolored_img = pcv.visualize.pseudocolor(gray_img=s, mask=kept_mask, cmap='jet') @@ -598,7 +598,7 @@ def main(): hierarchy=nir_hierarchy) # Analyze NIR intensity and object shape - nir_hist = pcv.analyze_nir_intensity(gray_img=nir2, mask=nir_combinedmask, bins=256, histplot=True, label=None) + nir_hist = pcv.analyze_nir_intensity(gray_img=nir2, mask=nir_combinedmask, bins=256, histplot=True, label="default") nir_shape_image = pcv.analyze_object(img=nir2, obj=nir_combined, mask=nir_combinedmask, label="NIR") # Save out the NIR histogram diff --git a/docs/vis_tutorial.md b/docs/vis_tutorial.md index bfddd1d4d..1beeff57e 100644 --- a/docs/vis_tutorial.md +++ b/docs/vis_tutorial.md @@ -382,7 +382,7 @@ The next step is to analyze the plant object for traits such as [horizontal heig # obj- Single or grouped contour object # mask - Binary image mask to use as mask for moments analysis # label - Optional label parameter, modifies the variable name of observations recorded - shape_img = pcv.analyze_object(img=img, obj=obj, mask=mask, label=None) + shape_img = pcv.analyze_object(img=img, obj=obj, mask=mask, label="default") # Shape properties relative to user boundary line (optional) @@ -394,7 +394,7 @@ The next step is to analyze the plant object for traits such as [horizontal heig # through the bottom of the image) # label - Optional label parameter, modifies the variable name of observations recorded boundary_img1 = pcv.analyze_bound_horizontal(img=img, obj=obj, mask=mask, - line_position=1680, label=None) + line_position=1680, label="default") # Determine color properties: Histograms, Color Slices, output color analyzed histogram (optional) @@ -404,7 +404,7 @@ The next step is to analyze the plant object for traits such as [horizontal heig # hist_plot_type - None (default), 'all', 'rgb', 'lab', or 'hsv' # This is the data to be printed to the SVG histogram file # label - Optional label parameter, modifies the variable name of observations recorded - color_histogram = pcv.analyze_color(rgb_img=img, mask=mask, hist_plot_type='all', label=None) + color_histogram = pcv.analyze_color(rgb_img=img, mask=mask, hist_plot_type='all', label="default") # Pseudocolor the grayscale image @@ -593,13 +593,13 @@ def main(): outfile = os.path.join(args.outdir, filename) # Find shape properties, output shape image (optional) - shape_imgs = pcv.analyze_object(img=img, obj=obj, mask=mask, label=None) + shape_imgs = pcv.analyze_object(img=img, obj=obj, mask=mask, label="default") # Shape properties relative to user boundary line (optional) - boundary_img1 = pcv.analyze_bound_horizontal(img=img, obj=obj, mask=mask, line_position=1680, label=None) + boundary_img1 = pcv.analyze_bound_horizontal(img=img, obj=obj, mask=mask, line_position=1680, label="default") # Determine color properties: Histograms, Color Slices, output color analyzed histogram (optional) - color_histogram = pcv.analyze_color(rgb_img=img, mask=mask, hist_plot_type='all', label=None) + color_histogram = pcv.analyze_color(rgb_img=img, mask=mask, hist_plot_type='all', label="default") # Pseudocolor the grayscale image pseudocolored_img = pcv.visualize.pseudocolor(gray_img=s, mask=mask, cmap='jet') diff --git a/docs/watershed.md b/docs/watershed.md index 5180dae17..e74c1fcdf 100644 --- a/docs/watershed.md +++ b/docs/watershed.md @@ -5,7 +5,7 @@ For more information see [https://github.com/lsx1980/Leaf_count](https://github. This function uses the watershed algorithm to detect boundary of objects. Needs a mask file which specifies area which is object is white, and background is black. -**plantcv.watershed_segmentation**(*rgb_img, mask, distance=10, label=None*) +**plantcv.watershed_segmentation**(*rgb_img, mask, distance=10, label="default"*) **returns** analysis_image @@ -33,7 +33,7 @@ from plantcv import plantcv as pcv pcv.params.debug = "print" # Segment image with watershed function -analysis_image = pcv.watershed_segmentation(rgb_img=crop_img, mask=bin_mask, distance=10, label=None) +analysis_image = pcv.watershed_segmentation(rgb_img=crop_img, mask=bin_mask, distance=10, label="default") ``` diff --git a/docs/within_frame.md b/docs/within_frame.md index fbb87c7f0..fbc442d96 100644 --- a/docs/within_frame.md +++ b/docs/within_frame.md @@ -3,7 +3,7 @@ This function tests whether an object (defined as nonzero pixels in a mask) falls completely within the bounds of an image, or if it touches the edge. -**plantcv.within_frame**(*mask, border_width=1, label=None*) +**plantcv.within_frame**(*mask, border_width=1, label="default"*) **returns** in_bounds diff --git a/docs/x_axis_pseudolandmarks.md b/docs/x_axis_pseudolandmarks.md index 7fd8f6a72..95b12d41d 100644 --- a/docs/x_axis_pseudolandmarks.md +++ b/docs/x_axis_pseudolandmarks.md @@ -3,7 +3,7 @@ Divide plant object into twenty equidistant bins and assign pseudolandmark points based upon their actual (not scaled) position. Once this data is scaled this approach may provide some information regarding shape independent of size. -**plantcv.x_axis_pseudolandmarks**(*img, obj, mask, label=None*) +**plantcv.x_axis_pseudolandmarks**(*img, obj, mask, label="default"*) **returns** landmarks_on_top (top), landmarks_on_bottom (bottom), landmarks_at_center_along_the_vertical_axis (center_V) @@ -29,10 +29,10 @@ pcv.params.debug = "plot" # Identify a set of land mark points # Results in set of point values that may indicate tip points -top, bottom, center_v = pcv.x_axis_pseudolandmarks(img=img, obj=obj, mask=mask, label=None) +top, bottom, center_v = pcv.x_axis_pseudolandmarks(img=img, obj=obj, mask=mask, label="default") # Access data stored out from x_axis_pseudolandmarks -bottom_landmarks = pcv.outputs.observations['bottom_lmk']['value'] +bottom_landmarks = pcv.outputs.observations['default_bottom_lmk']['value'] ``` From 179c161700241c4c6f81fad1d45e0f86ad48d31b Mon Sep 17 00:00:00 2001 From: HaleySchuhl Date: Tue, 9 Feb 2021 07:53:14 -0600 Subject: [PATCH 117/137] Update tests.py --- tests/tests.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/tests.py b/tests/tests.py index 54030b504..dc755ae96 100755 --- a/tests/tests.py +++ b/tests/tests.py @@ -4616,7 +4616,7 @@ def test_plantcv_hyperspectral_analyze_spectral(): mask = cv2.imread(os.path.join(HYPERSPECTRAL_TEST_DATA, HYPERSPECTRAL_MASK), -1) array_data = pcv.hyperspectral.read_data(filename=spectral_filename) pcv.params.debug = "plot" - _ = pcv.hyperspectral.analyze_spectral(array=array_data, mask=mask, histplot=True, label=None) + _ = pcv.hyperspectral.analyze_spectral(array=array_data, mask=mask, histplot=True) pcv.params.debug = "print" _ = pcv.hyperspectral.analyze_spectral(array=array_data, mask=mask, histplot=True, label="prefix") assert len(pcv.outputs.observations['prefix_spectral_frequencies']['value']) == 978 From f5ba1a95ddab6f3cfebfe73dea5453ce33a386d1 Mon Sep 17 00:00:00 2001 From: HaleySchuhl Date: Tue, 9 Feb 2021 10:06:39 -0600 Subject: [PATCH 118/137] update data variable names --- tests/tests.py | 53 +++++++++++++++++++++++++------------------------- 1 file changed, 27 insertions(+), 26 deletions(-) diff --git a/tests/tests.py b/tests/tests.py index dc755ae96..c2479cc61 100755 --- a/tests/tests.py +++ b/tests/tests.py @@ -1127,7 +1127,7 @@ def test_plantcv_analyze_bound_horizontal_neg_y(): _ = pcv.analyze_bound_horizontal(img=img, obj=object_contours, mask=mask, line_position=2056) shutil.copyfile(os.path.join(TEST_DATA, "data_results.txt"), os.path.join(cache_dir, "data_results.txt")) pcv.print_results(os.path.join(cache_dir, "data_results.txt")) - assert pcv.outputs.observations['height_above_reference']['value'] == 713 + assert pcv.outputs.observations['default_height_above_reference']['value'] == 713 pcv.outputs.clear() @@ -1151,7 +1151,7 @@ def test_plantcv_analyze_bound_vertical(): pcv.params.debug = None _ = pcv.analyze_bound_vertical(img=img, obj=object_contours, mask=mask, line_position=1000) pcv.print_results(os.path.join(cache_dir, "results.txt")) - assert pcv.outputs.observations['width_left_reference']['value'] == 94 + assert pcv.outputs.observations['default_width_left_reference']['value'] == 94 pcv.outputs.clear() @@ -1169,7 +1169,7 @@ def test_plantcv_analyze_bound_vertical_grayscale_image(): pcv.params.debug = "plot" _ = pcv.analyze_bound_vertical(img=img, obj=object_contours, mask=mask, line_position=1000) pcv.print_results(os.path.join(cache_dir, "results.txt")) - assert pcv.outputs.observations['width_left_reference']['value'] == 94 + assert pcv.outputs.observations['default_width_left_reference']['value'] == 94 pcv.outputs.clear() @@ -1187,7 +1187,7 @@ def test_plantcv_analyze_bound_vertical_neg_x(): pcv.params.debug = "plot" _ = pcv.analyze_bound_vertical(img=img, obj=object_contours, mask=mask, line_position=2454) pcv.print_results(os.path.join(cache_dir, "results.txt")) - assert pcv.outputs.observations['width_left_reference']['value'] == 441 + assert pcv.outputs.observations['default_width_left_reference']['value'] == 441 pcv.outputs.clear() @@ -1205,7 +1205,7 @@ def test_plantcv_analyze_bound_vertical_small_x(): pcv.params.debug = "plot" _ = pcv.analyze_bound_vertical(img=img, obj=object_contours, mask=mask, line_position=1) pcv.print_results(os.path.join(cache_dir, "results.txt")) - assert pcv.outputs.observations['width_right_reference']['value'] == 441 + assert pcv.outputs.observations['default_width_right_reference']['value'] == 441 pcv.outputs.clear() @@ -1233,7 +1233,7 @@ def test_plantcv_analyze_color(): pcv.params.debug = None _ = pcv.analyze_color(rgb_img=img, mask=mask, hist_plot_type='rgb') pcv.print_results(os.path.join(cache_dir, "results.txt")) - assert pcv.outputs.observations['hue_median']['value'] == 84.0 + assert pcv.outputs.observations['default_hue_median']['value'] == 84.0 pcv.outputs.clear() @@ -1280,7 +1280,7 @@ def test_plantcv_analyze_nir(): pcv.params.debug = None _ = pcv.analyze_nir_intensity(gray_img=img, mask=mask, bins=256, histplot=True) pcv.print_results(os.path.join(cache_dir, "results.txt")) - result = len(pcv.outputs.observations['nir_frequencies']['value']) + result = len(pcv.outputs.observations['default_nir_frequencies']['value']) pcv.outputs.clear() assert result == 256 @@ -1426,7 +1426,7 @@ def test_plantcv_analyze_thermal_values(): pcv.params.debug = "plot" thermal_hist = pcv.analyze_thermal_values(thermal_array=img, mask=mask, histplot=True) pcv.print_results(os.path.join(cache_dir, "results.txt")) - assert thermal_hist is not None and pcv.outputs.observations['median_temp']['value'] == 33.20922 + assert thermal_hist is not None and pcv.outputs.observations['default_median_temp']['value'] == 33.20922 def test_plantcv_apply_mask_white(): @@ -3652,7 +3652,7 @@ def test_plantcv_morphology_segment_curvature(): pcv.outputs.clear() _ = pcv.morphology.segment_curvature(segmented_img, seg_objects) pcv.print_results(os.path.join(cache_dir, "results.txt")) - assert len(pcv.outputs.observations['segment_curvature']['value']) == 22 + assert len(pcv.outputs.observations['default_segment_curvature']['value']) == 22 pcv.outputs.clear() @@ -3668,9 +3668,9 @@ def test_plantcv_morphology_check_cycles(): _ = pcv.morphology.check_cycles(mask) pcv.params.debug = None _ = pcv.morphology.check_cycles(mask) - print(pcv.outputs.observations["num_cycles"]["value"]) + print(pcv.outputs.observations["default_num_cycles"]["value"]) pcv.print_results(os.path.join(cache_dir, "results.txt")) - assert pcv.outputs.observations['num_cycles']['value'] == 1 + assert pcv.outputs.observations['default_num_cycles']['value'] == 1 pcv.outputs.clear() @@ -3770,9 +3770,9 @@ def test_plantcv_morphology_fill_segments(): pcv.params.debug = "plot" _ = pcv.morphology.fill_segments(mask, obj) pcv.print_results(os.path.join(cache_dir, "results.txt")) - tests = [pcv.outputs.observations['segment_area']['value'][42] == 5529, - pcv.outputs.observations['segment_area']['value'][20] == 5057, - pcv.outputs.observations['segment_area']['value'][49] == 3323] + tests = [pcv.outputs.observations['default_segment_area']['value'][42] == 5529, + pcv.outputs.observations['default_segment_area']['value'][20] == 5057, + pcv.outputs.observations['default_segment_area']['value'][49] == 3323] assert all(tests) pcv.outputs.clear() @@ -3792,7 +3792,7 @@ def test_plantcv_morphology_fill_segments_with_stem(): pcv.params.debug = "print" _ = pcv.morphology.fill_segments(mask, obj, stem_obj) pcv.print_results(os.path.join(cache_dir, "results.txt")) - num_objects = len(pcv.outputs.observations['segment_area']['value']) + num_objects = len(pcv.outputs.observations['default_segment_area']['value']) assert num_objects == 70 pcv.outputs.clear() @@ -3809,7 +3809,7 @@ def test_plantcv_morphology_segment_angle(): pcv.params.debug = "plot" _ = pcv.morphology.segment_angle(segmented_img, segment_objects) pcv.print_results(os.path.join(cache_dir, "results.txt")) - assert len(pcv.outputs.observations['segment_angle']['value']) == 22 + assert len(pcv.outputs.observations['default_segment_angle']['value']) == 22 pcv.outputs.clear() @@ -3822,7 +3822,7 @@ def test_plantcv_morphology_segment_angle_overflow(): skeleton = cv2.imread(os.path.join(TEST_DATA, TEST_INPUT_SKELETON), -1) segmented_img, segment_objects = pcv.morphology.segment_skeleton(skel_img=skeleton) _ = pcv.morphology.segment_angle(segmented_img, segment_objects) - assert len(pcv.outputs.observations['segment_angle']['value']) == 73 + assert len(pcv.outputs.observations['default_segment_angle']['value']) == 73 pcv.outputs.clear() @@ -3838,7 +3838,7 @@ def test_plantcv_morphology_segment_euclidean_length(): pcv.params.debug = "plot" _ = pcv.morphology.segment_euclidean_length(segmented_img, segment_objects) pcv.print_results(os.path.join(cache_dir, "results.txt")) - assert len(pcv.outputs.observations['segment_eu_length']['value']) == 22 + assert len(pcv.outputs.observations['default_segment_eu_length']['value']) == 22 pcv.outputs.clear() @@ -3863,7 +3863,7 @@ def test_plantcv_morphology_segment_path_length(): pcv.params.debug = "plot" _ = pcv.morphology.segment_path_length(segmented_img, segment_objects) pcv.print_results(os.path.join(cache_dir, "results.txt")) - assert len(pcv.outputs.observations['segment_path_length']['value']) == 22 + assert len(pcv.outputs.observations['default_segment_path_length']['value']) == 22 pcv.outputs.clear() @@ -3911,7 +3911,7 @@ def test_plantcv_morphology_segment_tangent_angle(): pcv.params.debug = "plot" _ = pcv.morphology.segment_tangent_angle(skel, objs, 2) pcv.print_results(os.path.join(cache_dir, "results.txt")) - assert len(pcv.outputs.observations['segment_tangent_angle']['value']) == 73 + assert len(pcv.outputs.observations['default_segment_tangent_angle']['value']) == 73 pcv.outputs.clear() @@ -3944,9 +3944,10 @@ def test_plantcv_morphology_segment_insertion_angle(): pcv.params.debug = "print" _ = pcv.morphology.segment_insertion_angle(pruned, segmented_img, leaf_obj, stem_obj, 10) pcv.print_results(os.path.join(cache_dir, "results.txt")) - assert pcv.outputs.observations['segment_insertion_angle']['value'][:6] == ['NA', 'NA', 'NA', 24.956918822001636, - 50.7313343343401, - 56.427712102130734] + assert pcv.outputs.observations['default_segment_insertion_angle']['value'][:6] == ['NA', 'NA', 'NA', + 24.956918822001636, + 50.7313343343401, + 56.427712102130734] pcv.outputs.clear() @@ -4007,7 +4008,7 @@ def test_plantcv_morphology_analyze_stem(): _ = pcv.morphology.analyze_stem(rgb_img=segmented_img, stem_objects=stem_obj, label="prefix") pcv.params.debug = "print" _ = pcv.morphology.analyze_stem(rgb_img=segmented_img, stem_objects=stem_obj) - assert pcv.outputs.observations['stem_angle']['value'] == -12.531776428222656 + assert pcv.outputs.observations['default_stem_angle']['value'] == -12.531776428222656 pcv.outputs.clear() @@ -4024,7 +4025,7 @@ def test_plantcv_morphology_analyze_stem_bad_angle(): # stem_obj = [stem_obj[3]] stem_obj = [[[[1116, 1728]], [[1116, 1]]]] _ = pcv.morphology.analyze_stem(rgb_img=segmented_img, stem_objects=stem_obj) - assert pcv.outputs.observations['stem_angle']['value'] == 22877334.0 + assert pcv.outputs.observations['default_stem_angle']['value'] == 22877334.0 pcv.outputs.clear() @@ -4815,7 +4816,7 @@ def test_plantcv_photosynthesis_analyze_fvfm_bad_fdark(): fmax = cv2.imread(os.path.join(TEST_DATA, TEST_INPUT_FMAX), -1) fmask = cv2.imread(os.path.join(TEST_DATA, TEST_INPUT_FMASK), -1) _ = pcv.photosynthesis.analyze_fvfm(fdark=fdark + 3000, fmin=fmin, fmax=fmax, mask=fmask, bins=1000) - check = pcv.outputs.observations['fdark_passed_qc']['value'] is False + check = pcv.outputs.observations['default_fdark_passed_qc']['value'] is False pcv.outputs.clear() assert check From 41b8f354a21cfd5027b83df88f1a6804e580f9eb Mon Sep 17 00:00:00 2001 From: HaleySchuhl Date: Tue, 9 Feb 2021 11:05:37 -0600 Subject: [PATCH 119/137] other tests failing to fix --- plantcv/plantcv/morphology/segment_curvature.py | 8 ++++---- tests/tests.py | 4 ++-- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/plantcv/plantcv/morphology/segment_curvature.py b/plantcv/plantcv/morphology/segment_curvature.py index 651c12024..fce0a430a 100644 --- a/plantcv/plantcv/morphology/segment_curvature.py +++ b/plantcv/plantcv/morphology/segment_curvature.py @@ -42,10 +42,10 @@ def segment_curvature(segmented_img, objects, label="default"): debug = params.debug params.debug = None - _ = segment_euclidean_length(segmented_img, objects) - _ = segment_path_length(segmented_img, objects) - eu_lengths = outputs.observations['segment_eu_length']['value'] - path_lengths = outputs.observations['segment_path_length']['value'] + _ = segment_euclidean_length(segmented_img, objects, label="backend") + _ = segment_path_length(segmented_img, objects, label="backend") + eu_lengths = outputs.observations['backend_segment_eu_length']['value'] + path_lengths = outputs.observations['backend_segment_path_length']['value'] curvature_measure = [float(x / y) for x, y in zip(path_lengths, eu_lengths)] # Create a color scale, use a previously stored scale if available rand_color = color_palette(num=len(objects), saved=True) diff --git a/tests/tests.py b/tests/tests.py index c2479cc61..bbdda8c43 100755 --- a/tests/tests.py +++ b/tests/tests.py @@ -4647,7 +4647,7 @@ def test_plantcv_hyperspectral_analyze_index_set_range(): index_array = pcv.spectral_index.savi(hsi=array_data, distance=801) mask_img = np.ones(np.shape(index_array.array_data), dtype=np.uint8) * 255 pcv.hyperspectral.analyze_index(index_array=index_array, mask=mask_img, histplot=True, min_bin=0, max_bin=1) - assert pcv.outputs.observations['mean_index_savi']['value'] > 0 + assert pcv.outputs.observations['default_mean_index_savi']['value'] > 0 def test_plantcv_hyperspectral_analyze_index_auto_range(): @@ -4659,7 +4659,7 @@ def test_plantcv_hyperspectral_analyze_index_auto_range(): index_array = pcv.spectral_index.savi(hsi=array_data, distance=801) mask_img = np.ones(np.shape(index_array.array_data), dtype=np.uint8) * 255 pcv.hyperspectral.analyze_index(index_array=index_array, mask=mask_img, min_bin="auto", max_bin="auto") - assert pcv.outputs.observations['mean_index_savi']['value'] > 0 + assert pcv.outputs.observations['default_mean_index_savi']['value'] > 0 def test_plantcv_hyperspectral_analyze_index_outside_range_warning(): From 8bf7d48f1c42ffd561248d673fbcdf6b7a85abb3 Mon Sep 17 00:00:00 2001 From: HaleySchuhl Date: Tue, 9 Feb 2021 11:35:09 -0600 Subject: [PATCH 120/137] Update tests.py --- tests/tests.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/tests.py b/tests/tests.py index bbdda8c43..3176ac168 100755 --- a/tests/tests.py +++ b/tests/tests.py @@ -4635,7 +4635,7 @@ def test_plantcv_hyperspectral_analyze_index(): pcv.hyperspectral.analyze_index(index_array=index_array, mask=mask_img, histplot=True) pcv.params.debug = "plot" pcv.hyperspectral.analyze_index(index_array=index_array, mask=mask_img, histplot=True) - assert pcv.outputs.observations['mean_index_savi']['value'] > 0 + assert pcv.outputs.observations['default_mean_index_savi']['value'] > 0 def test_plantcv_hyperspectral_analyze_index_set_range(): From a1b86fc400dde64125fa1af30fde8b1b56eb9450 Mon Sep 17 00:00:00 2001 From: nfahlgren Date: Thu, 11 Feb 2021 22:52:54 -0600 Subject: [PATCH 121/137] Add sample attribute to Outputs class --- plantcv/plantcv/__init__.py | 14 +++++++++++--- 1 file changed, 11 insertions(+), 3 deletions(-) diff --git a/plantcv/plantcv/__init__.py b/plantcv/plantcv/__init__.py index 0396acd9f..db681f0a2 100644 --- a/plantcv/plantcv/__init__.py +++ b/plantcv/plantcv/__init__.py @@ -8,7 +8,8 @@ class Params: """PlantCV parameters class.""" def __init__(self, device=0, debug=None, debug_outdir=".", line_thickness=5, dpi=100, text_size=0.55, - text_thickness=2, marker_size=60, color_scale="gist_rainbow", color_sequence="sequential", saved_color_scale=None): + text_thickness=2, marker_size=60, color_scale="gist_rainbow", color_sequence="sequential", + saved_color_scale=None): """Initialize parameters. Keyword arguments/parameters: @@ -66,9 +67,10 @@ def clear(self): self.observations = {} # Method to add observation to outputs - def add_observation(self, variable, trait, method, scale, datatype, value, label): + def add_observation(self, sample, variable, trait, method, scale, datatype, value, label): """ Keyword arguments/parameters: + sample = Sample name. Used to distinguish between multiple samples variable = A local unique identifier of a variable, e.g. a short name, that is a key linking the definitions of variables with observations. trait = A name of the trait mapped to an external ontology; if there is no exact mapping, an informative @@ -83,6 +85,7 @@ def add_observation(self, variable, trait, method, scale, datatype, value, label label = The label for each value (most useful when the data is a frequency table as in hue, or other tables) + :param sample: str :param variable: str :param trait: str :param method: str @@ -91,6 +94,7 @@ def add_observation(self, variable, trait, method, scale, datatype, value, label :param value: :param label: """ + self.sample = sample self.variable = variable self.trait = trait self.method = method @@ -99,7 +103,11 @@ def add_observation(self, variable, trait, method, scale, datatype, value, label self.value = value self.label = label - self.observations[variable] = { + # Create an empty dictionary for the sample if it does not exist + if sample not in self.observations: + self.observations[sample] = {} + # Save the observation for the sample and variable + self.observations[sample][variable] = { "trait": trait, "method": method, "scale": scale, From cea415141df25160a42c0e4385bd79b9cca2a066 Mon Sep 17 00:00:00 2001 From: nfahlgren Date: Thu, 11 Feb 2021 22:54:34 -0600 Subject: [PATCH 122/137] Process results with samples --- plantcv/parallel/process_results.py | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/plantcv/parallel/process_results.py b/plantcv/parallel/process_results.py index 73c907aa9..7feb4d7e3 100644 --- a/plantcv/parallel/process_results.py +++ b/plantcv/parallel/process_results.py @@ -42,9 +42,10 @@ def process_results(job_dir, json_file): for var in obs["metadata"]: data["variables"][var] = {"category": "metadata", "datatype": ""} # Keep track of all observations variables stored - for othervars in obs["observations"]: - data["variables"][othervars] = {"category": "observations", - "datatype": obs["observations"][othervars]["datatype"]} + for sample in obs["observations"]: + for othervars in obs["observations"][sample]: + data["variables"][othervars] = {"category": "observations", + "datatype": obs["observations"][sample][othervars]["datatype"]} # Write out json file with info from all images with open(json_file, 'w') as datafile: From aaf7f287dc827419c6c44cb05cafafe06b83a7bf Mon Sep 17 00:00:00 2001 From: nfahlgren Date: Thu, 11 Feb 2021 22:55:04 -0600 Subject: [PATCH 123/137] Output data per sample --- plantcv/utils/converters.py | 41 +++++++++++++++++++------------------ 1 file changed, 21 insertions(+), 20 deletions(-) diff --git a/plantcv/utils/converters.py b/plantcv/utils/converters.py index 454b175f3..01fa726be 100644 --- a/plantcv/utils/converters.py +++ b/plantcv/utils/converters.py @@ -28,7 +28,7 @@ def json2csv(json_file, csv_file): csv = open(csv_file + "-single-value-traits.csv", "w") # Build the single-value variables output table - csv.write(",".join(map(str, meta_vars + scalar_vars)) + "\n") + csv.write(",".join(map(str, meta_vars + ["sample"] + scalar_vars)) + "\n") for entity in data["entities"]: row = [] # Add metadata variables @@ -39,19 +39,21 @@ def json2csv(json_file, csv_file): else: row.append("NA") # Add scalar variables - for var in scalar_vars: - obs = entity[data["variables"][var]["category"]] - if var in obs: - row.append(obs[var]["value"]) - else: - row.append("NA") - csv.write(",".join(map(str, row)) + "\n") + for sample in entity["observations"]: + measurements = [sample] + for var in scalar_vars: + obs = entity[data["variables"][var]["category"]][sample] + if var in obs: + measurements.append(obs[var]["value"]) + else: + measurements.append("NA") + csv.write(",".join(map(str, row + measurements)) + "\n") # Close the CSV file csv.close() # Create a CSV file of multi-value variables csv = open(csv_file + "-multi-value-traits.csv", "w") - csv.write(",".join(map(str, meta_vars + ["trait", "value", "label"])) + "\n") + csv.write(",".join(map(str, meta_vars + ["sample", "trait", "value", "label"])) + "\n") for entity in data["entities"]: meta_row = [] # Add metadata variables @@ -62,17 +64,16 @@ def json2csv(json_file, csv_file): else: meta_row.append("NA") # Add multi-value variables - for var in multi_vars: - obs = entity[data["variables"][var]["category"]] - if var in obs: - if obs[var]["label"] != "none": - for i in range(0, len(obs[var]["value"])): - row = [var] - row.append(obs[var]["value"][i]) - row.append(obs[var]["label"][i]) - csv.write(",".join(map(str, meta_row + row)) + "\n") - else: - csv.write(",".join(map(str, meta_row + [var, "NA", "NA"])) + "\n") + for sample in entity["observations"]: + for var in multi_vars: + obs = entity[data["variables"][var]["category"]][sample] + if var in obs: + if obs[var]["label"] != "none": + for i in range(0, len(obs[var]["value"])): + row = [sample, var, obs[var]["value"][i], obs[var]["label"][i]] + csv.write(",".join(map(str, meta_row + row)) + "\n") + else: + csv.write(",".join(map(str, meta_row + [var, "NA", "NA"])) + "\n") csv.close() else: # If the file does not exist raise an error From 57bab830cc3daa5432105ec546fd0e87ab00fbdb Mon Sep 17 00:00:00 2001 From: nfahlgren Date: Thu, 11 Feb 2021 22:56:01 -0600 Subject: [PATCH 124/137] Add sample and remove measurement prefix Record the label input as a sample label instead of adding a prefix to measurement variables --- plantcv/plantcv/acute_vertex.py | 6 ++-- plantcv/plantcv/analyze_bound_horizontal.py | 17 +++++----- plantcv/plantcv/analyze_bound_vertical.py | 23 ++++++------- plantcv/plantcv/analyze_color.py | 26 +++++++------- plantcv/plantcv/analyze_nir_intensity.py | 10 +++--- plantcv/plantcv/analyze_object.py | 34 +++++++++---------- plantcv/plantcv/analyze_thermal_values.py | 15 ++++---- .../plantcv/hyperspectral/analyze_index.py | 16 ++++----- .../plantcv/hyperspectral/analyze_spectral.py | 19 +++++------ plantcv/plantcv/landmark_reference_pt_dist.py | 21 ++++++------ plantcv/plantcv/morphology/analyze_stem.py | 10 +++--- plantcv/plantcv/morphology/check_cycles.py | 6 ++-- plantcv/plantcv/morphology/fill_segments.py | 30 ++++++++-------- plantcv/plantcv/morphology/find_branch_pts.py | 7 ++-- plantcv/plantcv/morphology/find_tips.py | 7 ++-- plantcv/plantcv/morphology/segment_angle.py | 7 ++-- .../plantcv/morphology/segment_curvature.py | 7 ++-- .../morphology/segment_euclidean_length.py | 7 ++-- .../morphology/segment_insertion_angle.py | 8 ++--- .../plantcv/morphology/segment_path_length.py | 7 ++-- .../morphology/segment_tangent_angle.py | 7 ++-- .../plantcv/photosynthesis/analyze_fvfm.py | 19 +++++------ plantcv/plantcv/report_size_marker_area.py | 14 ++++---- plantcv/plantcv/transform/color_correction.py | 10 ++---- plantcv/plantcv/watershed.py | 16 +++------ plantcv/plantcv/within_frame.py | 4 +-- plantcv/plantcv/x_axis_pseudolandmarks.py | 8 ++--- plantcv/plantcv/y_axis_pseudolandmarks.py | 8 ++--- 28 files changed, 155 insertions(+), 214 deletions(-) diff --git a/plantcv/plantcv/acute_vertex.py b/plantcv/plantcv/acute_vertex.py index e9d9dc207..3bf5a08e2 100755 --- a/plantcv/plantcv/acute_vertex.py +++ b/plantcv/plantcv/acute_vertex.py @@ -99,15 +99,13 @@ 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) - prefix = label + "_" - if params.debug == 'print': - print_image(img2, os.path.join(params.debug_outdir, str(params.device) + prefix + '_acute_vertices.png')) + print_image(img2, os.path.join(params.debug_outdir, str(params.device) + '_acute_vertices.png')) elif params.debug == 'plot': plot_image(img2) # Store into global measurements - outputs.add_observation(variable=prefix + 'tip_coordinates', trait='tip coordinates', + 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') diff --git a/plantcv/plantcv/analyze_bound_horizontal.py b/plantcv/plantcv/analyze_bound_horizontal.py index ed9ab1ba5..6079395b6 100755 --- a/plantcv/plantcv/analyze_bound_horizontal.py +++ b/plantcv/plantcv/analyze_bound_horizontal.py @@ -146,27 +146,26 @@ def analyze_bound_horizontal(img, obj, mask, line_position, label="default"): plot_image(wback) plot_image(ori_img) - prefix = label + "_" - - outputs.add_observation(variable=prefix + 'horizontal_reference_position', trait='horizontal reference position', + outputs.add_observation(sample=label, variable='horizontal_reference_position', + trait='horizontal reference position', method='plantcv.plantcv.analyze_bound_horizontal', scale='none', datatype=int, value=line_position, label='none') - outputs.add_observation(variable=prefix + 'height_above_reference', trait='height above reference', + outputs.add_observation(sample=label, variable='height_above_reference', trait='height above reference', method='plantcv.plantcv.analyze_bound_horizontal', scale='pixels', datatype=int, value=height_above_bound, label='pixels') - outputs.add_observation(variable=prefix + 'height_below_reference', trait='height_below_reference', + outputs.add_observation(sample=label, variable='height_below_reference', trait='height_below_reference', method='plantcv.plantcv.analyze_bound_horizontal', scale='pixels', datatype=int, value=height_below_bound, label='pixels') - outputs.add_observation(variable=prefix + 'area_above_reference', trait='area above reference', + outputs.add_observation(sample=label, variable='area_above_reference', trait='area above reference', method='plantcv.plantcv.analyze_bound_horizontal', scale='pixels', datatype=int, value=above_bound_area, label='pixels') - outputs.add_observation(variable=prefix + 'percent_area_above_reference', trait='percent area above reference', + outputs.add_observation(sample=label, variable='percent_area_above_reference', trait='percent area above reference', method='plantcv.plantcv.analyze_bound_horizontal', scale='none', datatype=float, value=percent_bound_area_above, label='none') - outputs.add_observation(variable=prefix + 'area_below_reference', trait='area below reference', + outputs.add_observation(sample=label, variable='area_below_reference', trait='area below reference', method='plantcv.plantcv.analyze_bound_horizontal', scale='pixels', datatype=int, value=below_bound_area, label='pixels') - outputs.add_observation(variable=prefix + 'percent_area_below_reference', trait='percent area below reference', + outputs.add_observation(sample=label, variable='percent_area_below_reference', trait='percent area below reference', method='plantcv.plantcv.analyze_bound_horizontal', scale='none', datatype=float, value=percent_bound_area_below, label='none') diff --git a/plantcv/plantcv/analyze_bound_vertical.py b/plantcv/plantcv/analyze_bound_vertical.py index 58121577e..7adfd863b 100755 --- a/plantcv/plantcv/analyze_bound_vertical.py +++ b/plantcv/plantcv/analyze_bound_vertical.py @@ -146,29 +146,28 @@ def analyze_bound_vertical(img, obj, mask, line_position, label="default"): plot_image(wback) plot_image(ori_img) - prefix = label + "_" - - outputs.add_observation(variable=prefix + 'vertical_reference_position', trait='vertical reference position', + outputs.add_observation(sample=label, variable='vertical_reference_position', trait='vertical reference position', method='plantcv.plantcv.analyze_bound_vertical', scale='none', datatype=int, value=line_position, label='none') - outputs.add_observation(variable=prefix + 'width_left_reference', trait='width left of reference', + outputs.add_observation(sample=label, variable='width_left_reference', trait='width left of reference', method='plantcv.plantcv.analyze_bound_vertical', scale='pixels', datatype=int, value=width_left_bound, label='pixels') - outputs.add_observation(variable=prefix + 'width_right_reference', trait='width right of reference', + outputs.add_observation(sample=label, variable='width_right_reference', trait='width right of reference', method='plantcv.plantcv.analyze_bound_vertical', scale='pixels', datatype=int, value=width_right_bound, label='pixels') - outputs.add_observation(variable=prefix + 'area_left_reference', trait='area left of reference', + outputs.add_observation(sample=label, variable='area_left_reference', trait='area left of reference', method='plantcv.plantcv.analyze_bound_vertical', scale='pixels', datatype=int, value=left_bound_area, label='pixels') - outputs.add_observation(variable=prefix + 'percent_area_left_reference', trait='percent area left of reference', - method='plantcv.plantcv.analyze_bound_vertical', scale='none', datatype=float, + outputs.add_observation(sample=label, variable='percent_area_left_reference', + trait='percent area left of reference', method='plantcv.plantcv.analyze_bound_vertical', + scale='none', datatype=float, value=percent_bound_area_left, label='none') - outputs.add_observation(variable=prefix + 'area_right_reference', trait='area right of reference', + outputs.add_observation(sample=label, variable='area_right_reference', trait='area right of reference', method='plantcv.plantcv.analyze_bound_vertical', scale='pixels', datatype=int, value=right_bound_area, label='pixels') - outputs.add_observation(variable=prefix + 'percent_area_right_reference', trait='percent area right of reference', - method='plantcv.plantcv.analyze_bound_vertical', scale='none', datatype=float, - value=percent_bound_area_right, label='none') + outputs.add_observation(sample=label, variable='percent_area_right_reference', + trait='percent area right of reference', method='plantcv.plantcv.analyze_bound_vertical', + scale='none', datatype=float, value=percent_bound_area_right, label='none') # Store images outputs.images.append(analysis_images) diff --git a/plantcv/plantcv/analyze_color.py b/plantcv/plantcv/analyze_color.py index 319325960..720977d19 100755 --- a/plantcv/plantcv/analyze_color.py +++ b/plantcv/plantcv/analyze_color.py @@ -161,50 +161,48 @@ def analyze_color(rgb_img, mask, hist_plot_type=None, label="default"): # Diverging values on a -128 to 127 scale (green-magenta and blue-yellow) diverging_values = [i for i in range(-128, 128)] - prefix = label + "_" - if hist_plot_type is not None: if hist_plot_type.upper() == 'RGB' or hist_plot_type.upper() == 'ALL': - outputs.add_observation(variable=prefix + 'blue_frequencies', trait='blue frequencies', + outputs.add_observation(sample=label, variable='blue_frequencies', trait='blue frequencies', method='plantcv.plantcv.analyze_color', scale='frequency', datatype=list, value=histograms["b"]["hist"], label=rgb_values) - outputs.add_observation(variable=prefix + 'green_frequencies', trait='green frequencies', + outputs.add_observation(sample=label, variable='green_frequencies', trait='green frequencies', method='plantcv.plantcv.analyze_color', scale='frequency', datatype=list, value=histograms["g"]["hist"], label=rgb_values) - outputs.add_observation(variable=prefix + 'red_frequencies', trait='red frequencies', + outputs.add_observation(sample=label, variable='red_frequencies', trait='red frequencies', method='plantcv.plantcv.analyze_color', scale='frequency', datatype=list, value=histograms["r"]["hist"], label=rgb_values) if hist_plot_type.upper() == 'LAB' or hist_plot_type.upper() == 'ALL': - outputs.add_observation(variable=prefix + 'lightness_frequencies', trait='lightness frequencies', + outputs.add_observation(sample=label, variable='lightness_frequencies', trait='lightness frequencies', method='plantcv.plantcv.analyze_color', scale='frequency', datatype=list, value=histograms["l"]["hist"], label=percent_values) - outputs.add_observation(variable=prefix + 'green-magenta_frequencies', trait='green-magenta frequencies', + outputs.add_observation(sample=label, variable='green-magenta_frequencies', trait='green-magenta frequencies', method='plantcv.plantcv.analyze_color', scale='frequency', datatype=list, value=histograms["m"]["hist"], label=diverging_values) - outputs.add_observation(variable=prefix + 'blue-yellow_frequencies', trait='blue-yellow frequencies', + outputs.add_observation(sample=label, variable='blue-yellow_frequencies', trait='blue-yellow frequencies', method='plantcv.plantcv.analyze_color', scale='frequency', datatype=list, value=histograms["y"]["hist"], label=diverging_values) if hist_plot_type.upper() == 'HSV' or hist_plot_type.upper() == 'ALL': - outputs.add_observation(variable=prefix + 'hue_frequencies', trait='hue frequencies', + outputs.add_observation(sample=label, variable='hue_frequencies', trait='hue frequencies', method='plantcv.plantcv.analyze_color', scale='frequency', datatype=list, value=histograms["h"]["hist"][0:180], label=hue_values) - outputs.add_observation(variable=prefix + 'saturation_frequencies', trait='saturation frequencies', + outputs.add_observation(sample=label, variable='saturation_frequencies', trait='saturation frequencies', method='plantcv.plantcv.analyze_color', scale='frequency', datatype=list, value=histograms["s"]["hist"], label=percent_values) - outputs.add_observation(variable=prefix + 'value_frequencies', trait='value frequencies', + outputs.add_observation(sample=label, variable='value_frequencies', trait='value frequencies', method='plantcv.plantcv.analyze_color', scale='frequency', datatype=list, value=histograms["v"]["hist"], label=percent_values) # Always save hue stats - outputs.add_observation(variable=prefix + 'hue_circular_mean', trait='hue circular mean', + outputs.add_observation(sample=label, variable='hue_circular_mean', trait='hue circular mean', method='plantcv.plantcv.analyze_color', scale='degrees', datatype=float, value=hue_circular_mean, label='degrees') - outputs.add_observation(variable=prefix + 'hue_circular_std', trait='hue circular standard deviation', + outputs.add_observation(sample=label, variable='hue_circular_std', trait='hue circular standard deviation', method='plantcv.plantcv.analyze_color', scale='degrees', datatype=float, value=hue_circular_std, label='degrees') - outputs.add_observation(variable=prefix + 'hue_median', trait='hue median', + outputs.add_observation(sample=label, variable='hue_median', trait='hue median', method='plantcv.plantcv.analyze_color', scale='degrees', datatype=float, value=hue_median, label='degrees') diff --git a/plantcv/plantcv/analyze_nir_intensity.py b/plantcv/plantcv/analyze_nir_intensity.py index 6d51bc26a..106bfd922 100755 --- a/plantcv/plantcv/analyze_nir_intensity.py +++ b/plantcv/plantcv/analyze_nir_intensity.py @@ -93,18 +93,16 @@ def analyze_nir_intensity(gray_img, mask, bins=256, histplot=False, label="defau elif params.debug == "plot": print(fig_hist) - prefix = label + "_" - - outputs.add_observation(variable=prefix + 'nir_frequencies', trait='near-infrared frequencies', + outputs.add_observation(sample=label, variable='nir_frequencies', trait='near-infrared frequencies', method='plantcv.plantcv.analyze_nir_intensity', scale='frequency', datatype=list, value=hist_nir, label=bin_labels) - outputs.add_observation(variable=prefix + 'nir_mean', trait='near-infrared mean', + outputs.add_observation(sample=label, variable='nir_mean', trait='near-infrared mean', method='plantcv.plantcv.analyze_nir_intensity', scale='none', datatype=float, value=masked_nir_mean, label='none') - outputs.add_observation(variable=prefix + 'nir_median', trait='near-infrared median', + outputs.add_observation(sample=label, variable='nir_median', trait='near-infrared median', method='plantcv.plantcv.analyze_nir_intensity', scale='none', datatype=float, value=masked_nir_median, label='none') - outputs.add_observation(variable=prefix + 'nir_stdev', trait='near-infrared standard deviation', + outputs.add_observation(sample=label, variable='nir_stdev', trait='near-infrared standard deviation', method='plantcv.plantcv.analyze_nir_intensity', scale='none', datatype=float, value=masked_nir_std, label='none') diff --git a/plantcv/plantcv/analyze_object.py b/plantcv/plantcv/analyze_object.py index cd806f3e3..bc09848b2 100755 --- a/plantcv/plantcv/analyze_object.py +++ b/plantcv/plantcv/analyze_object.py @@ -48,7 +48,7 @@ def analyze_object(img, obj, mask, label="default"): background2 = np.zeros(size1, dtype=np.uint8) # Check is object is touching image boundaries (QC) - in_bounds = within_frame(mask) + in_bounds = within_frame(mask=mask, label=label) # Convex Hull hull = cv2.convexHull(obj) @@ -158,51 +158,49 @@ def analyze_object(img, obj, mask, label="default"): else: pass - prefix = label + "_" - - outputs.add_observation(variable=prefix + 'area', trait='area', + outputs.add_observation(sample=label, variable='area', trait='area', method='plantcv.plantcv.analyze_object', scale='pixels', datatype=int, value=area, label='pixels') - outputs.add_observation(variable=prefix + 'convex_hull_area', trait='convex hull area', + outputs.add_observation(sample=label, variable='convex_hull_area', trait='convex hull area', method='plantcv.plantcv.analyze_object', scale='pixels', datatype=int, value=hull_area, label='pixels') - outputs.add_observation(variable=prefix + 'solidity', trait='solidity', + outputs.add_observation(sample=label, variable='solidity', trait='solidity', method='plantcv.plantcv.analyze_object', scale='none', datatype=float, value=solidity, label='none') - outputs.add_observation(variable=prefix + 'perimeter', trait='perimeter', + outputs.add_observation(sample=label, variable='perimeter', trait='perimeter', method='plantcv.plantcv.analyze_object', scale='pixels', datatype=int, value=perimeter, label='pixels') - outputs.add_observation(variable=prefix + 'width', trait='width', + outputs.add_observation(sample=label, variable='width', trait='width', method='plantcv.plantcv.analyze_object', scale='pixels', datatype=int, value=width, label='pixels') - outputs.add_observation(variable=prefix + 'height', trait='height', + outputs.add_observation(sample=label, variable='height', trait='height', method='plantcv.plantcv.analyze_object', scale='pixels', datatype=int, value=height, label='pixels') - outputs.add_observation(variable=prefix + 'longest_path', trait='longest path', + outputs.add_observation(sample=label, variable='longest_path', trait='longest path', method='plantcv.plantcv.analyze_object', scale='pixels', datatype=int, value=caliper_length, label='pixels') - outputs.add_observation(variable=prefix + 'center_of_mass', trait='center of mass', + outputs.add_observation(sample=label, variable='center_of_mass', trait='center of mass', method='plantcv.plantcv.analyze_object', scale='none', datatype=tuple, value=(cmx, cmy), label='none') - outputs.add_observation(variable=prefix + 'convex_hull_vertices', trait='convex hull vertices', + outputs.add_observation(sample=label, variable='convex_hull_vertices', trait='convex hull vertices', method='plantcv.plantcv.analyze_object', scale='none', datatype=int, value=hull_vertices, label='none') - outputs.add_observation(variable=prefix + 'object_in_frame', trait='object in frame', + outputs.add_observation(sample=label, variable='object_in_frame', trait='object in frame', method='plantcv.plantcv.analyze_object', scale='none', datatype=bool, value=in_bounds, label='none') - outputs.add_observation(variable=prefix + 'ellipse_center', trait='ellipse center', + outputs.add_observation(sample=label, variable='ellipse_center', trait='ellipse center', method='plantcv.plantcv.analyze_object', scale='none', datatype=tuple, value=(center[0], center[1]), label='none') - outputs.add_observation(variable=prefix + 'ellipse_major_axis', trait='ellipse major axis length', + outputs.add_observation(sample=label, variable='ellipse_major_axis', trait='ellipse major axis length', method='plantcv.plantcv.analyze_object', scale='pixels', datatype=int, value=major_axis_length, label='pixels') - outputs.add_observation(variable=prefix + 'ellipse_minor_axis', trait='ellipse minor axis length', + outputs.add_observation(sample=label, variable='ellipse_minor_axis', trait='ellipse minor axis length', method='plantcv.plantcv.analyze_object', scale='pixels', datatype=int, value=minor_axis_length, label='pixels') - outputs.add_observation(variable=prefix + 'ellipse_angle', trait='ellipse major axis angle', + outputs.add_observation(sample=label, variable='ellipse_angle', trait='ellipse major axis angle', method='plantcv.plantcv.analyze_object', scale='degrees', datatype=float, value=float(angle), label='degrees') - outputs.add_observation(variable=prefix + 'ellipse_eccentricity', trait='ellipse eccentricity', + outputs.add_observation(sample=label, variable='ellipse_eccentricity', trait='ellipse eccentricity', method='plantcv.plantcv.analyze_object', scale='none', datatype=float, value=float(eccentricity), label='none') diff --git a/plantcv/plantcv/analyze_thermal_values.py b/plantcv/plantcv/analyze_thermal_values.py index 4b049fd75..43fb86238 100755 --- a/plantcv/plantcv/analyze_thermal_values.py +++ b/plantcv/plantcv/analyze_thermal_values.py @@ -59,22 +59,20 @@ def analyze_thermal_values(thermal_array, mask, histplot=False, label="default") avgtemp = np.average(masked_thermal) mediantemp = np.median(masked_thermal) - prefix = label + "_" - # Store data into outputs class - outputs.add_observation(variable=prefix + 'max_temp', trait='maximum temperature', + outputs.add_observation(sample=label, variable='max_temp', trait='maximum temperature', method='plantcv.plantcv.analyze_thermal_values', scale='degrees', datatype=float, value=maxtemp, label='degrees') - outputs.add_observation(variable=prefix + 'min_temp', trait='minimum temperature', + outputs.add_observation(sample=label, variable='min_temp', trait='minimum temperature', method='plantcv.plantcv.analyze_thermal_values', scale='degrees', datatype=float, value=mintemp, label='degrees') - outputs.add_observation(variable=prefix + 'mean_temp', trait='mean temperature', + outputs.add_observation(sample=label, variable='mean_temp', trait='mean temperature', method='plantcv.plantcv.analyze_thermal_values', scale='degrees', datatype=float, value=avgtemp, label='degrees') - outputs.add_observation(variable=prefix + 'median_temp', trait='median temperature', + outputs.add_observation(sample=label, variable='median_temp', trait='median temperature', method='plantcv.plantcv.analyze_thermal_values', scale='degrees', datatype=float, value=mediantemp, label='degrees') - outputs.add_observation(variable=prefix + 'thermal_frequencies', trait='thermal frequencies', + outputs.add_observation(sample=label, variable='thermal_frequencies', trait='thermal frequencies', method='plantcv.plantcv.analyze_thermal_values', scale='frequency', datatype=list, value=hist_percent, label=bin_labels) analysis_img = None @@ -91,8 +89,7 @@ def analyze_thermal_values(thermal_array, mask, histplot=False, label="default") analysis_img = fig_hist if params.debug == "print": - fig_hist.save(os.path.join(params.debug_outdir, str(params.device) + prefix + '_therm_histogram.png'), - verbose=False) + fig_hist.save(os.path.join(params.debug_outdir, str(params.device) + '_therm_histogram.png'), verbose=False) elif params.debug == "plot": print(fig_hist) diff --git a/plantcv/plantcv/hyperspectral/analyze_index.py b/plantcv/plantcv/hyperspectral/analyze_index.py index e6a49bf19..fd5b55dbe 100644 --- a/plantcv/plantcv/hyperspectral/analyze_index.py +++ b/plantcv/plantcv/hyperspectral/analyze_index.py @@ -107,32 +107,30 @@ def analyze_index(index_array, mask, histplot=False, bins=100, min_bin=0, max_bi elif params.debug == 'plot': print(fig_hist) - prefix = label + "_" - - outputs.add_observation(variable=prefix + 'mean_' + index_array.array_type, + outputs.add_observation(sample=label, variable='mean_' + index_array.array_type, trait='Average ' + index_array.array_type + ' reflectance', method='plantcv.plantcv.hyperspectral.analyze_index', scale='reflectance', datatype=float, value=float(index_mean), label='none') - outputs.add_observation(variable=prefix + 'med_' + index_array.array_type, + outputs.add_observation(sample=label, variable='med_' + index_array.array_type, trait='Median ' + index_array.array_type + ' reflectance', method='plantcv.plantcv.hyperspectral.analyze_index', scale='reflectance', datatype=float, value=float(index_median), label='none') - outputs.add_observation(variable=prefix + 'std_' + index_array.array_type, + outputs.add_observation(sample=label, variable='std_' + index_array.array_type, trait='Standard deviation ' + index_array.array_type + ' reflectance', method='plantcv.plantcv.hyperspectral.analyze_index', scale='reflectance', datatype=float, value=float(index_std), label='none') - outputs.add_observation(variable=prefix + 'index_frequencies_' + index_array.array_type, trait='index frequencies', - method='plantcv.plantcv.analyze_index', scale='frequency', datatype=list, - value=hist_percent, label=bin_labels) + outputs.add_observation(sample=label, variable='index_frequencies_' + index_array.array_type, + trait='index frequencies', method='plantcv.plantcv.analyze_index', scale='frequency', + datatype=list, value=hist_percent, label=bin_labels) if params.debug == "plot": plot_image(masked_array) elif params.debug == "print": print_image(img=masked_array, filename=os.path.join(params.debug_outdir, str(params.device) + - prefix + index_array.array_type + prefix + ".png")) + index_array.array_type + ".png")) # Store images outputs.images.append(analysis_image) diff --git a/plantcv/plantcv/hyperspectral/analyze_spectral.py b/plantcv/plantcv/hyperspectral/analyze_spectral.py index b5422e42b..a6b52a7b3 100644 --- a/plantcv/plantcv/hyperspectral/analyze_spectral.py +++ b/plantcv/plantcv/hyperspectral/analyze_spectral.py @@ -69,31 +69,30 @@ def analyze_spectral(array, mask, histplot=True, label="default"): for i in array.wavelength_dict.keys(): wavelength_labels.append(i) - prefix = label + "_" - # Store data into outputs class - outputs.add_observation(variable=prefix + 'global_mean_reflectance', trait='global mean reflectance', + outputs.add_observation(sample=label, variable='global_mean_reflectance', trait='global mean reflectance', method='plantcv.plantcv.hyperspectral.analyze_spectral', scale='reflectance', datatype=float, value=float(avg_reflectance), label='reflectance') - outputs.add_observation(variable=prefix + 'global_median_reflectance', trait='global median reflectance', + outputs.add_observation(sample=label, variable='global_median_reflectance', trait='global median reflectance', method='plantcv.plantcv.hyperspectral.analyze_spectral', scale='reflectance', datatype=float, value=float(median_reflectance), label='reflectance') - outputs.add_observation(variable=prefix + 'global_spectral_std', trait='pixel-wise standard deviation per band', + outputs.add_observation(sample=label, variable='global_spectral_std', + trait='pixel-wise standard deviation per band', method='plantcv.plantcv.hyperspectral.analyze_spectral', scale='None', datatype=float, value=float(std_reflectance), label='reflectance') - outputs.add_observation(variable=prefix + 'global_spectral_std', trait='pixel-wise standard deviation ', + outputs.add_observation(sample=label, variable='global_spectral_std', trait='pixel-wise standard deviation ', method='plantcv.plantcv.hyperspectral.analyze_spectral', scale='None', datatype=float, value=float(std_reflectance), label='reflectance') - outputs.add_observation(variable=prefix + 'max_reflectance', trait='maximum reflectance per band', + outputs.add_observation(sample=label, variable='max_reflectance', trait='maximum reflectance per band', method='plantcv.plantcv.hyperspectral.analyze_spectral', scale='reflectance', datatype=list, value=new_max_per_band, label=wavelength_labels) - outputs.add_observation(variable=prefix + 'min_reflectance', trait='minimum reflectance per band', + outputs.add_observation(sample=label, variable='min_reflectance', trait='minimum reflectance per band', method='plantcv.plantcv.hyperspectral.analyze_spectral', scale='reflectance', datatype=list, value=new_min_per_band, label=wavelength_labels) - outputs.add_observation(variable=prefix + 'spectral_std', trait='pixel-wise standard deviation per band', + outputs.add_observation(sample=label, variable='spectral_std', trait='pixel-wise standard deviation per band', method='plantcv.plantcv.hyperspectral.analyze_spectral', scale='None', datatype=list, value=new_std_per_band, label=wavelength_labels) - outputs.add_observation(variable=prefix + 'spectral_frequencies', trait='spectral frequencies', + outputs.add_observation(sample=label, variable='spectral_frequencies', trait='spectral frequencies', method='plantcv.plantcv.hyperspectral.analyze_spectral', scale='frequency', datatype=list, value=new_freq, label=wavelength_labels) diff --git a/plantcv/plantcv/landmark_reference_pt_dist.py b/plantcv/plantcv/landmark_reference_pt_dist.py index 2fa2d586f..0f2b8acc8 100755 --- a/plantcv/plantcv/landmark_reference_pt_dist.py +++ b/plantcv/plantcv/landmark_reference_pt_dist.py @@ -22,6 +22,7 @@ def landmark_reference_pt_dist(points_r, centroid_r, bline_r, label="default"): :param points_r: ndarray :param centroid_r: tuple :param bline_r: tuple + :param label: str """ params.device += 1 @@ -93,29 +94,29 @@ def landmark_reference_pt_dist(points_r, centroid_r, bline_r, label="default"): euc_ave_b = np.mean(euc_dist_b) ang_ave_b = np.mean(angles_b) - prefix = label + "_" - - outputs.add_observation(variable=prefix + 'vert_ave_c', trait='average vertical distance from centroid', + outputs.add_observation(sample=label, variable='vert_ave_c', trait='average vertical distance from centroid', method='plantcv.plantcv.landmark_reference_pt_dist', scale='pixels', datatype=float, value=vert_ave_c, label='pixels') - outputs.add_observation(variable=prefix + 'hori_ave_c', trait='average horizontal distance from centeroid', + outputs.add_observation(sample=label, variable='hori_ave_c', trait='average horizontal distance from centeroid', method='plantcv.plantcv.landmark_reference_pt_dist', scale='pixels', datatype=float, value=hori_ave_c, label='pixels') - outputs.add_observation(variable=prefix + 'euc_ave_c', trait='average euclidean distance from centroid', + outputs.add_observation(sample=label, variable='euc_ave_c', trait='average euclidean distance from centroid', method='plantcv.plantcv.landmark_reference_pt_dist', scale='pixels', datatype=float, value=euc_ave_c, label='pixels') - outputs.add_observation(variable=prefix + 'ang_ave_c', trait='average angle between landmark point and centroid', + outputs.add_observation(sample=label, variable='ang_ave_c', + trait='average angle between landmark point and centroid', method='plantcv.plantcv.landmark_reference_pt_dist', scale='degrees', datatype=float, value=ang_ave_c, label='degrees') - outputs.add_observation(variable=prefix + 'vert_ave_b', trait='average vertical distance from baseline', + outputs.add_observation(sample=label, variable='vert_ave_b', trait='average vertical distance from baseline', method='plantcv.plantcv.landmark_reference_pt_dist', scale='pixels', datatype=float, value=vert_ave_b, label='pixels') - outputs.add_observation(variable=prefix + 'hori_ave_b', trait='average horizontal distance from baseline', + outputs.add_observation(sample=label, variable='hori_ave_b', trait='average horizontal distance from baseline', method='plantcv.plantcv.landmark_reference_pt_dist', scale='pixels', datatype=float, value=hori_ave_b, label='pixels') - outputs.add_observation(variable=prefix + 'euc_ave_b', trait='average euclidean distance from baseline', + outputs.add_observation(sample=label, variable='euc_ave_b', trait='average euclidean distance from baseline', method='plantcv.plantcv.landmark_reference_pt_dist', scale='pixels', datatype=float, value=euc_ave_b, label='pixels') - outputs.add_observation(variable=prefix + 'ang_ave_b', trait='average angle between landmark point and baseline', + outputs.add_observation(sample=label, variable='ang_ave_b', + trait='average angle between landmark point and baseline', method='plantcv.plantcv.landmark_reference_pt_dist', scale='degrees', datatype=float, value=ang_ave_b, label='degrees') diff --git a/plantcv/plantcv/morphology/analyze_stem.py b/plantcv/plantcv/morphology/analyze_stem.py index aa722f082..0dd8937de 100644 --- a/plantcv/plantcv/morphology/analyze_stem.py +++ b/plantcv/plantcv/morphology/analyze_stem.py @@ -41,15 +41,13 @@ def analyze_stem(rgb_img, stem_objects, label="default"): # Calculate stem path length stem_length = cv2.arcLength(grouped_stem, False) / 2 - prefix = label + "_" - - outputs.add_observation(variable=prefix + 'stem_height', trait='vertical length of stem segments', + outputs.add_observation(sample=label, variable='stem_height', trait='vertical length of stem segments', method='plantcv.plantcv.morphology.analyze_stem', scale='pixels', datatype=float, value=height, label=None) - outputs.add_observation(variable=prefix + 'stem_angle', trait='angle of combined stem object', + outputs.add_observation(sample=label, variable='stem_angle', trait='angle of combined stem object', method='plantcv.plantcv.morphology.analyze_stem', scale='degrees', datatype=float, value=float(slope), label=None) - outputs.add_observation(variable=prefix + 'stem_length', trait='path length of combined stem object', + outputs.add_observation(sample=label, variable='stem_length', trait='path length of combined stem object', method='plantcv.plantcv.morphology.analyze_stem', scale='None', datatype=float, value=stem_length, label=None) @@ -57,7 +55,7 @@ def analyze_stem(rgb_img, stem_objects, label="default"): # Draw culm_height cv2.line(labeled_img, (int(stem_x), stem_y), (int(stem_x), stem_y + height), (0, 255, 0), params.line_thickness) # Draw combined stem angle - x_min = 0 # Set bounds for regression lines to get drawn + x_min = 0 # Set bounds for regression lines to get drawn x_max = img_x intercept1 = int(((x - x_min) * slope) + y) intercept2 = int(((x - x_max) * slope) + y) diff --git a/plantcv/plantcv/morphology/check_cycles.py b/plantcv/plantcv/morphology/check_cycles.py index 5c8359dc6..0984209e5 100644 --- a/plantcv/plantcv/morphology/check_cycles.py +++ b/plantcv/plantcv/morphology/check_cycles.py @@ -62,10 +62,8 @@ def check_cycles(skel_img, label="default"): cv2.drawContours(cycle_img, cycle_objects, i, rand_color[i], params.line_thickness, lineType=8, hierarchy=cycle_hierarchies) - prefix = label + "_" - # Store Cycle Data - outputs.add_observation(variable=prefix + 'num_cycles', trait='number of cycles', + outputs.add_observation(sample=label, variable='num_cycles', trait='number of cycles', method='plantcv.plantcv.morphology.check_cycles', scale='none', datatype=int, value=int(num_cycles), label='none') @@ -75,7 +73,7 @@ def check_cycles(skel_img, label="default"): params.device += 1 if params.debug == 'print': - print_image(cycle_img, os.path.join(params.debug_outdir, str(params.device) + prefix + '_cycles.png')) + print_image(cycle_img, os.path.join(params.debug_outdir, str(params.device) + '_cycles.png')) elif params.debug == 'plot': plot_image(cycle_img) diff --git a/plantcv/plantcv/morphology/fill_segments.py b/plantcv/plantcv/morphology/fill_segments.py index 6ff7d89d3..5cf99628c 100644 --- a/plantcv/plantcv/morphology/fill_segments.py +++ b/plantcv/plantcv/morphology/fill_segments.py @@ -22,46 +22,46 @@ def fill_segments(mask, objects, stem_objects=None, label="default"): filled_img = Filled mask :param mask: numpy.ndarray - :param object: list + :param objects: list + :param stem_objects: numpy.ndarray + :param label: str :return filled_img: numpy.ndarray """ params.device += 1 - h,w = mask.shape - markers = np.zeros((h,w)) + h, w = mask.shape + markers = np.zeros((h, w)) objects_unique = objects.copy() - if not stem_objects==None: + if stem_objects is not None: objects_unique.append(np.vstack(stem_objects)) labels = np.arange(len(objects_unique)) + 1 - for i,l in enumerate(labels): - cv2.drawContours(markers, objects_unique, i ,int(l) , 5) + for i, l in enumerate(labels): + cv2.drawContours(markers, objects_unique, i, int(l), 5) # Fill as a watershed segmentation from contours as markers - filled_mask = watershed(mask==0, markers=markers, - mask=mask!=0,compactness=0) + filled_mask = watershed(mask == 0, markers=markers, + mask=mask != 0, compactness=0) # Count area in pixels of each segment ids, counts = np.unique(filled_mask, return_counts=True) - - prefix = label + "_" - - outputs.add_observation(variable=prefix + 'segment_area', trait='segment area', + + outputs.add_observation(sample=label, variable='segment_area', trait='segment area', method='plantcv.plantcv.morphology.fill_segments', scale='pixels', datatype=list, value=counts[1:].tolist(), label=(ids[1:]-1).tolist()) rgb_vals = color_palette(num=len(labels), saved=False) - filled_img = np.zeros((h,w,3), dtype=np.uint8) + filled_img = np.zeros((h, w, 3), dtype=np.uint8) for l in labels: for ch in range(3): - filled_img[:,:,ch][filled_mask==l] = rgb_vals[l-1][ch] + filled_img[:, :, ch][filled_mask == l] = rgb_vals[l - 1][ch] if params.debug == 'print': - print_image(filled_img, os.path.join(params.debug_outdir, str(params.device) + prefix + '_filled_img.png')) + print_image(filled_img, os.path.join(params.debug_outdir, str(params.device) + '_filled_img.png')) elif params.debug == 'plot': plot_image(filled_img) diff --git a/plantcv/plantcv/morphology/find_branch_pts.py b/plantcv/plantcv/morphology/find_branch_pts.py index 09f23725a..55f7f6641 100644 --- a/plantcv/plantcv/morphology/find_branch_pts.py +++ b/plantcv/plantcv/morphology/find_branch_pts.py @@ -96,9 +96,8 @@ def find_branch_pts(skel_img, mask=None, label="default"): branch_labels.append(i) cv2.circle(branch_plot, (x, y), params.line_thickness, (255, 0, 255), -1) - prefix = label + "_" - - outputs.add_observation(variable='branch_pts', trait='list of branch-point coordinates identified from a skeleton', + outputs.add_observation(sample=label, variable='branch_pts', + trait='list of branch-point coordinates identified from a skeleton', method='plantcv.plantcv.morphology.find_branch_pts', scale='pixels', datatype=list, value=branch_list, label=branch_labels) @@ -108,7 +107,7 @@ def find_branch_pts(skel_img, mask=None, label="default"): params.device += 1 if params.debug == 'print': - print_image(branch_plot, os.path.join(params.debug_outdir, str(params.device) + prefix + '_branch_pts.png')) + print_image(branch_plot, os.path.join(params.debug_outdir, str(params.device) + '_branch_pts.png')) elif params.debug == 'plot': plot_image(branch_plot) diff --git a/plantcv/plantcv/morphology/find_tips.py b/plantcv/plantcv/morphology/find_tips.py index e4998bae9..6b5abd160 100644 --- a/plantcv/plantcv/morphology/find_tips.py +++ b/plantcv/plantcv/morphology/find_tips.py @@ -79,10 +79,7 @@ def find_tips(skel_img, mask=None, label="default"): tip_labels.append(i) cv2.circle(tip_plot, (x, y), params.line_thickness, (0, 255, 0), -1) - - prefix = label + "_" - - outputs.add_observation(variable=prefix + 'tips', trait='list of tip coordinates identified from a skeleton', + outputs.add_observation(sample=label, variable='tips', trait='list of tip coordinates identified from a skeleton', method='plantcv.plantcv.morphology.find_tips', scale='pixels', datatype=list, value=tip_list, label=tip_labels) @@ -92,7 +89,7 @@ def find_tips(skel_img, mask=None, label="default"): params.device += 1 if params.debug == 'print': - print_image(tip_plot, os.path.join(params.debug_outdir, str(params.device) + prefix + '_skeleton_tips.png')) + print_image(tip_plot, os.path.join(params.debug_outdir, str(params.device) + '_skeleton_tips.png')) elif params.debug == 'plot': plot_image(tip_plot) diff --git a/plantcv/plantcv/morphology/segment_angle.py b/plantcv/plantcv/morphology/segment_angle.py index 8f24a7154..fa30640a2 100644 --- a/plantcv/plantcv/morphology/segment_angle.py +++ b/plantcv/plantcv/morphology/segment_angle.py @@ -76,9 +76,7 @@ def segment_angle(segmented_img, objects, label="default"): # segment_label = "ID" + str(i) segment_ids.append(i) - prefix = label + "_" - - outputs.add_observation(variable=prefix + 'segment_angle', trait='segment angle', + outputs.add_observation(sample=label, variable='segment_angle', trait='segment angle', method='plantcv.plantcv.morphology.segment_angle', scale='degrees', datatype=list, value=segment_angles, label=segment_ids) @@ -86,8 +84,7 @@ def segment_angle(segmented_img, objects, label="default"): params.device += 1 if params.debug == 'print': - print_image(labeled_img, os.path.join(params.debug_outdir, str(params.device) + - prefix + '_segmented_angles.png')) + print_image(labeled_img, os.path.join(params.debug_outdir, str(params.device) + '_segmented_angles.png')) elif params.debug == 'plot': plot_image(labeled_img) diff --git a/plantcv/plantcv/morphology/segment_curvature.py b/plantcv/plantcv/morphology/segment_curvature.py index fce0a430a..4a6d76598 100644 --- a/plantcv/plantcv/morphology/segment_curvature.py +++ b/plantcv/plantcv/morphology/segment_curvature.py @@ -85,9 +85,7 @@ def segment_curvature(segmented_img, objects, label="default"): # segment_label = "ID" + str(i) segment_ids.append(i) - prefix = label + "_" - - outputs.add_observation(variable=prefix + 'segment_curvature', trait='segment curvature', + outputs.add_observation(sample=label, variable='segment_curvature', trait='segment curvature', method='plantcv.plantcv.morphology.segment_curvature', scale='none', datatype=list, value=curvature_measure, label=segment_ids) @@ -95,8 +93,7 @@ def segment_curvature(segmented_img, objects, label="default"): params.device += 1 if params.debug == 'print': - print_image(labeled_img, os.path.join(params.debug_outdir, str(params.device) + prefix + - '_segment_curvature.png')) + print_image(labeled_img, os.path.join(params.debug_outdir, str(params.device) + '_segment_curvature.png')) elif params.debug == 'plot': plot_image(labeled_img) diff --git a/plantcv/plantcv/morphology/segment_euclidean_length.py b/plantcv/plantcv/morphology/segment_euclidean_length.py index d5f048033..6f217a768 100644 --- a/plantcv/plantcv/morphology/segment_euclidean_length.py +++ b/plantcv/plantcv/morphology/segment_euclidean_length.py @@ -81,9 +81,7 @@ def segment_euclidean_length(segmented_img, objects, label="default"): # segment_label = "ID" + str(c) segment_ids.append(c) - prefix = label + "_" - - outputs.add_observation(variable=prefix + 'segment_eu_length', trait='segment euclidean length', + outputs.add_observation(sample=label, variable='segment_eu_length', trait='segment euclidean length', method='plantcv.plantcv.morphology.segment_euclidean_length', scale='pixels', datatype=list, value=segment_lengths, label=segment_ids) @@ -91,8 +89,7 @@ def segment_euclidean_length(segmented_img, objects, label="default"): params.device += 1 if params.debug == 'print': - print_image(labeled_img, os.path.join(params.debug_outdir, str(params.device) + prefix + - '_segment_eu_lengths.png')) + print_image(labeled_img, os.path.join(params.debug_outdir, str(params.device) + '_segment_eu_lengths.png')) elif params.debug == 'plot': plot_image(labeled_img) diff --git a/plantcv/plantcv/morphology/segment_insertion_angle.py b/plantcv/plantcv/morphology/segment_insertion_angle.py index dfbd2ec91..370412678 100644 --- a/plantcv/plantcv/morphology/segment_insertion_angle.py +++ b/plantcv/plantcv/morphology/segment_insertion_angle.py @@ -96,7 +96,7 @@ def segment_insertion_angle(skel_img, segmented_img, leaf_objects, stem_objects, segment_plot = np.zeros(segmented_img.shape[:2], np.uint8) cv2.drawContours(segment_plot, obj, -1, 255, 1, lineType=8) segment_plot = dilate(segment_plot, 3, 1) - #tips = dilate(tips, 3, 1) + # tips = dilate(tips, 3, 1) overlap_img = logical_and(segment_plot, tips) # If none of the tips are within a segment_end then it's an insertion segment @@ -186,9 +186,7 @@ def segment_insertion_angle(skel_img, segmented_img, leaf_objects, stem_objects, # segment_label = "ID" + str(i) segment_ids.append(i) - prefix = label + "_" - - outputs.add_observation(variable=prefix + 'segment_insertion_angle', trait='segment insertion angle', + outputs.add_observation(sample=label, variable='segment_insertion_angle', trait='segment insertion angle', method='plantcv.plantcv.morphology.segment_insertion_angle', scale='degrees', datatype=list, value=all_intersection_angles, label=segment_ids) @@ -199,7 +197,7 @@ def segment_insertion_angle(skel_img, segmented_img, leaf_objects, stem_objects, if params.debug == 'print': print_image(labeled_img, - os.path.join(params.debug_outdir, str(params.device) + prefix + '_segment_insertion_angles.png')) + os.path.join(params.debug_outdir, str(params.device) + '_segment_insertion_angles.png')) elif params.debug == 'plot': plot_image(labeled_img) diff --git a/plantcv/plantcv/morphology/segment_path_length.py b/plantcv/plantcv/morphology/segment_path_length.py index 174a51ebb..7aaa6fa8a 100644 --- a/plantcv/plantcv/morphology/segment_path_length.py +++ b/plantcv/plantcv/morphology/segment_path_length.py @@ -48,9 +48,7 @@ def segment_path_length(segmented_img, objects, label="default"): fontScale=params.text_size, color=(150, 150, 150), thickness=params.text_thickness) segment_ids.append(c) - prefix = label + "_" - - outputs.add_observation(variable=prefix + 'segment_path_length', trait='segment path length', + outputs.add_observation(sample=label, variable='segment_path_length', trait='segment path length', method='plantcv.plantcv.morphology.segment_path_length', scale='pixels', datatype=list, value=segment_lengths, label=segment_ids) @@ -58,8 +56,7 @@ def segment_path_length(segmented_img, objects, label="default"): params.device += 1 if params.debug == 'print': - print_image(labeled_img, os.path.join(params.debug_outdir, str(params.device) + prefix + - '_segment_path_lengths.png')) + print_image(labeled_img, os.path.join(params.debug_outdir, str(params.device) + '_segment_path_lengths.png')) elif params.debug == 'plot': plot_image(labeled_img) diff --git a/plantcv/plantcv/morphology/segment_tangent_angle.py b/plantcv/plantcv/morphology/segment_tangent_angle.py index 64127a7c3..73b746440 100644 --- a/plantcv/plantcv/morphology/segment_tangent_angle.py +++ b/plantcv/plantcv/morphology/segment_tangent_angle.py @@ -125,9 +125,7 @@ def segment_tangent_angle(segmented_img, objects, size, label="default"): # segment_label = "ID" + str(i) segment_ids.append(i) - prefix = label + "_" - - outputs.add_observation(variable=prefix + 'segment_tangent_angle', trait='segment tangent angle', + outputs.add_observation(sample=label, variable='segment_tangent_angle', trait='segment tangent angle', method='plantcv.plantcv.morphology.segment_tangent_angle', scale='degrees', datatype=list, value=intersection_angles, label=segment_ids) @@ -135,8 +133,7 @@ def segment_tangent_angle(segmented_img, objects, size, label="default"): params.device += 1 if params.debug == 'print': - print_image(labeled_img, os.path.join(params.debug_outdir, str(params.device) + prefix + - '_segment_tangent_angles.png')) + print_image(labeled_img, os.path.join(params.debug_outdir, str(params.device) + '_segment_tangent_angles.png')) elif params.debug == 'plot': plot_image(labeled_img) diff --git a/plantcv/plantcv/photosynthesis/analyze_fvfm.py b/plantcv/plantcv/photosynthesis/analyze_fvfm.py index a872513a6..9a3077e3e 100755 --- a/plantcv/plantcv/photosynthesis/analyze_fvfm.py +++ b/plantcv/plantcv/photosynthesis/analyze_fvfm.py @@ -89,30 +89,27 @@ def analyze_fvfm(fdark, fmin, fmax, mask, bins=256, label="default"): x=.15, y=205, size=8, color='green')) analysis_images.append(fvfm_hist_fig) - prefix = label + "_" - if params.debug == 'print': - print_image(fmin_mask, os.path.join(params.debug_outdir, str(params.device) + prefix + '_fmin_mask.png')) - print_image(fmax_mask, os.path.join(params.debug_outdir, str(params.device) + prefix + '_fmax_mask.png')) - print_image(fv, os.path.join(params.debug_outdir, str(params.device) + prefix + '_fv_convert.png')) - fvfm_hist_fig.save(os.path.join(params.debug_outdir, str(params.device) + prefix + '_fv_hist.png'), - verbose=False) + print_image(fmin_mask, os.path.join(params.debug_outdir, str(params.device) + '_fmin_mask.png')) + print_image(fmax_mask, os.path.join(params.debug_outdir, str(params.device) + '_fmax_mask.png')) + print_image(fv, os.path.join(params.debug_outdir, str(params.device) + '_fv_convert.png')) + fvfm_hist_fig.save(os.path.join(params.debug_outdir, str(params.device) + '_fv_hist.png'), verbose=False) elif params.debug == 'plot': plot_image(fmin_mask, cmap='gray') plot_image(fmax_mask, cmap='gray') plot_image(fv, cmap='gray') print(fvfm_hist_fig) - outputs.add_observation(variable=prefix + 'fvfm_hist', trait='Fv/Fm frequencies', + outputs.add_observation(sample=label, variable='fvfm_hist', trait='Fv/Fm frequencies', method='plantcv.plantcv.fluor_fvfm', scale='none', datatype=list, value=fvfm_hist.tolist(), label=np.around(midpoints, decimals=len(str(bins))).tolist()) - outputs.add_observation(variable=prefix + 'fvfm_hist_peak', trait='peak Fv/Fm value', + outputs.add_observation(sample=label, variable='fvfm_hist_peak', trait='peak Fv/Fm value', method='plantcv.plantcv.fluor_fvfm', scale='none', datatype=float, value=float(max_bin), label='none') - outputs.add_observation(variable=prefix + 'fvfm_median', trait='Fv/Fm median', + outputs.add_observation(sample=label, variable='fvfm_median', trait='Fv/Fm median', method='plantcv.plantcv.fluor_fvfm', scale='none', datatype=float, value=float(np.around(fvfm_median, decimals=4)), label='none') - outputs.add_observation(variable=prefix + 'fdark_passed_qc', trait='Fdark passed QC', + outputs.add_observation(sample=label, variable='fdark_passed_qc', trait='Fdark passed QC', method='plantcv.plantcv.fluor_fvfm', scale='none', datatype=bool, value=qc_fdark, label='none') diff --git a/plantcv/plantcv/report_size_marker_area.py b/plantcv/plantcv/report_size_marker_area.py index 9c2218f4c..09e6493e8 100755 --- a/plantcv/plantcv/report_size_marker_area.py +++ b/plantcv/plantcv/report_size_marker_area.py @@ -121,23 +121,23 @@ def report_size_marker_area(img, roi_contour, roi_hierarchy, marker='define', ob # Reset debug mode params.debug = debug - prefix = label + "_" - if params.debug == 'print': - print_image(ref_img, os.path.join(params.debug_outdir, str(params.device) + prefix + '_marker_shape.png')) + print_image(ref_img, os.path.join(params.debug_outdir, str(params.device) + '_marker_shape.png')) elif params.debug == 'plot': plot_image(ref_img) - outputs.add_observation(variable=prefix + 'marker_area', trait='marker area', + outputs.add_observation(sample=label, variable='marker_area', trait='marker area', method='plantcv.plantcv.report_size_marker_area', scale='pixels', datatype=int, value=marker_area, label='pixels') - outputs.add_observation(variable=prefix + 'marker_ellipse_major_axis', trait='marker ellipse major axis length', + outputs.add_observation(sample=label, variable='marker_ellipse_major_axis', + trait='marker ellipse major axis length', method='plantcv.plantcv.report_size_marker_area', scale='pixels', datatype=int, value=major_axis_length, label='pixels') - outputs.add_observation(variable=prefix + 'marker_ellipse_minor_axis', trait='marker ellipse minor axis length', + outputs.add_observation(sample=label, variable='marker_ellipse_minor_axis', + trait='marker ellipse minor axis length', method='plantcv.plantcv.report_size_marker_area', scale='pixels', datatype=int, value=minor_axis_length, label='pixels') - outputs.add_observation(variable=prefix + 'marker_ellipse_eccentricity', trait='marker ellipse eccentricity', + outputs.add_observation(sample=label, variable='marker_ellipse_eccentricity', trait='marker ellipse eccentricity', method='plantcv.plantcv.report_size_marker_area', scale='none', datatype=float, value=eccentricity, label='none') diff --git a/plantcv/plantcv/transform/color_correction.py b/plantcv/plantcv/transform/color_correction.py index 984bc46bd..98325db72 100644 --- a/plantcv/plantcv/transform/color_correction.py +++ b/plantcv/plantcv/transform/color_correction.py @@ -763,19 +763,15 @@ def find_color_card(rgb_img, threshold_type='adaptgauss', threshvalue=125, blurr chip_height = None chip_width = None # Store into global measurements - if label == None: - prefix = "" - else: - prefix = label + "_" - outputs.add_observation(variable=prefix + 'color_chip_size', trait='size of color card chips identified', + outputs.add_observation(sample=label, variable='color_chip_size', trait='size of color card chips identified', method='plantcv.plantcv.transform.find_color_card', scale='none', datatype=float, value=chip_size, label=str(record_chip_size)) method = record_chip_size.lower() - outputs.add_observation(variable=prefix + f'{method}_color_chip_height', + outputs.add_observation(sample=label, variable=f'{method}_color_chip_height', trait=f'{method} height of color card chips identified', method='plantcv.plantcv.transform.find_color_card', scale='none', datatype=float, value=chip_height, label=str(record_chip_size)) - outputs.add_observation(variable=prefix + f'{method}_color_chip_width', + outputs.add_observation(sample=label, variable=f'{method}_color_chip_width', trait=f'{method} size of color card chips identified', method='plantcv.plantcv.transform.find_color_card', scale='none', datatype=float, value=chip_width, label=str(record_chip_size)) diff --git a/plantcv/plantcv/watershed.py b/plantcv/plantcv/watershed.py index 7d3313bb2..18c27a8aa 100755 --- a/plantcv/plantcv/watershed.py +++ b/plantcv/plantcv/watershed.py @@ -43,9 +43,9 @@ def watershed_segmentation(rgb_img, mask, distance=10, label=None): dist_transform = cv2.distanceTransformWithLabels(mask, cv2.DIST_L2, maskSize=0)[0] - localMax = peak_local_max(dist_transform, indices=False, min_distance=distance, labels=mask) + local_max = peak_local_max(dist_transform, indices=False, min_distance=distance, labels=mask) - markers = ndi.label(localMax, structure=np.ones((3, 3)))[0] + markers = ndi.label(local_max, structure=np.ones((3, 3)))[0] dist_transform1 = -dist_transform labels = watershed(dist_transform1, markers, mask=mask) @@ -61,22 +61,16 @@ def watershed_segmentation(rgb_img, mask, distance=10, label=None): estimated_object_count = len(np.unique(markers)) - 1 - if label == None: - prefix = "" - else: - prefix = label + "_" - # Reset debug mode params.debug = debug if params.debug == 'print': - print_image(dist_transform, os.path.join(params.debug_outdir, str(params.device) + prefix + - '_watershed_dist_img.png')) - print_image(joined, os.path.join(params.debug_outdir, str(params.device) + prefix + '_watershed_img.png')) + 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) - outputs.add_observation(variable=prefix + 'estimated_object_count', trait='estimated object count', + outputs.add_observation(sample=label, variable='estimated_object_count', trait='estimated object count', method='plantcv.plantcv.watershed', scale='none', datatype=int, value=estimated_object_count, label='none') diff --git a/plantcv/plantcv/within_frame.py b/plantcv/plantcv/within_frame.py index 07d4f15d2..cd89b50a0 100644 --- a/plantcv/plantcv/within_frame.py +++ b/plantcv/plantcv/within_frame.py @@ -43,9 +43,7 @@ def within_frame(mask, border_width=1, label="default"): out_of_bounds = bool(np.count_nonzero(border_pxs)) in_bounds = not out_of_bounds - prefix = label + "_" - - outputs.add_observation(variable=prefix + 'in_bounds', trait='whether the plant goes out of bounds ', + outputs.add_observation(sample=label, variable='in_bounds', trait='whether the plant goes out of bounds ', method='plantcv.plantcv.within_frame', scale='none', datatype=bool, value=in_bounds, label='none') diff --git a/plantcv/plantcv/x_axis_pseudolandmarks.py b/plantcv/plantcv/x_axis_pseudolandmarks.py index 7f1b1a11f..36f4c57fb 100755 --- a/plantcv/plantcv/x_axis_pseudolandmarks.py +++ b/plantcv/plantcv/x_axis_pseudolandmarks.py @@ -218,15 +218,13 @@ def x_axis_pseudolandmarks(img, obj, mask, label="default"): for pt in center_v: center_v_list.append(pt[0].tolist()) - prefix = label + "_" - - outputs.add_observation(variable=prefix + 'top_lmk', trait='top landmark coordinates', + outputs.add_observation(sample=label, variable='top_lmk', trait='top landmark coordinates', method='plantcv.plantcv.x_axis_pseudolandmarks', scale='none', datatype=tuple, value=tuple(top_list), label='none') - outputs.add_observation(variable=prefix + 'bottom_lmk', trait='bottom landmark coordinates', + outputs.add_observation(sample=label, variable='bottom_lmk', trait='bottom landmark coordinates', method='plantcv.plantcv.x_axis_pseudolandmarks', scale='none', datatype=tuple, value=tuple(bottom_list), label='none') - outputs.add_observation(variable=prefix + 'center_v_lmk', trait='center vertical landmark coordinates', + outputs.add_observation(sample=label, variable='center_v_lmk', trait='center vertical landmark coordinates', method='plantcv.plantcv.x_axis_pseudolandmarks', scale='none', datatype=tuple, value=tuple(center_v_list), label='none') diff --git a/plantcv/plantcv/y_axis_pseudolandmarks.py b/plantcv/plantcv/y_axis_pseudolandmarks.py index 445a2c365..ae1d616ca 100755 --- a/plantcv/plantcv/y_axis_pseudolandmarks.py +++ b/plantcv/plantcv/y_axis_pseudolandmarks.py @@ -215,15 +215,13 @@ def y_axis_pseudolandmarks(img, obj, mask, label="default"): for pt in center_h: center_h_list.append(pt[0].tolist()) - prefix = label + "_" - - outputs.add_observation(variable=prefix + 'left_lmk', trait='left landmark coordinates', + outputs.add_observation(sample=label, variable='left_lmk', trait='left landmark coordinates', method='plantcv.plantcv.x_axis_pseudolandmarks', scale='none', datatype=tuple, value=tuple(left_list), label='none') - outputs.add_observation(variable=prefix + 'right_lmk', trait='right landmark coordinates', + outputs.add_observation(sample=label, variable='right_lmk', trait='right landmark coordinates', method='plantcv.plantcv.x_axis_pseudolandmarks', scale='none', datatype=tuple, value=tuple(right_list), label='none') - outputs.add_observation(variable=prefix + 'center_h_lmk', trait='center horizontal landmark coordinates', + outputs.add_observation(sample=label, variable='center_h_lmk', trait='center horizontal landmark coordinates', method='plantcv.plantcv.x_axis_pseudolandmarks', scale='none', datatype=tuple, value=tuple(center_h_list), label='none') From c84439060ea1753a33dc2db454a514b1bbcbfaa0 Mon Sep 17 00:00:00 2001 From: nfahlgren Date: Thu, 11 Feb 2021 23:15:29 -0600 Subject: [PATCH 125/137] Update test data with sample labels --- tests/parallel_data/appended_results.json | 253 +++++++++++++++++- tests/parallel_data/new_result.json | 162 ++++++++++- .../VIS_SV_0_z1_h1_g0_e82_117770.jpg.txt | 92 ++++++- tests/parallel_data/valid.json | 64 ++++- 4 files changed, 567 insertions(+), 4 deletions(-) diff --git a/tests/parallel_data/appended_results.json b/tests/parallel_data/appended_results.json index 100b415aa..0e4fe56df 100644 --- a/tests/parallel_data/appended_results.json +++ b/tests/parallel_data/appended_results.json @@ -1 +1,252 @@ -{"variables": {"camera": {"category": "metadata", "datatype": ""}, "imgtype": {"category": "metadata", "datatype": ""}, "zoom": {"category": "metadata", "datatype": ""}, "exposure": {"category": "metadata", "datatype": ""}, "gain": {"category": "metadata", "datatype": ""}, "frame": {"category": "metadata", "datatype": ""}, "lifter": {"category": "metadata", "datatype": ""}, "timestamp": {"category": "metadata", "datatype": ""}, "id": {"category": "metadata", "datatype": ""}, "plantbarcode": {"category": "metadata", "datatype": ""}, "treatment": {"category": "metadata", "datatype": ""}, "cartag": {"category": "metadata", "datatype": ""}, "measurementlabel": {"category": "metadata", "datatype": ""}, "other": {"category": "metadata", "datatype": ""}, "image": {"category": "metadata", "datatype": ""}, "test": {"category": "observations", "datatype": ""}}, "entities": [{"metadata": {"camera": {"label": "camera identifier", "datatype": "", "value": "SV"}, "imgtype": {"label": "image type", "datatype": "", "value": "VIS"}, "zoom": {"label": "camera zoom setting", "datatype": "", "value": "z1"}, "exposure": {"label": "camera exposure setting", "datatype": "", "value": "e82"}, "gain": {"label": "camera gain setting", "datatype": "", "value": "g0"}, "frame": {"label": "image series frame identifier", "datatype": "", "value": "0"}, "lifter": {"label": "imaging platform height setting", "datatype": "", "value": "h1"}, "timestamp": {"label": "datetime of image", "datatype": "", "value": "2014-10-22 17:49:35.187"}, "id": {"label": "image identifier", "datatype": "", "value": "117770"}, "plantbarcode": {"label": "plant barcode identifier", "datatype": "", "value": "Ca031AA010564"}, "treatment": {"label": "treatment identifier", "datatype": "", "value": "none"}, "cartag": {"label": "plant carrier identifier", "datatype": "", "value": "2143"}, "measurementlabel": {"label": "experiment identifier", "datatype": "", "value": "C002ch_092214_biomass"}, "other": {"label": "other identifier", "datatype": "", "value": "none"}, "image": {"label": "image file", "datatype": "", "value": "./snapshots/snapshot57383/VIS_SV_0_z1_h1_g0_e82_117770.jpg"}}, "observations": {"test": {"trait": "test trait", "method": "test", "scale": "none", "datatype": "", "value": "test", "label": "none"}}}, {"metadata": {"camera": {"label": "camera identifier", "datatype": "", "value": "SV"}, "imgtype": {"label": "image type", "datatype": "", "value": "VIS"}, "zoom": {"label": "camera zoom setting", "datatype": "", "value": "z1"}, "exposure": {"label": "camera exposure setting", "datatype": "", "value": "e82"}, "gain": {"label": "camera gain setting", "datatype": "", "value": "g0"}, "frame": {"label": "image series frame identifier", "datatype": "", "value": "0"}, "lifter": {"label": "imaging platform height setting", "datatype": "", "value": "h1"}, "timestamp": {"label": "datetime of image", "datatype": "", "value": "2014-10-22 17:49:35.187"}, "id": {"label": "image identifier", "datatype": "", "value": "117770"}, "plantbarcode": {"label": "plant barcode identifier", "datatype": "", "value": "Ca031AA010564"}, "treatment": {"label": "treatment identifier", "datatype": "", "value": "none"}, "cartag": {"label": "plant carrier identifier", "datatype": "", "value": "2143"}, "measurementlabel": {"label": "experiment identifier", "datatype": "", "value": "C002ch_092214_biomass"}, "other": {"label": "other identifier", "datatype": "", "value": "none"}, "image": {"label": "image file", "datatype": "", "value": "./snapshots/snapshot57383/VIS_SV_0_z1_h1_g0_e82_117770.jpg"}}, "observations": {"test": {"trait": "test trait", "method": "test", "scale": "none", "datatype": "", "value": "test", "label": "none"}}}]} \ No newline at end of file +{ + "variables": { + "camera": { + "category": "metadata", + "datatype": "" + }, + "imgtype": { + "category": "metadata", + "datatype": "" + }, + "zoom": { + "category": "metadata", + "datatype": "" + }, + "exposure": { + "category": "metadata", + "datatype": "" + }, + "gain": { + "category": "metadata", + "datatype": "" + }, + "frame": { + "category": "metadata", + "datatype": "" + }, + "lifter": { + "category": "metadata", + "datatype": "" + }, + "timestamp": { + "category": "metadata", + "datatype": "" + }, + "id": { + "category": "metadata", + "datatype": "" + }, + "plantbarcode": { + "category": "metadata", + "datatype": "" + }, + "treatment": { + "category": "metadata", + "datatype": "" + }, + "cartag": { + "category": "metadata", + "datatype": "" + }, + "measurementlabel": { + "category": "metadata", + "datatype": "" + }, + "other": { + "category": "metadata", + "datatype": "" + }, + "image": { + "category": "metadata", + "datatype": "" + }, + "test": { + "category": "observations", + "datatype": "" + } + }, + "entities": [ + { + "metadata": { + "camera": { + "label": "camera identifier", + "datatype": "", + "value": "SV" + }, + "imgtype": { + "label": "image type", + "datatype": "", + "value": "VIS" + }, + "zoom": { + "label": "camera zoom setting", + "datatype": "", + "value": "z1" + }, + "exposure": { + "label": "camera exposure setting", + "datatype": "", + "value": "e82" + }, + "gain": { + "label": "camera gain setting", + "datatype": "", + "value": "g0" + }, + "frame": { + "label": "image series frame identifier", + "datatype": "", + "value": "0" + }, + "lifter": { + "label": "imaging platform height setting", + "datatype": "", + "value": "h1" + }, + "timestamp": { + "label": "datetime of image", + "datatype": "", + "value": "2014-10-22 17:49:35.187" + }, + "id": { + "label": "image identifier", + "datatype": "", + "value": "117770" + }, + "plantbarcode": { + "label": "plant barcode identifier", + "datatype": "", + "value": "Ca031AA010564" + }, + "treatment": { + "label": "treatment identifier", + "datatype": "", + "value": "none" + }, + "cartag": { + "label": "plant carrier identifier", + "datatype": "", + "value": "2143" + }, + "measurementlabel": { + "label": "experiment identifier", + "datatype": "", + "value": "C002ch_092214_biomass" + }, + "other": { + "label": "other identifier", + "datatype": "", + "value": "none" + }, + "image": { + "label": "image file", + "datatype": "", + "value": "./snapshots/snapshot57383/VIS_SV_0_z1_h1_g0_e82_117770.jpg" + } + }, + "observations": { + "prefix": { + "test": { + "trait": "test trait", + "method": "test", + "scale": "none", + "datatype": "", + "value": "test", + "label": "none" + } + } + } + }, + { + "metadata": { + "camera": { + "label": "camera identifier", + "datatype": "", + "value": "SV" + }, + "imgtype": { + "label": "image type", + "datatype": "", + "value": "VIS" + }, + "zoom": { + "label": "camera zoom setting", + "datatype": "", + "value": "z1" + }, + "exposure": { + "label": "camera exposure setting", + "datatype": "", + "value": "e82" + }, + "gain": { + "label": "camera gain setting", + "datatype": "", + "value": "g0" + }, + "frame": { + "label": "image series frame identifier", + "datatype": "", + "value": "0" + }, + "lifter": { + "label": "imaging platform height setting", + "datatype": "", + "value": "h1" + }, + "timestamp": { + "label": "datetime of image", + "datatype": "", + "value": "2014-10-22 17:49:35.187" + }, + "id": { + "label": "image identifier", + "datatype": "", + "value": "117770" + }, + "plantbarcode": { + "label": "plant barcode identifier", + "datatype": "", + "value": "Ca031AA010564" + }, + "treatment": { + "label": "treatment identifier", + "datatype": "", + "value": "none" + }, + "cartag": { + "label": "plant carrier identifier", + "datatype": "", + "value": "2143" + }, + "measurementlabel": { + "label": "experiment identifier", + "datatype": "", + "value": "C002ch_092214_biomass" + }, + "other": { + "label": "other identifier", + "datatype": "", + "value": "none" + }, + "image": { + "label": "image file", + "datatype": "", + "value": "./snapshots/snapshot57383/VIS_SV_0_z1_h1_g0_e82_117770.jpg" + } + }, + "observations": { + "prefix": { + "test": { + "trait": "test trait", + "method": "test", + "scale": "none", + "datatype": "", + "value": "test", + "label": "none" + } + } + } + } + ] +} diff --git a/tests/parallel_data/new_result.json b/tests/parallel_data/new_result.json index f4e8ef81a..417d4a11b 100644 --- a/tests/parallel_data/new_result.json +++ b/tests/parallel_data/new_result.json @@ -1 +1,161 @@ -{"variables": {"camera": {"category": "metadata", "datatype": ""}, "imgtype": {"category": "metadata", "datatype": ""}, "zoom": {"category": "metadata", "datatype": ""}, "exposure": {"category": "metadata", "datatype": ""}, "gain": {"category": "metadata", "datatype": ""}, "frame": {"category": "metadata", "datatype": ""}, "lifter": {"category": "metadata", "datatype": ""}, "timestamp": {"category": "metadata", "datatype": ""}, "id": {"category": "metadata", "datatype": ""}, "plantbarcode": {"category": "metadata", "datatype": ""}, "treatment": {"category": "metadata", "datatype": ""}, "cartag": {"category": "metadata", "datatype": ""}, "measurementlabel": {"category": "metadata", "datatype": ""}, "other": {"category": "metadata", "datatype": ""}, "image": {"category": "metadata", "datatype": ""}, "test": {"category": "observations", "datatype": ""}}, "entities": [{"metadata": {"camera": {"label": "camera identifier", "datatype": "", "value": "SV"}, "imgtype": {"label": "image type", "datatype": "", "value": "VIS"}, "zoom": {"label": "camera zoom setting", "datatype": "", "value": "z1"}, "exposure": {"label": "camera exposure setting", "datatype": "", "value": "e82"}, "gain": {"label": "camera gain setting", "datatype": "", "value": "g0"}, "frame": {"label": "image series frame identifier", "datatype": "", "value": "0"}, "lifter": {"label": "imaging platform height setting", "datatype": "", "value": "h1"}, "timestamp": {"label": "datetime of image", "datatype": "", "value": "2014-10-22 17:49:35.187"}, "id": {"label": "image identifier", "datatype": "", "value": "117770"}, "plantbarcode": {"label": "plant barcode identifier", "datatype": "", "value": "Ca031AA010564"}, "treatment": {"label": "treatment identifier", "datatype": "", "value": "none"}, "cartag": {"label": "plant carrier identifier", "datatype": "", "value": "2143"}, "measurementlabel": {"label": "experiment identifier", "datatype": "", "value": "C002ch_092214_biomass"}, "other": {"label": "other identifier", "datatype": "", "value": "none"}, "image": {"label": "image file", "datatype": "", "value": "./snapshots/snapshot57383/VIS_SV_0_z1_h1_g0_e82_117770.jpg"}}, "observations": {"test": {"trait": "test trait", "method": "test", "scale": "none", "datatype": "", "value": "test", "label": "none"}}}]} \ No newline at end of file +{ + "variables": { + "camera": { + "category": "metadata", + "datatype": "" + }, + "imgtype": { + "category": "metadata", + "datatype": "" + }, + "zoom": { + "category": "metadata", + "datatype": "" + }, + "exposure": { + "category": "metadata", + "datatype": "" + }, + "gain": { + "category": "metadata", + "datatype": "" + }, + "frame": { + "category": "metadata", + "datatype": "" + }, + "lifter": { + "category": "metadata", + "datatype": "" + }, + "timestamp": { + "category": "metadata", + "datatype": "" + }, + "id": { + "category": "metadata", + "datatype": "" + }, + "plantbarcode": { + "category": "metadata", + "datatype": "" + }, + "treatment": { + "category": "metadata", + "datatype": "" + }, + "cartag": { + "category": "metadata", + "datatype": "" + }, + "measurementlabel": { + "category": "metadata", + "datatype": "" + }, + "other": { + "category": "metadata", + "datatype": "" + }, + "image": { + "category": "metadata", + "datatype": "" + }, + "test": { + "category": "observations", + "datatype": "" + } + }, + "entities": [ + { + "metadata": { + "camera": { + "label": "camera identifier", + "datatype": "", + "value": "SV" + }, + "imgtype": { + "label": "image type", + "datatype": "", + "value": "VIS" + }, + "zoom": { + "label": "camera zoom setting", + "datatype": "", + "value": "z1" + }, + "exposure": { + "label": "camera exposure setting", + "datatype": "", + "value": "e82" + }, + "gain": { + "label": "camera gain setting", + "datatype": "", + "value": "g0" + }, + "frame": { + "label": "image series frame identifier", + "datatype": "", + "value": "0" + }, + "lifter": { + "label": "imaging platform height setting", + "datatype": "", + "value": "h1" + }, + "timestamp": { + "label": "datetime of image", + "datatype": "", + "value": "2014-10-22 17:49:35.187" + }, + "id": { + "label": "image identifier", + "datatype": "", + "value": "117770" + }, + "plantbarcode": { + "label": "plant barcode identifier", + "datatype": "", + "value": "Ca031AA010564" + }, + "treatment": { + "label": "treatment identifier", + "datatype": "", + "value": "none" + }, + "cartag": { + "label": "plant carrier identifier", + "datatype": "", + "value": "2143" + }, + "measurementlabel": { + "label": "experiment identifier", + "datatype": "", + "value": "C002ch_092214_biomass" + }, + "other": { + "label": "other identifier", + "datatype": "", + "value": "none" + }, + "image": { + "label": "image file", + "datatype": "", + "value": "./snapshots/snapshot57383/VIS_SV_0_z1_h1_g0_e82_117770.jpg" + } + }, + "observations": { + "prefix": { + "test": { + "trait": "test trait", + "method": "test", + "scale": "none", + "datatype": "", + "value": "test", + "label": "none" + } + } + } + } + ] +} diff --git a/tests/parallel_data/results/VIS_SV_0_z1_h1_g0_e82_117770.jpg.txt b/tests/parallel_data/results/VIS_SV_0_z1_h1_g0_e82_117770.jpg.txt index 193bf0576..1b5cbca8f 100644 --- a/tests/parallel_data/results/VIS_SV_0_z1_h1_g0_e82_117770.jpg.txt +++ b/tests/parallel_data/results/VIS_SV_0_z1_h1_g0_e82_117770.jpg.txt @@ -1 +1,91 @@ -{"metadata": {"camera": {"label": "camera identifier", "datatype": "", "value": "SV"}, "imgtype": {"label": "image type", "datatype": "", "value": "VIS"}, "zoom": {"label": "camera zoom setting", "datatype": "", "value": "z1"}, "exposure": {"label": "camera exposure setting", "datatype": "", "value": "e82"}, "gain": {"label": "camera gain setting", "datatype": "", "value": "g0"}, "frame": {"label": "image series frame identifier", "datatype": "", "value": "0"}, "lifter": {"label": "imaging platform height setting", "datatype": "", "value": "h1"}, "timestamp": {"label": "datetime of image", "datatype": "", "value": "2014-10-22 17:49:35.187"}, "id": {"label": "image identifier", "datatype": "", "value": "117770"}, "plantbarcode": {"label": "plant barcode identifier", "datatype": "", "value": "Ca031AA010564"}, "treatment": {"label": "treatment identifier", "datatype": "", "value": "none"}, "cartag": {"label": "plant carrier identifier", "datatype": "", "value": "2143"}, "measurementlabel": {"label": "experiment identifier", "datatype": "", "value": "C002ch_092214_biomass"}, "other": {"label": "other identifier", "datatype": "", "value": "none"}, "image": {"label": "image file", "datatype": "", "value": "./snapshots/snapshot57383/VIS_SV_0_z1_h1_g0_e82_117770.jpg"}}, "observations": {"test": {"trait": "test trait", "method": "test", "scale": "none", "datatype": "", "value": "test", "label": "none"}}} \ No newline at end of file +{ + "metadata": { + "camera": { + "label": "camera identifier", + "datatype": "", + "value": "SV" + }, + "imgtype": { + "label": "image type", + "datatype": "", + "value": "VIS" + }, + "zoom": { + "label": "camera zoom setting", + "datatype": "", + "value": "z1" + }, + "exposure": { + "label": "camera exposure setting", + "datatype": "", + "value": "e82" + }, + "gain": { + "label": "camera gain setting", + "datatype": "", + "value": "g0" + }, + "frame": { + "label": "image series frame identifier", + "datatype": "", + "value": "0" + }, + "lifter": { + "label": "imaging platform height setting", + "datatype": "", + "value": "h1" + }, + "timestamp": { + "label": "datetime of image", + "datatype": "", + "value": "2014-10-22 17:49:35.187" + }, + "id": { + "label": "image identifier", + "datatype": "", + "value": "117770" + }, + "plantbarcode": { + "label": "plant barcode identifier", + "datatype": "", + "value": "Ca031AA010564" + }, + "treatment": { + "label": "treatment identifier", + "datatype": "", + "value": "none" + }, + "cartag": { + "label": "plant carrier identifier", + "datatype": "", + "value": "2143" + }, + "measurementlabel": { + "label": "experiment identifier", + "datatype": "", + "value": "C002ch_092214_biomass" + }, + "other": { + "label": "other identifier", + "datatype": "", + "value": "none" + }, + "image": { + "label": "image file", + "datatype": "", + "value": "./snapshots/snapshot57383/VIS_SV_0_z1_h1_g0_e82_117770.jpg" + } + }, + "observations": { + "prefix": { + "test": { + "trait": "test trait", + "method": "test", + "scale": "none", + "datatype": "", + "value": "test", + "label": "none" + } + } + } +} diff --git a/tests/parallel_data/valid.json b/tests/parallel_data/valid.json index 788d8ca13..ec7538b75 100644 --- a/tests/parallel_data/valid.json +++ b/tests/parallel_data/valid.json @@ -1 +1,63 @@ -{"metadata": {}, "observations": {"horizontal_line_position": {"trait": "horizontal_line_position", "method": "plantcv.plantcv.analyze_bound_horizontal", "scale": "none", "datatype": "", "value": 1756, "label": "none"}, "height_above_bound": {"trait": "height_above_bound", "method": "plantcv.plantcv.analyze_bound_horizontal", "scale": "pixels", "datatype": "", "value": 661, "label": "pixels"}, "height_below_bound": {"trait": "height_below_bound", "method": "plantcv.plantcv.analyze_bound_horizontal", "scale": "pixels", "datatype": "", "value": 52, "label": "pixels"}, "above_bound_area": {"trait": "above_bound_area", "method": "plantcv.plantcv.analyze_bound_horizontal", "scale": "pixels", "datatype": "", "value": 62555, "label": "pixels"}, "percent_above_bound_area": {"trait": "percent_above_bound_area", "method": "plantcv.plantcv.analyze_bound_horizontal", "scale": "none", "datatype": "", "value": 98.30745536836811, "label": "none"}, "below_bound_area": {"trait": "below_bound_area", "method": "plantcv.plantcv.analyze_bound_horizontal", "scale": "pixels", "datatype": "", "value": 1077, "label": "pixels"}, "percent_bound_area_below": {"trait": "percent_bound_area_below", "method": "plantcv.plantcv.analyze_bound_horizontal", "scale": "none", "datatype": "", "value": 1.6925446316318833, "label": "none"}}} \ No newline at end of file +{ + "metadata": {}, + "observations": { + "prefix": { + "horizontal_line_position": { + "trait": "horizontal_line_position", + "method": "plantcv.plantcv.analyze_bound_horizontal", + "scale": "none", + "datatype": "", + "value": 1756, + "label": "none" + }, + "height_above_bound": { + "trait": "height_above_bound", + "method": "plantcv.plantcv.analyze_bound_horizontal", + "scale": "pixels", + "datatype": "", + "value": 661, + "label": "pixels" + }, + "height_below_bound": { + "trait": "height_below_bound", + "method": "plantcv.plantcv.analyze_bound_horizontal", + "scale": "pixels", + "datatype": "", + "value": 52, + "label": "pixels" + }, + "above_bound_area": { + "trait": "above_bound_area", + "method": "plantcv.plantcv.analyze_bound_horizontal", + "scale": "pixels", + "datatype": "", + "value": 62555, + "label": "pixels" + }, + "percent_above_bound_area": { + "trait": "percent_above_bound_area", + "method": "plantcv.plantcv.analyze_bound_horizontal", + "scale": "none", + "datatype": "", + "value": 98.30745536836811, + "label": "none" + }, + "below_bound_area": { + "trait": "below_bound_area", + "method": "plantcv.plantcv.analyze_bound_horizontal", + "scale": "pixels", + "datatype": "", + "value": 1077, + "label": "pixels" + }, + "percent_bound_area_below": { + "trait": "percent_bound_area_below", + "method": "plantcv.plantcv.analyze_bound_horizontal", + "scale": "none", + "datatype": "", + "value": 1.6925446316318833, + "label": "none" + } + } + } +} From dca478e52472952185aa6b0867443feb40574507 Mon Sep 17 00:00:00 2001 From: nfahlgren Date: Thu, 11 Feb 2021 23:41:13 -0600 Subject: [PATCH 126/137] Remove undefined variable --- plantcv/plantcv/analyze_object.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/plantcv/plantcv/analyze_object.py b/plantcv/plantcv/analyze_object.py index bc09848b2..1e166e814 100755 --- a/plantcv/plantcv/analyze_object.py +++ b/plantcv/plantcv/analyze_object.py @@ -214,7 +214,7 @@ def analyze_object(img, obj, mask, label="default"): cv2.line(ori_img, (tuple(caliper_transpose[caliper_length - 1])), (tuple(caliper_transpose[0])), (255, 0, 255), params.line_thickness) if params.debug == 'print': - print_image(ori_img, os.path.join(params.debug_outdir, str(params.device) + prefix + '_shapes.png')) + print_image(ori_img, os.path.join(params.debug_outdir, str(params.device) + '_shapes.png')) elif params.debug == 'plot': if len(np.shape(img)) == 3: plot_image(ori_img) From 2374e1b709e217e048fa791f804c6306fc1cee85 Mon Sep 17 00:00:00 2001 From: nfahlgren Date: Thu, 11 Feb 2021 23:43:52 -0600 Subject: [PATCH 127/137] Lookup measurements by sample label --- plantcv/plantcv/morphology/segment_curvature.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/plantcv/plantcv/morphology/segment_curvature.py b/plantcv/plantcv/morphology/segment_curvature.py index 4a6d76598..fa90af810 100644 --- a/plantcv/plantcv/morphology/segment_curvature.py +++ b/plantcv/plantcv/morphology/segment_curvature.py @@ -44,8 +44,8 @@ def segment_curvature(segmented_img, objects, label="default"): _ = segment_euclidean_length(segmented_img, objects, label="backend") _ = segment_path_length(segmented_img, objects, label="backend") - eu_lengths = outputs.observations['backend_segment_eu_length']['value'] - path_lengths = outputs.observations['backend_segment_path_length']['value'] + eu_lengths = outputs.observations['backend']['segment_eu_length']['value'] + path_lengths = outputs.observations['backend']['segment_path_length']['value'] curvature_measure = [float(x / y) for x, y in zip(path_lengths, eu_lengths)] # Create a color scale, use a previously stored scale if available rand_color = color_palette(num=len(objects), saved=True) From 36b87d9d40d5945f5701256ee4f9f442da33742d Mon Sep 17 00:00:00 2001 From: nfahlgren Date: Thu, 11 Feb 2021 23:44:39 -0600 Subject: [PATCH 128/137] Remove undefined variable --- plantcv/plantcv/morphology/analyze_stem.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/plantcv/plantcv/morphology/analyze_stem.py b/plantcv/plantcv/morphology/analyze_stem.py index 0dd8937de..142809f14 100644 --- a/plantcv/plantcv/morphology/analyze_stem.py +++ b/plantcv/plantcv/morphology/analyze_stem.py @@ -64,7 +64,7 @@ def analyze_stem(rgb_img, stem_objects, label="default"): else: cv2.line(labeled_img, (x_max - 1, intercept2), (x_min, intercept1), (0, 0, 255), 1) if params.debug == 'print': - print_image(labeled_img, os.path.join(params.debug_outdir, str(params.device) + prefix + 'stem_analze.png')) + print_image(labeled_img, os.path.join(params.debug_outdir, str(params.device) + 'stem_analze.png')) elif params.debug == 'plot': plot_image(labeled_img) From a9e228956240eb1837088ad8496fcbcd10bb67c0 Mon Sep 17 00:00:00 2001 From: nfahlgren Date: Thu, 11 Feb 2021 23:51:27 -0600 Subject: [PATCH 129/137] Set default label --- plantcv/plantcv/transform/color_correction.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/plantcv/plantcv/transform/color_correction.py b/plantcv/plantcv/transform/color_correction.py index 98325db72..eced97fad 100644 --- a/plantcv/plantcv/transform/color_correction.py +++ b/plantcv/plantcv/transform/color_correction.py @@ -481,7 +481,7 @@ def quick_color_check(target_matrix, source_matrix, num_chips): def find_color_card(rgb_img, threshold_type='adaptgauss', threshvalue=125, blurry=False, background='dark', - record_chip_size="median", label=None): + record_chip_size="median", label="default"): """Automatically detects a color card and output info to use in create_color_card_mask function Algorithm written by Brandon Hurr. Updated and implemented into PlantCV by Haley Schuhl. @@ -496,7 +496,7 @@ def find_color_card(rgb_img, threshold_type='adaptgauss', threshvalue=125, blurr is a dark background record_chip_size = Optional str for choosing chip size measurement to be recorded, either "median", "mean", or None - label = optional label parameter, modifies the variable name of observations recorded + label = optional label parameter, modifies the variable name of observations recorded (default 'default') Returns: df = Dataframe containing information about the filtered contours From 837bde8566314868d24b840e09f1b3aaac5417f7 Mon Sep 17 00:00:00 2001 From: nfahlgren Date: Fri, 12 Feb 2021 00:04:15 -0600 Subject: [PATCH 130/137] Update tests to utilize sample labels --- tests/tests.py | 70 +++++++++++++++++++++++++------------------------- 1 file changed, 35 insertions(+), 35 deletions(-) diff --git a/tests/tests.py b/tests/tests.py index 3176ac168..ac88bc03a 100755 --- a/tests/tests.py +++ b/tests/tests.py @@ -1094,7 +1094,7 @@ def test_plantcv_analyze_bound_horizontal(): # Copy a test file to the cache directory shutil.copyfile(os.path.join(TEST_DATA, "data_results.txt"), os.path.join(cache_dir, "data_results.txt")) pcv.print_results(os.path.join(cache_dir, "data_results.txt")) - assert len(pcv.outputs.observations) == 7 + assert len(pcv.outputs.observations["default"]) == 7 pcv.outputs.clear() @@ -1127,7 +1127,7 @@ def test_plantcv_analyze_bound_horizontal_neg_y(): _ = pcv.analyze_bound_horizontal(img=img, obj=object_contours, mask=mask, line_position=2056) shutil.copyfile(os.path.join(TEST_DATA, "data_results.txt"), os.path.join(cache_dir, "data_results.txt")) pcv.print_results(os.path.join(cache_dir, "data_results.txt")) - assert pcv.outputs.observations['default_height_above_reference']['value'] == 713 + assert pcv.outputs.observations['default']['height_above_reference']['value'] == 713 pcv.outputs.clear() @@ -1151,7 +1151,7 @@ def test_plantcv_analyze_bound_vertical(): pcv.params.debug = None _ = pcv.analyze_bound_vertical(img=img, obj=object_contours, mask=mask, line_position=1000) pcv.print_results(os.path.join(cache_dir, "results.txt")) - assert pcv.outputs.observations['default_width_left_reference']['value'] == 94 + assert pcv.outputs.observations['default']['width_left_reference']['value'] == 94 pcv.outputs.clear() @@ -1169,7 +1169,7 @@ def test_plantcv_analyze_bound_vertical_grayscale_image(): pcv.params.debug = "plot" _ = pcv.analyze_bound_vertical(img=img, obj=object_contours, mask=mask, line_position=1000) pcv.print_results(os.path.join(cache_dir, "results.txt")) - assert pcv.outputs.observations['default_width_left_reference']['value'] == 94 + assert pcv.outputs.observations['default']['width_left_reference']['value'] == 94 pcv.outputs.clear() @@ -1187,7 +1187,7 @@ def test_plantcv_analyze_bound_vertical_neg_x(): pcv.params.debug = "plot" _ = pcv.analyze_bound_vertical(img=img, obj=object_contours, mask=mask, line_position=2454) pcv.print_results(os.path.join(cache_dir, "results.txt")) - assert pcv.outputs.observations['default_width_left_reference']['value'] == 441 + assert pcv.outputs.observations['default']['width_left_reference']['value'] == 441 pcv.outputs.clear() @@ -1205,7 +1205,7 @@ def test_plantcv_analyze_bound_vertical_small_x(): pcv.params.debug = "plot" _ = pcv.analyze_bound_vertical(img=img, obj=object_contours, mask=mask, line_position=1) pcv.print_results(os.path.join(cache_dir, "results.txt")) - assert pcv.outputs.observations['default_width_right_reference']['value'] == 441 + assert pcv.outputs.observations['default']['width_right_reference']['value'] == 441 pcv.outputs.clear() @@ -1233,7 +1233,7 @@ def test_plantcv_analyze_color(): pcv.params.debug = None _ = pcv.analyze_color(rgb_img=img, mask=mask, hist_plot_type='rgb') pcv.print_results(os.path.join(cache_dir, "results.txt")) - assert pcv.outputs.observations['default_hue_median']['value'] == 84.0 + assert pcv.outputs.observations['default']['hue_median']['value'] == 84.0 pcv.outputs.clear() @@ -1280,7 +1280,7 @@ def test_plantcv_analyze_nir(): pcv.params.debug = None _ = pcv.analyze_nir_intensity(gray_img=img, mask=mask, bins=256, histplot=True) pcv.print_results(os.path.join(cache_dir, "results.txt")) - result = len(pcv.outputs.observations['default_nir_frequencies']['value']) + result = len(pcv.outputs.observations['default']['nir_frequencies']['value']) pcv.outputs.clear() assert result == 256 @@ -1426,7 +1426,7 @@ def test_plantcv_analyze_thermal_values(): pcv.params.debug = "plot" thermal_hist = pcv.analyze_thermal_values(thermal_array=img, mask=mask, histplot=True) pcv.print_results(os.path.join(cache_dir, "results.txt")) - assert thermal_hist is not None and pcv.outputs.observations['default_median_temp']['value'] == 33.20922 + assert thermal_hist is not None and pcv.outputs.observations['default']['median_temp']['value'] == 33.20922 def test_plantcv_apply_mask_white(): @@ -2284,7 +2284,8 @@ def test_plantcv_landmark_reference_pt_dist(): pcv.landmark_reference_pt_dist(points_r=points_rescaled, centroid_r=centroid_rescaled, bline_r=bottomline_rescaled, label="prefix") pcv.print_results(os.path.join(cache_dir, "results.txt")) - assert len(pcv.outputs.observations) == 42 + print(pcv.outputs.observations['prefix']) + assert len(pcv.outputs.observations['prefix']) == 8 pcv.outputs.clear() @@ -3276,7 +3277,7 @@ def test_plantcv_watershed_segmentation(): pcv.params.debug = None _ = pcv.watershed_segmentation(rgb_img=img, mask=mask, distance=10) pcv.print_results(os.path.join(cache_dir, "results.txt")) - assert pcv.outputs.observations['estimated_object_count']['value'] > 9 + assert pcv.outputs.observations['default']['estimated_object_count']['value'] > 9 def test_plantcv_white_balance_gray_16bit(): @@ -3652,7 +3653,7 @@ def test_plantcv_morphology_segment_curvature(): pcv.outputs.clear() _ = pcv.morphology.segment_curvature(segmented_img, seg_objects) pcv.print_results(os.path.join(cache_dir, "results.txt")) - assert len(pcv.outputs.observations['default_segment_curvature']['value']) == 22 + assert len(pcv.outputs.observations['default']['segment_curvature']['value']) == 22 pcv.outputs.clear() @@ -3668,9 +3669,8 @@ def test_plantcv_morphology_check_cycles(): _ = pcv.morphology.check_cycles(mask) pcv.params.debug = None _ = pcv.morphology.check_cycles(mask) - print(pcv.outputs.observations["default_num_cycles"]["value"]) pcv.print_results(os.path.join(cache_dir, "results.txt")) - assert pcv.outputs.observations['default_num_cycles']['value'] == 1 + assert pcv.outputs.observations['default']['num_cycles']['value'] == 1 pcv.outputs.clear() @@ -3770,9 +3770,9 @@ def test_plantcv_morphology_fill_segments(): pcv.params.debug = "plot" _ = pcv.morphology.fill_segments(mask, obj) pcv.print_results(os.path.join(cache_dir, "results.txt")) - tests = [pcv.outputs.observations['default_segment_area']['value'][42] == 5529, - pcv.outputs.observations['default_segment_area']['value'][20] == 5057, - pcv.outputs.observations['default_segment_area']['value'][49] == 3323] + tests = [pcv.outputs.observations['default']['segment_area']['value'][42] == 5529, + pcv.outputs.observations['default']['segment_area']['value'][20] == 5057, + pcv.outputs.observations['default']['segment_area']['value'][49] == 3323] assert all(tests) pcv.outputs.clear() @@ -3792,7 +3792,7 @@ def test_plantcv_morphology_fill_segments_with_stem(): pcv.params.debug = "print" _ = pcv.morphology.fill_segments(mask, obj, stem_obj) pcv.print_results(os.path.join(cache_dir, "results.txt")) - num_objects = len(pcv.outputs.observations['default_segment_area']['value']) + num_objects = len(pcv.outputs.observations['default']['segment_area']['value']) assert num_objects == 70 pcv.outputs.clear() @@ -3809,7 +3809,7 @@ def test_plantcv_morphology_segment_angle(): pcv.params.debug = "plot" _ = pcv.morphology.segment_angle(segmented_img, segment_objects) pcv.print_results(os.path.join(cache_dir, "results.txt")) - assert len(pcv.outputs.observations['default_segment_angle']['value']) == 22 + assert len(pcv.outputs.observations['default']['segment_angle']['value']) == 22 pcv.outputs.clear() @@ -3822,7 +3822,7 @@ def test_plantcv_morphology_segment_angle_overflow(): skeleton = cv2.imread(os.path.join(TEST_DATA, TEST_INPUT_SKELETON), -1) segmented_img, segment_objects = pcv.morphology.segment_skeleton(skel_img=skeleton) _ = pcv.morphology.segment_angle(segmented_img, segment_objects) - assert len(pcv.outputs.observations['default_segment_angle']['value']) == 73 + assert len(pcv.outputs.observations['default']['segment_angle']['value']) == 73 pcv.outputs.clear() @@ -3838,7 +3838,7 @@ def test_plantcv_morphology_segment_euclidean_length(): pcv.params.debug = "plot" _ = pcv.morphology.segment_euclidean_length(segmented_img, segment_objects) pcv.print_results(os.path.join(cache_dir, "results.txt")) - assert len(pcv.outputs.observations['default_segment_eu_length']['value']) == 22 + assert len(pcv.outputs.observations['default']['segment_eu_length']['value']) == 22 pcv.outputs.clear() @@ -3863,7 +3863,7 @@ def test_plantcv_morphology_segment_path_length(): pcv.params.debug = "plot" _ = pcv.morphology.segment_path_length(segmented_img, segment_objects) pcv.print_results(os.path.join(cache_dir, "results.txt")) - assert len(pcv.outputs.observations['default_segment_path_length']['value']) == 22 + assert len(pcv.outputs.observations['default']['segment_path_length']['value']) == 22 pcv.outputs.clear() @@ -3911,7 +3911,7 @@ def test_plantcv_morphology_segment_tangent_angle(): pcv.params.debug = "plot" _ = pcv.morphology.segment_tangent_angle(skel, objs, 2) pcv.print_results(os.path.join(cache_dir, "results.txt")) - assert len(pcv.outputs.observations['default_segment_tangent_angle']['value']) == 73 + assert len(pcv.outputs.observations['default']['segment_tangent_angle']['value']) == 73 pcv.outputs.clear() @@ -3944,7 +3944,7 @@ def test_plantcv_morphology_segment_insertion_angle(): pcv.params.debug = "print" _ = pcv.morphology.segment_insertion_angle(pruned, segmented_img, leaf_obj, stem_obj, 10) pcv.print_results(os.path.join(cache_dir, "results.txt")) - assert pcv.outputs.observations['default_segment_insertion_angle']['value'][:6] == ['NA', 'NA', 'NA', + assert pcv.outputs.observations['default']['segment_insertion_angle']['value'][:6] == ['NA', 'NA', 'NA', 24.956918822001636, 50.7313343343401, 56.427712102130734] @@ -4008,7 +4008,7 @@ def test_plantcv_morphology_analyze_stem(): _ = pcv.morphology.analyze_stem(rgb_img=segmented_img, stem_objects=stem_obj, label="prefix") pcv.params.debug = "print" _ = pcv.morphology.analyze_stem(rgb_img=segmented_img, stem_objects=stem_obj) - assert pcv.outputs.observations['default_stem_angle']['value'] == -12.531776428222656 + assert pcv.outputs.observations['default']['stem_angle']['value'] == -12.531776428222656 pcv.outputs.clear() @@ -4025,7 +4025,7 @@ def test_plantcv_morphology_analyze_stem_bad_angle(): # stem_obj = [stem_obj[3]] stem_obj = [[[[1116, 1728]], [[1116, 1]]]] _ = pcv.morphology.analyze_stem(rgb_img=segmented_img, stem_objects=stem_obj) - assert pcv.outputs.observations['default_stem_angle']['value'] == 22877334.0 + assert pcv.outputs.observations['default']['stem_angle']['value'] == 22877334.0 pcv.outputs.clear() @@ -4620,7 +4620,7 @@ def test_plantcv_hyperspectral_analyze_spectral(): _ = pcv.hyperspectral.analyze_spectral(array=array_data, mask=mask, histplot=True) pcv.params.debug = "print" _ = pcv.hyperspectral.analyze_spectral(array=array_data, mask=mask, histplot=True, label="prefix") - assert len(pcv.outputs.observations['prefix_spectral_frequencies']['value']) == 978 + assert len(pcv.outputs.observations['prefix']['spectral_frequencies']['value']) == 978 def test_plantcv_hyperspectral_analyze_index(): @@ -4635,7 +4635,7 @@ def test_plantcv_hyperspectral_analyze_index(): pcv.hyperspectral.analyze_index(index_array=index_array, mask=mask_img, histplot=True) pcv.params.debug = "plot" pcv.hyperspectral.analyze_index(index_array=index_array, mask=mask_img, histplot=True) - assert pcv.outputs.observations['default_mean_index_savi']['value'] > 0 + assert pcv.outputs.observations['default']['mean_index_savi']['value'] > 0 def test_plantcv_hyperspectral_analyze_index_set_range(): @@ -4647,7 +4647,7 @@ def test_plantcv_hyperspectral_analyze_index_set_range(): index_array = pcv.spectral_index.savi(hsi=array_data, distance=801) mask_img = np.ones(np.shape(index_array.array_data), dtype=np.uint8) * 255 pcv.hyperspectral.analyze_index(index_array=index_array, mask=mask_img, histplot=True, min_bin=0, max_bin=1) - assert pcv.outputs.observations['default_mean_index_savi']['value'] > 0 + assert pcv.outputs.observations['default']['mean_index_savi']['value'] > 0 def test_plantcv_hyperspectral_analyze_index_auto_range(): @@ -4659,7 +4659,7 @@ def test_plantcv_hyperspectral_analyze_index_auto_range(): index_array = pcv.spectral_index.savi(hsi=array_data, distance=801) mask_img = np.ones(np.shape(index_array.array_data), dtype=np.uint8) * 255 pcv.hyperspectral.analyze_index(index_array=index_array, mask=mask_img, min_bin="auto", max_bin="auto") - assert pcv.outputs.observations['default_mean_index_savi']['value'] > 0 + assert pcv.outputs.observations['default']['mean_index_savi']['value'] > 0 def test_plantcv_hyperspectral_analyze_index_outside_range_warning(): @@ -4816,7 +4816,7 @@ def test_plantcv_photosynthesis_analyze_fvfm_bad_fdark(): fmax = cv2.imread(os.path.join(TEST_DATA, TEST_INPUT_FMAX), -1) fmask = cv2.imread(os.path.join(TEST_DATA, TEST_INPUT_FMASK), -1) _ = pcv.photosynthesis.analyze_fvfm(fdark=fdark + 3000, fmin=fmin, fmax=fmax, mask=fmask, bins=1000) - check = pcv.outputs.observations['default_fdark_passed_qc']['value'] is False + check = pcv.outputs.observations['default']['fdark_passed_qc']['value'] is False pcv.outputs.clear() assert check @@ -5395,7 +5395,7 @@ def test_plantcv_transform_find_color_card_optional_parameters(): # Test with threshold ='normal' df1, start1, space1 = pcv.transform.find_color_card(rgb_img=rgb_img, threshold_type='normal', blurry=True, background='light', threshvalue=90, label="prefix") - assert pcv.outputs.observations["prefix_color_chip_size"]["value"] > 15000 + assert pcv.outputs.observations["prefix"]["color_chip_size"]["value"] > 15000 def test_plantcv_transform_find_color_card_optional_size_parameters(): @@ -5406,7 +5406,7 @@ def test_plantcv_transform_find_color_card_optional_size_parameters(): os.mkdir(cache_dir) pcv.params.debug_outdir = cache_dir _, _, _ = pcv.transform.find_color_card(rgb_img=rgb_img, record_chip_size="mean") - assert pcv.outputs.observations["color_chip_size"]["value"] > 15000 + assert pcv.outputs.observations["default"]["color_chip_size"]["value"] > 15000 def test_plantcv_transform_find_color_card_optional_size_parameters_none(): @@ -5418,7 +5418,7 @@ def test_plantcv_transform_find_color_card_optional_size_parameters_none(): os.mkdir(cache_dir) pcv.params.debug_outdir = cache_dir _, _, _ = pcv.transform.find_color_card(rgb_img=rgb_img, record_chip_size=None) - assert pcv.outputs.observations.get("color_chip_size") is None + assert pcv.outputs.observations.get("default") is None def test_plantcv_transform_find_color_card_bad_record_chip_size(): @@ -5426,7 +5426,7 @@ def test_plantcv_transform_find_color_card_bad_record_chip_size(): rgb_img = cv2.imread(os.path.join(TEST_DATA, TEST_TARGET_IMG)) pcv.params.debug = None _, _, _ = pcv.transform.find_color_card(rgb_img=rgb_img, record_chip_size='averageeeed') - assert pcv.outputs.observations["color_chip_size"]["value"] is None + assert pcv.outputs.observations["default"]["color_chip_size"]["value"] is None def test_plantcv_transform_find_color_card_bad_thresh_input(): From 5a460c124909ea8b6579a637cfd8e2a39742e8fb Mon Sep 17 00:00:00 2001 From: nfahlgren Date: Fri, 12 Feb 2021 18:31:58 -0600 Subject: [PATCH 131/137] Fixed sample label tests --- plantcv/plantcv/watershed.py | 2 +- tests/tests.py | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/plantcv/plantcv/watershed.py b/plantcv/plantcv/watershed.py index 18c27a8aa..c18030693 100755 --- a/plantcv/plantcv/watershed.py +++ b/plantcv/plantcv/watershed.py @@ -16,7 +16,7 @@ from plantcv.plantcv import outputs -def watershed_segmentation(rgb_img, mask, distance=10, label=None): +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). diff --git a/tests/tests.py b/tests/tests.py index ac88bc03a..6a8fe82d0 100755 --- a/tests/tests.py +++ b/tests/tests.py @@ -2285,7 +2285,7 @@ def test_plantcv_landmark_reference_pt_dist(): label="prefix") pcv.print_results(os.path.join(cache_dir, "results.txt")) print(pcv.outputs.observations['prefix']) - assert len(pcv.outputs.observations['prefix']) == 8 + assert len(pcv.outputs.observations['prefix'].keys()) == 8 pcv.outputs.clear() From 0818158301a80a31515746a90b379137becf0764 Mon Sep 17 00:00:00 2001 From: nfahlgren Date: Fri, 12 Feb 2021 20:06:53 -0600 Subject: [PATCH 132/137] Clear outputs before tests --- tests/tests.py | 89 ++++++++++++++++++++++++++++++++++++-------------- 1 file changed, 64 insertions(+), 25 deletions(-) diff --git a/tests/tests.py b/tests/tests.py index 6a8fe82d0..77249104e 100755 --- a/tests/tests.py +++ b/tests/tests.py @@ -1069,6 +1069,8 @@ 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) @@ -1095,7 +1097,6 @@ def test_plantcv_analyze_bound_horizontal(): shutil.copyfile(os.path.join(TEST_DATA, "data_results.txt"), os.path.join(cache_dir, "data_results.txt")) pcv.print_results(os.path.join(cache_dir, "data_results.txt")) assert len(pcv.outputs.observations["default"]) == 7 - pcv.outputs.clear() def test_plantcv_analyze_bound_horizontal_grayscale_image(): @@ -1111,6 +1112,8 @@ def test_plantcv_analyze_bound_horizontal_grayscale_image(): def test_plantcv_analyze_bound_horizontal_neg_y(): + # 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) @@ -1128,10 +1131,11 @@ def test_plantcv_analyze_bound_horizontal_neg_y(): shutil.copyfile(os.path.join(TEST_DATA, "data_results.txt"), os.path.join(cache_dir, "data_results.txt")) pcv.print_results(os.path.join(cache_dir, "data_results.txt")) assert pcv.outputs.observations['default']['height_above_reference']['value'] == 713 - pcv.outputs.clear() 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) @@ -1152,7 +1156,6 @@ def test_plantcv_analyze_bound_vertical(): _ = pcv.analyze_bound_vertical(img=img, obj=object_contours, mask=mask, line_position=1000) pcv.print_results(os.path.join(cache_dir, "results.txt")) assert pcv.outputs.observations['default']['width_left_reference']['value'] == 94 - pcv.outputs.clear() def test_plantcv_analyze_bound_vertical_grayscale_image(): @@ -1174,6 +1177,8 @@ def test_plantcv_analyze_bound_vertical_grayscale_image(): def test_plantcv_analyze_bound_vertical_neg_x(): + # 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) @@ -1188,10 +1193,11 @@ def test_plantcv_analyze_bound_vertical_neg_x(): _ = pcv.analyze_bound_vertical(img=img, obj=object_contours, mask=mask, line_position=2454) pcv.print_results(os.path.join(cache_dir, "results.txt")) assert pcv.outputs.observations['default']['width_left_reference']['value'] == 441 - pcv.outputs.clear() def test_plantcv_analyze_bound_vertical_small_x(): + # 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) @@ -1206,10 +1212,11 @@ def test_plantcv_analyze_bound_vertical_small_x(): _ = pcv.analyze_bound_vertical(img=img, obj=object_contours, mask=mask, line_position=1) pcv.print_results(os.path.join(cache_dir, "results.txt")) assert pcv.outputs.observations['default']['width_right_reference']['value'] == 441 - pcv.outputs.clear() def test_plantcv_analyze_color(): + # Clear previous outputs + pcv.outputs.clear() # Test cache directory cache_dir = os.path.join(TEST_TMPDIR, "test_plantcv_analyze_color") os.mkdir(cache_dir) @@ -1234,7 +1241,6 @@ def test_plantcv_analyze_color(): _ = pcv.analyze_color(rgb_img=img, mask=mask, hist_plot_type='rgb') pcv.print_results(os.path.join(cache_dir, "results.txt")) assert pcv.outputs.observations['default']['hue_median']['value'] == 84.0 - pcv.outputs.clear() def test_plantcv_analyze_color_incorrect_image(): @@ -1261,6 +1267,8 @@ def test_plantcv_analyze_color_incorrect_hist_plot_type(): def test_plantcv_analyze_nir(): + # Clear previous outputs + pcv.outputs.clear() # Test cache directory cache_dir = os.path.join(TEST_TMPDIR, "test_plantcv_analyze_nir") os.mkdir(cache_dir) @@ -1281,7 +1289,6 @@ def test_plantcv_analyze_nir(): _ = pcv.analyze_nir_intensity(gray_img=img, mask=mask, bins=256, histplot=True) pcv.print_results(os.path.join(cache_dir, "results.txt")) result = len(pcv.outputs.observations['default']['nir_frequencies']['value']) - pcv.outputs.clear() assert result == 256 @@ -1411,6 +1418,8 @@ def test_plantcv_analyze_object_small_contour(): def test_plantcv_analyze_thermal_values(): + # Clear previous outputs + pcv.outputs.clear() # Test cache directory cache_dir = os.path.join(TEST_TMPDIR, "test_plantcv_analyze_thermal_values") os.mkdir(cache_dir) @@ -2269,6 +2278,8 @@ def test_plantcv_invert(): def test_plantcv_landmark_reference_pt_dist(): + # Clear previous outputs + pcv.outputs.clear() cache_dir = os.path.join(TEST_TMPDIR, "test_plantcv_landmark_reference") os.mkdir(cache_dir) points_rescaled = [(0.0139, 0.2569), (0.2361, 0.2917), (0.3542, 0.3819), (0.3542, 0.4167), (0.375, 0.4236), @@ -2281,12 +2292,10 @@ def test_plantcv_landmark_reference_pt_dist(): _ = pcv.landmark_reference_pt_dist(points_r=[], centroid_r=('a', 'b'), bline_r=(0, 0)) _ = pcv.landmark_reference_pt_dist(points_r=[(10, 1000)], centroid_r=(10, 10), bline_r=(10, 10)) _ = pcv.landmark_reference_pt_dist(points_r=[], centroid_r=(0, 0), bline_r=(0, 0)) - pcv.landmark_reference_pt_dist(points_r=points_rescaled, centroid_r=centroid_rescaled, bline_r=bottomline_rescaled, - label="prefix") + _ = pcv.landmark_reference_pt_dist(points_r=points_rescaled, centroid_r=centroid_rescaled, + bline_r=bottomline_rescaled, label="prefix") pcv.print_results(os.path.join(cache_dir, "results.txt")) - print(pcv.outputs.observations['prefix']) assert len(pcv.outputs.observations['prefix'].keys()) == 8 - pcv.outputs.clear() def test_plantcv_laplace_filter(): @@ -3260,6 +3269,8 @@ def test_plantcv_stdev_filter(): def test_plantcv_watershed_segmentation(): + # Clear previous outputs + pcv.outputs.clear() # Test cache directory cache_dir = os.path.join(TEST_TMPDIR, "test_plantcv_watershed_segmentation") os.mkdir(cache_dir) @@ -3640,6 +3651,8 @@ def test_plantcv_learn_naive_bayes_multiclass(): # Tests for the morphology subpackage # #################################### def test_plantcv_morphology_segment_curvature(): + # Clear previous outputs + pcv.outputs.clear() # Test cache directory cache_dir = os.path.join(TEST_TMPDIR, "test_plantcv_morphology_curvature") os.mkdir(cache_dir) @@ -3654,10 +3667,11 @@ def test_plantcv_morphology_segment_curvature(): _ = pcv.morphology.segment_curvature(segmented_img, seg_objects) pcv.print_results(os.path.join(cache_dir, "results.txt")) assert len(pcv.outputs.observations['default']['segment_curvature']['value']) == 22 - pcv.outputs.clear() def test_plantcv_morphology_check_cycles(): + # Clear previous outputs + pcv.outputs.clear() # Test cache directory cache_dir = os.path.join(TEST_TMPDIR, "test_plantcv_morphology_branches") os.mkdir(cache_dir) @@ -3671,7 +3685,6 @@ def test_plantcv_morphology_check_cycles(): _ = pcv.morphology.check_cycles(mask) pcv.print_results(os.path.join(cache_dir, "results.txt")) assert pcv.outputs.observations['default']['num_cycles']['value'] == 1 - pcv.outputs.clear() def test_plantcv_morphology_find_branch_pts(): @@ -3756,6 +3769,8 @@ def test_plantcv_morphology_segment_skeleton(): def test_plantcv_morphology_fill_segments(): + # Clear previous outputs + pcv.outputs.clear() # Test cache directory cache_dir = os.path.join(TEST_TMPDIR, "test_plantcv_morphology_fill_segments") os.mkdir(cache_dir) @@ -3774,10 +3789,11 @@ def test_plantcv_morphology_fill_segments(): pcv.outputs.observations['default']['segment_area']['value'][20] == 5057, pcv.outputs.observations['default']['segment_area']['value'][49] == 3323] assert all(tests) - pcv.outputs.clear() def test_plantcv_morphology_fill_segments_with_stem(): + # Clear previous outputs + pcv.outputs.clear() # Test cache directory cache_dir = os.path.join(TEST_TMPDIR, "test_plantcv_morphology_fill_segments") os.mkdir(cache_dir) @@ -3794,10 +3810,11 @@ def test_plantcv_morphology_fill_segments_with_stem(): pcv.print_results(os.path.join(cache_dir, "results.txt")) num_objects = len(pcv.outputs.observations['default']['segment_area']['value']) assert num_objects == 70 - pcv.outputs.clear() def test_plantcv_morphology_segment_angle(): + # Clear previous outputs + pcv.outputs.clear() # Test cache directory cache_dir = os.path.join(TEST_TMPDIR, "test_plantcv_morphology_segment_angles") os.mkdir(cache_dir) @@ -3810,10 +3827,11 @@ def test_plantcv_morphology_segment_angle(): _ = pcv.morphology.segment_angle(segmented_img, segment_objects) pcv.print_results(os.path.join(cache_dir, "results.txt")) assert len(pcv.outputs.observations['default']['segment_angle']['value']) == 22 - pcv.outputs.clear() def test_plantcv_morphology_segment_angle_overflow(): + # Clear previous outputs + pcv.outputs.clear() # Don't prune, would usually give overflow error without extra if statement in segment_angle # Test cache directory cache_dir = os.path.join(TEST_TMPDIR, "test_plantcv_morphology_segment_angles") @@ -3823,10 +3841,11 @@ def test_plantcv_morphology_segment_angle_overflow(): segmented_img, segment_objects = pcv.morphology.segment_skeleton(skel_img=skeleton) _ = pcv.morphology.segment_angle(segmented_img, segment_objects) assert len(pcv.outputs.observations['default']['segment_angle']['value']) == 73 - pcv.outputs.clear() def test_plantcv_morphology_segment_euclidean_length(): + # Clear previous outputs + pcv.outputs.clear() # Test cache directory cache_dir = os.path.join(TEST_TMPDIR, "test_plantcv_morphology_segment_eu_length") os.mkdir(cache_dir) @@ -3839,7 +3858,6 @@ def test_plantcv_morphology_segment_euclidean_length(): _ = pcv.morphology.segment_euclidean_length(segmented_img, segment_objects) pcv.print_results(os.path.join(cache_dir, "results.txt")) assert len(pcv.outputs.observations['default']['segment_eu_length']['value']) == 22 - pcv.outputs.clear() def test_plantcv_morphology_segment_euclidean_length_bad_input(): @@ -3852,6 +3870,8 @@ def test_plantcv_morphology_segment_euclidean_length_bad_input(): def test_plantcv_morphology_segment_path_length(): + # Clear previous outputs + pcv.outputs.clear() # Test cache directory cache_dir = os.path.join(TEST_TMPDIR, "test_plantcv_morphology_segment_path_length") os.mkdir(cache_dir) @@ -3864,7 +3884,6 @@ def test_plantcv_morphology_segment_path_length(): _ = pcv.morphology.segment_path_length(segmented_img, segment_objects) pcv.print_results(os.path.join(cache_dir, "results.txt")) assert len(pcv.outputs.observations['default']['segment_path_length']['value']) == 22 - pcv.outputs.clear() def test_plantcv_morphology_skeletonize(): @@ -3899,6 +3918,8 @@ def test_plantcv_morphology_segment_sort(): def test_plantcv_morphology_segment_tangent_angle(): + # Clear previous outputs + pcv.outputs.clear() # Test cache directory cache_dir = os.path.join(TEST_TMPDIR, "test_plantcv_morphology_segment_tangent_angle") os.mkdir(cache_dir) @@ -3912,7 +3933,6 @@ def test_plantcv_morphology_segment_tangent_angle(): _ = pcv.morphology.segment_tangent_angle(skel, objs, 2) pcv.print_results(os.path.join(cache_dir, "results.txt")) assert len(pcv.outputs.observations['default']['segment_tangent_angle']['value']) == 73 - pcv.outputs.clear() def test_plantcv_morphology_segment_id(): @@ -3931,6 +3951,8 @@ def test_plantcv_morphology_segment_id(): def test_plantcv_morphology_segment_insertion_angle(): + # Clear previous outputs + pcv.outputs.clear() # Test cache directory cache_dir = os.path.join(TEST_TMPDIR, "test_plantcv_morphology_segment_insertion_angle") os.mkdir(cache_dir) @@ -3948,7 +3970,6 @@ def test_plantcv_morphology_segment_insertion_angle(): 24.956918822001636, 50.7313343343401, 56.427712102130734] - pcv.outputs.clear() def test_plantcv_morphology_segment_insertion_angle_bad_stem(): @@ -3996,6 +4017,8 @@ def test_plantcv_morphology_segment_combine_bad_input(): def test_plantcv_morphology_analyze_stem(): + # Clear previous outputs + pcv.outputs.clear() # Test cache directory cache_dir = os.path.join(TEST_TMPDIR, "test_plantcv_morphology_analyze_stem") os.mkdir(cache_dir) @@ -4009,10 +4032,11 @@ def test_plantcv_morphology_analyze_stem(): pcv.params.debug = "print" _ = pcv.morphology.analyze_stem(rgb_img=segmented_img, stem_objects=stem_obj) assert pcv.outputs.observations['default']['stem_angle']['value'] == -12.531776428222656 - pcv.outputs.clear() def test_plantcv_morphology_analyze_stem_bad_angle(): + # Clear previous outputs + pcv.outputs.clear() # Test cache directory cache_dir = os.path.join(TEST_TMPDIR, "test_plantcv_morphology_segment_insertion_angle") os.mkdir(cache_dir) @@ -4026,7 +4050,6 @@ def test_plantcv_morphology_analyze_stem_bad_angle(): stem_obj = [[[[1116, 1728]], [[1116, 1]]]] _ = pcv.morphology.analyze_stem(rgb_img=segmented_img, stem_objects=stem_obj) assert pcv.outputs.observations['default']['stem_angle']['value'] == 22877334.0 - pcv.outputs.clear() # ######################################## @@ -4609,6 +4632,8 @@ def test_plantcv_spectral_index_wi_bad_input(): def test_plantcv_hyperspectral_analyze_spectral(): + # Clear previous outputs + pcv.outputs.clear() cache_dir = os.path.join(TEST_TMPDIR, "test_plantcv_hyperspectral_analyze_spectral") os.mkdir(cache_dir) pcv.params.debug_outdir = cache_dir @@ -4624,6 +4649,8 @@ def test_plantcv_hyperspectral_analyze_spectral(): def test_plantcv_hyperspectral_analyze_index(): + # Clear previous outputs + pcv.outputs.clear() cache_dir = os.path.join(TEST_TMPDIR, "test_plantcv_hyperspectral_analyze_index") os.mkdir(cache_dir) pcv.params.debug_outdir = cache_dir @@ -4639,6 +4666,8 @@ def test_plantcv_hyperspectral_analyze_index(): def test_plantcv_hyperspectral_analyze_index_set_range(): + # Clear previous outputs + pcv.outputs.clear() cache_dir = os.path.join(TEST_TMPDIR, "test_plantcv_hyperspectral_analyze_index_set_range") os.mkdir(cache_dir) pcv.params.debug_outdir = cache_dir @@ -4651,6 +4680,8 @@ def test_plantcv_hyperspectral_analyze_index_set_range(): def test_plantcv_hyperspectral_analyze_index_auto_range(): + # Clear previous outputs + pcv.outputs.clear() cache_dir = os.path.join(TEST_TMPDIR, "test_plantcv_hyperspectral_analyze_index_auto_range") os.mkdir(cache_dir) pcv.params.debug_outdir = cache_dir @@ -4807,6 +4838,8 @@ def test_plantcv_photosynthesis_analyze_fvfm_print_analysis_results(): def test_plantcv_photosynthesis_analyze_fvfm_bad_fdark(): + # Clear previous outputs + pcv.outputs.clear() cache_dir = os.path.join(TEST_TMPDIR, "test_plantcv_analyze_fvfm") os.mkdir(cache_dir) pcv.params.debug_outdir = cache_dir @@ -4817,7 +4850,6 @@ def test_plantcv_photosynthesis_analyze_fvfm_bad_fdark(): fmask = cv2.imread(os.path.join(TEST_DATA, TEST_INPUT_FMASK), -1) _ = pcv.photosynthesis.analyze_fvfm(fdark=fdark + 3000, fmin=fmin, fmax=fmax, mask=fmask, bins=1000) check = pcv.outputs.observations['default']['fdark_passed_qc']['value'] is False - pcv.outputs.clear() assert check @@ -5386,6 +5418,8 @@ def test_plantcv_transform_find_color_card(): def test_plantcv_transform_find_color_card_optional_parameters(): + # Clear previous outputs + pcv.outputs.clear() # Load rgb image rgb_img = cv2.imread(os.path.join(TEST_DATA, TEST_TARGET_IMG_COLOR_CARD)) # Test cache directory @@ -5399,6 +5433,8 @@ def test_plantcv_transform_find_color_card_optional_parameters(): def test_plantcv_transform_find_color_card_optional_size_parameters(): + # Clear previous outputs + pcv.outputs.clear() # Load rgb image rgb_img = cv2.imread(os.path.join(TEST_DATA, TEST_TARGET_IMG_COLOR_CARD)) # Test cache directory @@ -5410,7 +5446,8 @@ def test_plantcv_transform_find_color_card_optional_size_parameters(): def test_plantcv_transform_find_color_card_optional_size_parameters_none(): - pcv.outputs.observations.clear() + # Clear previous outputs + pcv.outputs.clear() # Load rgb image rgb_img = cv2.imread(os.path.join(TEST_DATA, TEST_TARGET_IMG_COLOR_CARD)) # Test cache directory @@ -5422,6 +5459,8 @@ def test_plantcv_transform_find_color_card_optional_size_parameters_none(): def test_plantcv_transform_find_color_card_bad_record_chip_size(): + # Clear previous outputs + pcv.outputs.clear() # Load rgb image rgb_img = cv2.imread(os.path.join(TEST_DATA, TEST_TARGET_IMG)) pcv.params.debug = None From c801343e9834653e086c2fbfb5d6fd0fc4f8d2ba Mon Sep 17 00:00:00 2001 From: nfahlgren Date: Fri, 12 Feb 2021 21:32:11 -0600 Subject: [PATCH 133/137] Add samples to docs --- docs/analyze_NIR_intensity.md | 2 +- docs/analyze_bound_horizontal.md | 4 +-- docs/analyze_bound_vertical.md | 4 +-- docs/analyze_color.md | 2 +- docs/analyze_shape.md | 4 +-- docs/analyze_spectral.md | 2 +- docs/analyze_stem.md | 4 +-- docs/analyze_thermal_values.md | 2 +- docs/check_cycles.md | 2 +- docs/fill_segments.md | 2 +- docs/find_color_card.md | 2 +- docs/landmark_reference_pt_dist.md | 2 +- docs/output_measurements.md | 41 ++++++++++++++++------------- docs/outputs.md | 7 +++-- docs/photosynthesis_analyze_fvfm.md | 2 +- docs/report_size_marker.md | 2 +- docs/segment_angle.md | 2 +- docs/segment_curvature.md | 5 ++-- docs/segment_euclidean_length.md | 4 +-- docs/segment_insertion_angle.md | 2 +- docs/segment_pathlength.md | 2 +- docs/segment_tangent_angle.md | 2 +- docs/x_axis_pseudolandmarks.md | 2 +- docs/y_axis_pseudolandmarks.md | 6 ++--- 24 files changed, 57 insertions(+), 52 deletions(-) diff --git a/docs/analyze_NIR_intensity.md b/docs/analyze_NIR_intensity.md index 12c55e6c6..49cc86bd4 100644 --- a/docs/analyze_NIR_intensity.md +++ b/docs/analyze_NIR_intensity.md @@ -37,7 +37,7 @@ pcv.params.debug = "print" analysis_image = pcv.analyze_nir_intensity(gray_img, mask, 256, histplot=True, label="default") # Access data stored out from analyze_nir_intensity -nir_frequencies = pcv.outputs.observations['default_nir_frequencies']['value'] +nir_frequencies = pcv.outputs.observations['default']['nir_frequencies']['value'] ``` diff --git a/docs/analyze_bound_horizontal.md b/docs/analyze_bound_horizontal.md index 9fb80203a..a8f670403 100644 --- a/docs/analyze_bound_horizontal.md +++ b/docs/analyze_bound_horizontal.md @@ -13,7 +13,7 @@ best if the pot size/position of the plant remains relatively constant. - obj - single or grouped contour object - mask - binary mask of selected contours - line_position - position of boundary line (a value of 0 would draw the line through the top of the image) - - label - Optional label parameter, modifies the variable name of observations recorded. (default `label=None`) + - label - Optional label parameter, modifies the variable name of observations recorded. (default `label="default"`) - **Context:** - Used to define a boundary line for the image, to find the height above and below as well as area above and below a boundary line. - **Example use:** @@ -34,7 +34,7 @@ pcv.params.debug = "print" boundary_image = pcv.analyze_bound_horizontal(img=img, obj=obj, mask=bin_mask, line_position=300, label="default") # Access data stored out from analyze_bound_horizontal -percent_area_below_reference = pcv.outputs.observations['default_percent_area_below_reference']['value'] +percent_area_below_reference = pcv.outputs.observations['default']['percent_area_below_reference']['value'] ``` diff --git a/docs/analyze_bound_vertical.md b/docs/analyze_bound_vertical.md index ddadb9590..ffbdc35ec 100644 --- a/docs/analyze_bound_vertical.md +++ b/docs/analyze_bound_vertical.md @@ -13,7 +13,7 @@ best if the pot size/position of the plant remains relatively constant. - obj - single or grouped contour object - mask - binary mask of selected contours - line_position - position of boundary line (a value of 0 would draw the line through the left of the image) - - label - Optional label parameter, modifies the variable name of observations recorded. (default `label=None`) + - label - Optional label parameter, modifies the variable name of observations recorded. (default `label="default"`) - **Context:** - Used to define a boundary line for the image, to find the width to the right and to the left as well as area to the right and to the left of a boundary line. - **Example use:** @@ -34,7 +34,7 @@ pcv.params.debug = "print" boundary_image = pcv.analyze_bound_vertical(img=img, obj=obj, mask=bin_mask, line_position=1000, label="default") # Access data stored out from analyze_bound_vertical -area_right_reference = pcv.outputs.observations['default_area_right_reference']['value'] +area_right_reference = pcv.outputs.observations['default']['area_right_reference']['value'] ``` diff --git a/docs/analyze_color.md b/docs/analyze_color.md index e67456fe3..8bba10043 100644 --- a/docs/analyze_color.md +++ b/docs/analyze_color.md @@ -39,7 +39,7 @@ pcv.params.debug = "print" analysis_image = pcv.analyze_color(rgb_img=rgb_img, mask=mask, hist_plot_type='all', label="default") # Access data stored out from analyze_color -hue_circular_mean = pcv.outputs.observations['default_hue_circular_mean']['value'] +hue_circular_mean = pcv.outputs.observations['default']['hue_circular_mean']['value'] ``` diff --git a/docs/analyze_shape.md b/docs/analyze_shape.md index 9d025ecb2..19c6a0daa 100644 --- a/docs/analyze_shape.md +++ b/docs/analyze_shape.md @@ -18,7 +18,7 @@ Shape analysis outputs numeric properties for an input object (contour or groupe - **Example use:** - [Use In VIS Tutorial](vis_tutorial.md) - [Use In NIR Tutorial](nir_tutorial.md) - - [Use In PSII Tutorial](psII_tutorial.md)
 + - [Use In PSII Tutorial](psII_tutorial.md) - **Output data stored:** Data ('area', 'convex_hull_area', 'solidity', 'perimeter', 'width', 'height', 'longest_path', 'center_of_mass, 'convex_hull_vertices', 'object_in_frame', 'ellipse_center', 'ellipse_major_axis', 'ellipse_minor_axis', 'ellipse_angle', 'ellipse_eccentricity') automatically gets stored to the [`Outputs` class](outputs.md) when this function is ran. @@ -45,7 +45,7 @@ shape_image = pcv.analyze_object(img=img, obj=objects, mask=mask, label="default pcv.print_image(shape_image, '/home/malia/setaria_shape_img.png') # Access data stored out from analyze_object -plant_solidity = pcv.outputs.observations['default_solidity']['value'] +plant_solidity = pcv.outputs.observations['default']['solidity']['value'] ``` diff --git a/docs/analyze_spectral.md b/docs/analyze_spectral.md index 66dd63551..8fec460b0 100644 --- a/docs/analyze_spectral.md +++ b/docs/analyze_spectral.md @@ -31,7 +31,7 @@ pcv.params.debug = "print" spectral_hist = pcv.hyperspectral.analyze_spectral(array=spectral_data, mask=mask, histplot=True, label="default") # Access data stored -reflectance_range = max(pcv.outputs.observations['default_max_reflectance']['value']) - min(pcv.outputs.observations['default_min_reflectance']['value']) +reflectance_range = max(pcv.outputs.observations['default']['max_reflectance']['value']) - min(pcv.outputs.observations['default']['min_reflectance']['value']) ``` diff --git a/docs/analyze_stem.md b/docs/analyze_stem.md index d73c1f407..574c7e34a 100644 --- a/docs/analyze_stem.md +++ b/docs/analyze_stem.md @@ -34,10 +34,10 @@ pcv.params.debug = "print" stem_debug_img1 = pcv.morphology.analyze_stem(rgb_img=img1, stem_objects=stem_objects1, label="default") # Access data stored out from analyze_object -stem_angle = pcv.outputs.observations['default_stem_angle']['value'] +stem_angle = pcv.outputs.observations['default']['stem_angle']['value'] stem_debug_img2 = pcv.morphology.analyze_stem(rgb_img=img2, stem_objects=stem_objects2, label="rep1") -stem_angle = pcv.outputs.observations['rep1_stem_angle']['value'] +stem_angle = pcv.outputs.observations['rep1']['stem_angle']['value'] ``` diff --git a/docs/analyze_thermal_values.md b/docs/analyze_thermal_values.md index 7805c947b..9569c887e 100644 --- a/docs/analyze_thermal_values.md +++ b/docs/analyze_thermal_values.md @@ -37,7 +37,7 @@ pcv.params.debug = "print" thermal_hist = pcv.analyze_thermal_values(thermal_array=thermal_img, maks=mask, histplot=True, label="default") # Access data stored out from analyze_thermal_values -temp_range = pcv.outputs.observations['default_max_temp']['value'] - pcv.outputs.observations['default_min_temp']['value'] +temp_range = pcv.outputs.observations['default']['max_temp']['value'] - pcv.outputs.observations['default']['min_temp']['value'] ``` diff --git a/docs/check_cycles.md b/docs/check_cycles.md index 6cfee24a5..22b72df99 100644 --- a/docs/check_cycles.md +++ b/docs/check_cycles.md @@ -33,7 +33,7 @@ pcv.params.debug = "print" cycle_img = pcv.morphology.check_cycles(skel_img=skeleton, label="default") # Access data stored out from check_cycles -num_cycles = pcv.outputs.observations['default_num_cycles']['value'] +num_cycles = pcv.outputs.observations['default']['num_cycles']['value'] ``` diff --git a/docs/fill_segments.md b/docs/fill_segments.md index b3f249560..7133bb93d 100644 --- a/docs/fill_segments.md +++ b/docs/fill_segments.md @@ -36,7 +36,7 @@ pcv.params.debug = "print" filled_img = pcv.morphology.fill_segments(mask=plant_mask, objects=obj, label="default") # Access data stored out from fill_segments -segments_area = pcv.outputs.observations['default_segment_area']['value'] +segments_area = pcv.outputs.observations['default']['segment_area']['value'] ``` diff --git a/docs/find_color_card.md b/docs/find_color_card.md index 8fcbf29d6..f1db3927b 100644 --- a/docs/find_color_card.md +++ b/docs/find_color_card.md @@ -34,7 +34,7 @@ df, start, space = pcv.transform.find_color_card(rgb_img=rgb_img) # Use these outputs to create a labeled color card mask mask = pcv.transform.create_color_card_mask(rgb_img=img, radius=10, start_coord=start, spacing=space, ncols=6, nrows=4, label="prefix") -avg_chip_size = pcv.outputs.observations['prefix_color_chip_size']['value'] +avg_chip_size = pcv.outputs.observations['prefix']['color_chip_size']['value'] ``` diff --git a/docs/landmark_reference_pt_dist.md b/docs/landmark_reference_pt_dist.md index c6f0fabf2..fc2395cc3 100644 --- a/docs/landmark_reference_pt_dist.md +++ b/docs/landmark_reference_pt_dist.md @@ -35,7 +35,7 @@ pcv.params.debug = "print" pcv.landmark_reference_pt_dist(points_r=points_r, centroid_r=centroid_r, bline_r=bline_r, label="default") # Access data stored out from landmark_reference_pt_dist -avg_vert_distance = pcv.outputs.observations['default_vert_ave_c']['value'] +avg_vert_distance = pcv.outputs.observations['default']['vert_ave_c']['value'] ``` diff --git a/docs/output_measurements.md b/docs/output_measurements.md index 1d51fcd79..2f1cf9a5a 100644 --- a/docs/output_measurements.md +++ b/docs/output_measurements.md @@ -12,10 +12,11 @@ The JSON output file has two top-level sections: `variables` is a collection of dataset, and `entities` is a list of data blocks for each unit of analysis (typically an image, or a sub-region of an image) in the dataset. For each entity there are two data blocks: `metadata` is a set of key-value pairs of metadata keywords and their values (e.g. image or experimental metadata such as timestamp, treatment, etc.), and `observations` -is a set of data blocks of observational data or measurements. Each observation has the same set of information, -roughly following the [MIAPPE](https://www.miappe.org/) guidelines: `trait` is the name of the observation, `method` is generally the PlantCV -function name used (but it could be another method), `scale` is the observation units, `datatype` is the Python data -type the data are stored as, `value` is the observation output value(s), and `label` is the data/category label. +is a set of data blocks of observational data or measurements. Observations contain samples. Each sample has the same +set of information, roughly following the [MIAPPE](https://www.miappe.org/) guidelines: `trait` is the name of the +observation, `method` is generally the PlantCV function name used (but it could be another method), `scale` is the +observation units, `datatype` is the Python data type the data are stored as, `value` is the observation output +value(s), and `label` is the data/category label. Example (abbreviated) JSON data: @@ -90,21 +91,23 @@ Example (abbreviated) JSON data: } }, "observations": { - "pixel_area": { - "trait": "area", - "method": "plantcv.plantcv.analyze_object", - "scale": "pixels", - "datatype": "", - "value": 10000, - "label": "pixels" - }, - "hull_area": { - "trait": "convex hull area", - "method": "plantcv.plantcv.analyze_object", - "scale": "pixels", - "datatype": "", - "value": 100000, - "label": "pixels" + "sample1": { + "pixel_area": { + "trait": "area", + "method": "plantcv.plantcv.analyze_object", + "scale": "pixels", + "datatype": "", + "value": 10000, + "label": "pixels" + }, + "hull_area": { + "trait": "convex hull area", + "method": "plantcv.plantcv.analyze_object", + "scale": "pixels", + "datatype": "", + "value": 100000, + "label": "pixels" + } } } } diff --git a/docs/outputs.md b/docs/outputs.md index c11761dd4..113f1c181 100644 --- a/docs/outputs.md +++ b/docs/outputs.md @@ -38,6 +38,8 @@ Methods are accessed as plantcv.outputs.*method*. **add_observation**: Add new measurement or other information +* sample: A sample name or label. Observations are organized by sample name. + * variable: A local unique identifier of a variable, e.g. a short name, that is a key linking the definitions of variables with observations. * trait: A name of the trait mapped to an external ontology; if there is no exact mapping, an informative description of the trait. @@ -66,7 +68,7 @@ from plantcv import plantcv as pcv shape_img = pcv.analyze_object(img, obj, mask, label="default") # Look at object area data without writing to a file -plant_area = pcv.outputs.observations['default_pixel_area']['value'] +plant_area = pcv.outputs.observations['default']['pixel_area']['value'] # Write shape data to results file pcv.print_results(filename=args.result) @@ -97,7 +99,8 @@ healthy_plant = np.count_nonzero(mask['plant']) percent_diseased = sick_plant / (sick_plant + healthy_plant) # Create a new measurement -pcv.outputs.add_observation(variable='percent_diseased', trait='percent of plant detected to be diseased', +pcv.outputs.add_observation(sample='default', variable='percent_diseased', + trait='percent of plant detected to be diseased', method='ratio of pixels', scale='percent', datatype=float, value=percent_diseased, label='percent') diff --git a/docs/photosynthesis_analyze_fvfm.md b/docs/photosynthesis_analyze_fvfm.md index d61e8409c..54cfac96e 100644 --- a/docs/photosynthesis_analyze_fvfm.md +++ b/docs/photosynthesis_analyze_fvfm.md @@ -45,7 +45,7 @@ pcv.params.debug = "print" fvfm_images = pcv.photosynthesis.analyze_fvfm(fdark=fdark, fmin=fmin, fmax=fmax, mask=kept_mask, bins=256, label="fluor") # Access data stored out from fluor_fvfm -fvfm_median = pcv.outputs.observations['fluor_fvfm_median']['value'] +fvfm_median = pcv.outputs.observations['fluor']['fvfm_median']['value'] # Store the two images fvfm_img = fvfm_images[0] diff --git a/docs/report_size_marker.md b/docs/report_size_marker.md index 82bfebca1..8adebc4a3 100644 --- a/docs/report_size_marker.md +++ b/docs/report_size_marker.md @@ -45,7 +45,7 @@ image = pcv.report_size_marker_area(img=img1, roi_contour=roi_contour, roi_hiera marker='detect', objcolor='light', thresh_channel='s', thresh=120, label="default") # Access data stored out from report_size_marker_area -marker_area = pcv.outputs.observations['default_marker_area']['value'] +marker_area = pcv.outputs.observations['default']['marker_area']['value'] ``` diff --git a/docs/segment_angle.md b/docs/segment_angle.md index f1398d1d9..dad595ca0 100644 --- a/docs/segment_angle.md +++ b/docs/segment_angle.md @@ -34,7 +34,7 @@ pcv.params.debug = "print" labeled_img = pcv.morphology.segment_angle(segmented_img=segmented_img, objects=obj, label="default") # Access data stored out from segment_angle -segment_angles = pcv.outputs.observations['default_segment_angle']['value'] +segment_angles = pcv.outputs.observations['default']['segment_angle']['value'] ``` diff --git a/docs/segment_curvature.md b/docs/segment_curvature.md index 0261119a8..65b715133 100644 --- a/docs/segment_curvature.md +++ b/docs/segment_curvature.md @@ -36,9 +36,8 @@ labeled_img2 = pcv.morphology.segment_curvature(segmented_img=leaf_segmented, objects=leaf_obj, label="leaf") # Access data stored out from segment_curvature -all_curvatures = pcv.outputs.observations['all_segment_curvature']['value'] -leaf_curvatures = pcv.outputs.observations['leaf_segment_curvature']['value'] - +all_curvatures = pcv.outputs.observations['all']['segment_curvature']['value'] +leaf_curvatures = pcv.outputs.observations['leaf']['segment_curvature']['value'] ``` diff --git a/docs/segment_euclidean_length.md b/docs/segment_euclidean_length.md index 8df4e187f..75712c39f 100644 --- a/docs/segment_euclidean_length.md +++ b/docs/segment_euclidean_length.md @@ -33,10 +33,10 @@ from plantcv import plantcv as pcv pcv.params.debug = "print" labeled_img = pcv.morphology.segment_euclidean_length(segmented_img=segmented_img, - objects=obj, label=None) + objects=obj, label="default") # Access data stored out from segment_euclidean_length -euclidean_lengths = pcv.outputs.observations['segment_eu_length']['value'] +euclidean_lengths = pcv.outputs.observations['default']['segment_eu_length']['value'] ``` diff --git a/docs/segment_insertion_angle.md b/docs/segment_insertion_angle.md index 0f9526e16..a98a7ae65 100644 --- a/docs/segment_insertion_angle.md +++ b/docs/segment_insertion_angle.md @@ -45,7 +45,7 @@ labeled_img = pcv.morphology.segment_insertion_angle(skel_img=skeleton, size=20, label="default") # Access data stored out from segment_insertion_angle -segment_insertion_angles = pcv.outputs.observations['default_segment_insertion_angle']['value'] +segment_insertion_angles = pcv.outputs.observations['default']['segment_insertion_angle']['value'] ``` diff --git a/docs/segment_pathlength.md b/docs/segment_pathlength.md index b6b432b64..25ea97394 100644 --- a/docs/segment_pathlength.md +++ b/docs/segment_pathlength.md @@ -36,7 +36,7 @@ labeled_img = pcv.morphology.segment_path_length(segmented_img=segmented_img, objects=obj, label="default") # Access data stored out from segment_path_length -path_lengths = pcv.outputs.observations['default_segment_path_length']['value'] +path_lengths = pcv.outputs.observations['default']['segment_path_length']['value'] ``` diff --git a/docs/segment_tangent_angle.md b/docs/segment_tangent_angle.md index 84fddb33a..c0a8e7f8b 100644 --- a/docs/segment_tangent_angle.md +++ b/docs/segment_tangent_angle.md @@ -43,7 +43,7 @@ labeled_img = pcv.morphology.segment_tangent_angle(segmented_img=leaves_segment, size=15, label="default") # Access data stored out from segment_tangent_angle -leaf_tangent_angles = pcv.outputs.observations['default_segment_tangent_angle']['value'] +leaf_tangent_angles = pcv.outputs.observations['default']['segment_tangent_angle']['value'] ``` diff --git a/docs/x_axis_pseudolandmarks.md b/docs/x_axis_pseudolandmarks.md index 95b12d41d..8f70414f4 100644 --- a/docs/x_axis_pseudolandmarks.md +++ b/docs/x_axis_pseudolandmarks.md @@ -32,7 +32,7 @@ pcv.params.debug = "plot" top, bottom, center_v = pcv.x_axis_pseudolandmarks(img=img, obj=obj, mask=mask, label="default") # Access data stored out from x_axis_pseudolandmarks -bottom_landmarks = pcv.outputs.observations['default_bottom_lmk']['value'] +bottom_landmarks = pcv.outputs.observations['default']['bottom_lmk']['value'] ``` diff --git a/docs/y_axis_pseudolandmarks.md b/docs/y_axis_pseudolandmarks.md index 94fa1829d..4dca0ad7d 100644 --- a/docs/y_axis_pseudolandmarks.md +++ b/docs/y_axis_pseudolandmarks.md @@ -4,7 +4,7 @@ Divide plant object into twenty equidistant bins along the y-axis and assign pse actual (not scaled) position. Once this data is scaled this approach may provide some information regarding shape independent of size. -**plantcv.y_axis_pseudolandmarks**(*img, obj, mask, label=None*) +**plantcv.y_axis_pseudolandmarks**(*img, obj, mask, label="default"*) **returns** landmarks_on_leftside (left), landmarks_on_right (right), landmarks_at_center_along_the_horizontal_axis (center_h) @@ -32,10 +32,10 @@ pcv.params.debug = "plot" # Identify a set of land mark points # Results in set of point values that may indicate tip points -left, right, center_h = pcv.y_axis_pseudolandmarks(img=img, obj=obj, mask=mask, label=None) +left, right, center_h = pcv.y_axis_pseudolandmarks(img=img, obj=obj, mask=mask, label="default") # Access data stored out from y_axis_pseudolandmarks -left_landmarks = pcv.outputs.observations['left_lmk']['value'] +left_landmarks = pcv.outputs.observations['default']['left_lmk']['value'] ``` From beb829be3f4ae1049f5db143758b4b8de4c13dbe Mon Sep 17 00:00:00 2001 From: nfahlgren Date: Fri, 12 Feb 2021 21:38:31 -0600 Subject: [PATCH 134/137] Remove trailing whitespace --- plantcv/plantcv/report_size_marker_area.py | 2 +- plantcv/plantcv/y_axis_pseudolandmarks.py | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/plantcv/plantcv/report_size_marker_area.py b/plantcv/plantcv/report_size_marker_area.py index 09e6493e8..c6f31eacb 100755 --- a/plantcv/plantcv/report_size_marker_area.py +++ b/plantcv/plantcv/report_size_marker_area.py @@ -41,7 +41,7 @@ def report_size_marker_area(img, roi_contour, roi_hierarchy, marker='define', ob :param objcolor: str :param thresh_channel: str :param thresh: int - :param label: str + :param label: str :return: analysis_images: list """ # Store debug diff --git a/plantcv/plantcv/y_axis_pseudolandmarks.py b/plantcv/plantcv/y_axis_pseudolandmarks.py index ae1d616ca..e8d763a40 100755 --- a/plantcv/plantcv/y_axis_pseudolandmarks.py +++ b/plantcv/plantcv/y_axis_pseudolandmarks.py @@ -27,7 +27,7 @@ def y_axis_pseudolandmarks(img, obj, mask, label="default"): :param img: numpy.ndarray :param obj: list :param mask: numpy.ndarray - :param label: str + :param label: str :return left: list :return right: list :return center_h: list From a295a591c359ceac82ab24fbd0a58d694ce2c81c Mon Sep 17 00:00:00 2001 From: nfahlgren Date: Fri, 12 Feb 2021 21:38:43 -0600 Subject: [PATCH 135/137] Add sample to docs --- docs/acute_vertex.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/acute_vertex.md b/docs/acute_vertex.md index 463beea2d..d41b75088 100644 --- a/docs/acute_vertex.md +++ b/docs/acute_vertex.md @@ -36,7 +36,7 @@ pcv.params.debug = "print" list_of_acute_points, points_img = pcv.acute_vertex(img=img, obj=obj, window=30, thresh=15, sep=100, label="default") # Access data stored out from acute_vertex -vertices = pcv.outputs.observations['default_tip_coordinates']['value'] +vertices = pcv.outputs.observations['default']['tip_coordinates']['value'] ``` From ba443e4fac8a395e725e245fd0e588911d29a6e7 Mon Sep 17 00:00:00 2001 From: nfahlgren Date: Sat, 13 Feb 2021 10:13:04 -0600 Subject: [PATCH 136/137] Update test data with samples --- tests/data/merged_output.json | 5760 ++++++++++++++++++++++++++++++++- 1 file changed, 5759 insertions(+), 1 deletion(-) diff --git a/tests/data/merged_output.json b/tests/data/merged_output.json index 1326fef5d..f70c2d9ab 100644 --- a/tests/data/merged_output.json +++ b/tests/data/merged_output.json @@ -1 +1,5759 @@ -{"variables": {"camera": {"category": "metadata", "datatype": ""}, "imgtype": {"category": "metadata", "datatype": ""}, "zoom": {"category": "metadata", "datatype": ""}, "exposure": {"category": "metadata", "datatype": ""}, "gain": {"category": "metadata", "datatype": ""}, "frame": {"category": "metadata", "datatype": ""}, "lifter": {"category": "metadata", "datatype": ""}, "timestamp": {"category": "metadata", "datatype": ""}, "id": {"category": "metadata", "datatype": ""}, "plantbarcode": {"category": "metadata", "datatype": ""}, "treatment": {"category": "metadata", "datatype": ""}, "cartag": {"category": "metadata", "datatype": ""}, "measurementlabel": {"category": "metadata", "datatype": ""}, "other": {"category": "metadata", "datatype": ""}, "image": {"category": "metadata", "datatype": ""}, "nir_frequencies": {"category": "observations", "datatype": ""}, "area": {"category": "observations", "datatype": ""}, "convex_hull_area": {"category": "observations", "datatype": ""}, "solidity": {"category": "observations", "datatype": ""}, "perimeter": {"category": "observations", "datatype": ""}, "width": {"category": "observations", "datatype": ""}, "height": {"category": "observations", "datatype": ""}, "longest_path": {"category": "observations", "datatype": ""}, "center_of_mass": {"category": "observations", "datatype": ""}, "convex_hull_vertices": {"category": "observations", "datatype": ""}, "object_in_frame": {"category": "observations", "datatype": ""}, "ellipse_center": {"category": "observations", "datatype": ""}, "ellipse_major_axis": {"category": "observations", "datatype": ""}, "ellipse_minor_axis": {"category": "observations", "datatype": ""}, "ellipse_angle": {"category": "observations", "datatype": ""}, "ellipse_eccentricity": {"category": "observations", "datatype": ""}, "horizontal_reference_position": {"category": "observations", "datatype": ""}, "height_above_reference": {"category": "observations", "datatype": ""}, "height_below_reference": {"category": "observations", "datatype": ""}, "area_above_reference": {"category": "observations", "datatype": ""}, "percent_area_above_reference": {"category": "observations", "datatype": ""}, "area_below_reference": {"category": "observations", "datatype": ""}, "percent_area_below_reference": {"category": "observations", "datatype": ""}, "blue_frequencies": {"category": "observations", "datatype": ""}, "green_frequencies": {"category": "observations", "datatype": ""}, "red_frequencies": {"category": "observations", "datatype": ""}, "lightness_frequencies": {"category": "observations", "datatype": ""}, "green-magenta_frequencies": {"category": "observations", "datatype": ""}, "blue-yellow_frequencies": {"category": "observations", "datatype": ""}, "hue_frequencies": {"category": "observations", "datatype": ""}, "saturation_frequencies": {"category": "observations", "datatype": ""}, "value_frequencies": {"category": "observations", "datatype": ""}, "hue_circular_mean": {"category": "observations", "datatype": ""}, "hue_circular_std": {"category": "observations", "datatype": ""}, "hue_median": {"category": "observations", "datatype": ""}}, "entities": [{"metadata": {"camera": {"label": "camera identifier", "datatype": "", "value": "SV"}, "imgtype": {"label": "image type", "datatype": "", "value": "NIR"}, "zoom": {"label": "camera zoom setting", "datatype": "", "value": "z1"}, "exposure": {"label": "camera exposure setting", "datatype": "", "value": "e65"}, "gain": {"label": "camera gain setting", "datatype": "", "value": "g0"}, "frame": {"label": "image series frame identifier", "datatype": "", "value": "90"}, "lifter": {"label": "imaging platform height setting", "datatype": "", "value": "h1"}, "timestamp": {"label": "datetime of image", "datatype": "", "value": "2014-10-22 17:59:23.046"}, "id": {"label": "image identifier", "datatype": "", "value": "117881"}, "plantbarcode": {"label": "plant barcode identifier", "datatype": "", "value": "Ca002AA010557"}, "treatment": {"label": "treatment identifier", "datatype": "", "value": "none"}, "cartag": {"label": "plant carrier identifier", "datatype": "", "value": "1663"}, "measurementlabel": {"label": "experiment identifier", "datatype": "", "value": "C002ch_092214_biomass"}, "other": {"label": "other identifier", "datatype": "", "value": "none"}, "image": {"label": "image file", "datatype": "", "value": "./images/snapshot57393/NIR_SV_90_z1_h1_g0_e65_117881.png"}}, "observations": {"nir_frequencies": {"trait": "near-infrared frequencies", "method": "plantcv.plantcv.analyze_nir_intensity", "scale": "frequency", "datatype": "", "value": [0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 1.0, 3.0, 3.0, 2.0, 8.0, 9.0, 3.0, 5.0, 2.0, 8.0, 2.0, 3.0, 3.0, 2.0, 4.0, 3.0, 2.0, 3.0, 3.0, 4.0, 4.0, 4.0, 4.0, 4.0, 1.0, 1.0, 3.0, 3.0, 3.0, 6.0, 7.0, 6.0, 13.0, 13.0, 8.0, 7.0, 8.0, 10.0, 12.0, 10.0, 11.0, 6.0, 14.0, 14.0, 14.0, 8.0, 9.0, 9.0, 9.0, 9.0, 9.0, 5.0, 7.0, 6.0, 7.0, 4.0, 5.0, 8.0, 5.0, 6.0, 3.0, 5.0, 5.0, 5.0, 5.0, 7.0, 6.0, 7.0, 5.0, 5.0, 6.0, 12.0, 7.0, 10.0, 15.0, 14.0, 12.0, 15.0, 11.0, 4.0, 9.0, 10.0, 4.0, 15.0, 10.0, 11.0, 6.0, 18.0, 11.0, 5.0, 7.0, 4.0, 5.0, 5.0, 10.0, 5.0, 10.0, 6.0, 11.0, 12.0, 8.0, 6.0, 1.0, 8.0, 9.0, 9.0, 11.0, 9.0, 9.0, 7.0, 13.0, 6.0, 4.0, 7.0, 8.0, 7.0, 8.0, 4.0, 4.0, 9.0, 3.0, 1.0, 1.0, 2.0, 5.0, 9.0, 3.0, 7.0, 10.0, 10.0, 5.0, 2.0, 5.0, 4.0, 0.0, 1.0, 1.0, 1.0, 2.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 1.0, 0.0, 2.0, 1.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0], "label": [1.0, 2.0, 2.99, 3.99, 4.98, 5.98, 6.98, 7.97, 8.97, 9.96, 10.96, 11.96, 12.95, 13.95, 14.95, 15.94, 16.94, 17.93, 18.93, 19.93, 20.92, 21.92, 22.91, 23.91, 24.91, 25.9, 26.9, 27.89, 28.89, 29.89, 30.88, 31.88, 32.88, 33.87, 34.87, 35.86, 36.86, 37.86, 38.85, 39.85, 40.84, 41.84, 42.84, 43.83, 44.83, 45.82, 46.82, 47.82, 48.81, 49.81, 50.8, 51.8, 52.8, 53.79, 54.79, 55.79, 56.78, 57.78, 58.77, 59.77, 60.77, 61.76, 62.76, 63.75, 64.75, 65.75, 66.74, 67.74, 68.73, 69.73, 70.73, 71.72, 72.72, 73.71, 74.71, 75.71, 76.7, 77.7, 78.7, 79.69, 80.69, 81.68, 82.68, 83.68, 84.67, 85.67, 86.66, 87.66, 88.66, 89.65, 90.65, 91.64, 92.64, 93.64, 94.63, 95.63, 96.62, 97.62, 98.62, 99.61, 100.61, 101.61, 102.6, 103.6, 104.59, 105.59, 106.59, 107.58, 108.58, 109.57, 110.57, 111.57, 112.56, 113.56, 114.55, 115.55, 116.55, 117.54, 118.54, 119.54, 120.53, 121.53, 122.52, 123.52, 124.52, 125.51, 126.51, 127.5, 128.5, 129.5, 130.49, 131.49, 132.48, 133.48, 134.48, 135.47, 136.47, 137.46, 138.46, 139.46, 140.45, 141.45, 142.45, 143.44, 144.44, 145.43, 146.43, 147.43, 148.42, 149.42, 150.41, 151.41, 152.41, 153.4, 154.4, 155.39, 156.39, 157.39, 158.38, 159.38, 160.38, 161.37, 162.37, 163.36, 164.36, 165.36, 166.35, 167.35, 168.34, 169.34, 170.34, 171.33, 172.33, 173.32, 174.32, 175.32, 176.31, 177.31, 178.3, 179.3, 180.3, 181.29, 182.29, 183.29, 184.28, 185.28, 186.27, 187.27, 188.27, 189.26, 190.26, 191.25, 192.25, 193.25, 194.24, 195.24, 196.23, 197.23, 198.23, 199.22, 200.22, 201.21, 202.21, 203.21, 204.2, 205.2, 206.2, 207.19, 208.19, 209.18, 210.18, 211.18, 212.17, 213.17, 214.16, 215.16, 216.16, 217.15, 218.15, 219.14, 220.14, 221.14, 222.13, 223.13, 224.12, 225.12, 226.12, 227.11, 228.11, 229.11, 230.1, 231.1, 232.09, 233.09, 234.09, 235.08, 236.08, 237.07, 238.07, 239.07, 240.06, 241.06, 242.05, 243.05, 244.05, 245.04, 246.04, 247.04, 248.03, 249.03, 250.02, 251.02, 252.02, 253.01, 254.01, 255.0]}, "area": {"trait": "area", "method": "plantcv.plantcv.analyze_object", "scale": "pixels", "datatype": "", "value": 923.0, "label": "pixels"}, "convex_hull_area": {"trait": "convex hull area", "method": "plantcv.plantcv.analyze_object", "scale": "pixels", "datatype": "", "value": 3027.0, "label": "pixels"}, "solidity": {"trait": "solidity", "method": "plantcv.plantcv.analyze_object", "scale": "none", "datatype": "", "value": 0.3049223653782623, "label": "none"}, "perimeter": {"trait": "perimeter", "method": "plantcv.plantcv.analyze_object", "scale": "pixels", "datatype": "", "value": 627.1807925701141, "label": "pixels"}, "width": {"trait": "width", "method": "plantcv.plantcv.analyze_object", "scale": "pixels", "datatype": "", "value": 54, "label": "pixels"}, "height": {"trait": "height", "method": "plantcv.plantcv.analyze_object", "scale": "pixels", "datatype": "", "value": 78, "label": "pixels"}, "longest_path": {"trait": "longest path", "method": "plantcv.plantcv.analyze_object", "scale": "pixels", "datatype": "", "value": 513, "label": "pixels"}, "center_of_mass": {"trait": "center of mass", "method": "plantcv.plantcv.analyze_object", "scale": "none", "datatype": "", "value": [151.19501625135428, 192.3694474539545], "label": "none"}, "convex_hull_vertices": {"trait": "convex hull vertices", "method": "plantcv.plantcv.analyze_object", "scale": "none", "datatype": "", "value": 14, "label": "none"}, "object_in_frame": {"trait": "object in frame", "method": "plantcv.plantcv.analyze_object", "scale": "none", "datatype": "", "value": true, "label": "none"}, "ellipse_center": {"trait": "ellipse center", "method": "plantcv.plantcv.analyze_object", "scale": "none", "datatype": "", "value": [153.5628662109375, 192.63124084472656], "label": "none"}, "ellipse_major_axis": {"trait": "ellipse major axis length", "method": "plantcv.plantcv.analyze_object", "scale": "pixels", "datatype": "", "value": 65.83857727050781, "label": "pixels"}, "ellipse_minor_axis": {"trait": "ellipse minor axis length", "method": "plantcv.plantcv.analyze_object", "scale": "pixels", "datatype": "", "value": 42.24153518676758, "label": "pixels"}, "ellipse_angle": {"trait": "ellipse major axis angle", "method": "plantcv.plantcv.analyze_object", "scale": "degrees", "datatype": "", "value": 167.28292846679688, "label": "degrees"}, "ellipse_eccentricity": {"trait": "ellipse eccentricity", "method": "plantcv.plantcv.analyze_object", "scale": "none", "datatype": "", "value": 0.7670457006165471, "label": "none"}}}, {"metadata": {"camera": {"label": "camera identifier", "datatype": "", "value": "SV"}, "imgtype": {"label": "image type", "datatype": "", "value": "VIS"}, "zoom": {"label": "camera zoom setting", "datatype": "", "value": "z1"}, "exposure": {"label": "camera exposure setting", "datatype": "", "value": "e82"}, "gain": {"label": "camera gain setting", "datatype": "", "value": "g0"}, "frame": {"label": "image series frame identifier", "datatype": "", "value": "90"}, "timestamp": {"label": "datetime of image", "datatype": "", "value": "2014-10-22 17:59:23.046"}, "id": {"label": "image identifier", "datatype": "", "value": "117872"}, "plantbarcode": {"label": "plant barcode identifier", "datatype": "", "value": "Ca002AA010557"}, "treatment": {"label": "treatment identifier", "datatype": "", "value": "none"}, "cartag": {"label": "plant carrier identifier", "datatype": "", "value": "1663"}, "measurementlabel": {"label": "experiment identifier", "datatype": "", "value": "C002ch_092214_biomass"}, "other": {"label": "other identifier", "datatype": "", "value": "none"}, "image": {"label": "image file", "datatype": "", "value": "./images/snapshot57393/VIS_SV_90_z1_h1_g0_e82_117872.png"}}, "observations": {"area": {"trait": "area", "method": "plantcv.plantcv.analyze_object", "scale": "pixels", "datatype": "", "value": 65851.0, "label": "pixels"}, "convex_hull_area": {"trait": "convex hull area", "method": "plantcv.plantcv.analyze_object", "scale": "pixels", "datatype": "", "value": 232885.5, "label": "pixels"}, "solidity": {"trait": "solidity", "method": "plantcv.plantcv.analyze_object", "scale": "none", "datatype": "", "value": 0.28276127109674065, "label": "none"}, "perimeter": {"trait": "perimeter", "method": "plantcv.plantcv.analyze_object", "scale": "pixels", "datatype": "", "value": 7412.37744474411, "label": "pixels"}, "width": {"trait": "width", "method": "plantcv.plantcv.analyze_object", "scale": "pixels", "datatype": "", "value": 472, "label": "pixels"}, "height": {"trait": "height", "method": "plantcv.plantcv.analyze_object", "scale": "pixels", "datatype": "", "value": 677, "label": "pixels"}, "longest_path": {"trait": "longest path", "method": "plantcv.plantcv.analyze_object", "scale": "pixels", "datatype": "", "value": 4533, "label": "pixels"}, "center_of_mass": {"trait": "center of mass", "method": "plantcv.plantcv.analyze_object", "scale": "none", "datatype": "", "value": [1286.1963068138677, 1418.1369151569452], "label": "none"}, "convex_hull_vertices": {"trait": "convex hull vertices", "method": "plantcv.plantcv.analyze_object", "scale": "none", "datatype": "", "value": 20, "label": "none"}, "object_in_frame": {"trait": "object in frame", "method": "plantcv.plantcv.analyze_object", "scale": "none", "datatype": "", "value": true, "label": "none"}, "ellipse_center": {"trait": "ellipse center", "method": "plantcv.plantcv.analyze_object", "scale": "none", "datatype": "", "value": [1265.687255859375, 1426.276123046875], "label": "none"}, "ellipse_major_axis": {"trait": "ellipse major axis length", "method": "plantcv.plantcv.analyze_object", "scale": "pixels", "datatype": "", "value": 576.3345336914062, "label": "pixels"}, "ellipse_minor_axis": {"trait": "ellipse minor axis length", "method": "plantcv.plantcv.analyze_object", "scale": "pixels", "datatype": "", "value": 367.6441955566406, "label": "pixels"}, "ellipse_angle": {"trait": "ellipse major axis angle", "method": "plantcv.plantcv.analyze_object", "scale": "degrees", "datatype": "", "value": 12.61721134185791, "label": "degrees"}, "ellipse_eccentricity": {"trait": "ellipse eccentricity", "method": "plantcv.plantcv.analyze_object", "scale": "none", "datatype": "", "value": 0.77011863518315, "label": "none"}, "horizontal_reference_position": {"trait": "horizontal reference position", "method": "plantcv.plantcv.analyze_bound_horizontal", "scale": "none", "datatype": "", "value": 384, "label": "none"}, "height_below_reference": {"trait": "height_below_reference", "method": "plantcv.plantcv.analyze_bound_horizontal", "scale": "pixels", "datatype": "", "value": 677, "label": "pixels"}, "area_above_reference": {"trait": "area above reference", "method": "plantcv.plantcv.analyze_bound_horizontal", "scale": "pixels", "datatype": "", "value": 0, "label": "pixels"}, "percent_area_above_reference": {"trait": "percent area above reference", "method": "plantcv.plantcv.analyze_bound_horizontal", "scale": "none", "datatype": "", "value": 0.0, "label": "none"}, "area_below_reference": {"trait": "area below reference", "method": "plantcv.plantcv.analyze_bound_horizontal", "scale": "pixels", "datatype": "", "value": 65851, "label": "pixels"}, "percent_area_below_reference": {"trait": "percent area below reference", "method": "plantcv.plantcv.analyze_bound_horizontal", "scale": "none", "datatype": "", "value": 100.0, "label": "none"}, "blue_frequencies": {"trait": "blue frequencies", "method": "plantcv.plantcv.analyze_color", "scale": "frequency", "datatype": "", "value": [0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 1.0, 10.0, 14.0, 56.0, 141.0, 290.0, 382.0, 481.0, 725.0, 1017.0, 1295.0, 1683.0, 1897.0, 2269.0, 2446.0, 2709.0, 2826.0, 3149.0, 3142.0, 2989.0, 2943.0, 2765.0, 2665.0, 2110.0, 1856.0, 1622.0, 1576.0, 1391.0, 1301.0, 1288.0, 1232.0, 1180.0, 1110.0, 1007.0, 886.0, 786.0, 679.0, 605.0, 566.0, 503.0, 465.0, 459.0, 419.0, 379.0, 309.0, 303.0, 288.0, 255.0, 202.0, 203.0, 188.0, 180.0, 158.0, 165.0, 144.0, 150.0, 144.0, 126.0, 141.0, 111.0, 123.0, 111.0, 95.0, 102.0, 80.0, 83.0, 89.0, 70.0, 99.0, 78.0, 72.0, 80.0, 86.0, 74.0, 70.0, 65.0, 58.0, 79.0, 62.0, 68.0, 71.0, 69.0, 69.0, 74.0, 68.0, 52.0, 53.0, 60.0, 67.0, 39.0, 64.0, 54.0, 44.0, 59.0, 59.0, 46.0, 48.0, 46.0, 58.0, 73.0, 58.0, 54.0, 43.0, 58.0, 53.0, 55.0, 58.0, 41.0, 50.0, 48.0, 73.0, 50.0, 35.0, 52.0, 49.0, 42.0, 51.0, 50.0, 49.0, 59.0, 57.0, 40.0, 43.0, 31.0, 51.0, 46.0, 60.0, 41.0, 62.0, 50.0, 57.0, 40.0, 43.0, 41.0, 42.0, 51.0, 37.0, 36.0, 31.0, 39.0, 31.0, 37.0, 38.0, 39.0, 42.0, 26.0, 30.0, 40.0, 23.0, 34.0, 16.0, 30.0, 30.0, 30.0, 29.0, 20.0, 15.0, 16.0, 24.0, 13.0, 17.0, 15.0, 8.0, 9.0, 8.0, 13.0, 9.0, 13.0, 6.0, 7.0, 9.0, 4.0, 5.0, 6.0, 2.0, 4.0, 2.0, 2.0, 5.0, 6.0, 0.0, 0.0, 2.0, 1.0, 0.0, 2.0, 1.0, 1.0, 1.0, 0.0, 1.0, 2.0, 1.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0], "label": [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 64, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, 95, 96, 97, 98, 99, 100, 101, 102, 103, 104, 105, 106, 107, 108, 109, 110, 111, 112, 113, 114, 115, 116, 117, 118, 119, 120, 121, 122, 123, 124, 125, 126, 127, 128, 129, 130, 131, 132, 133, 134, 135, 136, 137, 138, 139, 140, 141, 142, 143, 144, 145, 146, 147, 148, 149, 150, 151, 152, 153, 154, 155, 156, 157, 158, 159, 160, 161, 162, 163, 164, 165, 166, 167, 168, 169, 170, 171, 172, 173, 174, 175, 176, 177, 178, 179, 180, 181, 182, 183, 184, 185, 186, 187, 188, 189, 190, 191, 192, 193, 194, 195, 196, 197, 198, 199, 200, 201, 202, 203, 204, 205, 206, 207, 208, 209, 210, 211, 212, 213, 214, 215, 216, 217, 218, 219, 220, 221, 222, 223, 224, 225, 226, 227, 228, 229, 230, 231, 232, 233, 234, 235, 236, 237, 238, 239, 240, 241, 242, 243, 244, 245, 246, 247, 248, 249, 250, 251, 252, 253, 254, 255]}, "green_frequencies": {"trait": "green frequencies", "method": "plantcv.plantcv.analyze_color", "scale": "frequency", "datatype": "", "value": [0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 1.0, 1.0, 2.0, 12.0, 12.0, 13.0, 9.0, 14.0, 12.0, 19.0, 31.0, 46.0, 74.0, 103.0, 133.0, 159.0, 222.0, 197.0, 299.0, 319.0, 395.0, 484.0, 547.0, 604.0, 734.0, 850.0, 965.0, 991.0, 1085.0, 1243.0, 1427.0, 1541.0, 1619.0, 1711.0, 1834.0, 1861.0, 1948.0, 1807.0, 1833.0, 1750.0, 1834.0, 1712.0, 1812.0, 1930.0, 1946.0, 2154.0, 2005.0, 2014.0, 1697.0, 1383.0, 1201.0, 1075.0, 965.0, 969.0, 847.0, 917.0, 875.0, 803.0, 713.0, 652.0, 613.0, 574.0, 542.0, 510.0, 448.0, 393.0, 376.0, 341.0, 331.0, 297.0, 245.0, 212.0, 202.0, 179.0, 159.0, 144.0, 130.0, 120.0, 127.0, 110.0, 110.0, 106.0, 105.0, 90.0, 84.0, 93.0, 88.0, 100.0, 88.0, 73.0, 104.0, 75.0, 72.0, 79.0, 79.0, 88.0, 64.0, 75.0, 80.0, 68.0, 75.0, 67.0, 69.0, 63.0, 64.0, 57.0, 68.0, 56.0, 53.0, 67.0, 69.0, 61.0, 57.0, 52.0, 68.0, 52.0, 46.0, 68.0, 53.0, 60.0, 75.0, 46.0, 55.0, 51.0, 54.0, 41.0, 58.0, 61.0, 57.0, 46.0, 44.0, 50.0, 54.0, 61.0, 46.0, 40.0, 35.0, 67.0, 47.0, 45.0, 53.0, 35.0, 52.0, 35.0, 54.0, 51.0, 39.0, 54.0, 43.0, 55.0, 44.0, 37.0, 30.0, 45.0, 41.0, 30.0, 39.0, 37.0, 47.0, 30.0, 26.0, 41.0, 29.0, 36.0, 34.0, 24.0, 27.0, 25.0, 25.0, 25.0, 23.0, 23.0, 15.0, 12.0, 12.0, 12.0, 16.0, 13.0, 12.0, 10.0, 4.0, 14.0, 10.0, 8.0, 6.0, 6.0, 9.0, 13.0, 8.0, 0.0, 3.0, 5.0, 6.0, 0.0, 2.0, 4.0, 1.0, 0.0, 3.0, 1.0, 2.0, 3.0, 0.0, 1.0, 1.0, 0.0, 1.0, 4.0, 1.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0], "label": [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 64, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, 95, 96, 97, 98, 99, 100, 101, 102, 103, 104, 105, 106, 107, 108, 109, 110, 111, 112, 113, 114, 115, 116, 117, 118, 119, 120, 121, 122, 123, 124, 125, 126, 127, 128, 129, 130, 131, 132, 133, 134, 135, 136, 137, 138, 139, 140, 141, 142, 143, 144, 145, 146, 147, 148, 149, 150, 151, 152, 153, 154, 155, 156, 157, 158, 159, 160, 161, 162, 163, 164, 165, 166, 167, 168, 169, 170, 171, 172, 173, 174, 175, 176, 177, 178, 179, 180, 181, 182, 183, 184, 185, 186, 187, 188, 189, 190, 191, 192, 193, 194, 195, 196, 197, 198, 199, 200, 201, 202, 203, 204, 205, 206, 207, 208, 209, 210, 211, 212, 213, 214, 215, 216, 217, 218, 219, 220, 221, 222, 223, 224, 225, 226, 227, 228, 229, 230, 231, 232, 233, 234, 235, 236, 237, 238, 239, 240, 241, 242, 243, 244, 245, 246, 247, 248, 249, 250, 251, 252, 253, 254, 255]}, "red_frequencies": {"trait": "red frequencies", "method": "plantcv.plantcv.analyze_color", "scale": "frequency", "datatype": "", "value": [0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 4.0, 8.0, 16.0, 39.0, 68.0, 95.0, 136.0, 180.0, 279.0, 452.0, 544.0, 769.0, 859.0, 1009.0, 1041.0, 1218.0, 1372.0, 1446.0, 1573.0, 1826.0, 2054.0, 2320.0, 2190.0, 2194.0, 2127.0, 2090.0, 1989.0, 2131.0, 2431.0, 2169.0, 2148.0, 1961.0, 1898.0, 1542.0, 1356.0, 1267.0, 1169.0, 1010.0, 953.0, 825.0, 818.0, 728.0, 674.0, 618.0, 621.0, 556.0, 584.0, 568.0, 560.0, 447.0, 419.0, 346.0, 332.0, 323.0, 312.0, 298.0, 279.0, 243.0, 240.0, 217.0, 198.0, 163.0, 166.0, 173.0, 160.0, 150.0, 128.0, 128.0, 121.0, 136.0, 103.0, 112.0, 110.0, 96.0, 103.0, 118.0, 119.0, 100.0, 99.0, 81.0, 98.0, 95.0, 96.0, 86.0, 95.0, 68.0, 97.0, 74.0, 97.0, 75.0, 90.0, 78.0, 92.0, 83.0, 72.0, 64.0, 64.0, 69.0, 75.0, 71.0, 79.0, 75.0, 66.0, 66.0, 76.0, 77.0, 71.0, 59.0, 50.0, 69.0, 67.0, 66.0, 55.0, 77.0, 58.0, 53.0, 70.0, 73.0, 57.0, 52.0, 74.0, 55.0, 66.0, 79.0, 52.0, 48.0, 55.0, 53.0, 46.0, 63.0, 71.0, 41.0, 52.0, 45.0, 54.0, 41.0, 53.0, 51.0, 59.0, 44.0, 39.0, 43.0, 41.0, 43.0, 43.0, 36.0, 50.0, 44.0, 41.0, 43.0, 43.0, 34.0, 40.0, 36.0, 41.0, 36.0, 35.0, 28.0, 36.0, 28.0, 29.0, 31.0, 23.0, 26.0, 27.0, 27.0, 25.0, 23.0, 19.0, 22.0, 23.0, 16.0, 20.0, 17.0, 14.0, 11.0, 11.0, 6.0, 13.0, 8.0, 5.0, 14.0, 6.0, 11.0, 4.0, 7.0, 5.0, 3.0, 10.0, 3.0, 5.0, 6.0, 2.0, 3.0, 3.0, 2.0, 5.0, 5.0, 3.0, 3.0, 3.0, 0.0, 1.0, 0.0, 1.0, 1.0, 0.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0], "label": [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 64, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, 95, 96, 97, 98, 99, 100, 101, 102, 103, 104, 105, 106, 107, 108, 109, 110, 111, 112, 113, 114, 115, 116, 117, 118, 119, 120, 121, 122, 123, 124, 125, 126, 127, 128, 129, 130, 131, 132, 133, 134, 135, 136, 137, 138, 139, 140, 141, 142, 143, 144, 145, 146, 147, 148, 149, 150, 151, 152, 153, 154, 155, 156, 157, 158, 159, 160, 161, 162, 163, 164, 165, 166, 167, 168, 169, 170, 171, 172, 173, 174, 175, 176, 177, 178, 179, 180, 181, 182, 183, 184, 185, 186, 187, 188, 189, 190, 191, 192, 193, 194, 195, 196, 197, 198, 199, 200, 201, 202, 203, 204, 205, 206, 207, 208, 209, 210, 211, 212, 213, 214, 215, 216, 217, 218, 219, 220, 221, 222, 223, 224, 225, 226, 227, 228, 229, 230, 231, 232, 233, 234, 235, 236, 237, 238, 239, 240, 241, 242, 243, 244, 245, 246, 247, 248, 249, 250, 251, 252, 253, 254, 255]}, "lightness_frequencies": {"trait": "lightness frequencies", "method": "plantcv.plantcv.analyze_color", "scale": "frequency", "datatype": "", "value": [0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 1.0, 1.0, 3.0, 5.0, 8.0, 9.0, 17.0, 6.0, 7.0, 16.0, 20.0, 38.0, 41.0, 89.0, 61.0, 111.0, 188.0, 104.0, 243.0, 289.0, 315.0, 378.0, 187.0, 518.0, 478.0, 678.0, 690.0, 1142.0, 925.0, 801.0, 911.0, 1502.0, 1124.0, 1184.0, 1863.0, 1223.0, 1818.0, 1405.0, 2022.0, 1773.0, 1349.0, 1878.0, 1742.0, 1563.0, 1722.0, 1690.0, 1773.0, 1885.0, 2070.0, 1901.0, 2204.0, 1321.0, 1200.0, 1352.0, 828.0, 1067.0, 1010.0, 690.0, 918.0, 829.0, 828.0, 738.0, 655.0, 579.0, 593.0, 512.0, 478.0, 467.0, 506.0, 351.0, 374.0, 277.0, 336.0, 242.0, 301.0, 234.0, 245.0, 186.0, 216.0, 162.0, 135.0, 140.0, 161.0, 114.0, 110.0, 105.0, 81.0, 121.0, 109.0, 124.0, 90.0, 90.0, 100.0, 79.0, 70.0, 99.0, 83.0, 76.0, 84.0, 96.0, 64.0, 88.0, 77.0, 71.0, 82.0, 82.0, 78.0, 63.0, 77.0, 83.0, 61.0, 68.0, 67.0, 57.0, 62.0, 69.0, 63.0, 49.0, 63.0, 50.0, 82.0, 52.0, 63.0, 48.0, 55.0, 72.0, 47.0, 57.0, 56.0, 81.0, 55.0, 63.0, 62.0, 44.0, 60.0, 52.0, 53.0, 64.0, 59.0, 64.0, 38.0, 41.0, 45.0, 56.0, 47.0, 49.0, 56.0, 54.0, 40.0, 56.0, 56.0, 49.0, 39.0, 50.0, 52.0, 46.0, 53.0, 43.0, 48.0, 43.0, 45.0, 40.0, 41.0, 34.0, 45.0, 45.0, 30.0, 33.0, 31.0, 32.0, 45.0, 29.0, 27.0, 26.0, 22.0, 20.0, 15.0, 27.0, 20.0, 17.0, 14.0, 7.0, 11.0, 15.0, 7.0, 16.0, 11.0, 10.0, 11.0, 6.0, 7.0, 8.0, 9.0, 1.0, 3.0, 3.0, 6.0, 3.0, 2.0, 2.0, 3.0, 4.0, 1.0, 0.0, 2.0, 0.0, 2.0, 0.0, 2.0, 0.0, 1.0, 2.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0], "label": [0.0, 0.39, 0.78, 1.18, 1.57, 1.96, 2.35, 2.75, 3.14, 3.53, 3.92, 4.31, 4.71, 5.1, 5.49, 5.88, 6.27, 6.67, 7.06, 7.45, 7.84, 8.24, 8.63, 9.02, 9.41, 9.8, 10.2, 10.59, 10.98, 11.37, 11.76, 12.16, 12.55, 12.94, 13.33, 13.73, 14.12, 14.51, 14.9, 15.29, 15.69, 16.08, 16.47, 16.86, 17.25, 17.65, 18.04, 18.43, 18.82, 19.22, 19.61, 20.0, 20.39, 20.78, 21.18, 21.57, 21.96, 22.35, 22.75, 23.14, 23.53, 23.92, 24.31, 24.71, 25.1, 25.49, 25.88, 26.27, 26.67, 27.06, 27.45, 27.84, 28.24, 28.63, 29.02, 29.41, 29.8, 30.2, 30.59, 30.98, 31.37, 31.76, 32.16, 32.55, 32.94, 33.33, 33.73, 34.12, 34.51, 34.9, 35.29, 35.69, 36.08, 36.47, 36.86, 37.25, 37.65, 38.04, 38.43, 38.82, 39.22, 39.61, 40.0, 40.39, 40.78, 41.18, 41.57, 41.96, 42.35, 42.75, 43.14, 43.53, 43.92, 44.31, 44.71, 45.1, 45.49, 45.88, 46.27, 46.67, 47.06, 47.45, 47.84, 48.24, 48.63, 49.02, 49.41, 49.8, 50.2, 50.59, 50.98, 51.37, 51.76, 52.16, 52.55, 52.94, 53.33, 53.73, 54.12, 54.51, 54.9, 55.29, 55.69, 56.08, 56.47, 56.86, 57.25, 57.65, 58.04, 58.43, 58.82, 59.22, 59.61, 60.0, 60.39, 60.78, 61.18, 61.57, 61.96, 62.35, 62.75, 63.14, 63.53, 63.92, 64.31, 64.71, 65.1, 65.49, 65.88, 66.27, 66.67, 67.06, 67.45, 67.84, 68.24, 68.63, 69.02, 69.41, 69.8, 70.2, 70.59, 70.98, 71.37, 71.76, 72.16, 72.55, 72.94, 73.33, 73.73, 74.12, 74.51, 74.9, 75.29, 75.69, 76.08, 76.47, 76.86, 77.25, 77.65, 78.04, 78.43, 78.82, 79.22, 79.61, 80.0, 80.39, 80.78, 81.18, 81.57, 81.96, 82.35, 82.75, 83.14, 83.53, 83.92, 84.31, 84.71, 85.1, 85.49, 85.88, 86.27, 86.67, 87.06, 87.45, 87.84, 88.24, 88.63, 89.02, 89.41, 89.8, 90.2, 90.59, 90.98, 91.37, 91.76, 92.16, 92.55, 92.94, 93.33, 93.73, 94.12, 94.51, 94.9, 95.29, 95.69, 96.08, 96.47, 96.86, 97.25, 97.65, 98.04, 98.43, 98.82, 99.22, 99.61, 100.0]}, "green-magenta_frequencies": {"trait": "green-magenta frequencies", "method": "plantcv.plantcv.analyze_color", "scale": "frequency", "datatype": "", "value": [0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 5.0, 17.0, 76.0, 429.0, 1525.0, 3788.0, 6803.0, 9196.0, 9962.0, 8484.0, 6621.0, 4859.0, 3467.0, 2368.0, 1852.0, 1510.0, 1199.0, 935.0, 743.0, 577.0, 415.0, 320.0, 247.0, 176.0, 125.0, 80.0, 42.0, 11.0, 12.0, 5.0, 2.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0], "label": [-128, -127, -126, -125, -124, -123, -122, -121, -120, -119, -118, -117, -116, -115, -114, -113, -112, -111, -110, -109, -108, -107, -106, -105, -104, -103, -102, -101, -100, -99, -98, -97, -96, -95, -94, -93, -92, -91, -90, -89, -88, -87, -86, -85, -84, -83, -82, -81, -80, -79, -78, -77, -76, -75, -74, -73, -72, -71, -70, -69, -68, -67, -66, -65, -64, -63, -62, -61, -60, -59, -58, -57, -56, -55, -54, -53, -52, -51, -50, -49, -48, -47, -46, -45, -44, -43, -42, -41, -40, -39, -38, -37, -36, -35, -34, -33, -32, -31, -30, -29, -28, -27, -26, -25, -24, -23, -22, -21, -20, -19, -18, -17, -16, -15, -14, -13, -12, -11, -10, -9, -8, -7, -6, -5, -4, -3, -2, -1, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 64, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, 95, 96, 97, 98, 99, 100, 101, 102, 103, 104, 105, 106, 107, 108, 109, 110, 111, 112, 113, 114, 115, 116, 117, 118, 119, 120, 121, 122, 123, 124, 125, 126, 127]}, "blue-yellow_frequencies": {"trait": "blue-yellow frequencies", "method": "plantcv.plantcv.analyze_color", "scale": "frequency", "datatype": "", "value": [0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 352.0, 377.0, 472.0, 711.0, 1009.0, 1659.0, 2405.0, 3140.0, 4487.0, 5885.0, 6881.0, 7038.0, 6708.0, 7055.0, 5978.0, 4737.0, 3087.0, 1820.0, 886.0, 450.0, 219.0, 148.0, 109.0, 89.0, 59.0, 38.0, 25.0, 15.0, 7.0, 5.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0], "label": [-128, -127, -126, -125, -124, -123, -122, -121, -120, -119, -118, -117, -116, -115, -114, -113, -112, -111, -110, -109, -108, -107, -106, -105, -104, -103, -102, -101, -100, -99, -98, -97, -96, -95, -94, -93, -92, -91, -90, -89, -88, -87, -86, -85, -84, -83, -82, -81, -80, -79, -78, -77, -76, -75, -74, -73, -72, -71, -70, -69, -68, -67, -66, -65, -64, -63, -62, -61, -60, -59, -58, -57, -56, -55, -54, -53, -52, -51, -50, -49, -48, -47, -46, -45, -44, -43, -42, -41, -40, -39, -38, -37, -36, -35, -34, -33, -32, -31, -30, -29, -28, -27, -26, -25, -24, -23, -22, -21, -20, -19, -18, -17, -16, -15, -14, -13, -12, -11, -10, -9, -8, -7, -6, -5, -4, -3, -2, -1, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 64, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, 95, 96, 97, 98, 99, 100, 101, 102, 103, 104, 105, 106, 107, 108, 109, 110, 111, 112, 113, 114, 115, 116, 117, 118, 119, 120, 121, 122, 123, 124, 125, 126, 127]}, "hue_frequencies": {"trait": "hue frequencies", "method": "plantcv.plantcv.analyze_color", "scale": "frequency", "datatype": "", "value": [0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 4.0, 10.0, 15.0, 22.0, 47.0, 63.0, 114.0, 125.0, 164.0, 209.0, 270.0, 272.0, 406.0, 395.0, 420.0, 511.0, 399.0, 552.0, 590.0, 637.0, 752.0, 843.0, 1147.0, 1295.0, 1972.0, 2583.0, 3537.0, 5285.0, 7184.0, 8334.0, 8292.0, 7947.0, 4566.0, 3209.0, 1625.0, 848.0, 385.0, 187.0, 96.0, 119.0, 52.0, 48.0, 56.0, 36.0, 31.0, 24.0, 24.0, 26.0, 17.0, 27.0, 18.0, 16.0, 20.0, 12.0, 5.0, 3.0, 3.0, 1.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0], "label": [1, 3, 5, 7, 9, 11, 13, 15, 17, 19, 21, 23, 25, 27, 29, 31, 33, 35, 37, 39, 41, 43, 45, 47, 49, 51, 53, 55, 57, 59, 61, 63, 65, 67, 69, 71, 73, 75, 77, 79, 81, 83, 85, 87, 89, 91, 93, 95, 97, 99, 101, 103, 105, 107, 109, 111, 113, 115, 117, 119, 121, 123, 125, 127, 129, 131, 133, 135, 137, 139, 141, 143, 145, 147, 149, 151, 153, 155, 157, 159, 161, 163, 165, 167, 169, 171, 173, 175, 177, 179, 181, 183, 185, 187, 189, 191, 193, 195, 197, 199, 201, 203, 205, 207, 209, 211, 213, 215, 217, 219, 221, 223, 225, 227, 229, 231, 233, 235, 237, 239, 241, 243, 245, 247, 249, 251, 253, 255, 257, 259, 261, 263, 265, 267, 269, 271, 273, 275, 277, 279, 281, 283, 285, 287, 289, 291, 293, 295, 297, 299, 301, 303, 305, 307, 309, 311, 313, 315, 317, 319, 321, 323, 325, 327, 329, 331, 333, 335, 337, 339, 341, 343, 345, 347, 349, 351, 353, 355, 357, 359]}, "saturation_frequencies": {"trait": "saturation frequencies", "method": "plantcv.plantcv.analyze_color", "scale": "frequency", "datatype": "", "value": [0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 1.0, 1.0, 2.0, 4.0, 5.0, 12.0, 10.0, 13.0, 17.0, 24.0, 27.0, 34.0, 50.0, 55.0, 60.0, 70.0, 78.0, 56.0, 92.0, 56.0, 85.0, 74.0, 104.0, 97.0, 94.0, 84.0, 112.0, 115.0, 102.0, 111.0, 140.0, 119.0, 109.0, 120.0, 135.0, 124.0, 125.0, 119.0, 130.0, 132.0, 111.0, 137.0, 155.0, 135.0, 122.0, 120.0, 129.0, 126.0, 99.0, 116.0, 97.0, 123.0, 119.0, 104.0, 108.0, 120.0, 120.0, 120.0, 113.0, 101.0, 130.0, 111.0, 107.0, 114.0, 134.0, 124.0, 123.0, 130.0, 132.0, 123.0, 160.0, 137.0, 153.0, 168.0, 193.0, 208.0, 137.0, 257.0, 241.0, 234.0, 315.0, 257.0, 319.0, 301.0, 355.0, 369.0, 353.0, 452.0, 425.0, 464.0, 531.0, 521.0, 514.0, 596.0, 625.0, 709.0, 648.0, 753.0, 855.0, 604.0, 1057.0, 790.0, 717.0, 1176.0, 687.0, 1023.0, 917.0, 955.0, 949.0, 971.0, 1002.0, 862.0, 1143.0, 1072.0, 1047.0, 1024.0, 1090.0, 1230.0, 988.0, 1179.0, 1255.0, 1153.0, 1223.0, 1080.0, 1265.0, 990.0, 1347.0, 922.0, 1308.0, 1071.0, 1087.0, 968.0, 1099.0, 1176.0, 877.0, 868.0, 933.0, 891.0, 745.0, 726.0, 754.0, 693.0, 478.0, 561.0, 657.0, 452.0, 276.0, 487.0, 333.0, 246.0, 213.0, 285.0, 186.0, 195.0, 152.0, 116.0, 97.0, 91.0, 80.0, 73.0, 49.0, 34.0, 34.0, 23.0, 24.0, 13.0, 8.0, 4.0, 5.0, 4.0, 2.0, 3.0, 1.0, 2.0, 0.0, 1.0, 1.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0], "label": [0.0, 0.39, 0.78, 1.18, 1.57, 1.96, 2.35, 2.75, 3.14, 3.53, 3.92, 4.31, 4.71, 5.1, 5.49, 5.88, 6.27, 6.67, 7.06, 7.45, 7.84, 8.24, 8.63, 9.02, 9.41, 9.8, 10.2, 10.59, 10.98, 11.37, 11.76, 12.16, 12.55, 12.94, 13.33, 13.73, 14.12, 14.51, 14.9, 15.29, 15.69, 16.08, 16.47, 16.86, 17.25, 17.65, 18.04, 18.43, 18.82, 19.22, 19.61, 20.0, 20.39, 20.78, 21.18, 21.57, 21.96, 22.35, 22.75, 23.14, 23.53, 23.92, 24.31, 24.71, 25.1, 25.49, 25.88, 26.27, 26.67, 27.06, 27.45, 27.84, 28.24, 28.63, 29.02, 29.41, 29.8, 30.2, 30.59, 30.98, 31.37, 31.76, 32.16, 32.55, 32.94, 33.33, 33.73, 34.12, 34.51, 34.9, 35.29, 35.69, 36.08, 36.47, 36.86, 37.25, 37.65, 38.04, 38.43, 38.82, 39.22, 39.61, 40.0, 40.39, 40.78, 41.18, 41.57, 41.96, 42.35, 42.75, 43.14, 43.53, 43.92, 44.31, 44.71, 45.1, 45.49, 45.88, 46.27, 46.67, 47.06, 47.45, 47.84, 48.24, 48.63, 49.02, 49.41, 49.8, 50.2, 50.59, 50.98, 51.37, 51.76, 52.16, 52.55, 52.94, 53.33, 53.73, 54.12, 54.51, 54.9, 55.29, 55.69, 56.08, 56.47, 56.86, 57.25, 57.65, 58.04, 58.43, 58.82, 59.22, 59.61, 60.0, 60.39, 60.78, 61.18, 61.57, 61.96, 62.35, 62.75, 63.14, 63.53, 63.92, 64.31, 64.71, 65.1, 65.49, 65.88, 66.27, 66.67, 67.06, 67.45, 67.84, 68.24, 68.63, 69.02, 69.41, 69.8, 70.2, 70.59, 70.98, 71.37, 71.76, 72.16, 72.55, 72.94, 73.33, 73.73, 74.12, 74.51, 74.9, 75.29, 75.69, 76.08, 76.47, 76.86, 77.25, 77.65, 78.04, 78.43, 78.82, 79.22, 79.61, 80.0, 80.39, 80.78, 81.18, 81.57, 81.96, 82.35, 82.75, 83.14, 83.53, 83.92, 84.31, 84.71, 85.1, 85.49, 85.88, 86.27, 86.67, 87.06, 87.45, 87.84, 88.24, 88.63, 89.02, 89.41, 89.8, 90.2, 90.59, 90.98, 91.37, 91.76, 92.16, 92.55, 92.94, 93.33, 93.73, 94.12, 94.51, 94.9, 95.29, 95.69, 96.08, 96.47, 96.86, 97.25, 97.65, 98.04, 98.43, 98.82, 99.22, 99.61, 100.0]}, "value_frequencies": {"trait": "value frequencies", "method": "plantcv.plantcv.analyze_color", "scale": "frequency", "datatype": "", "value": [0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 1.0, 1.0, 2.0, 12.0, 11.0, 14.0, 9.0, 13.0, 12.0, 20.0, 26.0, 47.0, 75.0, 104.0, 133.0, 157.0, 224.0, 193.0, 300.0, 322.0, 391.0, 478.0, 546.0, 600.0, 734.0, 852.0, 958.0, 996.0, 1088.0, 1241.0, 1429.0, 1545.0, 1616.0, 1711.0, 1832.0, 1860.0, 1937.0, 1806.0, 1832.0, 1749.0, 1826.0, 1712.0, 1807.0, 1926.0, 1944.0, 2150.0, 1997.0, 2012.0, 1683.0, 1380.0, 1189.0, 1082.0, 958.0, 958.0, 835.0, 914.0, 879.0, 792.0, 698.0, 642.0, 596.0, 561.0, 524.0, 502.0, 433.0, 390.0, 364.0, 329.0, 325.0, 298.0, 241.0, 229.0, 191.0, 171.0, 177.0, 132.0, 120.0, 121.0, 125.0, 100.0, 116.0, 96.0, 111.0, 104.0, 93.0, 86.0, 83.0, 97.0, 90.0, 82.0, 98.0, 71.0, 62.0, 81.0, 91.0, 91.0, 80.0, 87.0, 75.0, 75.0, 80.0, 72.0, 79.0, 65.0, 50.0, 62.0, 71.0, 71.0, 51.0, 76.0, 66.0, 65.0, 72.0, 64.0, 71.0, 54.0, 49.0, 65.0, 58.0, 63.0, 70.0, 51.0, 60.0, 57.0, 52.0, 55.0, 70.0, 50.0, 60.0, 45.0, 56.0, 58.0, 50.0, 60.0, 60.0, 43.0, 35.0, 58.0, 44.0, 48.0, 53.0, 34.0, 47.0, 39.0, 55.0, 52.0, 41.0, 53.0, 48.0, 53.0, 47.0, 41.0, 40.0, 41.0, 49.0, 34.0, 39.0, 36.0, 48.0, 33.0, 29.0, 48.0, 24.0, 39.0, 34.0, 29.0, 29.0, 28.0, 28.0, 28.0, 21.0, 24.0, 18.0, 12.0, 16.0, 18.0, 15.0, 14.0, 15.0, 12.0, 7.0, 15.0, 11.0, 6.0, 12.0, 6.0, 11.0, 14.0, 4.0, 1.0, 3.0, 5.0, 10.0, 2.0, 3.0, 6.0, 4.0, 0.0, 4.0, 1.0, 3.0, 2.0, 0.0, 2.0, 1.0, 1.0, 2.0, 3.0, 1.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0], "label": [0.0, 0.39, 0.78, 1.18, 1.57, 1.96, 2.35, 2.75, 3.14, 3.53, 3.92, 4.31, 4.71, 5.1, 5.49, 5.88, 6.27, 6.67, 7.06, 7.45, 7.84, 8.24, 8.63, 9.02, 9.41, 9.8, 10.2, 10.59, 10.98, 11.37, 11.76, 12.16, 12.55, 12.94, 13.33, 13.73, 14.12, 14.51, 14.9, 15.29, 15.69, 16.08, 16.47, 16.86, 17.25, 17.65, 18.04, 18.43, 18.82, 19.22, 19.61, 20.0, 20.39, 20.78, 21.18, 21.57, 21.96, 22.35, 22.75, 23.14, 23.53, 23.92, 24.31, 24.71, 25.1, 25.49, 25.88, 26.27, 26.67, 27.06, 27.45, 27.84, 28.24, 28.63, 29.02, 29.41, 29.8, 30.2, 30.59, 30.98, 31.37, 31.76, 32.16, 32.55, 32.94, 33.33, 33.73, 34.12, 34.51, 34.9, 35.29, 35.69, 36.08, 36.47, 36.86, 37.25, 37.65, 38.04, 38.43, 38.82, 39.22, 39.61, 40.0, 40.39, 40.78, 41.18, 41.57, 41.96, 42.35, 42.75, 43.14, 43.53, 43.92, 44.31, 44.71, 45.1, 45.49, 45.88, 46.27, 46.67, 47.06, 47.45, 47.84, 48.24, 48.63, 49.02, 49.41, 49.8, 50.2, 50.59, 50.98, 51.37, 51.76, 52.16, 52.55, 52.94, 53.33, 53.73, 54.12, 54.51, 54.9, 55.29, 55.69, 56.08, 56.47, 56.86, 57.25, 57.65, 58.04, 58.43, 58.82, 59.22, 59.61, 60.0, 60.39, 60.78, 61.18, 61.57, 61.96, 62.35, 62.75, 63.14, 63.53, 63.92, 64.31, 64.71, 65.1, 65.49, 65.88, 66.27, 66.67, 67.06, 67.45, 67.84, 68.24, 68.63, 69.02, 69.41, 69.8, 70.2, 70.59, 70.98, 71.37, 71.76, 72.16, 72.55, 72.94, 73.33, 73.73, 74.12, 74.51, 74.9, 75.29, 75.69, 76.08, 76.47, 76.86, 77.25, 77.65, 78.04, 78.43, 78.82, 79.22, 79.61, 80.0, 80.39, 80.78, 81.18, 81.57, 81.96, 82.35, 82.75, 83.14, 83.53, 83.92, 84.31, 84.71, 85.1, 85.49, 85.88, 86.27, 86.67, 87.06, 87.45, 87.84, 88.24, 88.63, 89.02, 89.41, 89.8, 90.2, 90.59, 90.98, 91.37, 91.76, 92.16, 92.55, 92.94, 93.33, 93.73, 94.12, 94.51, 94.9, 95.29, 95.69, 96.08, 96.47, 96.86, 97.25, 97.65, 98.04, 98.43, 98.82, 99.22, 99.61, 100.0]}, "hue_circular_mean": {"trait": "hue circular mean", "method": "plantcv.plantcv.analyze_color", "scale": "degrees", "datatype": "", "value": 83.67294573455045, "label": "degrees"}, "hue_circular_std": {"trait": "hue circular standard deviation", "method": "plantcv.plantcv.analyze_color", "scale": "degrees", "datatype": "", "value": 86.0, "label": "degrees"}, "hue_median": {"trait": "hue median", "method": "plantcv.plantcv.analyze_color", "scale": "degrees", "datatype": "", "value": 86.0, "label": "degrees"}}}]} \ No newline at end of file +{ + "variables": { + "camera": { + "category": "metadata", + "datatype": "" + }, + "imgtype": { + "category": "metadata", + "datatype": "" + }, + "zoom": { + "category": "metadata", + "datatype": "" + }, + "exposure": { + "category": "metadata", + "datatype": "" + }, + "gain": { + "category": "metadata", + "datatype": "" + }, + "frame": { + "category": "metadata", + "datatype": "" + }, + "lifter": { + "category": "metadata", + "datatype": "" + }, + "timestamp": { + "category": "metadata", + "datatype": "" + }, + "id": { + "category": "metadata", + "datatype": "" + }, + "plantbarcode": { + "category": "metadata", + "datatype": "" + }, + "treatment": { + "category": "metadata", + "datatype": "" + }, + "cartag": { + "category": "metadata", + "datatype": "" + }, + "measurementlabel": { + "category": "metadata", + "datatype": "" + }, + "other": { + "category": "metadata", + "datatype": "" + }, + "image": { + "category": "metadata", + "datatype": "" + }, + "nir_frequencies": { + "category": "observations", + "datatype": "" + }, + "area": { + "category": "observations", + "datatype": "" + }, + "convex_hull_area": { + "category": "observations", + "datatype": "" + }, + "solidity": { + "category": "observations", + "datatype": "" + }, + "perimeter": { + "category": "observations", + "datatype": "" + }, + "width": { + "category": "observations", + "datatype": "" + }, + "height": { + "category": "observations", + "datatype": "" + }, + "longest_path": { + "category": "observations", + "datatype": "" + }, + "center_of_mass": { + "category": "observations", + "datatype": "" + }, + "convex_hull_vertices": { + "category": "observations", + "datatype": "" + }, + "object_in_frame": { + "category": "observations", + "datatype": "" + }, + "ellipse_center": { + "category": "observations", + "datatype": "" + }, + "ellipse_major_axis": { + "category": "observations", + "datatype": "" + }, + "ellipse_minor_axis": { + "category": "observations", + "datatype": "" + }, + "ellipse_angle": { + "category": "observations", + "datatype": "" + }, + "ellipse_eccentricity": { + "category": "observations", + "datatype": "" + }, + "horizontal_reference_position": { + "category": "observations", + "datatype": "" + }, + "height_above_reference": { + "category": "observations", + "datatype": "" + }, + "height_below_reference": { + "category": "observations", + "datatype": "" + }, + "area_above_reference": { + "category": "observations", + "datatype": "" + }, + "percent_area_above_reference": { + "category": "observations", + "datatype": "" + }, + "area_below_reference": { + "category": "observations", + "datatype": "" + }, + "percent_area_below_reference": { + "category": "observations", + "datatype": "" + }, + "blue_frequencies": { + "category": "observations", + "datatype": "" + }, + "green_frequencies": { + "category": "observations", + "datatype": "" + }, + "red_frequencies": { + "category": "observations", + "datatype": "" + }, + "lightness_frequencies": { + "category": "observations", + "datatype": "" + }, + "green-magenta_frequencies": { + "category": "observations", + "datatype": "" + }, + "blue-yellow_frequencies": { + "category": "observations", + "datatype": "" + }, + "hue_frequencies": { + "category": "observations", + "datatype": "" + }, + "saturation_frequencies": { + "category": "observations", + "datatype": "" + }, + "value_frequencies": { + "category": "observations", + "datatype": "" + }, + "hue_circular_mean": { + "category": "observations", + "datatype": "" + }, + "hue_circular_std": { + "category": "observations", + "datatype": "" + }, + "hue_median": { + "category": "observations", + "datatype": "" + } + }, + "entities": [ + { + "metadata": { + "camera": { + "label": "camera identifier", + "datatype": "", + "value": "SV" + }, + "imgtype": { + "label": "image type", + "datatype": "", + "value": "NIR" + }, + "zoom": { + "label": "camera zoom setting", + "datatype": "", + "value": "z1" + }, + "exposure": { + "label": "camera exposure setting", + "datatype": "", + "value": "e65" + }, + "gain": { + "label": "camera gain setting", + "datatype": "", + "value": "g0" + }, + "frame": { + "label": "image series frame identifier", + "datatype": "", + "value": "90" + }, + "lifter": { + "label": "imaging platform height setting", + "datatype": "", + "value": "h1" + }, + "timestamp": { + "label": "datetime of image", + "datatype": "", + "value": "2014-10-22 17:59:23.046" + }, + "id": { + "label": "image identifier", + "datatype": "", + "value": "117881" + }, + "plantbarcode": { + "label": "plant barcode identifier", + "datatype": "", + "value": "Ca002AA010557" + }, + "treatment": { + "label": "treatment identifier", + "datatype": "", + "value": "none" + }, + "cartag": { + "label": "plant carrier identifier", + "datatype": "", + "value": "1663" + }, + "measurementlabel": { + "label": "experiment identifier", + "datatype": "", + "value": "C002ch_092214_biomass" + }, + "other": { + "label": "other identifier", + "datatype": "", + "value": "none" + }, + "image": { + "label": "image file", + "datatype": "", + "value": "./images/snapshot57393/NIR_SV_90_z1_h1_g0_e65_117881.png" + } + }, + "observations": { + "sample1": { + "nir_frequencies": { + "trait": "near-infrared frequencies", + "method": "plantcv.plantcv.analyze_nir_intensity", + "scale": "frequency", + "datatype": "", + "value": [ + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 1, + 3, + 3, + 2, + 8, + 9, + 3, + 5, + 2, + 8, + 2, + 3, + 3, + 2, + 4, + 3, + 2, + 3, + 3, + 4, + 4, + 4, + 4, + 4, + 1, + 1, + 3, + 3, + 3, + 6, + 7, + 6, + 13, + 13, + 8, + 7, + 8, + 10, + 12, + 10, + 11, + 6, + 14, + 14, + 14, + 8, + 9, + 9, + 9, + 9, + 9, + 5, + 7, + 6, + 7, + 4, + 5, + 8, + 5, + 6, + 3, + 5, + 5, + 5, + 5, + 7, + 6, + 7, + 5, + 5, + 6, + 12, + 7, + 10, + 15, + 14, + 12, + 15, + 11, + 4, + 9, + 10, + 4, + 15, + 10, + 11, + 6, + 18, + 11, + 5, + 7, + 4, + 5, + 5, + 10, + 5, + 10, + 6, + 11, + 12, + 8, + 6, + 1, + 8, + 9, + 9, + 11, + 9, + 9, + 7, + 13, + 6, + 4, + 7, + 8, + 7, + 8, + 4, + 4, + 9, + 3, + 1, + 1, + 2, + 5, + 9, + 3, + 7, + 10, + 10, + 5, + 2, + 5, + 4, + 0, + 1, + 1, + 1, + 2, + 1, + 0, + 0, + 0, + 0, + 1, + 1, + 0, + 2, + 1, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0 + ], + "label": [ + 1, + 2, + 2.99, + 3.99, + 4.98, + 5.98, + 6.98, + 7.97, + 8.97, + 9.96, + 10.96, + 11.96, + 12.95, + 13.95, + 14.95, + 15.94, + 16.94, + 17.93, + 18.93, + 19.93, + 20.92, + 21.92, + 22.91, + 23.91, + 24.91, + 25.9, + 26.9, + 27.89, + 28.89, + 29.89, + 30.88, + 31.88, + 32.88, + 33.87, + 34.87, + 35.86, + 36.86, + 37.86, + 38.85, + 39.85, + 40.84, + 41.84, + 42.84, + 43.83, + 44.83, + 45.82, + 46.82, + 47.82, + 48.81, + 49.81, + 50.8, + 51.8, + 52.8, + 53.79, + 54.79, + 55.79, + 56.78, + 57.78, + 58.77, + 59.77, + 60.77, + 61.76, + 62.76, + 63.75, + 64.75, + 65.75, + 66.74, + 67.74, + 68.73, + 69.73, + 70.73, + 71.72, + 72.72, + 73.71, + 74.71, + 75.71, + 76.7, + 77.7, + 78.7, + 79.69, + 80.69, + 81.68, + 82.68, + 83.68, + 84.67, + 85.67, + 86.66, + 87.66, + 88.66, + 89.65, + 90.65, + 91.64, + 92.64, + 93.64, + 94.63, + 95.63, + 96.62, + 97.62, + 98.62, + 99.61, + 100.61, + 101.61, + 102.6, + 103.6, + 104.59, + 105.59, + 106.59, + 107.58, + 108.58, + 109.57, + 110.57, + 111.57, + 112.56, + 113.56, + 114.55, + 115.55, + 116.55, + 117.54, + 118.54, + 119.54, + 120.53, + 121.53, + 122.52, + 123.52, + 124.52, + 125.51, + 126.51, + 127.5, + 128.5, + 129.5, + 130.49, + 131.49, + 132.48, + 133.48, + 134.48, + 135.47, + 136.47, + 137.46, + 138.46, + 139.46, + 140.45, + 141.45, + 142.45, + 143.44, + 144.44, + 145.43, + 146.43, + 147.43, + 148.42, + 149.42, + 150.41, + 151.41, + 152.41, + 153.4, + 154.4, + 155.39, + 156.39, + 157.39, + 158.38, + 159.38, + 160.38, + 161.37, + 162.37, + 163.36, + 164.36, + 165.36, + 166.35, + 167.35, + 168.34, + 169.34, + 170.34, + 171.33, + 172.33, + 173.32, + 174.32, + 175.32, + 176.31, + 177.31, + 178.3, + 179.3, + 180.3, + 181.29, + 182.29, + 183.29, + 184.28, + 185.28, + 186.27, + 187.27, + 188.27, + 189.26, + 190.26, + 191.25, + 192.25, + 193.25, + 194.24, + 195.24, + 196.23, + 197.23, + 198.23, + 199.22, + 200.22, + 201.21, + 202.21, + 203.21, + 204.2, + 205.2, + 206.2, + 207.19, + 208.19, + 209.18, + 210.18, + 211.18, + 212.17, + 213.17, + 214.16, + 215.16, + 216.16, + 217.15, + 218.15, + 219.14, + 220.14, + 221.14, + 222.13, + 223.13, + 224.12, + 225.12, + 226.12, + 227.11, + 228.11, + 229.11, + 230.1, + 231.1, + 232.09, + 233.09, + 234.09, + 235.08, + 236.08, + 237.07, + 238.07, + 239.07, + 240.06, + 241.06, + 242.05, + 243.05, + 244.05, + 245.04, + 246.04, + 247.04, + 248.03, + 249.03, + 250.02, + 251.02, + 252.02, + 253.01, + 254.01, + 255 + ] + }, + "area": { + "trait": "area", + "method": "plantcv.plantcv.analyze_object", + "scale": "pixels", + "datatype": "", + "value": 923, + "label": "pixels" + }, + "convex_hull_area": { + "trait": "convex hull area", + "method": "plantcv.plantcv.analyze_object", + "scale": "pixels", + "datatype": "", + "value": 3027, + "label": "pixels" + }, + "solidity": { + "trait": "solidity", + "method": "plantcv.plantcv.analyze_object", + "scale": "none", + "datatype": "", + "value": 0.3049223653782623, + "label": "none" + }, + "perimeter": { + "trait": "perimeter", + "method": "plantcv.plantcv.analyze_object", + "scale": "pixels", + "datatype": "", + "value": 627.1807925701141, + "label": "pixels" + }, + "width": { + "trait": "width", + "method": "plantcv.plantcv.analyze_object", + "scale": "pixels", + "datatype": "", + "value": 54, + "label": "pixels" + }, + "height": { + "trait": "height", + "method": "plantcv.plantcv.analyze_object", + "scale": "pixels", + "datatype": "", + "value": 78, + "label": "pixels" + }, + "longest_path": { + "trait": "longest path", + "method": "plantcv.plantcv.analyze_object", + "scale": "pixels", + "datatype": "", + "value": 513, + "label": "pixels" + }, + "center_of_mass": { + "trait": "center of mass", + "method": "plantcv.plantcv.analyze_object", + "scale": "none", + "datatype": "", + "value": [ + 151.19501625135428, + 192.3694474539545 + ], + "label": "none" + }, + "convex_hull_vertices": { + "trait": "convex hull vertices", + "method": "plantcv.plantcv.analyze_object", + "scale": "none", + "datatype": "", + "value": 14, + "label": "none" + }, + "object_in_frame": { + "trait": "object in frame", + "method": "plantcv.plantcv.analyze_object", + "scale": "none", + "datatype": "", + "value": true, + "label": "none" + }, + "ellipse_center": { + "trait": "ellipse center", + "method": "plantcv.plantcv.analyze_object", + "scale": "none", + "datatype": "", + "value": [ + 153.5628662109375, + 192.63124084472656 + ], + "label": "none" + }, + "ellipse_major_axis": { + "trait": "ellipse major axis length", + "method": "plantcv.plantcv.analyze_object", + "scale": "pixels", + "datatype": "", + "value": 65.83857727050781, + "label": "pixels" + }, + "ellipse_minor_axis": { + "trait": "ellipse minor axis length", + "method": "plantcv.plantcv.analyze_object", + "scale": "pixels", + "datatype": "", + "value": 42.24153518676758, + "label": "pixels" + }, + "ellipse_angle": { + "trait": "ellipse major axis angle", + "method": "plantcv.plantcv.analyze_object", + "scale": "degrees", + "datatype": "", + "value": 167.28292846679688, + "label": "degrees" + }, + "ellipse_eccentricity": { + "trait": "ellipse eccentricity", + "method": "plantcv.plantcv.analyze_object", + "scale": "none", + "datatype": "", + "value": 0.7670457006165471, + "label": "none" + } + } + } + }, + { + "metadata": { + "camera": { + "label": "camera identifier", + "datatype": "", + "value": "SV" + }, + "imgtype": { + "label": "image type", + "datatype": "", + "value": "VIS" + }, + "zoom": { + "label": "camera zoom setting", + "datatype": "", + "value": "z1" + }, + "exposure": { + "label": "camera exposure setting", + "datatype": "", + "value": "e82" + }, + "gain": { + "label": "camera gain setting", + "datatype": "", + "value": "g0" + }, + "frame": { + "label": "image series frame identifier", + "datatype": "", + "value": "90" + }, + "timestamp": { + "label": "datetime of image", + "datatype": "", + "value": "2014-10-22 17:59:23.046" + }, + "id": { + "label": "image identifier", + "datatype": "", + "value": "117872" + }, + "plantbarcode": { + "label": "plant barcode identifier", + "datatype": "", + "value": "Ca002AA010557" + }, + "treatment": { + "label": "treatment identifier", + "datatype": "", + "value": "none" + }, + "cartag": { + "label": "plant carrier identifier", + "datatype": "", + "value": "1663" + }, + "measurementlabel": { + "label": "experiment identifier", + "datatype": "", + "value": "C002ch_092214_biomass" + }, + "other": { + "label": "other identifier", + "datatype": "", + "value": "none" + }, + "image": { + "label": "image file", + "datatype": "", + "value": "./images/snapshot57393/VIS_SV_90_z1_h1_g0_e82_117872.png" + } + }, + "observations": { + "sample1": { + "area": { + "trait": "area", + "method": "plantcv.plantcv.analyze_object", + "scale": "pixels", + "datatype": "", + "value": 65851, + "label": "pixels" + }, + "convex_hull_area": { + "trait": "convex hull area", + "method": "plantcv.plantcv.analyze_object", + "scale": "pixels", + "datatype": "", + "value": 232885.5, + "label": "pixels" + }, + "solidity": { + "trait": "solidity", + "method": "plantcv.plantcv.analyze_object", + "scale": "none", + "datatype": "", + "value": 0.28276127109674065, + "label": "none" + }, + "perimeter": { + "trait": "perimeter", + "method": "plantcv.plantcv.analyze_object", + "scale": "pixels", + "datatype": "", + "value": 7412.37744474411, + "label": "pixels" + }, + "width": { + "trait": "width", + "method": "plantcv.plantcv.analyze_object", + "scale": "pixels", + "datatype": "", + "value": 472, + "label": "pixels" + }, + "height": { + "trait": "height", + "method": "plantcv.plantcv.analyze_object", + "scale": "pixels", + "datatype": "", + "value": 677, + "label": "pixels" + }, + "longest_path": { + "trait": "longest path", + "method": "plantcv.plantcv.analyze_object", + "scale": "pixels", + "datatype": "", + "value": 4533, + "label": "pixels" + }, + "center_of_mass": { + "trait": "center of mass", + "method": "plantcv.plantcv.analyze_object", + "scale": "none", + "datatype": "", + "value": [ + 1286.1963068138677, + 1418.1369151569452 + ], + "label": "none" + }, + "convex_hull_vertices": { + "trait": "convex hull vertices", + "method": "plantcv.plantcv.analyze_object", + "scale": "none", + "datatype": "", + "value": 20, + "label": "none" + }, + "object_in_frame": { + "trait": "object in frame", + "method": "plantcv.plantcv.analyze_object", + "scale": "none", + "datatype": "", + "value": true, + "label": "none" + }, + "ellipse_center": { + "trait": "ellipse center", + "method": "plantcv.plantcv.analyze_object", + "scale": "none", + "datatype": "", + "value": [ + 1265.687255859375, + 1426.276123046875 + ], + "label": "none" + }, + "ellipse_major_axis": { + "trait": "ellipse major axis length", + "method": "plantcv.plantcv.analyze_object", + "scale": "pixels", + "datatype": "", + "value": 576.3345336914062, + "label": "pixels" + }, + "ellipse_minor_axis": { + "trait": "ellipse minor axis length", + "method": "plantcv.plantcv.analyze_object", + "scale": "pixels", + "datatype": "", + "value": 367.6441955566406, + "label": "pixels" + }, + "ellipse_angle": { + "trait": "ellipse major axis angle", + "method": "plantcv.plantcv.analyze_object", + "scale": "degrees", + "datatype": "", + "value": 12.61721134185791, + "label": "degrees" + }, + "ellipse_eccentricity": { + "trait": "ellipse eccentricity", + "method": "plantcv.plantcv.analyze_object", + "scale": "none", + "datatype": "", + "value": 0.77011863518315, + "label": "none" + }, + "horizontal_reference_position": { + "trait": "horizontal reference position", + "method": "plantcv.plantcv.analyze_bound_horizontal", + "scale": "none", + "datatype": "", + "value": 384, + "label": "none" + }, + "height_below_reference": { + "trait": "height_below_reference", + "method": "plantcv.plantcv.analyze_bound_horizontal", + "scale": "pixels", + "datatype": "", + "value": 677, + "label": "pixels" + }, + "area_above_reference": { + "trait": "area above reference", + "method": "plantcv.plantcv.analyze_bound_horizontal", + "scale": "pixels", + "datatype": "", + "value": 0, + "label": "pixels" + }, + "percent_area_above_reference": { + "trait": "percent area above reference", + "method": "plantcv.plantcv.analyze_bound_horizontal", + "scale": "none", + "datatype": "", + "value": 0, + "label": "none" + }, + "area_below_reference": { + "trait": "area below reference", + "method": "plantcv.plantcv.analyze_bound_horizontal", + "scale": "pixels", + "datatype": "", + "value": 65851, + "label": "pixels" + }, + "percent_area_below_reference": { + "trait": "percent area below reference", + "method": "plantcv.plantcv.analyze_bound_horizontal", + "scale": "none", + "datatype": "", + "value": 100, + "label": "none" + }, + "blue_frequencies": { + "trait": "blue frequencies", + "method": "plantcv.plantcv.analyze_color", + "scale": "frequency", + "datatype": "", + "value": [ + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 1, + 10, + 14, + 56, + 141, + 290, + 382, + 481, + 725, + 1017, + 1295, + 1683, + 1897, + 2269, + 2446, + 2709, + 2826, + 3149, + 3142, + 2989, + 2943, + 2765, + 2665, + 2110, + 1856, + 1622, + 1576, + 1391, + 1301, + 1288, + 1232, + 1180, + 1110, + 1007, + 886, + 786, + 679, + 605, + 566, + 503, + 465, + 459, + 419, + 379, + 309, + 303, + 288, + 255, + 202, + 203, + 188, + 180, + 158, + 165, + 144, + 150, + 144, + 126, + 141, + 111, + 123, + 111, + 95, + 102, + 80, + 83, + 89, + 70, + 99, + 78, + 72, + 80, + 86, + 74, + 70, + 65, + 58, + 79, + 62, + 68, + 71, + 69, + 69, + 74, + 68, + 52, + 53, + 60, + 67, + 39, + 64, + 54, + 44, + 59, + 59, + 46, + 48, + 46, + 58, + 73, + 58, + 54, + 43, + 58, + 53, + 55, + 58, + 41, + 50, + 48, + 73, + 50, + 35, + 52, + 49, + 42, + 51, + 50, + 49, + 59, + 57, + 40, + 43, + 31, + 51, + 46, + 60, + 41, + 62, + 50, + 57, + 40, + 43, + 41, + 42, + 51, + 37, + 36, + 31, + 39, + 31, + 37, + 38, + 39, + 42, + 26, + 30, + 40, + 23, + 34, + 16, + 30, + 30, + 30, + 29, + 20, + 15, + 16, + 24, + 13, + 17, + 15, + 8, + 9, + 8, + 13, + 9, + 13, + 6, + 7, + 9, + 4, + 5, + 6, + 2, + 4, + 2, + 2, + 5, + 6, + 0, + 0, + 2, + 1, + 0, + 2, + 1, + 1, + 1, + 0, + 1, + 2, + 1, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 1, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0 + ], + "label": [ + 0, + 1, + 2, + 3, + 4, + 5, + 6, + 7, + 8, + 9, + 10, + 11, + 12, + 13, + 14, + 15, + 16, + 17, + 18, + 19, + 20, + 21, + 22, + 23, + 24, + 25, + 26, + 27, + 28, + 29, + 30, + 31, + 32, + 33, + 34, + 35, + 36, + 37, + 38, + 39, + 40, + 41, + 42, + 43, + 44, + 45, + 46, + 47, + 48, + 49, + 50, + 51, + 52, + 53, + 54, + 55, + 56, + 57, + 58, + 59, + 60, + 61, + 62, + 63, + 64, + 65, + 66, + 67, + 68, + 69, + 70, + 71, + 72, + 73, + 74, + 75, + 76, + 77, + 78, + 79, + 80, + 81, + 82, + 83, + 84, + 85, + 86, + 87, + 88, + 89, + 90, + 91, + 92, + 93, + 94, + 95, + 96, + 97, + 98, + 99, + 100, + 101, + 102, + 103, + 104, + 105, + 106, + 107, + 108, + 109, + 110, + 111, + 112, + 113, + 114, + 115, + 116, + 117, + 118, + 119, + 120, + 121, + 122, + 123, + 124, + 125, + 126, + 127, + 128, + 129, + 130, + 131, + 132, + 133, + 134, + 135, + 136, + 137, + 138, + 139, + 140, + 141, + 142, + 143, + 144, + 145, + 146, + 147, + 148, + 149, + 150, + 151, + 152, + 153, + 154, + 155, + 156, + 157, + 158, + 159, + 160, + 161, + 162, + 163, + 164, + 165, + 166, + 167, + 168, + 169, + 170, + 171, + 172, + 173, + 174, + 175, + 176, + 177, + 178, + 179, + 180, + 181, + 182, + 183, + 184, + 185, + 186, + 187, + 188, + 189, + 190, + 191, + 192, + 193, + 194, + 195, + 196, + 197, + 198, + 199, + 200, + 201, + 202, + 203, + 204, + 205, + 206, + 207, + 208, + 209, + 210, + 211, + 212, + 213, + 214, + 215, + 216, + 217, + 218, + 219, + 220, + 221, + 222, + 223, + 224, + 225, + 226, + 227, + 228, + 229, + 230, + 231, + 232, + 233, + 234, + 235, + 236, + 237, + 238, + 239, + 240, + 241, + 242, + 243, + 244, + 245, + 246, + 247, + 248, + 249, + 250, + 251, + 252, + 253, + 254, + 255 + ] + }, + "green_frequencies": { + "trait": "green frequencies", + "method": "plantcv.plantcv.analyze_color", + "scale": "frequency", + "datatype": "", + "value": [ + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 1, + 1, + 2, + 12, + 12, + 13, + 9, + 14, + 12, + 19, + 31, + 46, + 74, + 103, + 133, + 159, + 222, + 197, + 299, + 319, + 395, + 484, + 547, + 604, + 734, + 850, + 965, + 991, + 1085, + 1243, + 1427, + 1541, + 1619, + 1711, + 1834, + 1861, + 1948, + 1807, + 1833, + 1750, + 1834, + 1712, + 1812, + 1930, + 1946, + 2154, + 2005, + 2014, + 1697, + 1383, + 1201, + 1075, + 965, + 969, + 847, + 917, + 875, + 803, + 713, + 652, + 613, + 574, + 542, + 510, + 448, + 393, + 376, + 341, + 331, + 297, + 245, + 212, + 202, + 179, + 159, + 144, + 130, + 120, + 127, + 110, + 110, + 106, + 105, + 90, + 84, + 93, + 88, + 100, + 88, + 73, + 104, + 75, + 72, + 79, + 79, + 88, + 64, + 75, + 80, + 68, + 75, + 67, + 69, + 63, + 64, + 57, + 68, + 56, + 53, + 67, + 69, + 61, + 57, + 52, + 68, + 52, + 46, + 68, + 53, + 60, + 75, + 46, + 55, + 51, + 54, + 41, + 58, + 61, + 57, + 46, + 44, + 50, + 54, + 61, + 46, + 40, + 35, + 67, + 47, + 45, + 53, + 35, + 52, + 35, + 54, + 51, + 39, + 54, + 43, + 55, + 44, + 37, + 30, + 45, + 41, + 30, + 39, + 37, + 47, + 30, + 26, + 41, + 29, + 36, + 34, + 24, + 27, + 25, + 25, + 25, + 23, + 23, + 15, + 12, + 12, + 12, + 16, + 13, + 12, + 10, + 4, + 14, + 10, + 8, + 6, + 6, + 9, + 13, + 8, + 0, + 3, + 5, + 6, + 0, + 2, + 4, + 1, + 0, + 3, + 1, + 2, + 3, + 0, + 1, + 1, + 0, + 1, + 4, + 1, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 1, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0 + ], + "label": [ + 0, + 1, + 2, + 3, + 4, + 5, + 6, + 7, + 8, + 9, + 10, + 11, + 12, + 13, + 14, + 15, + 16, + 17, + 18, + 19, + 20, + 21, + 22, + 23, + 24, + 25, + 26, + 27, + 28, + 29, + 30, + 31, + 32, + 33, + 34, + 35, + 36, + 37, + 38, + 39, + 40, + 41, + 42, + 43, + 44, + 45, + 46, + 47, + 48, + 49, + 50, + 51, + 52, + 53, + 54, + 55, + 56, + 57, + 58, + 59, + 60, + 61, + 62, + 63, + 64, + 65, + 66, + 67, + 68, + 69, + 70, + 71, + 72, + 73, + 74, + 75, + 76, + 77, + 78, + 79, + 80, + 81, + 82, + 83, + 84, + 85, + 86, + 87, + 88, + 89, + 90, + 91, + 92, + 93, + 94, + 95, + 96, + 97, + 98, + 99, + 100, + 101, + 102, + 103, + 104, + 105, + 106, + 107, + 108, + 109, + 110, + 111, + 112, + 113, + 114, + 115, + 116, + 117, + 118, + 119, + 120, + 121, + 122, + 123, + 124, + 125, + 126, + 127, + 128, + 129, + 130, + 131, + 132, + 133, + 134, + 135, + 136, + 137, + 138, + 139, + 140, + 141, + 142, + 143, + 144, + 145, + 146, + 147, + 148, + 149, + 150, + 151, + 152, + 153, + 154, + 155, + 156, + 157, + 158, + 159, + 160, + 161, + 162, + 163, + 164, + 165, + 166, + 167, + 168, + 169, + 170, + 171, + 172, + 173, + 174, + 175, + 176, + 177, + 178, + 179, + 180, + 181, + 182, + 183, + 184, + 185, + 186, + 187, + 188, + 189, + 190, + 191, + 192, + 193, + 194, + 195, + 196, + 197, + 198, + 199, + 200, + 201, + 202, + 203, + 204, + 205, + 206, + 207, + 208, + 209, + 210, + 211, + 212, + 213, + 214, + 215, + 216, + 217, + 218, + 219, + 220, + 221, + 222, + 223, + 224, + 225, + 226, + 227, + 228, + 229, + 230, + 231, + 232, + 233, + 234, + 235, + 236, + 237, + 238, + 239, + 240, + 241, + 242, + 243, + 244, + 245, + 246, + 247, + 248, + 249, + 250, + 251, + 252, + 253, + 254, + 255 + ] + }, + "red_frequencies": { + "trait": "red frequencies", + "method": "plantcv.plantcv.analyze_color", + "scale": "frequency", + "datatype": "", + "value": [ + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 4, + 8, + 16, + 39, + 68, + 95, + 136, + 180, + 279, + 452, + 544, + 769, + 859, + 1009, + 1041, + 1218, + 1372, + 1446, + 1573, + 1826, + 2054, + 2320, + 2190, + 2194, + 2127, + 2090, + 1989, + 2131, + 2431, + 2169, + 2148, + 1961, + 1898, + 1542, + 1356, + 1267, + 1169, + 1010, + 953, + 825, + 818, + 728, + 674, + 618, + 621, + 556, + 584, + 568, + 560, + 447, + 419, + 346, + 332, + 323, + 312, + 298, + 279, + 243, + 240, + 217, + 198, + 163, + 166, + 173, + 160, + 150, + 128, + 128, + 121, + 136, + 103, + 112, + 110, + 96, + 103, + 118, + 119, + 100, + 99, + 81, + 98, + 95, + 96, + 86, + 95, + 68, + 97, + 74, + 97, + 75, + 90, + 78, + 92, + 83, + 72, + 64, + 64, + 69, + 75, + 71, + 79, + 75, + 66, + 66, + 76, + 77, + 71, + 59, + 50, + 69, + 67, + 66, + 55, + 77, + 58, + 53, + 70, + 73, + 57, + 52, + 74, + 55, + 66, + 79, + 52, + 48, + 55, + 53, + 46, + 63, + 71, + 41, + 52, + 45, + 54, + 41, + 53, + 51, + 59, + 44, + 39, + 43, + 41, + 43, + 43, + 36, + 50, + 44, + 41, + 43, + 43, + 34, + 40, + 36, + 41, + 36, + 35, + 28, + 36, + 28, + 29, + 31, + 23, + 26, + 27, + 27, + 25, + 23, + 19, + 22, + 23, + 16, + 20, + 17, + 14, + 11, + 11, + 6, + 13, + 8, + 5, + 14, + 6, + 11, + 4, + 7, + 5, + 3, + 10, + 3, + 5, + 6, + 2, + 3, + 3, + 2, + 5, + 5, + 3, + 3, + 3, + 0, + 1, + 0, + 1, + 1, + 0, + 1, + 1, + 1, + 1, + 1, + 1, + 0, + 1, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0 + ], + "label": [ + 0, + 1, + 2, + 3, + 4, + 5, + 6, + 7, + 8, + 9, + 10, + 11, + 12, + 13, + 14, + 15, + 16, + 17, + 18, + 19, + 20, + 21, + 22, + 23, + 24, + 25, + 26, + 27, + 28, + 29, + 30, + 31, + 32, + 33, + 34, + 35, + 36, + 37, + 38, + 39, + 40, + 41, + 42, + 43, + 44, + 45, + 46, + 47, + 48, + 49, + 50, + 51, + 52, + 53, + 54, + 55, + 56, + 57, + 58, + 59, + 60, + 61, + 62, + 63, + 64, + 65, + 66, + 67, + 68, + 69, + 70, + 71, + 72, + 73, + 74, + 75, + 76, + 77, + 78, + 79, + 80, + 81, + 82, + 83, + 84, + 85, + 86, + 87, + 88, + 89, + 90, + 91, + 92, + 93, + 94, + 95, + 96, + 97, + 98, + 99, + 100, + 101, + 102, + 103, + 104, + 105, + 106, + 107, + 108, + 109, + 110, + 111, + 112, + 113, + 114, + 115, + 116, + 117, + 118, + 119, + 120, + 121, + 122, + 123, + 124, + 125, + 126, + 127, + 128, + 129, + 130, + 131, + 132, + 133, + 134, + 135, + 136, + 137, + 138, + 139, + 140, + 141, + 142, + 143, + 144, + 145, + 146, + 147, + 148, + 149, + 150, + 151, + 152, + 153, + 154, + 155, + 156, + 157, + 158, + 159, + 160, + 161, + 162, + 163, + 164, + 165, + 166, + 167, + 168, + 169, + 170, + 171, + 172, + 173, + 174, + 175, + 176, + 177, + 178, + 179, + 180, + 181, + 182, + 183, + 184, + 185, + 186, + 187, + 188, + 189, + 190, + 191, + 192, + 193, + 194, + 195, + 196, + 197, + 198, + 199, + 200, + 201, + 202, + 203, + 204, + 205, + 206, + 207, + 208, + 209, + 210, + 211, + 212, + 213, + 214, + 215, + 216, + 217, + 218, + 219, + 220, + 221, + 222, + 223, + 224, + 225, + 226, + 227, + 228, + 229, + 230, + 231, + 232, + 233, + 234, + 235, + 236, + 237, + 238, + 239, + 240, + 241, + 242, + 243, + 244, + 245, + 246, + 247, + 248, + 249, + 250, + 251, + 252, + 253, + 254, + 255 + ] + }, + "lightness_frequencies": { + "trait": "lightness frequencies", + "method": "plantcv.plantcv.analyze_color", + "scale": "frequency", + "datatype": "", + "value": [ + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 1, + 1, + 3, + 5, + 8, + 9, + 17, + 6, + 7, + 16, + 20, + 38, + 41, + 89, + 61, + 111, + 188, + 104, + 243, + 289, + 315, + 378, + 187, + 518, + 478, + 678, + 690, + 1142, + 925, + 801, + 911, + 1502, + 1124, + 1184, + 1863, + 1223, + 1818, + 1405, + 2022, + 1773, + 1349, + 1878, + 1742, + 1563, + 1722, + 1690, + 1773, + 1885, + 2070, + 1901, + 2204, + 1321, + 1200, + 1352, + 828, + 1067, + 1010, + 690, + 918, + 829, + 828, + 738, + 655, + 579, + 593, + 512, + 478, + 467, + 506, + 351, + 374, + 277, + 336, + 242, + 301, + 234, + 245, + 186, + 216, + 162, + 135, + 140, + 161, + 114, + 110, + 105, + 81, + 121, + 109, + 124, + 90, + 90, + 100, + 79, + 70, + 99, + 83, + 76, + 84, + 96, + 64, + 88, + 77, + 71, + 82, + 82, + 78, + 63, + 77, + 83, + 61, + 68, + 67, + 57, + 62, + 69, + 63, + 49, + 63, + 50, + 82, + 52, + 63, + 48, + 55, + 72, + 47, + 57, + 56, + 81, + 55, + 63, + 62, + 44, + 60, + 52, + 53, + 64, + 59, + 64, + 38, + 41, + 45, + 56, + 47, + 49, + 56, + 54, + 40, + 56, + 56, + 49, + 39, + 50, + 52, + 46, + 53, + 43, + 48, + 43, + 45, + 40, + 41, + 34, + 45, + 45, + 30, + 33, + 31, + 32, + 45, + 29, + 27, + 26, + 22, + 20, + 15, + 27, + 20, + 17, + 14, + 7, + 11, + 15, + 7, + 16, + 11, + 10, + 11, + 6, + 7, + 8, + 9, + 1, + 3, + 3, + 6, + 3, + 2, + 2, + 3, + 4, + 1, + 0, + 2, + 0, + 2, + 0, + 2, + 0, + 1, + 2, + 0, + 0, + 0, + 0, + 1, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0 + ], + "label": [ + 0, + 0.39, + 0.78, + 1.18, + 1.57, + 1.96, + 2.35, + 2.75, + 3.14, + 3.53, + 3.92, + 4.31, + 4.71, + 5.1, + 5.49, + 5.88, + 6.27, + 6.67, + 7.06, + 7.45, + 7.84, + 8.24, + 8.63, + 9.02, + 9.41, + 9.8, + 10.2, + 10.59, + 10.98, + 11.37, + 11.76, + 12.16, + 12.55, + 12.94, + 13.33, + 13.73, + 14.12, + 14.51, + 14.9, + 15.29, + 15.69, + 16.08, + 16.47, + 16.86, + 17.25, + 17.65, + 18.04, + 18.43, + 18.82, + 19.22, + 19.61, + 20, + 20.39, + 20.78, + 21.18, + 21.57, + 21.96, + 22.35, + 22.75, + 23.14, + 23.53, + 23.92, + 24.31, + 24.71, + 25.1, + 25.49, + 25.88, + 26.27, + 26.67, + 27.06, + 27.45, + 27.84, + 28.24, + 28.63, + 29.02, + 29.41, + 29.8, + 30.2, + 30.59, + 30.98, + 31.37, + 31.76, + 32.16, + 32.55, + 32.94, + 33.33, + 33.73, + 34.12, + 34.51, + 34.9, + 35.29, + 35.69, + 36.08, + 36.47, + 36.86, + 37.25, + 37.65, + 38.04, + 38.43, + 38.82, + 39.22, + 39.61, + 40, + 40.39, + 40.78, + 41.18, + 41.57, + 41.96, + 42.35, + 42.75, + 43.14, + 43.53, + 43.92, + 44.31, + 44.71, + 45.1, + 45.49, + 45.88, + 46.27, + 46.67, + 47.06, + 47.45, + 47.84, + 48.24, + 48.63, + 49.02, + 49.41, + 49.8, + 50.2, + 50.59, + 50.98, + 51.37, + 51.76, + 52.16, + 52.55, + 52.94, + 53.33, + 53.73, + 54.12, + 54.51, + 54.9, + 55.29, + 55.69, + 56.08, + 56.47, + 56.86, + 57.25, + 57.65, + 58.04, + 58.43, + 58.82, + 59.22, + 59.61, + 60, + 60.39, + 60.78, + 61.18, + 61.57, + 61.96, + 62.35, + 62.75, + 63.14, + 63.53, + 63.92, + 64.31, + 64.71, + 65.1, + 65.49, + 65.88, + 66.27, + 66.67, + 67.06, + 67.45, + 67.84, + 68.24, + 68.63, + 69.02, + 69.41, + 69.8, + 70.2, + 70.59, + 70.98, + 71.37, + 71.76, + 72.16, + 72.55, + 72.94, + 73.33, + 73.73, + 74.12, + 74.51, + 74.9, + 75.29, + 75.69, + 76.08, + 76.47, + 76.86, + 77.25, + 77.65, + 78.04, + 78.43, + 78.82, + 79.22, + 79.61, + 80, + 80.39, + 80.78, + 81.18, + 81.57, + 81.96, + 82.35, + 82.75, + 83.14, + 83.53, + 83.92, + 84.31, + 84.71, + 85.1, + 85.49, + 85.88, + 86.27, + 86.67, + 87.06, + 87.45, + 87.84, + 88.24, + 88.63, + 89.02, + 89.41, + 89.8, + 90.2, + 90.59, + 90.98, + 91.37, + 91.76, + 92.16, + 92.55, + 92.94, + 93.33, + 93.73, + 94.12, + 94.51, + 94.9, + 95.29, + 95.69, + 96.08, + 96.47, + 96.86, + 97.25, + 97.65, + 98.04, + 98.43, + 98.82, + 99.22, + 99.61, + 100 + ] + }, + "green-magenta_frequencies": { + "trait": "green-magenta frequencies", + "method": "plantcv.plantcv.analyze_color", + "scale": "frequency", + "datatype": "", + "value": [ + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 5, + 17, + 76, + 429, + 1525, + 3788, + 6803, + 9196, + 9962, + 8484, + 6621, + 4859, + 3467, + 2368, + 1852, + 1510, + 1199, + 935, + 743, + 577, + 415, + 320, + 247, + 176, + 125, + 80, + 42, + 11, + 12, + 5, + 2, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0 + ], + "label": [ + -128, + -127, + -126, + -125, + -124, + -123, + -122, + -121, + -120, + -119, + -118, + -117, + -116, + -115, + -114, + -113, + -112, + -111, + -110, + -109, + -108, + -107, + -106, + -105, + -104, + -103, + -102, + -101, + -100, + -99, + -98, + -97, + -96, + -95, + -94, + -93, + -92, + -91, + -90, + -89, + -88, + -87, + -86, + -85, + -84, + -83, + -82, + -81, + -80, + -79, + -78, + -77, + -76, + -75, + -74, + -73, + -72, + -71, + -70, + -69, + -68, + -67, + -66, + -65, + -64, + -63, + -62, + -61, + -60, + -59, + -58, + -57, + -56, + -55, + -54, + -53, + -52, + -51, + -50, + -49, + -48, + -47, + -46, + -45, + -44, + -43, + -42, + -41, + -40, + -39, + -38, + -37, + -36, + -35, + -34, + -33, + -32, + -31, + -30, + -29, + -28, + -27, + -26, + -25, + -24, + -23, + -22, + -21, + -20, + -19, + -18, + -17, + -16, + -15, + -14, + -13, + -12, + -11, + -10, + -9, + -8, + -7, + -6, + -5, + -4, + -3, + -2, + -1, + 0, + 1, + 2, + 3, + 4, + 5, + 6, + 7, + 8, + 9, + 10, + 11, + 12, + 13, + 14, + 15, + 16, + 17, + 18, + 19, + 20, + 21, + 22, + 23, + 24, + 25, + 26, + 27, + 28, + 29, + 30, + 31, + 32, + 33, + 34, + 35, + 36, + 37, + 38, + 39, + 40, + 41, + 42, + 43, + 44, + 45, + 46, + 47, + 48, + 49, + 50, + 51, + 52, + 53, + 54, + 55, + 56, + 57, + 58, + 59, + 60, + 61, + 62, + 63, + 64, + 65, + 66, + 67, + 68, + 69, + 70, + 71, + 72, + 73, + 74, + 75, + 76, + 77, + 78, + 79, + 80, + 81, + 82, + 83, + 84, + 85, + 86, + 87, + 88, + 89, + 90, + 91, + 92, + 93, + 94, + 95, + 96, + 97, + 98, + 99, + 100, + 101, + 102, + 103, + 104, + 105, + 106, + 107, + 108, + 109, + 110, + 111, + 112, + 113, + 114, + 115, + 116, + 117, + 118, + 119, + 120, + 121, + 122, + 123, + 124, + 125, + 126, + 127 + ] + }, + "blue-yellow_frequencies": { + "trait": "blue-yellow frequencies", + "method": "plantcv.plantcv.analyze_color", + "scale": "frequency", + "datatype": "", + "value": [ + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 352, + 377, + 472, + 711, + 1009, + 1659, + 2405, + 3140, + 4487, + 5885, + 6881, + 7038, + 6708, + 7055, + 5978, + 4737, + 3087, + 1820, + 886, + 450, + 219, + 148, + 109, + 89, + 59, + 38, + 25, + 15, + 7, + 5, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0 + ], + "label": [ + -128, + -127, + -126, + -125, + -124, + -123, + -122, + -121, + -120, + -119, + -118, + -117, + -116, + -115, + -114, + -113, + -112, + -111, + -110, + -109, + -108, + -107, + -106, + -105, + -104, + -103, + -102, + -101, + -100, + -99, + -98, + -97, + -96, + -95, + -94, + -93, + -92, + -91, + -90, + -89, + -88, + -87, + -86, + -85, + -84, + -83, + -82, + -81, + -80, + -79, + -78, + -77, + -76, + -75, + -74, + -73, + -72, + -71, + -70, + -69, + -68, + -67, + -66, + -65, + -64, + -63, + -62, + -61, + -60, + -59, + -58, + -57, + -56, + -55, + -54, + -53, + -52, + -51, + -50, + -49, + -48, + -47, + -46, + -45, + -44, + -43, + -42, + -41, + -40, + -39, + -38, + -37, + -36, + -35, + -34, + -33, + -32, + -31, + -30, + -29, + -28, + -27, + -26, + -25, + -24, + -23, + -22, + -21, + -20, + -19, + -18, + -17, + -16, + -15, + -14, + -13, + -12, + -11, + -10, + -9, + -8, + -7, + -6, + -5, + -4, + -3, + -2, + -1, + 0, + 1, + 2, + 3, + 4, + 5, + 6, + 7, + 8, + 9, + 10, + 11, + 12, + 13, + 14, + 15, + 16, + 17, + 18, + 19, + 20, + 21, + 22, + 23, + 24, + 25, + 26, + 27, + 28, + 29, + 30, + 31, + 32, + 33, + 34, + 35, + 36, + 37, + 38, + 39, + 40, + 41, + 42, + 43, + 44, + 45, + 46, + 47, + 48, + 49, + 50, + 51, + 52, + 53, + 54, + 55, + 56, + 57, + 58, + 59, + 60, + 61, + 62, + 63, + 64, + 65, + 66, + 67, + 68, + 69, + 70, + 71, + 72, + 73, + 74, + 75, + 76, + 77, + 78, + 79, + 80, + 81, + 82, + 83, + 84, + 85, + 86, + 87, + 88, + 89, + 90, + 91, + 92, + 93, + 94, + 95, + 96, + 97, + 98, + 99, + 100, + 101, + 102, + 103, + 104, + 105, + 106, + 107, + 108, + 109, + 110, + 111, + 112, + 113, + 114, + 115, + 116, + 117, + 118, + 119, + 120, + 121, + 122, + 123, + 124, + 125, + 126, + 127 + ] + }, + "hue_frequencies": { + "trait": "hue frequencies", + "method": "plantcv.plantcv.analyze_color", + "scale": "frequency", + "datatype": "", + "value": [ + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 1, + 0, + 4, + 10, + 15, + 22, + 47, + 63, + 114, + 125, + 164, + 209, + 270, + 272, + 406, + 395, + 420, + 511, + 399, + 552, + 590, + 637, + 752, + 843, + 1147, + 1295, + 1972, + 2583, + 3537, + 5285, + 7184, + 8334, + 8292, + 7947, + 4566, + 3209, + 1625, + 848, + 385, + 187, + 96, + 119, + 52, + 48, + 56, + 36, + 31, + 24, + 24, + 26, + 17, + 27, + 18, + 16, + 20, + 12, + 5, + 3, + 3, + 1, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0 + ], + "label": [ + 1, + 3, + 5, + 7, + 9, + 11, + 13, + 15, + 17, + 19, + 21, + 23, + 25, + 27, + 29, + 31, + 33, + 35, + 37, + 39, + 41, + 43, + 45, + 47, + 49, + 51, + 53, + 55, + 57, + 59, + 61, + 63, + 65, + 67, + 69, + 71, + 73, + 75, + 77, + 79, + 81, + 83, + 85, + 87, + 89, + 91, + 93, + 95, + 97, + 99, + 101, + 103, + 105, + 107, + 109, + 111, + 113, + 115, + 117, + 119, + 121, + 123, + 125, + 127, + 129, + 131, + 133, + 135, + 137, + 139, + 141, + 143, + 145, + 147, + 149, + 151, + 153, + 155, + 157, + 159, + 161, + 163, + 165, + 167, + 169, + 171, + 173, + 175, + 177, + 179, + 181, + 183, + 185, + 187, + 189, + 191, + 193, + 195, + 197, + 199, + 201, + 203, + 205, + 207, + 209, + 211, + 213, + 215, + 217, + 219, + 221, + 223, + 225, + 227, + 229, + 231, + 233, + 235, + 237, + 239, + 241, + 243, + 245, + 247, + 249, + 251, + 253, + 255, + 257, + 259, + 261, + 263, + 265, + 267, + 269, + 271, + 273, + 275, + 277, + 279, + 281, + 283, + 285, + 287, + 289, + 291, + 293, + 295, + 297, + 299, + 301, + 303, + 305, + 307, + 309, + 311, + 313, + 315, + 317, + 319, + 321, + 323, + 325, + 327, + 329, + 331, + 333, + 335, + 337, + 339, + 341, + 343, + 345, + 347, + 349, + 351, + 353, + 355, + 357, + 359 + ] + }, + "saturation_frequencies": { + "trait": "saturation frequencies", + "method": "plantcv.plantcv.analyze_color", + "scale": "frequency", + "datatype": "", + "value": [ + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 1, + 1, + 2, + 4, + 5, + 12, + 10, + 13, + 17, + 24, + 27, + 34, + 50, + 55, + 60, + 70, + 78, + 56, + 92, + 56, + 85, + 74, + 104, + 97, + 94, + 84, + 112, + 115, + 102, + 111, + 140, + 119, + 109, + 120, + 135, + 124, + 125, + 119, + 130, + 132, + 111, + 137, + 155, + 135, + 122, + 120, + 129, + 126, + 99, + 116, + 97, + 123, + 119, + 104, + 108, + 120, + 120, + 120, + 113, + 101, + 130, + 111, + 107, + 114, + 134, + 124, + 123, + 130, + 132, + 123, + 160, + 137, + 153, + 168, + 193, + 208, + 137, + 257, + 241, + 234, + 315, + 257, + 319, + 301, + 355, + 369, + 353, + 452, + 425, + 464, + 531, + 521, + 514, + 596, + 625, + 709, + 648, + 753, + 855, + 604, + 1057, + 790, + 717, + 1176, + 687, + 1023, + 917, + 955, + 949, + 971, + 1002, + 862, + 1143, + 1072, + 1047, + 1024, + 1090, + 1230, + 988, + 1179, + 1255, + 1153, + 1223, + 1080, + 1265, + 990, + 1347, + 922, + 1308, + 1071, + 1087, + 968, + 1099, + 1176, + 877, + 868, + 933, + 891, + 745, + 726, + 754, + 693, + 478, + 561, + 657, + 452, + 276, + 487, + 333, + 246, + 213, + 285, + 186, + 195, + 152, + 116, + 97, + 91, + 80, + 73, + 49, + 34, + 34, + 23, + 24, + 13, + 8, + 4, + 5, + 4, + 2, + 3, + 1, + 2, + 0, + 1, + 1, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0 + ], + "label": [ + 0, + 0.39, + 0.78, + 1.18, + 1.57, + 1.96, + 2.35, + 2.75, + 3.14, + 3.53, + 3.92, + 4.31, + 4.71, + 5.1, + 5.49, + 5.88, + 6.27, + 6.67, + 7.06, + 7.45, + 7.84, + 8.24, + 8.63, + 9.02, + 9.41, + 9.8, + 10.2, + 10.59, + 10.98, + 11.37, + 11.76, + 12.16, + 12.55, + 12.94, + 13.33, + 13.73, + 14.12, + 14.51, + 14.9, + 15.29, + 15.69, + 16.08, + 16.47, + 16.86, + 17.25, + 17.65, + 18.04, + 18.43, + 18.82, + 19.22, + 19.61, + 20, + 20.39, + 20.78, + 21.18, + 21.57, + 21.96, + 22.35, + 22.75, + 23.14, + 23.53, + 23.92, + 24.31, + 24.71, + 25.1, + 25.49, + 25.88, + 26.27, + 26.67, + 27.06, + 27.45, + 27.84, + 28.24, + 28.63, + 29.02, + 29.41, + 29.8, + 30.2, + 30.59, + 30.98, + 31.37, + 31.76, + 32.16, + 32.55, + 32.94, + 33.33, + 33.73, + 34.12, + 34.51, + 34.9, + 35.29, + 35.69, + 36.08, + 36.47, + 36.86, + 37.25, + 37.65, + 38.04, + 38.43, + 38.82, + 39.22, + 39.61, + 40, + 40.39, + 40.78, + 41.18, + 41.57, + 41.96, + 42.35, + 42.75, + 43.14, + 43.53, + 43.92, + 44.31, + 44.71, + 45.1, + 45.49, + 45.88, + 46.27, + 46.67, + 47.06, + 47.45, + 47.84, + 48.24, + 48.63, + 49.02, + 49.41, + 49.8, + 50.2, + 50.59, + 50.98, + 51.37, + 51.76, + 52.16, + 52.55, + 52.94, + 53.33, + 53.73, + 54.12, + 54.51, + 54.9, + 55.29, + 55.69, + 56.08, + 56.47, + 56.86, + 57.25, + 57.65, + 58.04, + 58.43, + 58.82, + 59.22, + 59.61, + 60, + 60.39, + 60.78, + 61.18, + 61.57, + 61.96, + 62.35, + 62.75, + 63.14, + 63.53, + 63.92, + 64.31, + 64.71, + 65.1, + 65.49, + 65.88, + 66.27, + 66.67, + 67.06, + 67.45, + 67.84, + 68.24, + 68.63, + 69.02, + 69.41, + 69.8, + 70.2, + 70.59, + 70.98, + 71.37, + 71.76, + 72.16, + 72.55, + 72.94, + 73.33, + 73.73, + 74.12, + 74.51, + 74.9, + 75.29, + 75.69, + 76.08, + 76.47, + 76.86, + 77.25, + 77.65, + 78.04, + 78.43, + 78.82, + 79.22, + 79.61, + 80, + 80.39, + 80.78, + 81.18, + 81.57, + 81.96, + 82.35, + 82.75, + 83.14, + 83.53, + 83.92, + 84.31, + 84.71, + 85.1, + 85.49, + 85.88, + 86.27, + 86.67, + 87.06, + 87.45, + 87.84, + 88.24, + 88.63, + 89.02, + 89.41, + 89.8, + 90.2, + 90.59, + 90.98, + 91.37, + 91.76, + 92.16, + 92.55, + 92.94, + 93.33, + 93.73, + 94.12, + 94.51, + 94.9, + 95.29, + 95.69, + 96.08, + 96.47, + 96.86, + 97.25, + 97.65, + 98.04, + 98.43, + 98.82, + 99.22, + 99.61, + 100 + ] + }, + "value_frequencies": { + "trait": "value frequencies", + "method": "plantcv.plantcv.analyze_color", + "scale": "frequency", + "datatype": "", + "value": [ + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 1, + 1, + 2, + 12, + 11, + 14, + 9, + 13, + 12, + 20, + 26, + 47, + 75, + 104, + 133, + 157, + 224, + 193, + 300, + 322, + 391, + 478, + 546, + 600, + 734, + 852, + 958, + 996, + 1088, + 1241, + 1429, + 1545, + 1616, + 1711, + 1832, + 1860, + 1937, + 1806, + 1832, + 1749, + 1826, + 1712, + 1807, + 1926, + 1944, + 2150, + 1997, + 2012, + 1683, + 1380, + 1189, + 1082, + 958, + 958, + 835, + 914, + 879, + 792, + 698, + 642, + 596, + 561, + 524, + 502, + 433, + 390, + 364, + 329, + 325, + 298, + 241, + 229, + 191, + 171, + 177, + 132, + 120, + 121, + 125, + 100, + 116, + 96, + 111, + 104, + 93, + 86, + 83, + 97, + 90, + 82, + 98, + 71, + 62, + 81, + 91, + 91, + 80, + 87, + 75, + 75, + 80, + 72, + 79, + 65, + 50, + 62, + 71, + 71, + 51, + 76, + 66, + 65, + 72, + 64, + 71, + 54, + 49, + 65, + 58, + 63, + 70, + 51, + 60, + 57, + 52, + 55, + 70, + 50, + 60, + 45, + 56, + 58, + 50, + 60, + 60, + 43, + 35, + 58, + 44, + 48, + 53, + 34, + 47, + 39, + 55, + 52, + 41, + 53, + 48, + 53, + 47, + 41, + 40, + 41, + 49, + 34, + 39, + 36, + 48, + 33, + 29, + 48, + 24, + 39, + 34, + 29, + 29, + 28, + 28, + 28, + 21, + 24, + 18, + 12, + 16, + 18, + 15, + 14, + 15, + 12, + 7, + 15, + 11, + 6, + 12, + 6, + 11, + 14, + 4, + 1, + 3, + 5, + 10, + 2, + 3, + 6, + 4, + 0, + 4, + 1, + 3, + 2, + 0, + 2, + 1, + 1, + 2, + 3, + 1, + 0, + 1, + 0, + 0, + 0, + 0, + 0, + 1, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0 + ], + "label": [ + 0, + 0.39, + 0.78, + 1.18, + 1.57, + 1.96, + 2.35, + 2.75, + 3.14, + 3.53, + 3.92, + 4.31, + 4.71, + 5.1, + 5.49, + 5.88, + 6.27, + 6.67, + 7.06, + 7.45, + 7.84, + 8.24, + 8.63, + 9.02, + 9.41, + 9.8, + 10.2, + 10.59, + 10.98, + 11.37, + 11.76, + 12.16, + 12.55, + 12.94, + 13.33, + 13.73, + 14.12, + 14.51, + 14.9, + 15.29, + 15.69, + 16.08, + 16.47, + 16.86, + 17.25, + 17.65, + 18.04, + 18.43, + 18.82, + 19.22, + 19.61, + 20, + 20.39, + 20.78, + 21.18, + 21.57, + 21.96, + 22.35, + 22.75, + 23.14, + 23.53, + 23.92, + 24.31, + 24.71, + 25.1, + 25.49, + 25.88, + 26.27, + 26.67, + 27.06, + 27.45, + 27.84, + 28.24, + 28.63, + 29.02, + 29.41, + 29.8, + 30.2, + 30.59, + 30.98, + 31.37, + 31.76, + 32.16, + 32.55, + 32.94, + 33.33, + 33.73, + 34.12, + 34.51, + 34.9, + 35.29, + 35.69, + 36.08, + 36.47, + 36.86, + 37.25, + 37.65, + 38.04, + 38.43, + 38.82, + 39.22, + 39.61, + 40, + 40.39, + 40.78, + 41.18, + 41.57, + 41.96, + 42.35, + 42.75, + 43.14, + 43.53, + 43.92, + 44.31, + 44.71, + 45.1, + 45.49, + 45.88, + 46.27, + 46.67, + 47.06, + 47.45, + 47.84, + 48.24, + 48.63, + 49.02, + 49.41, + 49.8, + 50.2, + 50.59, + 50.98, + 51.37, + 51.76, + 52.16, + 52.55, + 52.94, + 53.33, + 53.73, + 54.12, + 54.51, + 54.9, + 55.29, + 55.69, + 56.08, + 56.47, + 56.86, + 57.25, + 57.65, + 58.04, + 58.43, + 58.82, + 59.22, + 59.61, + 60, + 60.39, + 60.78, + 61.18, + 61.57, + 61.96, + 62.35, + 62.75, + 63.14, + 63.53, + 63.92, + 64.31, + 64.71, + 65.1, + 65.49, + 65.88, + 66.27, + 66.67, + 67.06, + 67.45, + 67.84, + 68.24, + 68.63, + 69.02, + 69.41, + 69.8, + 70.2, + 70.59, + 70.98, + 71.37, + 71.76, + 72.16, + 72.55, + 72.94, + 73.33, + 73.73, + 74.12, + 74.51, + 74.9, + 75.29, + 75.69, + 76.08, + 76.47, + 76.86, + 77.25, + 77.65, + 78.04, + 78.43, + 78.82, + 79.22, + 79.61, + 80, + 80.39, + 80.78, + 81.18, + 81.57, + 81.96, + 82.35, + 82.75, + 83.14, + 83.53, + 83.92, + 84.31, + 84.71, + 85.1, + 85.49, + 85.88, + 86.27, + 86.67, + 87.06, + 87.45, + 87.84, + 88.24, + 88.63, + 89.02, + 89.41, + 89.8, + 90.2, + 90.59, + 90.98, + 91.37, + 91.76, + 92.16, + 92.55, + 92.94, + 93.33, + 93.73, + 94.12, + 94.51, + 94.9, + 95.29, + 95.69, + 96.08, + 96.47, + 96.86, + 97.25, + 97.65, + 98.04, + 98.43, + 98.82, + 99.22, + 99.61, + 100 + ] + }, + "hue_circular_mean": { + "trait": "hue circular mean", + "method": "plantcv.plantcv.analyze_color", + "scale": "degrees", + "datatype": "", + "value": 83.67294573455045, + "label": "degrees" + }, + "hue_circular_std": { + "trait": "hue circular standard deviation", + "method": "plantcv.plantcv.analyze_color", + "scale": "degrees", + "datatype": "", + "value": 86, + "label": "degrees" + }, + "hue_median": { + "trait": "hue median", + "method": "plantcv.plantcv.analyze_color", + "scale": "degrees", + "datatype": "", + "value": 86, + "label": "degrees" + } + } + } + } + ] +} From 6bb9450294fcaf83ae588470217ab6dc055534b8 Mon Sep 17 00:00:00 2001 From: nfahlgren Date: Sat, 13 Feb 2021 11:35:11 -0600 Subject: [PATCH 137/137] Add test to cover additional conditions --- tests/tests.py | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/tests/tests.py b/tests/tests.py index 77249104e..3d25c6328 100755 --- a/tests/tests.py +++ b/tests/tests.py @@ -5432,6 +5432,21 @@ def test_plantcv_transform_find_color_card_optional_parameters(): assert pcv.outputs.observations["prefix"]["color_chip_size"]["value"] > 15000 +def test_plantcv_transform_find_color_card_otsu(): + # Clear previous outputs + pcv.outputs.clear() + # Load rgb image + rgb_img = cv2.imread(os.path.join(TEST_DATA, TEST_TARGET_IMG_COLOR_CARD)) + # Test cache directory + cache_dir = os.path.join(TEST_TMPDIR, "test_plantcv_transform_find_color_card_otsu") + os.mkdir(cache_dir) + pcv.params.debug_outdir = cache_dir + # Test with threshold ='normal' + df1, start1, space1 = pcv.transform.find_color_card(rgb_img=rgb_img, threshold_type='otsu', blurry=True, + background='light', threshvalue=90, label="prefix") + assert pcv.outputs.observations["prefix"]["color_chip_size"]["value"] > 15000 + + def test_plantcv_transform_find_color_card_optional_size_parameters(): # Clear previous outputs pcv.outputs.clear()