Skip to content

Commit d3311d3

Browse files
authored
Merge pull request #824 from danforthcenter/update-4x
Synchronize the main branch with the 4x branch
2 parents e5b78d7 + c0ffc79 commit d3311d3

51 files changed

Lines changed: 514 additions & 1017 deletions

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

plantcv/plantcv/acute_vertex.py

Lines changed: 26 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -4,10 +4,9 @@
44
import cv2
55
import numpy as np
66
import math
7-
from plantcv.plantcv import print_image
8-
from plantcv.plantcv import plot_image
97
from plantcv.plantcv import params
108
from plantcv.plantcv import outputs
9+
from plantcv.plantcv._debug import _debug
1110

1211

1312
def acute_vertex(img, obj, win, thresh, sep, label="default"):
@@ -50,15 +49,17 @@ def acute_vertex(img, obj, win, thresh, sep, label="default"):
5049
post_x, post_y = obj[i + win].ravel()
5150

5251
# Angle in radians derived from Law of Cosines, converted to degrees
53-
P12 = np.sqrt((x-pre_x)*(x-pre_x)+(y-pre_y)*(y-pre_y))
54-
P13 = np.sqrt((x-post_x)*(x-post_x)+(y-post_y)*(y-post_y))
55-
P23 = np.sqrt((pre_x-post_x)*(pre_x-post_x)+(pre_y-post_y)*(pre_y-post_y))
56-
if (2*P12*P13) > 0.001:
57-
dot = (P12*P12 + P13*P13 - P23*P23)/(2*P12*P13)
58-
elif (2*P12*P13) < 0.001:
59-
dot = (P12*P12 + P13*P13 - P23*P23)/0.001
60-
61-
if dot < -1: # If float exceeds -1 prevent arcos error and force to equal -1
52+
P12 = np.sqrt((x - pre_x) * (x - pre_x) + (y - pre_y) * (y - pre_y))
53+
P13 = np.sqrt((x - post_x) * (x - post_x) + (y - post_y) *
54+
(y - post_y))
55+
P23 = np.sqrt((pre_x - post_x) * (pre_x - post_x) + (pre_y - post_y) *
56+
(pre_y - post_y))
57+
if (2 * P12 * P13) > 0.001:
58+
dot = (P12 * P12 + P13 * P13 - P23 * P23) / (2 * P12 * P13)
59+
elif (2 * P12 * P13) < 0.001:
60+
dot = (P12 * P12 + P13 * P13 - P23 * P23) / 0.001
61+
62+
if dot < -1: # If float exceeds -1 prevent arcos error and force to equal -1
6263
dot = -1
6364
ang = math.degrees(math.acos(dot))
6465
chain.append(ang)
@@ -73,11 +74,11 @@ def acute_vertex(img, obj, win, thresh, sep, label="default"):
7374
# Sep is the number of points to evaluate the number of vertices
7475
out = []
7576
tester = []
76-
for i in range(len(index)-1):
77+
for i in range(len(index) - 1):
7778
# print str(index[i])
78-
if index[i+1] - index[i] < sep:
79+
if index[i + 1] - index[i] < sep:
7980
tester.append(index[i])
80-
if index[i+1] - index[i] >= sep:
81+
if index[i + 1] - index[i] >= sep:
8182
tester.append(index[i])
8283
# print(tester)
8384
angles = ([chain[d] for d in tester])
@@ -99,14 +100,18 @@ def acute_vertex(img, obj, win, thresh, sep, label="default"):
99100
x, y = i.ravel()
100101
cv2.circle(img2, (x, y), params.line_thickness, (255, 0, 255), -1)
101102

102-
if params.debug == 'print':
103-
print_image(img2, os.path.join(params.debug_outdir, str(params.device) + '_acute_vertices.png'))
104-
elif params.debug == 'plot':
105-
plot_image(img2)
103+
_debug(visual=img2,
104+
filename=os.path.join(params.debug_outdir,
105+
str(params.device) + '_acute_vertices.png'))
106106

107107
# Store into global measurements
108-
outputs.add_observation(sample=label, variable='tip_coordinates', trait='tip coordinates',
109-
method='plantcv.plantcv.acute_vertex', scale='none', datatype=list,
110-
value=acute_points, label='none')
108+
outputs.add_observation(sample=label,
109+
variable='tip_coordinates',
110+
trait='tip coordinates',
111+
method='plantcv.plantcv.acute_vertex',
112+
scale='none',
113+
datatype=list,
114+
value=acute_points,
115+
label='none')
111116

112117
return acute_points, img2

plantcv/plantcv/analyze_bound_horizontal.py

Lines changed: 7 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -3,14 +3,14 @@
33
import os
44
import cv2
55
import numpy as np
6-
from plantcv.plantcv import print_image
7-
from plantcv.plantcv import plot_image
6+
from plantcv.plantcv._debug import _debug
87
from plantcv.plantcv import params
98
from plantcv.plantcv import outputs
109

1110

1211
def analyze_bound_horizontal(img, obj, mask, line_position, label="default"):
13-
"""User-input boundary line tool
12+
"""
13+
User-input boundary line tool
1414
1515
Inputs:
1616
img = RGB or grayscale image data for plotting
@@ -29,7 +29,6 @@ def analyze_bound_horizontal(img, obj, mask, line_position, label="default"):
2929
:param label: str
3030
:return analysis_images: list
3131
"""
32-
3332
ori_img = np.copy(img)
3433

3534
# Draw line horizontal line through bottom of image, that is adjusted to user input height
@@ -139,12 +138,10 @@ def analyze_bound_horizontal(img, obj, mask, line_position, label="default"):
139138
params.line_thickness)
140139
cv2.line(wback, (int(cmx), y_coor - 2), (int(cmx), y_coor + height_below_bound), (0, 255, 0),
141140
params.line_thickness)
142-
if params.debug == 'print':
143-
print_image(wback, os.path.join(params.debug_outdir, str(params.device) + '_boundary_on_white.png'))
144-
print_image(ori_img, os.path.join(params.debug_outdir, str(params.device) + '_boundary_on_img.png'))
145-
if params.debug == 'plot':
146-
plot_image(wback)
147-
plot_image(ori_img)
141+
_debug(visual=wback,
142+
filename=os.path.join(params.debug_outdir, str(params.device) + '_boundary_on_white.png'))
143+
_debug(visual=ori_img,
144+
filename=os.path.join(params.debug_outdir, str(params.device) + '_boundary_on_img.png'))
148145

149146
outputs.add_observation(sample=label, variable='horizontal_reference_position',
150147
trait='horizontal reference position',

plantcv/plantcv/analyze_bound_vertical.py

Lines changed: 9 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -3,21 +3,19 @@
33
import os
44
import cv2
55
import numpy as np
6-
from plantcv.plantcv import print_image
7-
from plantcv.plantcv import plot_image
6+
from plantcv.plantcv._debug import _debug
87
from plantcv.plantcv import params
98
from plantcv.plantcv import outputs
109

1110

1211
def analyze_bound_vertical(img, obj, mask, line_position, label="default"):
13-
"""User-input boundary line tool
12+
"""
13+
User-input boundary line tool
1414
1515
Inputs:
1616
img = RGB or grayscale image data for plotting
1717
obj = single or grouped contour object
1818
mask = Binary mask made from selected contours
19-
shape_header = pass shape header data to function
20-
shape_data = pass shape data so that analyze_bound data can be appended to it
2119
line_position = position of boundary line (a value of 0 would draw the line through the left side of the image)
2220
label = optional label parameter, modifies the variable name of observations recorded
2321
@@ -92,7 +90,7 @@ def analyze_bound_vertical(img, obj, mask, line_position, label="default"):
9290
cv2.line(ori_img, point3, point4, (255, 0, 255), params.line_thickness)
9391
cv2.line(wback, point3, point4, (255, 0, 255), params.line_thickness)
9492
m = cv2.moments(mask, binaryImage=True)
95-
cmx, cmy = (m['m10'] / m['m00'], m['m01'] / m['m00'])
93+
_, cmy = (m['m10'] / m['m00'], m['m01'] / m['m00'])
9694
if x_coor - x <= 0:
9795
cv2.line(ori_img, (x, int(cmy)), (x + width, int(cmy)), (0, 255, 0), params.line_thickness)
9896
cv2.line(wback, (x, int(cmy)), (x + width, int(cmy)), (0, 255, 0), params.line_thickness)
@@ -121,7 +119,7 @@ def analyze_bound_vertical(img, obj, mask, line_position, label="default"):
121119
cv2.line(ori_img, point3, point4, (255, 0, 255), params.line_thickness)
122120
cv2.line(wback, point3, point4, (255, 0, 255), params.line_thickness)
123121
m = cv2.moments(mask, binaryImage=True)
124-
cmx, cmy = (m['m10'] / m['m00'], m['m01'] / m['m00'])
122+
_, cmy = (m['m10'] / m['m00'], m['m01'] / m['m00'])
125123
if x_coor - x <= 0:
126124
cv2.line(ori_img, (x, int(cmy)), (x + width, int(cmy)), (0, 255, 0), params.line_thickness)
127125
cv2.line(wback, (x, int(cmy)), (x + width, int(cmy)), (0, 255, 0), params.line_thickness)
@@ -139,12 +137,10 @@ def analyze_bound_vertical(img, obj, mask, line_position, label="default"):
139137
params.line_thickness)
140138
cv2.line(wback, (x_coor + 2, int(cmy)), (x_coor - width_right_bound, int(cmy)), (0, 255, 0),
141139
params.line_thickness)
142-
if params.debug == 'print':
143-
print_image(wback, os.path.join(params.debug_outdir, str(params.device) + '_boundary_on_white.png'))
144-
print_image(ori_img, os.path.join(params.debug_outdir, str(params.device) + '_boundary_on_img.png'))
145-
if params.debug == 'plot':
146-
plot_image(wback)
147-
plot_image(ori_img)
140+
_debug(visual=wback,
141+
filename=os.path.join(params.debug_outdir, str(params.device) + '_boundary_on_white.png'))
142+
_debug(visual=ori_img,
143+
filename=os.path.join(params.debug_outdir, str(params.device) + '_boundary_on_img.png'))
148144

149145
outputs.add_observation(sample=label, variable='vertical_reference_position', trait='vertical reference position',
150146
method='plantcv.plantcv.analyze_bound_vertical', scale='none', datatype=int,

plantcv/plantcv/apply_mask.py

Lines changed: 5 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -4,8 +4,7 @@
44
import cv2
55
import numpy as np
66
from plantcv.plantcv import params
7-
from plantcv.plantcv import plot_image
8-
from plantcv.plantcv import print_image
7+
from plantcv.plantcv._debug import _debug
98
from plantcv.plantcv import fatal_error
109
from plantcv.plantcv.transform import rescale
1110

@@ -27,8 +26,6 @@ def apply_mask(img, mask, mask_color):
2726
:return masked_img: numpy.ndarray
2827
"""
2928

30-
params.device += 1
31-
3229
if mask_color.upper() == "WHITE":
3330
color_val = 255
3431
elif mask_color.upper() == "BLACK":
@@ -53,14 +50,10 @@ def apply_mask(img, mask, mask_color):
5350
rescale(array_data[:, :, num_bands - 1])))
5451
params.debug = debug
5552

56-
if params.debug == 'print':
57-
print_image(pseudo_rgb, os.path.join(params.debug_outdir, str(params.device) + '_masked.png'))
58-
elif params.debug == 'plot':
59-
plot_image(pseudo_rgb)
53+
_debug(visual=pseudo_rgb,
54+
filename=os.path.join(params.debug_outdir, str(params.device) + '_masked.png'))
6055
else:
61-
if params.debug == 'print':
62-
print_image(array_data, os.path.join(params.debug_outdir, str(params.device) + '_masked.png'))
63-
elif params.debug == 'plot':
64-
plot_image(array_data)
56+
_debug(visual=array_data,
57+
filename=os.path.join(params.debug_outdir, str(params.device) + '_masked.png'))
6558

6659
return array_data

plantcv/plantcv/auto_crop.py

Lines changed: 19 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -3,14 +3,14 @@
33
import os
44
import cv2
55
import numpy as np
6-
from plantcv.plantcv import print_image
7-
from plantcv.plantcv import plot_image
6+
from plantcv.plantcv._debug import _debug
87
from plantcv.plantcv import params
98
from plantcv.plantcv import fatal_error
109

1110

1211
def auto_crop(img, obj, padding_x=0, padding_y=0, color='black'):
13-
"""Resize image.
12+
"""
13+
Resize image.
1414
1515
Inputs:
1616
img = RGB or grayscale image data
@@ -59,30 +59,32 @@ def auto_crop(img, obj, padding_x=0, padding_y=0, color='black'):
5959

6060
if color.upper() == 'BLACK':
6161
colorval = (0, 0, 0)
62-
cropped = cv2.copyMakeBorder(crop_img, offsety_top, offsety_bottom, offsetx_left, offsetx_right, cv2.BORDER_CONSTANT, value=colorval)
62+
cropped = cv2.copyMakeBorder(crop_img, offsety_top, offsety_bottom, offsetx_left,
63+
offsetx_right, cv2.BORDER_CONSTANT, value=colorval)
6364
elif color.upper() == 'WHITE':
6465
colorval = (255, 255, 255)
65-
cropped = cv2.copyMakeBorder(crop_img, offsety_top, offsety_bottom, offsetx_left, offsetx_right, cv2.BORDER_CONSTANT, value=colorval)
66+
cropped = cv2.copyMakeBorder(crop_img, offsety_top, offsety_bottom, offsetx_left,
67+
offsetx_right, cv2.BORDER_CONSTANT, value=colorval)
6668
elif color.upper() == 'IMAGE':
6769
# Check whether the ROI is correctly bounded inside the image
68-
if x - offsetx_right < 0 or y - offsety_top < 0 or x + w + offsetx_right > width or y + h + offsety_bottom > height:
70+
if x - offsetx_right < 0 or y - offsety_top < 0 or x + w + offsetx_right > width or y + h + offsety_bottom > height:
6971
cropped = img_copy2[y:y + h, x:x + w]
7072
else:
7173
# If padding is the image, crop the image with a buffer rather than cropping and adding a buffer
7274
cropped = img_copy2[y - offsety_top:y + h + offsety_bottom, x - offsetx_left:x + w + offsetx_right]
7375
else:
7476
fatal_error('Color was provided but ' + str(color) + ' is not "white", "black", or "image"!')
7577

76-
77-
if params.debug == 'print':
78-
print_image(img_copy, os.path.join(params.debug_outdir, str(params.device) + "_crop_area.png"))
79-
print_image(cropped, os.path.join(params.debug_outdir, str(params.device) + "_auto_cropped.png"))
80-
elif params.debug == 'plot':
81-
if len(np.shape(img_copy)) == 3:
82-
plot_image(img_copy)
83-
plot_image(cropped)
84-
else:
85-
plot_image(img_copy, cmap='gray')
86-
plot_image(cropped, cmap='gray')
78+
if len(np.shape(img_copy)) == 3:
79+
cmap = None
80+
else:
81+
cmap = 'gray'
82+
83+
_debug(visual=img_copy,
84+
filename=os.path.join(params.debug_outdir, str(params.device) + "_crop_area.png"),
85+
cmap=cmap)
86+
_debug(visual=cropped,
87+
filename=os.path.join(params.debug_outdir, str(params.device) + "_auto_cropped.png"),
88+
cmap=cmap)
8789

8890
return cropped

plantcv/plantcv/background_subtraction.py

Lines changed: 6 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -4,14 +4,14 @@
44
import os
55
import cv2
66
import numpy as np
7-
from plantcv.plantcv import print_image
8-
from plantcv.plantcv import plot_image
7+
from plantcv.plantcv._debug import _debug
98
from plantcv.plantcv import fatal_error
109
from plantcv.plantcv import params
1110

1211

1312
def background_subtraction(background_image, foreground_image):
14-
"""Creates a binary image from a background subtraction of the foreground using cv2.BackgroundSubtractorMOG().
13+
"""
14+
Creates a binary image from a background subtraction of the foreground using cv2.BackgroundSubtractorMOG().
1515
The binary image returned is a mask that should contain mostly foreground pixels.
1616
The background image should be the same background as the foreground image except not containing the object
1717
of interest.
@@ -31,8 +31,6 @@ def background_subtraction(background_image, foreground_image):
3131
:param foreground_image: numpy.ndarray
3232
:return fgmask: numpy.ndarray
3333
"""
34-
35-
params.device += 1
3634
# Copying images to make sure not alter originals
3735
bg_img = np.copy(background_image)
3836
fg_img = np.copy(foreground_image)
@@ -57,10 +55,8 @@ def background_subtraction(background_image, foreground_image):
5755
# Applying the foreground image to the background subtractor (therefore removing the background)
5856
fgmask = bgsub.apply(fg_img)
5957

60-
# Debug options
61-
if params.debug == "print":
62-
print_image(fgmask, os.path.join(params.debug_outdir, str(params.device) + "_background_subtraction.png"))
63-
elif params.debug == "plot":
64-
plot_image(fgmask, cmap="gray")
58+
_debug(visual=fgmask,
59+
filename=os.path.join(params.debug_outdir, str(params.device) + "_background_subtraction.png"),
60+
cmap='gray')
6561

6662
return fgmask

plantcv/plantcv/canny_edge_detect.py

Lines changed: 6 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,6 @@
11
# Canny edge detection
22

3-
from plantcv.plantcv import print_image
4-
from plantcv.plantcv import plot_image
3+
from plantcv.plantcv._debug import _debug
54
from plantcv.plantcv import dilate
65
from plantcv.plantcv import params
76
from plantcv.plantcv import fatal_error
@@ -13,7 +12,8 @@
1312

1413
def canny_edge_detect(img, mask=None, sigma=1.0, low_thresh=None, high_thresh=None, thickness=1,
1514
mask_color=None, use_quantiles=False):
16-
"""Edge filter an image using the Canny algorithm.
15+
"""
16+
Edge filter an image using the Canny algorithm.
1717
1818
Inputs:
1919
img = RGB or grayscale image data
@@ -52,8 +52,6 @@ def canny_edge_detect(img, mask=None, sigma=1.0, low_thresh=None, high_thresh=No
5252
Original author: Lee Kamentsky
5353
"""
5454

55-
params.device += 1
56-
5755
# Check if the image is grayscale; if color img then make it grayscale
5856
dimensions = np.shape(img)
5957
if len(dimensions) == 3:
@@ -83,9 +81,8 @@ def canny_edge_detect(img, mask=None, sigma=1.0, low_thresh=None, high_thresh=No
8381
params.debug = debug
8482

8583
# Print or plot the binary image
86-
if params.debug == 'print':
87-
print_image(bin_img, os.path.join(params.debug_outdir, (str(params.device) + '_canny_edge_detect.png')))
88-
elif params.debug == 'plot':
89-
plot_image(bin_img, cmap='gray')
84+
_debug(visual=bin_img,
85+
filename=os.path.join(params.debug_outdir, (str(params.device) + '_canny_edge_detect.png')),
86+
cmap='gray')
9087

9188
return bin_img

plantcv/plantcv/closing.py

Lines changed: 4 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -2,8 +2,7 @@
22
import numpy as np
33
from skimage import morphology
44
from plantcv.plantcv import params
5-
from plantcv.plantcv import print_image
6-
from plantcv.plantcv import plot_image
5+
from plantcv.plantcv._debug import _debug
76
from plantcv.plantcv import fatal_error
87

98

@@ -19,8 +18,6 @@ def closing(gray_img, kernel=None):
1918
:return filtered_img: ndarray
2019
"""
2120

22-
params.device += 1
23-
2421
# Make sure the image is binary/grayscale
2522
if len(np.shape(gray_img)) != 2:
2623
fatal_error("Input image must be grayscale or binary")
@@ -33,9 +30,8 @@ def closing(gray_img, kernel=None):
3330
else:
3431
filtered_img = morphology.closing(gray_img, kernel)
3532

36-
if params.debug == 'print':
37-
print_image(filtered_img, os.path.join(params.debug_outdir, str(params.device) + '_opening' + '.png'))
38-
elif params.debug == 'plot':
39-
plot_image(filtered_img, cmap='gray')
33+
_debug(visual=filtered_img,
34+
filename=os.path.join(params.debug_outdir, str(params.device) + '_opening' + '.png'),
35+
cmap='gray')
4036

4137
return filtered_img

0 commit comments

Comments
 (0)