1
1
#!/usr/bin/python
2
2
3
3
# This is a computational pipeline which uses the plantcv module to sharpen, filter and analyze NIR images
4
- # Pipeline designed for use with Setaria plants at zoom X500
4
+ # Pipeline designed for use with Setaria plants at zoom X3500
5
5
# The strategy/methodology is adopted from the textbook "Digital Image Processing" by Gonzalez and Woods
6
6
# Version 0.9 Max Feldman 7.29.14
7
7
8
-
9
8
import argparse
10
9
import scipy
11
10
from scipy import ndimage
@@ -27,7 +26,6 @@ def options():
27
26
parser .add_argument ("-i" , "--image" , help = "Input image file." , required = True )
28
27
parser .add_argument ("-m" , "--roi" , help = "Input region of interest file." , required = False )
29
28
parser .add_argument ("-o" , "--outdir" , help = "Output directory for image files." , required = False )
30
- # parser.add_argument("-b", "--bkgrd", help="Image of average pixel intensity of background.", required=True)
31
29
parser .add_argument ("-D" , "--debug" , help = "Turn on debug, prints intermediate images." , action = "store_true" )
32
30
args = parser .parse_args ()
33
31
return args
@@ -44,27 +42,26 @@ def main():
44
42
img = cv2 .imread (args .image , flags = 0 )
45
43
path , img_name = os .path .split (args .image )
46
44
# Read in image which is average of average of backgrounds
47
- img_bkgrd = cv2 .imread ("/home/mgehan/LemnaTec/ddpsc_image_git/docs/background_nir_z3500 .png" , flags = 0 )
45
+ img_bkgrd = cv2 .imread ("bkgrd_ave_z3500 .png" , flags = 0 )
48
46
49
47
# NIR images for burnin2 are up-side down. This may be fixed in later experiments
50
- img = ndimage .rotate (img , 0 )
51
- img_bkgrd = ndimage .rotate (img_bkgrd , 0 )
48
+ img = ndimage .rotate (img , 180 )
49
+ img_bkgrd = ndimage .rotate (img_bkgrd , 180 )
52
50
53
51
# Subtract the image from the image background to make the plant more prominent
54
52
device , bkg_sub_img = pcv .image_subtract (img , img_bkgrd , device , args .debug )
55
53
if args .debug :
56
54
pcv .plot_hist (bkg_sub_img , 'bkg_sub_img' )
57
- device , bkg_sub_thres_img = pcv .binary_threshold (bkg_sub_img , 150 , 255 , 'dark' , device , args .debug )
58
- bkg_sub_thres_img = cv2 .inRange (bkg_sub_img , 50 , 190 )
55
+ device , bkg_sub_thres_img = pcv .binary_threshold (bkg_sub_img , 145 , 255 , 'dark' , device , args .debug )
56
+ bkg_sub_thres_img = cv2 .inRange (bkg_sub_img , 30 , 220 )
59
57
if args .debug :
60
58
cv2 .imwrite ('bkgrd_sub_thres.png' , bkg_sub_thres_img )
61
-
59
+
62
60
#device, bkg_sub_thres_img = pcv.binary_threshold_2_sided(img_bkgrd, 50, 190, device, args.debug)
63
-
61
+
64
62
# if a region of interest is specified read it in
65
63
roi = cv2 .imread (args .roi )
66
-
67
-
64
+
68
65
# Start by examining the distribution of pixel intensity values
69
66
if args .debug :
70
67
pcv .plot_hist (img , 'hist_img' )
@@ -83,7 +80,7 @@ def main():
83
80
device , lp_shrp_img = pcv .image_subtract (img , lp_img , device , args .debug )
84
81
if args .debug :
85
82
pcv .plot_hist (lp_shrp_img , 'hist_lp_shrp' )
86
-
83
+
87
84
# Sobel filtering
88
85
# 1st derivative sobel filtering along horizontal axis, kernel = 1, unscaled)
89
86
device , sbx_img = pcv .sobel_filter (img , 1 , 0 , 1 , 1 , device , args .debug )
@@ -112,7 +109,7 @@ def main():
112
109
pcv .plot_hist (edge_shrp_img , 'hist_edge_shrp_img' )
113
110
114
111
# Perform thresholding to generate a binary image
115
- device , tr_es_img = pcv .binary_threshold (edge_shrp_img , 150 , 255 , 'dark' , device , args .debug )
112
+ device , tr_es_img = pcv .binary_threshold (edge_shrp_img , 145 , 255 , 'dark' , device , args .debug )
116
113
117
114
# Prepare a few small kernels for morphological filtering
118
115
kern = np .zeros ((3 ,3 ), dtype = np .uint8 )
@@ -129,6 +126,7 @@ def main():
129
126
kern [1 ,0 :3 ]= 1
130
127
kern [0 :3 ,1 ]= 1
131
128
129
+
132
130
# Perform erosion with 4 small kernels
133
131
device , e1_img = pcv .erode (tr_es_img , kern1 , 1 , device , args .debug )
134
132
device , e2_img = pcv .erode (tr_es_img , kern2 , 1 , device , args .debug )
@@ -151,13 +149,13 @@ def main():
151
149
152
150
# Need to remove the edges of the image, we did that by generating a set of rectangles to mask the edges
153
151
# img is (254 X 320)
154
-
152
+
155
153
# mask for the bottom of the image
156
- device , box1_img , rect_contour1 , hierarchy1 = pcv .rectangle_mask (img , (75 , 212 ), (250 ,252 ), device , args .debug )
154
+ device , box1_img , rect_contour1 , hierarchy1 = pcv .rectangle_mask (img , (100 , 210 ), (230 ,252 ), device , args .debug )
157
155
# mask for the left side of the image
158
- device , box2_img , rect_contour2 , hierarchy2 = pcv .rectangle_mask (img , (1 ,1 ), (75 ,252 ), device , args .debug )
156
+ device , box2_img , rect_contour2 , hierarchy2 = pcv .rectangle_mask (img , (1 ,1 ), (85 ,252 ), device , args .debug )
159
157
# mask for the right side of the image
160
- device , box3_img , rect_contour3 , hierarchy3 = pcv .rectangle_mask (img , (245 ,1 ), (318 ,252 ), device , args .debug )
158
+ device , box3_img , rect_contour3 , hierarchy3 = pcv .rectangle_mask (img , (240 ,1 ), (318 ,252 ), device , args .debug )
161
159
# mask the edges
162
160
device , box4_img , rect_contour4 , hierarchy4 = pcv .border_mask (img , (1 ,1 ), (318 ,252 ), device , args .debug )
163
161
@@ -167,36 +165,34 @@ def main():
167
165
device , bx1234_img = pcv .logical_or (bx123_img , box4_img , device , args .debug )
168
166
device , inv_bx1234_img = pcv .invert (bx1234_img , device , args .debug )
169
167
168
+
170
169
# Make a ROI around the plant, include connected objects
171
170
# Apply the box mask to the image
172
171
# device, masked_img = pcv.apply_mask(masked_erd_dil, inv_bx1234_img, 'black', device, args.debug)
173
-
174
172
device , edge_masked_img = pcv .apply_mask (masked_erd , inv_bx1234_img , 'black' , device , args .debug )
175
-
176
- device , roi_img , roi_contour , roi_hierarchy = pcv .rectangle_mask (img , (50 ,50 ), (280 ,215 ), device , args .debug )
177
-
173
+ device , roi_img , roi_contour , roi_hierarchy = pcv .rectangle_mask (img , (100 ,75 ), (220 ,208 ), device , args .debug )
178
174
plant_objects , plant_hierarchy = cv2 .findContours (edge_masked_img ,cv2 .RETR_TREE ,cv2 .CHAIN_APPROX_NONE )
175
+
179
176
device , roi_objects , hierarchy5 , kept_mask , obj_area = pcv .roi_objects (img , 'partial' , roi_contour , roi_hierarchy , plant_objects , plant_hierarchy , device , args .debug )
180
177
178
+
181
179
# Apply the box mask to the image
180
+ # device, masked_img = pcv.apply_mask(masked_erd_dil, inv_bx1234_img, 'black', device, args.debug)
182
181
device , masked_img = pcv .apply_mask (kept_mask , inv_bx1234_img , 'black' , device , args .debug )
183
182
rgb = cv2 .cvtColor (img ,cv2 .COLOR_GRAY2RGB )
184
-
183
+
185
184
# Generate a binary to send to the analysis function
186
185
device , mask = pcv .binary_threshold (masked_img , 1 , 255 , 'light' , device , args .debug )
187
186
mask3d = np .copy (mask )
188
187
plant_objects_2 , plant_hierarchy_2 = cv2 .findContours (mask3d ,cv2 .RETR_TREE ,cv2 .CHAIN_APPROX_NONE )
189
188
device , o , m = pcv .object_composition (rgb , roi_objects , hierarchy5 , device , args .debug )
190
189
191
-
192
190
### Analysis ###
193
191
device , hist_header , hist_data , h_norm = pcv .analyze_NIR_intensity (img , args .image , mask , 256 , device , args .debug , args .outdir + '/' + img_name )
194
-
195
192
device , shape_header , shape_data , ori_img = pcv .analyze_object (rgb , args .image , o , m , device , args .debug , args .outdir + '/' + img_name )
193
+
196
194
pcv .print_results (args .image , hist_header , hist_data )
197
195
pcv .print_results (args .image , shape_header , shape_data )
198
196
199
-
200
-
201
197
if __name__ == '__main__' :
202
198
main ()
0 commit comments