|
| 1 | +import cv2 as cv |
| 2 | +import numpy as np |
| 3 | +import os |
| 4 | +import matplotlib.pyplot as plot |
| 5 | +import copy |
| 6 | + |
| 7 | + |
| 8 | +class constants: |
| 9 | + class HSV: |
| 10 | + max_value = 255 |
| 11 | + max_value_H = 360//2 |
| 12 | + |
| 13 | + low_H = 30 |
| 14 | + low_S = 30 |
| 15 | + low_V = 30 |
| 16 | + high_H = 75 |
| 17 | + high_S = 255 |
| 18 | + high_V = 255 |
| 19 | + |
| 20 | + low_H_name = 'Low H' |
| 21 | + low_S_name = 'Low S' |
| 22 | + low_V_name = 'Low V' |
| 23 | + high_H_name = 'High H' |
| 24 | + high_S_name = 'High S' |
| 25 | + high_V_name = 'High V' |
| 26 | + |
| 27 | + class window: |
| 28 | + window1 = 'Altered' |
| 29 | + window2 = 'Original' |
| 30 | + |
| 31 | + class asth: |
| 32 | + font = cv.FONT_HERSHEY_SIMPLEX |
| 33 | + |
| 34 | + class cntr: |
| 35 | + next_k = ord('m') |
| 36 | + prev_k = ord('n') |
| 37 | + exit_k = 27 |
| 38 | + |
| 39 | + m1_k = ord('1') |
| 40 | + m2_k = ord('2') |
| 41 | + m3_k = ord('3') |
| 42 | + m4_k = ord('4') |
| 43 | + m5_k = ord('5') |
| 44 | + |
| 45 | + class flow: |
| 46 | + HSV_filtering_and_watershed = True |
| 47 | + bg_fg_segm = False |
| 48 | + |
| 49 | + |
| 50 | +class PlantDetector: |
| 51 | + |
| 52 | + def on_low_H_thresh_trackbar(self, val): |
| 53 | + self.c.HSV.low_H = val |
| 54 | + self.c.HSV.low_H = min(self.c.HSV.high_H-1, self.c.HSV.low_H) |
| 55 | + cv.setTrackbarPos(self.c.HSV.low_H_name, self.window1, self.c.HSV.low_H) |
| 56 | + def on_high_H_thresh_trackbar(self, val): |
| 57 | + self.c.HSV.high_H = val |
| 58 | + self.c.HSV.high_H = max(self.c.HSV.high_H, self.c.HSV.low_H+1) |
| 59 | + cv.setTrackbarPos(self.c.HSV.high_H_name, self.window1, self.c.HSV.high_H) |
| 60 | + def on_low_S_thresh_trackbar(self, val): |
| 61 | + self.c.HSV.low_S = val |
| 62 | + self.c.HSV.low_S = min(self.c.HSV.high_S-1, self.c.HSV.low_S) |
| 63 | + cv.setTrackbarPos(self.c.HSV.low_S_name, self.window1, self.c.HSV.low_S) |
| 64 | + def on_high_S_thresh_trackbar(self, val): |
| 65 | + self.c.HSV.high_S = val |
| 66 | + self.c.HSV.high_S = max(self.c.HSV.high_S, self.c.HSV.low_S+1) |
| 67 | + cv.setTrackbarPos(self.c.HSV.high_S_name, self.window1, self.c.HSV.high_S) |
| 68 | + def on_low_V_thresh_trackbar(self, val): |
| 69 | + self.c.HSV.low_V = val |
| 70 | + self.c.HSV.low_V = min(self.c.HSV.high_V-1, self.c.HSV.low_V) |
| 71 | + cv.setTrackbarPos(self.c.HSV.low_V_name, self.window1, self.c.HSV.low_V) |
| 72 | + def on_high_V_thresh_trackbar(self, val): |
| 73 | + self.c.HSV.high_V = val |
| 74 | + self.c.HSV.high_V = max(self.c.HSV.high_V, self.c.HSV.low_V+1) |
| 75 | + cv.setTrackbarPos(self.c.HSV.high_V_name, self.window1, self.c.HSV.high_V) |
| 76 | + |
| 77 | + def prepare_plant_collection(self, src = 'multi_plant'): |
| 78 | + plants = [] |
| 79 | + plant_groups = dict() |
| 80 | + files = os.listdir( src ) |
| 81 | + files.sort() |
| 82 | + for fl in files: |
| 83 | + input_im = cv.imread(src + '/' + fl, cv.IMREAD_COLOR) |
| 84 | + if ( input_im is None ): |
| 85 | + exit() |
| 86 | + |
| 87 | + plants.append({ |
| 88 | + 'p': input_im, |
| 89 | + 'n': fl |
| 90 | + }) |
| 91 | + if fl.split('_')[2] not in plant_groups: |
| 92 | + plant_groups[fl.split('_')[2]] = [] |
| 93 | + plant_groups[fl.split('_')[2]].append(input_im) |
| 94 | + |
| 95 | + return plants, plant_groups |
| 96 | + |
| 97 | + def __init__(self, src = 'multi_plant'): |
| 98 | + self.c = constants() |
| 99 | + self.window1 = self.c.window.window1 |
| 100 | + self.window2 = self.c.window.window2 |
| 101 | + |
| 102 | + cv.namedWindow(self.window1) |
| 103 | + cv.namedWindow(self.window2) |
| 104 | + |
| 105 | + cv.moveWindow(self.window2, 800, 0) |
| 106 | + |
| 107 | + cv.createTrackbar(self.c.HSV.low_H_name, self.window1 , self.c.HSV.low_H, self.c.HSV.max_value_H, self.on_low_H_thresh_trackbar) |
| 108 | + cv.createTrackbar(self.c.HSV.high_H_name, self.window1 , self.c.HSV.high_H,self.c.HSV.max_value_H, self.on_high_H_thresh_trackbar) |
| 109 | + cv.createTrackbar(self.c.HSV.low_S_name, self.window1 , self.c.HSV.low_S, self.c.HSV.max_value, self.on_low_S_thresh_trackbar) |
| 110 | + cv.createTrackbar(self.c.HSV.high_S_name, self.window1 , self.c.HSV.high_S,self.c.HSV.max_value, self.on_high_S_thresh_trackbar) |
| 111 | + cv.createTrackbar(self.c.HSV.low_V_name, self.window1 , self.c.HSV.low_V, self.c.HSV.max_value, self.on_low_V_thresh_trackbar) |
| 112 | + cv.createTrackbar(self.c.HSV.high_V_name, self.window1 , self.c.HSV.high_V,self.c.HSV.max_value, self.on_high_V_thresh_trackbar) |
| 113 | + |
| 114 | + self.plants, self.plant_groups = self.prepare_plant_collection(src) |
| 115 | + |
| 116 | + if self.c.flow.bg_fg_segm is False: |
| 117 | + return |
| 118 | + |
| 119 | + if False: |
| 120 | + backSub = cv.createBackgroundSubtractorMOG2() |
| 121 | + else: |
| 122 | + backSub = cv.createBackgroundSubtractorKNN() |
| 123 | + |
| 124 | + for key in self.plant_groups: |
| 125 | + if True: |
| 126 | + backSub = cv.createBackgroundSubtractorMOG2(history = 60, detectShadows=True) |
| 127 | + else: |
| 128 | + backSub = cv.createBackgroundSubtractorKNN() |
| 129 | + fgMask = None |
| 130 | + for i, image in enumerate(self.plant_groups[key]): |
| 131 | + fgMask = backSub.apply(image) |
| 132 | + self.plant_groups[key][i] = fgMask |
| 133 | + # self.plant_groups[key] = backSub.getBackgroundImage() |
| 134 | + |
| 135 | + def parse(self): |
| 136 | + key = 0 |
| 137 | + mode = 0 |
| 138 | + i = 0 |
| 139 | + |
| 140 | + while key != self.c.cntr.exit_k: |
| 141 | + |
| 142 | + image = copy.deepcopy(self.plants[i]['p']) |
| 143 | + |
| 144 | + if self.c.flow.HSV_filtering_and_watershed: |
| 145 | + if not self.c.flow.bg_fg_segm: |
| 146 | + wt_image, markers, im_threshold = self.HSV_filtering_and_watershed(image) |
| 147 | + else: |
| 148 | + wt_image, markers, im_threshold = self.HSV_filtering_and_watershed( |
| 149 | + cv.cvtColor(self.plant_groups[self.plants[i]['n'].split('_')[2]][i % 60], cv.COLOR_GRAY2BGR) |
| 150 | + ) |
| 151 | + |
| 152 | + if mode == 5 and self.c.flow.bg_fg_segm: |
| 153 | + alt = image |
| 154 | + mask = self.plant_groups[self.plants[i]['n'].split('_')[2]] |
| 155 | + alt[mask == 255] = [0, 0, 0] |
| 156 | + elif mode == 4 and self.c.flow.bg_fg_segm: |
| 157 | + alt = self.plant_groups[self.plants[i]['n'].split('_')[2]][i % 60] |
| 158 | + text = f'Fore/Background segmentation {self.plants[i]["n"]}' |
| 159 | + tcol = (255,255,255) |
| 160 | + elif mode == 3 and self.c.flow.HSV_filtering_and_watershed: |
| 161 | + alt = markers |
| 162 | + text = f'Watershed algorithm areas {self.plants[i]["n"]}' |
| 163 | + tcol = (0, 0, 0) |
| 164 | + |
| 165 | + elif mode == 2 and self.c.flow.HSV_filtering_and_watershed: |
| 166 | + alt = wt_image |
| 167 | + text = f'Watershed algorithm borders {self.plants[i]["n"]}' |
| 168 | + tcol = (0, 0, 0) |
| 169 | + elif mode == 1 and self.c.flow.HSV_filtering_and_watershed: |
| 170 | + alt = im_threshold |
| 171 | + text = f'HSV inRange threshold {self.plants[i]["n"]}' |
| 172 | + tcol = (255,255,255) |
| 173 | + else: |
| 174 | + alt = self.plants[i]['p'] |
| 175 | + text = f'Original {self.plants[i]["n"]}' |
| 176 | + tcol = (0, 0, 0) |
| 177 | + |
| 178 | + cv.putText(alt, text, (0,20), self.c.asth.font, .5, tcol, 1) |
| 179 | + cv.putText(self.plants[i]['p'], 'Original', (0,20), self.c.asth.font, .5, (0,0,0), 1) |
| 180 | + |
| 181 | + cv.imshow(self.window1, alt) |
| 182 | + cv.imshow(self.window2, self.plants[i]['p']) |
| 183 | + |
| 184 | + key = cv.waitKey(10) |
| 185 | + |
| 186 | + if key == self.c.cntr.prev_k and i > 0: |
| 187 | + i -= 1 |
| 188 | + if key == self.c.cntr.next_k and i < len(self.plants) - 1: |
| 189 | + i += 1 |
| 190 | + |
| 191 | + if key == self.c.cntr.m1_k: |
| 192 | + mode = 1 |
| 193 | + elif key == self.c.cntr.m2_k: |
| 194 | + mode = 2 |
| 195 | + elif key == self.c.cntr.m3_k: |
| 196 | + mode = 3 |
| 197 | + elif key == self.c.cntr.m4_k: |
| 198 | + mode = 4 |
| 199 | + elif key == self.c.cntr.m5_k: |
| 200 | + mode = 5 |
| 201 | + |
| 202 | + def HSV_filtering_and_watershed(self, input_im): |
| 203 | + |
| 204 | + im_threshold = cv.inRange(cv.cvtColor(input_im, cv.COLOR_BGR2HSV), (self.c.HSV.low_H, self.c.HSV.low_S, self.c.HSV.low_V), (self.c.HSV.high_H, self.c.HSV.high_S, self.c.HSV.high_V)) |
| 205 | + |
| 206 | + kernel = np.ones((3,3),np.uint8) |
| 207 | + opening = cv.morphologyEx(im_threshold,cv.MORPH_OPEN,kernel, iterations = 2) |
| 208 | + |
| 209 | + sure_bg = cv.dilate(opening,kernel,iterations=7) |
| 210 | + |
| 211 | + dist_transform = cv.distanceTransform(opening,cv.DIST_L2,5) |
| 212 | + _, sure_fg = cv.threshold(dist_transform,0.3*dist_transform.max(),255,0) |
| 213 | + |
| 214 | + sure_fg = np.uint8(sure_fg) |
| 215 | + unknown = cv.subtract(sure_bg,sure_fg) |
| 216 | + |
| 217 | + # Marker labelling |
| 218 | + _, markers = cv.connectedComponents(sure_fg) |
| 219 | + # Add one to all labels so that sure background is not 0, but 1 |
| 220 | + markers = markers+1 |
| 221 | + # Now, mark the region of unknown with zero |
| 222 | + markers[unknown==255] = 0 |
| 223 | + |
| 224 | + markers = cv.watershed(input_im,markers) |
| 225 | + input_im[markers == -1] = [255,0,0] |
| 226 | + |
| 227 | + fig = plot.figure() |
| 228 | + plot.imshow(markers) |
| 229 | + fig.canvas.draw() |
| 230 | + |
| 231 | + img = np.fromstring(fig.canvas.tostring_rgb(), dtype=np.uint8, |
| 232 | + sep='') |
| 233 | + img = img.reshape(fig.canvas.get_width_height()[::-1] + (3,)) |
| 234 | + markers = cv.cvtColor(img,cv.COLOR_RGB2BGR) |
| 235 | + |
| 236 | + plot.close(fig) |
| 237 | + |
| 238 | + return input_im, markers, im_threshold |
| 239 | + |
| 240 | + |
| 241 | +# Main |
| 242 | + |
| 243 | +plDt = PlantDetector() |
| 244 | +plDt.parse() |
| 245 | + |
0 commit comments