Skip to content
Merged
Show file tree
Hide file tree
Changes from 71 commits
Commits
Show all changes
72 commits
Select commit Hold shift + click to select a range
9c754ff
support kwargs for plot_image
dschneiderch Jul 22, 2021
ccc2f56
autopep8 formatting on tests.py (--max-line-length=120)
dschneiderch Jul 22, 2021
b8e7e6f
acute_vertex
dschneiderch Jul 22, 2021
71fc2ef
analyze_bound_horizontal
dschneiderch Jul 22, 2021
6eec5e0
analyze_bound_vertical
dschneiderch Jul 22, 2021
4eff1ad
auto_crop
dschneiderch Jul 22, 2021
c526fca
background_subtraction
dschneiderch Jul 22, 2021
4ad8113
fix cov auto_crop
dschneiderch Jul 24, 2021
ccfc8fa
Merge branch 'master' into convert_debug
dschneiderch Jul 24, 2021
7d78171
Fix format for my header: https://gist.github.com/2fc0611e02e4a3af8ee…
typelogic Aug 10, 2021
c9a4e84
Fix format for my header to lowercase
typelogic Aug 10, 2021
260aa20
Merge pull request #813 from typelogic/hdr_format_issue
nfahlgren Aug 12, 2021
fac5a9e
Merge branch 'master' into convert_debug
dschneiderch Aug 17, 2021
a84945b
canny edge detect
dschneiderch Aug 17, 2021
a3429b5
closing
dschneiderch Aug 17, 2021
66b98dd
cluster contours
dschneiderch Aug 17, 2021
b1b13c3
crop
dschneiderch Aug 17, 2021
98fbd77
dilate
dschneiderch Aug 17, 2021
b2b6e4f
distance transform
dschneiderch Aug 17, 2021
34f4738
erode
dschneiderch Aug 17, 2021
df20d74
fill holes
dschneiderch Aug 17, 2021
a0feb28
fill
dschneiderch Aug 17, 2021
7588f83
find objects
dschneiderch Aug 17, 2021
414dec3
fip
dschneiderch Aug 17, 2021
11cc31c
gaussian blue
dschneiderch Aug 17, 2021
6574839
hist_equalization
dschneiderch Aug 17, 2021
c9ecac5
image_add
dschneiderch Aug 17, 2021
14feeb7
image subtract
dschneiderch Aug 17, 2021
3043bc9
invert
dschneiderch Aug 17, 2021
62e7a66
laplace filter
dschneiderch Aug 17, 2021
2b6840e
logical and
dschneiderch Aug 17, 2021
1a73c3e
logical or
dschneiderch Aug 17, 2021
f8b5fe8
logical xor
dschneiderch Aug 17, 2021
33a33e7
median_blue
dschneiderch Aug 17, 2021
550a4b1
object composition
dschneiderch Aug 17, 2021
73323c1
opening
dschneiderch Aug 17, 2021
40514e4
readbayer
dschneiderch Aug 17, 2021
86c1ab5
rectangle maks
dschneiderch Aug 17, 2021
23c4a37
report size marker area
dschneiderch Aug 17, 2021
696875e
rgb2gray hsv
dschneiderch Aug 17, 2021
caf2f45
rgb2gray lab
dschneiderch Aug 18, 2021
4b7c6bf
roi objects
dschneiderch Aug 18, 2021
e51f37d
scale features
dschneiderch Aug 18, 2021
7002fcd
scharr filter
dschneiderch Aug 18, 2021
fdf148f
shift image
dschneiderch Aug 18, 2021
92e983c
sobel filter
dschneiderch Aug 18, 2021
dfbb584
spatial clustering
dschneiderch Aug 18, 2021
967d1de
stdev filter
dschneiderch Aug 18, 2021
de14bc4
watershed segmentation
dschneiderch Aug 18, 2021
757bab0
white balance
dschneiderch Aug 18, 2021
0306be9
x axis pseudolandmarks
dschneiderch Aug 18, 2021
3cfa85f
y axis pseudolandmarks
dschneiderch Aug 18, 2021
12de1d7
white balance: catch bad mode. previously missed in tests?
dschneiderch Aug 25, 2021
d3f8216
fix debug filename
dschneiderch Aug 25, 2021
5a60276
white balance logic should be 'and'
dschneiderch Aug 25, 2021
9be2bae
_debug even if debug is not None to avoid additional testing
dschneiderch Aug 25, 2021
898b1c9
undelete readbayer bad input test
dschneiderch Aug 25, 2021
136db97
cover plot logic scale_features
dschneiderch Aug 25, 2021
0fcef7e
cover plotting logic for cluster_contours
dschneiderch Aug 25, 2021
eb223ba
apply_mask
dschneiderch Aug 25, 2021
e3e452c
finish crop_position_mask
dschneiderch Aug 25, 2021
02b25d7
naive_bayes_classifier
dschneiderch Aug 25, 2021
294514e
roi_methods
dschneiderch Aug 25, 2021
801c7ef
roi2mask
dschneiderch Aug 25, 2021
69951ee
Merge branch 'master' into update-4x
nfahlgren Sep 15, 2021
a820f08
Remove device counter
nfahlgren Sep 15, 2021
b95503c
Move docstring title to newline
nfahlgren Sep 15, 2021
79eb566
Move docstring titles to newlines
nfahlgren Sep 15, 2021
b25234d
Move docstring titles to newline
nfahlgren Sep 15, 2021
f0b4a24
Merge pull request #807 from danforthcenter/convert_debug
nfahlgren Sep 15, 2021
dc71abd
Merge branch 'master' into update-4x
nfahlgren Sep 15, 2021
c0ffc79
Merge branch '4.x' into update-4x
nfahlgren Sep 15, 2021
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
47 changes: 26 additions & 21 deletions plantcv/plantcv/acute_vertex.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,10 +4,9 @@
import cv2
import numpy as np
import math
from plantcv.plantcv import print_image
from plantcv.plantcv import plot_image
from plantcv.plantcv import params
from plantcv.plantcv import outputs
from plantcv.plantcv._debug import _debug


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

# Angle in radians derived from Law of Cosines, converted to degrees
P12 = np.sqrt((x-pre_x)*(x-pre_x)+(y-pre_y)*(y-pre_y))
P13 = np.sqrt((x-post_x)*(x-post_x)+(y-post_y)*(y-post_y))
P23 = np.sqrt((pre_x-post_x)*(pre_x-post_x)+(pre_y-post_y)*(pre_y-post_y))
if (2*P12*P13) > 0.001:
dot = (P12*P12 + P13*P13 - P23*P23)/(2*P12*P13)
elif (2*P12*P13) < 0.001:
dot = (P12*P12 + P13*P13 - P23*P23)/0.001

if dot < -1: # If float exceeds -1 prevent arcos error and force to equal -1
P12 = np.sqrt((x - pre_x) * (x - pre_x) + (y - pre_y) * (y - pre_y))
P13 = np.sqrt((x - post_x) * (x - post_x) + (y - post_y) *
(y - post_y))
P23 = np.sqrt((pre_x - post_x) * (pre_x - post_x) + (pre_y - post_y) *
(pre_y - post_y))
if (2 * P12 * P13) > 0.001:
dot = (P12 * P12 + P13 * P13 - P23 * P23) / (2 * P12 * P13)
elif (2 * P12 * P13) < 0.001:
dot = (P12 * P12 + P13 * P13 - P23 * P23) / 0.001

if dot < -1: # If float exceeds -1 prevent arcos error and force to equal -1
dot = -1
ang = math.degrees(math.acos(dot))
chain.append(ang)
Expand All @@ -73,11 +74,11 @@ def acute_vertex(img, obj, win, thresh, sep, label="default"):
# Sep is the number of points to evaluate the number of vertices
out = []
tester = []
for i in range(len(index)-1):
for i in range(len(index) - 1):
# print str(index[i])
if index[i+1] - index[i] < sep:
if index[i + 1] - index[i] < sep:
tester.append(index[i])
if index[i+1] - index[i] >= sep:
if index[i + 1] - index[i] >= sep:
tester.append(index[i])
# print(tester)
angles = ([chain[d] for d in tester])
Expand All @@ -99,14 +100,18 @@ def acute_vertex(img, obj, win, thresh, sep, label="default"):
x, y = i.ravel()
cv2.circle(img2, (x, y), params.line_thickness, (255, 0, 255), -1)

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

# Store into global measurements
outputs.add_observation(sample=label, variable='tip_coordinates', trait='tip coordinates',
method='plantcv.plantcv.acute_vertex', scale='none', datatype=list,
value=acute_points, label='none')
outputs.add_observation(sample=label,
variable='tip_coordinates',
trait='tip coordinates',
method='plantcv.plantcv.acute_vertex',
scale='none',
datatype=list,
value=acute_points,
label='none')

return acute_points, img2
17 changes: 7 additions & 10 deletions plantcv/plantcv/analyze_bound_horizontal.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,14 +3,14 @@
import os
import cv2
import numpy as np
from plantcv.plantcv import print_image
from plantcv.plantcv import plot_image
from plantcv.plantcv._debug import _debug
from plantcv.plantcv import params
from plantcv.plantcv import outputs


def analyze_bound_horizontal(img, obj, mask, line_position, label="default"):
"""User-input boundary line tool
"""
User-input boundary line tool

Inputs:
img = RGB or grayscale image data for plotting
Expand All @@ -29,7 +29,6 @@ def analyze_bound_horizontal(img, obj, mask, line_position, label="default"):
:param label: str
:return analysis_images: list
"""

ori_img = np.copy(img)

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

outputs.add_observation(sample=label, variable='horizontal_reference_position',
trait='horizontal reference position',
Expand Down
22 changes: 9 additions & 13 deletions plantcv/plantcv/analyze_bound_vertical.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,21 +3,19 @@
import os
import cv2
import numpy as np
from plantcv.plantcv import print_image
from plantcv.plantcv import plot_image
from plantcv.plantcv._debug import _debug
from plantcv.plantcv import params
from plantcv.plantcv import outputs


def analyze_bound_vertical(img, obj, mask, line_position, label="default"):
"""User-input boundary line tool
"""
User-input boundary line tool

Inputs:
img = RGB or grayscale image data for plotting
obj = single or grouped contour object
mask = Binary mask made from selected contours
shape_header = pass shape header data to function
shape_data = pass shape data so that analyze_bound data can be appended to it
line_position = position of boundary line (a value of 0 would draw the line through the left side of the image)
label = optional label parameter, modifies the variable name of observations recorded

Expand Down Expand Up @@ -92,7 +90,7 @@ def analyze_bound_vertical(img, obj, mask, line_position, label="default"):
cv2.line(ori_img, point3, point4, (255, 0, 255), params.line_thickness)
cv2.line(wback, point3, point4, (255, 0, 255), params.line_thickness)
m = cv2.moments(mask, binaryImage=True)
cmx, cmy = (m['m10'] / m['m00'], m['m01'] / m['m00'])
_, cmy = (m['m10'] / m['m00'], m['m01'] / m['m00'])
if x_coor - x <= 0:
cv2.line(ori_img, (x, int(cmy)), (x + width, int(cmy)), (0, 255, 0), params.line_thickness)
cv2.line(wback, (x, int(cmy)), (x + width, int(cmy)), (0, 255, 0), params.line_thickness)
Expand Down Expand Up @@ -121,7 +119,7 @@ def analyze_bound_vertical(img, obj, mask, line_position, label="default"):
cv2.line(ori_img, point3, point4, (255, 0, 255), params.line_thickness)
cv2.line(wback, point3, point4, (255, 0, 255), params.line_thickness)
m = cv2.moments(mask, binaryImage=True)
cmx, cmy = (m['m10'] / m['m00'], m['m01'] / m['m00'])
_, cmy = (m['m10'] / m['m00'], m['m01'] / m['m00'])
if x_coor - x <= 0:
cv2.line(ori_img, (x, int(cmy)), (x + width, int(cmy)), (0, 255, 0), params.line_thickness)
cv2.line(wback, (x, int(cmy)), (x + width, int(cmy)), (0, 255, 0), params.line_thickness)
Expand All @@ -139,12 +137,10 @@ def analyze_bound_vertical(img, obj, mask, line_position, label="default"):
params.line_thickness)
cv2.line(wback, (x_coor + 2, int(cmy)), (x_coor - width_right_bound, int(cmy)), (0, 255, 0),
params.line_thickness)
if params.debug == 'print':
print_image(wback, os.path.join(params.debug_outdir, str(params.device) + '_boundary_on_white.png'))
print_image(ori_img, os.path.join(params.debug_outdir, str(params.device) + '_boundary_on_img.png'))
if params.debug == 'plot':
plot_image(wback)
plot_image(ori_img)
_debug(visual=wback,
filename=os.path.join(params.debug_outdir, str(params.device) + '_boundary_on_white.png'))
_debug(visual=ori_img,
filename=os.path.join(params.debug_outdir, str(params.device) + '_boundary_on_img.png'))

outputs.add_observation(sample=label, variable='vertical_reference_position', trait='vertical reference position',
method='plantcv.plantcv.analyze_bound_vertical', scale='none', datatype=int,
Expand Down
17 changes: 5 additions & 12 deletions plantcv/plantcv/apply_mask.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,7 @@
import cv2
import numpy as np
from plantcv.plantcv import params
from plantcv.plantcv import plot_image
from plantcv.plantcv import print_image
from plantcv.plantcv._debug import _debug
from plantcv.plantcv import fatal_error
from plantcv.plantcv.transform import rescale

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

params.device += 1

if mask_color.upper() == "WHITE":
color_val = 255
elif mask_color.upper() == "BLACK":
Expand All @@ -53,14 +50,10 @@ def apply_mask(img, mask, mask_color):
rescale(array_data[:, :, num_bands - 1])))
params.debug = debug

if params.debug == 'print':
print_image(pseudo_rgb, os.path.join(params.debug_outdir, str(params.device) + '_masked.png'))
elif params.debug == 'plot':
plot_image(pseudo_rgb)
_debug(visual=pseudo_rgb,
filename=os.path.join(params.debug_outdir, str(params.device) + '_masked.png'))
else:
if params.debug == 'print':
print_image(array_data, os.path.join(params.debug_outdir, str(params.device) + '_masked.png'))
elif params.debug == 'plot':
plot_image(array_data)
_debug(visual=array_data,
filename=os.path.join(params.debug_outdir, str(params.device) + '_masked.png'))

return array_data
36 changes: 19 additions & 17 deletions plantcv/plantcv/auto_crop.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,14 +3,14 @@
import os
import cv2
import numpy as np
from plantcv.plantcv import print_image
from plantcv.plantcv import plot_image
from plantcv.plantcv._debug import _debug
from plantcv.plantcv import params
from plantcv.plantcv import fatal_error


def auto_crop(img, obj, padding_x=0, padding_y=0, color='black'):
"""Resize image.
"""
Resize image.

Inputs:
img = RGB or grayscale image data
Expand Down Expand Up @@ -59,30 +59,32 @@ def auto_crop(img, obj, padding_x=0, padding_y=0, color='black'):

if color.upper() == 'BLACK':
colorval = (0, 0, 0)
cropped = cv2.copyMakeBorder(crop_img, offsety_top, offsety_bottom, offsetx_left, offsetx_right, cv2.BORDER_CONSTANT, value=colorval)
cropped = cv2.copyMakeBorder(crop_img, offsety_top, offsety_bottom, offsetx_left,
offsetx_right, cv2.BORDER_CONSTANT, value=colorval)
elif color.upper() == 'WHITE':
colorval = (255, 255, 255)
cropped = cv2.copyMakeBorder(crop_img, offsety_top, offsety_bottom, offsetx_left, offsetx_right, cv2.BORDER_CONSTANT, value=colorval)
cropped = cv2.copyMakeBorder(crop_img, offsety_top, offsety_bottom, offsetx_left,
offsetx_right, cv2.BORDER_CONSTANT, value=colorval)
elif color.upper() == 'IMAGE':
# Check whether the ROI is correctly bounded inside the image
if x - offsetx_right < 0 or y - offsety_top < 0 or x + w + offsetx_right > width or y + h + offsety_bottom > height:
if x - offsetx_right < 0 or y - offsety_top < 0 or x + w + offsetx_right > width or y + h + offsety_bottom > height:
cropped = img_copy2[y:y + h, x:x + w]
else:
# If padding is the image, crop the image with a buffer rather than cropping and adding a buffer
cropped = img_copy2[y - offsety_top:y + h + offsety_bottom, x - offsetx_left:x + w + offsetx_right]
else:
fatal_error('Color was provided but ' + str(color) + ' is not "white", "black", or "image"!')


if params.debug == 'print':
print_image(img_copy, os.path.join(params.debug_outdir, str(params.device) + "_crop_area.png"))
print_image(cropped, os.path.join(params.debug_outdir, str(params.device) + "_auto_cropped.png"))
elif params.debug == 'plot':
if len(np.shape(img_copy)) == 3:
plot_image(img_copy)
plot_image(cropped)
else:
plot_image(img_copy, cmap='gray')
plot_image(cropped, cmap='gray')
if len(np.shape(img_copy)) == 3:
cmap = None
else:
cmap = 'gray'

_debug(visual=img_copy,
filename=os.path.join(params.debug_outdir, str(params.device) + "_crop_area.png"),
cmap=cmap)
_debug(visual=cropped,
filename=os.path.join(params.debug_outdir, str(params.device) + "_auto_cropped.png"),
cmap=cmap)

return cropped
16 changes: 6 additions & 10 deletions plantcv/plantcv/background_subtraction.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,14 +4,14 @@
import os
import cv2
import numpy as np
from plantcv.plantcv import print_image
from plantcv.plantcv import plot_image
from plantcv.plantcv._debug import _debug
from plantcv.plantcv import fatal_error
from plantcv.plantcv import params


def background_subtraction(background_image, foreground_image):
"""Creates a binary image from a background subtraction of the foreground using cv2.BackgroundSubtractorMOG().
"""
Creates a binary image from a background subtraction of the foreground using cv2.BackgroundSubtractorMOG().
The binary image returned is a mask that should contain mostly foreground pixels.
The background image should be the same background as the foreground image except not containing the object
of interest.
Expand All @@ -31,8 +31,6 @@ def background_subtraction(background_image, foreground_image):
:param foreground_image: numpy.ndarray
:return fgmask: numpy.ndarray
"""

params.device += 1
# Copying images to make sure not alter originals
bg_img = np.copy(background_image)
fg_img = np.copy(foreground_image)
Expand All @@ -57,10 +55,8 @@ def background_subtraction(background_image, foreground_image):
# Applying the foreground image to the background subtractor (therefore removing the background)
fgmask = bgsub.apply(fg_img)

# Debug options
if params.debug == "print":
print_image(fgmask, os.path.join(params.debug_outdir, str(params.device) + "_background_subtraction.png"))
elif params.debug == "plot":
plot_image(fgmask, cmap="gray")
_debug(visual=fgmask,
filename=os.path.join(params.debug_outdir, str(params.device) + "_background_subtraction.png"),
cmap='gray')

return fgmask
15 changes: 6 additions & 9 deletions plantcv/plantcv/canny_edge_detect.py
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
# Canny edge detection

from plantcv.plantcv import print_image
from plantcv.plantcv import plot_image
from plantcv.plantcv._debug import _debug
from plantcv.plantcv import dilate
from plantcv.plantcv import params
from plantcv.plantcv import fatal_error
Expand All @@ -13,7 +12,8 @@

def canny_edge_detect(img, mask=None, sigma=1.0, low_thresh=None, high_thresh=None, thickness=1,
mask_color=None, use_quantiles=False):
"""Edge filter an image using the Canny algorithm.
"""
Edge filter an image using the Canny algorithm.

Inputs:
img = RGB or grayscale image data
Expand Down Expand Up @@ -52,8 +52,6 @@ def canny_edge_detect(img, mask=None, sigma=1.0, low_thresh=None, high_thresh=No
Original author: Lee Kamentsky
"""

params.device += 1

# Check if the image is grayscale; if color img then make it grayscale
dimensions = np.shape(img)
if len(dimensions) == 3:
Expand Down Expand Up @@ -83,9 +81,8 @@ def canny_edge_detect(img, mask=None, sigma=1.0, low_thresh=None, high_thresh=No
params.debug = debug

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

return bin_img
12 changes: 4 additions & 8 deletions plantcv/plantcv/closing.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,7 @@
import numpy as np
from skimage import morphology
from plantcv.plantcv import params
from plantcv.plantcv import print_image
from plantcv.plantcv import plot_image
from plantcv.plantcv._debug import _debug
from plantcv.plantcv import fatal_error


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

params.device += 1

# Make sure the image is binary/grayscale
if len(np.shape(gray_img)) != 2:
fatal_error("Input image must be grayscale or binary")
Expand All @@ -33,9 +30,8 @@ def closing(gray_img, kernel=None):
else:
filtered_img = morphology.closing(gray_img, kernel)

if params.debug == 'print':
print_image(filtered_img, os.path.join(params.debug_outdir, str(params.device) + '_opening' + '.png'))
elif params.debug == 'plot':
plot_image(filtered_img, cmap='gray')
_debug(visual=filtered_img,
filename=os.path.join(params.debug_outdir, str(params.device) + '_opening' + '.png'),
cmap='gray')

return filtered_img
Loading