def generate_plant_mask_new(input_image): ''' Generate a mask which segments the plant out in the input image Ref: https://plantcv.readthedocs.io/en/latest/vis_tutorial/ Args: input_image: the input image Returns: mask: boolean numpy array as the same size of the input image which segments the plant ''' # Get the saturation channel # hsv_image = rgb2hsv(input_image) # s = hsv_image[:,:,1] s = pcv.rgb2gray_hsv(rgb_img=input_image, channel='s') # threshold the saturation image s_thresh = s > 130 # perform blur on the thresholding # s_mblur = pcv.median_blur(gray_img=s_thresh, ksize=5) s_cnt = pcv.median_blur(gray_img=s_thresh, ksize=15) # extract the LAb channels and theshold them b = pcv.rgb2gray_lab(rgb_img=input_image, channel='b') a = pcv.rgb2gray_lab(rgb_img=input_image, channel='a') a_thresh = a <= 120 b_thresh = b >= 105 lab_mask = np.logical_and(a_thresh, b_thresh) lab_cnt = pcv.median_blur(gray_img=lab_mask, ksize=15) # join the two thresholdes mask bs = np.logical_and(s_cnt, lab_cnt) # filling small holes res = np.ones(bs.shape, dtype=np.uint8) * 255 res[bs] = 0 kernel = cv2.getStructuringElement(cv2.MORPH_ELLIPSE, (15, 15)) res = cv2.morphologyEx(res, cv2.MORPH_OPEN, kernel) res = res == 0 return res
def plant_cv(img): counter = 0 debug = None counter, s = pcv.rgb2gray_hsv(img, 's', counter, debug) counter, s_thresh = pcv.binary_threshold(s, 145, 255, 'light', counter, debug) counter, s_mblur = pcv.median_blur(s_thresh, 5, counter, debug) # Convert RGB to LAB and extract the Blue channel counter, b = pcv.rgb2gray_lab(img, 'b', counter, debug) # Threshold the blue image counter, b_thresh = pcv.binary_threshold(b, 145, 255, 'light', counter, debug) counter, b_cnt = pcv.binary_threshold(b, 145, 255, 'light', counter, debug) # Join the thresholded saturation and blue-yellow images counter, bs = pcv.logical_or(s_mblur, b_cnt, counter, debug) counter, masked = pcv.apply_mask(img, bs, 'white', counter, debug) #---------------------------------------- # Convert RGB to LAB and extract the Green-Magenta and Blue-Yellow channels counter, masked_a = pcv.rgb2gray_lab(masked, 'a', counter, debug) counter, masked_b = pcv.rgb2gray_lab(masked, 'b', counter, debug) # Threshold the green-magenta and blue images counter, maskeda_thresh = pcv.binary_threshold(masked_a, 115, 255, 'dark', counter, debug) counter, maskeda_thresh1 = pcv.binary_threshold(masked_a, 135, 255, 'light', counter, debug) counter, maskedb_thresh = pcv.binary_threshold(masked_b, 128, 255, 'light', counter, debug) # Join the thresholded saturation and blue-yellow images (OR) counter, ab1 = pcv.logical_or(maskeda_thresh, maskedb_thresh, counter, debug) counter, ab = pcv.logical_or(maskeda_thresh1, ab1, counter, debug) counter, ab_cnt = pcv.logical_or(maskeda_thresh1, ab1, counter, debug) # Fill small objects counter, ab_fill = pcv.fill(ab, ab_cnt, 200, counter, debug) # Apply mask (for vis images, mask_color=white) counter, masked2 = pcv.apply_mask(masked, ab_fill, 'white', counter, debug) zeros = np.zeros(masked2.shape[:2], dtype="uint8") merged = cv2.merge([zeros, ab_fill, zeros]) return merged, masked2
def plot_hotspots(directory, filename): # Read image in_full_path = os.path.join(directory, filename) outfile = 'Hotspot' + filename out_full_path = os.path.join(directory, outfile) img, path, filename = pcv.readimage(in_full_path, mode="rgb") # Convert RGB to HSV and extract the saturation channel s = pcv.rgb2gray_hsv(rgb_img=img, channel='s') # Threshold the saturation image s_thresh = pcv.threshold.binary(gray_img=s, threshold=85, max_value=255, object_type='light') # Median Blur s_mblur = pcv.median_blur(gray_img=s_thresh, ksize=5) edge = cv2.Canny(s_mblur, 60, 180) fig, ax = plt.subplots(1, figsize=(12, 8)) plt.imshow(edge, cmap='Greys') contours, hierarchy = cv2.findContours(edge.copy(), cv2.RETR_TREE, cv2.CHAIN_APPROX_NONE)[-2:] centroids = [] contours = sorted(contours, key=cv2.contourArea, reverse=True) for i, cnt in enumerate(contours): if (cv2.contourArea(cnt) > 10): moment = cv2.moments(contours[i]) Cx = int(moment["m10"] / moment["m00"]) Cy = int(moment["m01"] / moment["m00"]) center = (Cx, Cy) centroids.append((contours, center, moment["m00"], 0)) cv2.circle(img, (Cx, Cy), 5, (255, 255, 255), -1) coordinate = '(' + str(Cx) + ',' + str(Cy) + ')' cv2.putText(img, coordinate, (Cx, Cy), cv2.FONT_HERSHEY_SIMPLEX, 0.5, RED, 1, cv2.LINE_AA) print(cv2.contourArea(cnt), Cx, Cy) cv2.imwrite(out_full_path, img) #cv2.imshow('canvasOutput', img); #cv2.waitKey(0) return
def create_mask(grayscale): ndvi_mask = np.zeros(shape=[img.shape[0], img.shape[1]], dtype=np.uint8) for x in range(img.shape[1]): for y in range(img.shape[0]): # We keep pixels if they are within a certain range in terms of # grayscale intensity if X <= gray[y, x] <= 255: ndvi_mask[y, x] = gray[y, x] pcv.plot_image(ndvi_mask) # We use an opening function which removes noise from the image. opened = pcv.opening(ndvi_mask) # We blur pixels together, which removes more noise, and cleans up our mask. clean = pcv.median_blur(opened, X) return clean
def main(): # Get options args = options() pcv.params.debug = args.debug # set debug mode pcv.params.debug_outdir = args.outdir # set output directory # Read image img, path, filename = pcv.readimage(filename=args.image) # Convert RGB to HSV and extract the saturation channel h = pcv.rgb2gray_hsv(rgb_img=img, channel='h') # Threshold the saturation image h_thresh = pcv.threshold.binary(gray_img=h, threshold=85, max_value=255, object_type='dark') # Median Blur h_mblur = pcv.median_blur(gray_img=h_thresh, ksize=20)
def segmentation(imgW, imgNIR, shape): # VIS example from PlantCV with few modifications # Higher value = more strict selection s_threshold = 165 b_threshold = 200 # Read image img = imread(imgW) #img = cvtColor(img, COLOR_BGR2RGB) imgNIR = imread(imgNIR) #imgNIR = cvtColor(imgNIR, COLOR_BGR2RGB) #img, path, img_filename = pcv.readimage(filename=imgW, mode="native") #imgNIR, pathNIR, imgNIR_filename = pcv.readimage(filename=imgNIR, mode="native") # Convert RGB to HSV and extract the saturation channel s = pcv.rgb2gray_hsv(rgb_img=img, channel='s') # Threshold the saturation image s_thresh = pcv.threshold.binary(gray_img=s, threshold=s_threshold, max_value=255, object_type='light') # Median Blur s_mblur = pcv.median_blur(gray_img=s_thresh, ksize=5) s_cnt = pcv.median_blur(gray_img=s_thresh, ksize=5) # Convert RGB to LAB and extract the Blue channel b = pcv.rgb2gray_lab(rgb_img=img, channel='b') # Threshold the blue image ORIGINAL 160 b_thresh = pcv.threshold.binary(gray_img=b, threshold=b_threshold, max_value=255, object_type='light') b_cnt = pcv.threshold.binary(gray_img=b, threshold=b_threshold, max_value=255, object_type='light') # Join the thresholded saturation and blue-yellow images bs = pcv.logical_or(bin_img1=s_mblur, bin_img2=b_cnt) # Apply Mask (for VIS images, mask_color=white) masked = pcv.apply_mask(img=img, mask=bs, mask_color='white') # Convert RGB to LAB and extract the Green-Magenta and Blue-Yellow channels masked_a = pcv.rgb2gray_lab(rgb_img=masked, channel='a') masked_b = pcv.rgb2gray_lab(rgb_img=masked, channel='b') # Threshold the green-magenta and blue images # 115 # 135 # 128 maskeda_thresh = pcv.threshold.binary(gray_img=masked_a, threshold=115, max_value=255, object_type='dark') maskeda_thresh1 = pcv.threshold.binary(gray_img=masked_a, threshold=135, max_value=255, object_type='light') maskedb_thresh = pcv.threshold.binary(gray_img=masked_b, threshold=128, max_value=255, object_type='light') # Join the thresholded saturation and blue-yellow images (OR) ab1 = pcv.logical_or(bin_img1=maskeda_thresh, bin_img2=maskedb_thresh) ab = pcv.logical_or(bin_img1=maskeda_thresh1, bin_img2=ab1) # Fill small objects ab_fill = pcv.fill(bin_img=ab, size=200) # Apply mask (for VIS images, mask_color=white) masked2 = pcv.apply_mask(img=masked, mask=ab_fill, mask_color='white') # Identify objects id_objects, obj_hierarchy = pcv.find_objects(img=masked2, mask=ab_fill) # Define ROI height = shape[0] width = shape[1] roi1, roi_hierarchy= pcv.roi.rectangle(img=masked2, x=0, y=0, h=height, w=width) # Decide which objects to keep roi_objects, hierarchy3, kept_mask, obj_area = pcv.roi_objects(img=img, roi_contour=roi1, roi_hierarchy=roi_hierarchy, object_contour=id_objects, obj_hierarchy=obj_hierarchy, roi_type='partial') # Object combine kept objects obj, mask = pcv.object_composition(img=img, contours=roi_objects, hierarchy=hierarchy3) # Filling holes in the mask, works great for alive plants, not so good for dead plants filled_mask = pcv.fill_holes(mask) final = pcv.apply_mask(img=imgNIR, mask=mask, mask_color='white') pcv.print_image(final, "./segment/segment-temp.png")
# Collect the cropped image cropped_img = image[int(roi[1]):int(roi[1] + roi[3]), int(roi[0]):int(roi[0] + roi[2])] # Convert RGB to HSV and extract saturation channel # The HSV value can be changed to be h, s, or v depending on the colour of the flower saturation_img = pcv.rgb2gray_hsv(cropped_img, 'h') # Threshold the saturation img # Depending on the output of the saturation image, the value can be light or dark # Light or dark is what defines what part of the image its to be removed saturation_thresh = pcv.threshold.binary(saturation_img, 85, 255, 'light') # Apply median blur saturation_mblur = pcv.median_blur(saturation_thresh, 5) # Convert RGB to LAB and extract blue channel # Like the HSV function this can be l, a, or b depending on the colour of the flower blue_channel_img = pcv.rgb2gray_lab(cropped_img, 'l') blue_channel_cnt = pcv.threshold.binary(blue_channel_img, 160, 255, 'light') # Join thresholded saturated and blue channel imgs blue_saturated = pcv.logical_or(saturation_mblur, blue_channel_cnt) # Apply black colour mask masked = pcv.apply_mask(cropped_img, blue_saturated, 'black') # Save image cv2.imwrite('tmp/' + image, masked)
# cv2.imshow('aligned', ir_ir) # aligned_depth_color_frame = rs.colorizer().colorize(aligned_depth_frame) # aligned_depth_color_image = np.asanyarray(aligned_depth_color_frame.get_data()) # cv2.imshow('aligned', aligned_depth_color_image) # Validate that both frames are valid if not aligned_depth_frame or not color_frame: continue depth_image = np.asanyarray(aligned_depth_frame.get_data()) color_image = np.asanyarray(color_frame.get_data()) s = pcv.rgb2gray_hsv(color_image, 's') # plantcv s_thresh = pcv.threshold.binary(s, 85, 255, 'light') # plantcv s_mblur = pcv.median_blur(s_thresh, 5) s_cnt = pcv.median_blur(s_thresh, 5) # cv2.imshow('color - depth3', s_mblur) # Convert RGB to LAB and extract the Blue channel b = pcv.rgb2gray_lab(color_image, 'b') # Threshold the blue image b_thresh = pcv.threshold.binary(b, 160, 255, 'light') b_cnt = pcv.threshold.binary(b, 160, 255, 'light') # Fill small objects # b_fill = pcv.fill(b_thresh, 10) mask = pcv.naive_bayes_classifier(color_image, "naive_bayes_pdfs.txt") #histogram_low = np.sum(mask["plant"][int(360/2):, :], axis=0) #histogram_up = np.sum(mask["plant"][:int(360/2), :], axis=0) histogram = np.sum(mask["plant"][int(360 / 2):, :], axis=0)
def test(true_positive_file, test_parameters): hue_lower_tresh = test_parameters[0] hue_higher_tresh = test_parameters[1] saturation_lower_tresh = test_parameters[2] saturation_higher_tresh = test_parameters[3] value_lower_tresh = test_parameters[4] value_higher_tresh = test_parameters[5] green_lower_tresh = test_parameters[6] green_higher_tresh = test_parameters[7] red_lower_tresh = test_parameters[8] red_higher_thresh = test_parameters[9] blue_lower_tresh = test_parameters[10] blue_higher_tresh = test_parameters[11] blur_k = test_parameters[12] fill_k = test_parameters[13] class args: #image = "C:\\Users\\RensD\\OneDrive\\studie\\Master\\The_big_project\\top_perspective\\0214_2018-03-07 08.55 - 26_cam9.png" image = true_positive_file outdir = "C:\\Users\\RensD\\OneDrive\\studie\\Master\\The_big_project\\top_perspective\\output" debug = debug_setting result = "results.txt" # Get options pcv.params.debug=args.debug #set debug mode pcv.params.debug_outdir=args.outdir #set output directory # Read image (readimage mode defaults to native but if image is RGBA then specify mode='rgb') # Inputs: # filename - Image file to be read in # mode - Return mode of image; either 'native' (default), 'rgb', 'gray', or 'csv' img, path, filename = pcv.readimage(filename=args.image, mode='rgb') s = pcv.rgb2gray_hsv(rgb_img=img, channel='h') mask, masked_image = pcv.threshold.custom_range(rgb_img=s, lower_thresh=[hue_lower_tresh], upper_thresh=[hue_higher_tresh], channel='gray') masked = pcv.apply_mask(rgb_img=img, mask = mask, mask_color = 'white') #print("filtered on hue") s = pcv.rgb2gray_hsv(rgb_img=masked, channel='s') mask, masked_image = pcv.threshold.custom_range(rgb_img=s, lower_thresh=[saturation_lower_tresh], upper_thresh=[saturation_higher_tresh], channel='gray') masked = pcv.apply_mask(rgb_img=masked, mask = mask, mask_color = 'white') #print("filtered on saturation") s = pcv.rgb2gray_hsv(rgb_img=masked, channel='v') mask, masked_image = pcv.threshold.custom_range(rgb_img=s, lower_thresh=[value_lower_tresh], upper_thresh=[value_higher_tresh], channel='gray') masked = pcv.apply_mask(rgb_img=masked, mask = mask, mask_color = 'white') #print("filtered on value") mask, masked = pcv.threshold.custom_range(rgb_img=masked, lower_thresh=[0,green_lower_tresh,0], upper_thresh=[255,green_higher_tresh,255], channel='RGB') masked = pcv.apply_mask(rgb_img=masked, mask = mask, mask_color = 'white') #print("filtered on green") mask, masked = pcv.threshold.custom_range(rgb_img=masked, lower_thresh=[red_lower_tresh,0,0], upper_thresh=[red_higher_thresh,255,255], channel='RGB') masked = pcv.apply_mask(rgb_img=masked, mask = mask, mask_color = 'white') #print("filtered on red") mask_old, masked_old = pcv.threshold.custom_range(rgb_img=masked, lower_thresh=[0,0,blue_lower_tresh], upper_thresh=[255,255,blue_higher_tresh], channel='RGB') masked = pcv.apply_mask(rgb_img=masked_old, mask = mask_old, mask_color = 'white') #print("filtered on blue") ###____________________________________ Blur to minimize try: s_mblur = pcv.median_blur(gray_img = masked_old, ksize = blur_k) s = pcv.rgb2gray_hsv(rgb_img=s_mblur, channel='v') mask, masked_image = pcv.threshold.custom_range(rgb_img=s, lower_thresh=[0], upper_thresh=[254], channel='gray') except: print("failed blur step") try: mask = pcv.fill(mask, fill_k) except: pass masked = pcv.apply_mask(rgb_img=masked, mask = mask, mask_color = 'white') ###_____________________________________ Now to identify objects masked_a = pcv.rgb2gray_lab(rgb_img=masked, channel='a') masked_b = pcv.rgb2gray_lab(rgb_img=masked, channel='b') # Threshold the green-magenta and blue images maskeda_thresh = pcv.threshold.binary(gray_img=masked_a, threshold=115, max_value=255, object_type='dark') maskeda_thresh1 = pcv.threshold.binary(gray_img=masked_a, threshold=135, max_value=255, object_type='light') maskedb_thresh = pcv.threshold.binary(gray_img=masked_b, threshold=128, max_value=255, object_type='light') ab1 = pcv.logical_or(bin_img1=maskeda_thresh, bin_img2=maskedb_thresh) ab = pcv.logical_or(bin_img1=maskeda_thresh1, bin_img2=ab1) # Fill small objects # Inputs: # bin_img - Binary image data # size - Minimum object area size in pixels (must be an integer), and smaller objects will be filled ab_fill = pcv.fill(bin_img=ab, size=200) #print("filled") # Apply mask (for VIS images, mask_color=white) masked2 = pcv.apply_mask(rgb_img=masked, mask=ab_fill, mask_color='white') id_objects, obj_hierarchy = pcv.find_objects(masked, ab_fill) # Let's just take the largest roi1, roi_hierarchy= pcv.roi.rectangle(img=masked, x=0, y=0, h=960, w=1280) # Currently hardcoded with HiddenPrints(): roi_objects, hierarchy3, kept_mask, obj_area = pcv.roi_objects(img=img, roi_contour=roi1, roi_hierarchy=roi_hierarchy, object_contour=id_objects, obj_hierarchy=obj_hierarchy, roi_type=roi_type) obj, mask = pcv.object_composition(img=img, contours=roi_objects, hierarchy=hierarchy3) if use_mask == True: return(mask) else: masked2 = pcv.apply_mask(rgb_img=masked, mask=mask, mask_color='white') return(masked2)
def initcrop(imagePath): dire = os.getcwd() path = dire + '/Classifyer_dump' try: os.makedirs(path) except OSError: pass image = cv2.imread(imagePath) gray = cv2.cvtColor(image, cv2.COLOR_BGR2GRAY) cv2.imwrite(os.path.join(path, "gray.png"), gray) ret, thres = cv2.threshold(gray, 127, 255, cv2.THRESH_BINARY) # 127 137 cv2.imwrite(os.path.join(path, 'Wholepic.png'), thres) fill = pcv.fill(thres, 100000) cv2.imwrite(os.path.join(path, "noiseReduced.png"), fill) im2, contours, hierarchy = cv2.findContours(fill, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE) test = [] for c in contours: peri = cv2.arcLength(c, True) test.append(peri) index_max = np.argmax(test) x, y, w, h = cv2.boundingRect(contours[index_max]) c = max(contours, key=cv2.contourArea) x, y, w, h = cv2.boundingRect(c) # draw the biggest contour (c) in green # cv2.rectangle(image,(x,y),(x+w,y+h),(0,255,0),5) image = image[y:y + h, x:x + w] cv2.imwrite(os.path.join(path, "cropped.png"), image) L, a, b = cv2.split(image) # can do l a or b thres = cv2.adaptiveThreshold(b, 255, cv2.ADAPTIVE_THRESH_GAUSSIAN_C, cv2.THRESH_BINARY, 255, -1) # For liz's pictures 241 cv2.imwrite(os.path.join(path, "cropped_thres.png"), thres) fill = pcv.fill(thres, 1000) cv2.imwrite(os.path.join(path, "cropped_thres_filled.png"), fill) blur = cv2.blur(fill, (15, 15), 0) fill_hole = cv2.morphologyEx(fill, cv2.MORPH_CLOSE, cv2.getStructuringElement( cv2.MORPH_RECT, (21, 21)), iterations=2) cv2.imwrite(os.path.join(path, "cropped_thres_filled.png"), fill_hole) nb_components, output, stats, centroids = cv2.connectedComponentsWithStats( fill_hole, connectivity=8) new_centroids = [] sizes = stats[1:, -1] nb_components = nb_components - 1 min_size = 20000 img2 = np.zeros((output.shape)) for i in range(0, nb_components): if sizes[i] <= min_size: img2[output == i + 1] = 255 new_centroids.append(centroids[i]) cv2.imwrite(os.path.join(path, "filter.png"), img2) # print(len(centroids)) # print(len(new_centroids)) # print(new_centroids[0]) # print(new_centroids[0][1]) y = [] x = [] for i in range(len(new_centroids)): y.append(new_centroids[i][1]) x.append(new_centroids[i][0]) # print(len(x)) XARRAY = sorted(x) YARRAY = sorted(y) smallX = int(XARRAY[4]) - 80 bigX = int(XARRAY[len(XARRAY) - 4]) + 80 smallY = int(YARRAY[4]) - 80 bigY = int(YARRAY[len(YARRAY) - 4]) + 80 # print(smallX, smallY, bigX, bigY) image = cv2.imread(os.path.join(path, "cropped.png")) image = image[smallY:bigY, smallX:bigX] #print(image.shape) cv2.imwrite(os.path.join(path, "final.png"), image) L, a, b = cv2.split(image) # can do l a or b blur_image = pcv.median_blur(a, 10) Gaussian_blue = cv2.adaptiveThreshold(a, 255, cv2.ADAPTIVE_THRESH_GAUSSIAN_C, cv2.THRESH_BINARY, 281, -1) # For liz's pictures 241 heavy_fill_blue = pcv.fill(Gaussian_blue, 1000) # value 400 hole_fill = pcv.fill_holes(heavy_fill_blue) cv2.imwrite(os.path.join(path, "Cropped_Threshold.png"), hole_fill) # cv2.imwrite(os.path.join(test1, "Cropped_thres%d.png" % image_counter),hole_fill) image = cv2.resize(image, (800, 600)) cv2.imwrite(os.path.join(path, "scaled.png"), image) image = os.path.join(path, "scaled.png") msg = "Does this crop look good" choices = ["Yes", "No"] reply = easygui.indexbox(msg, image=image, choices=choices) if reply == 0: df = pd.DataFrame([smallY, bigY, smallX, bigX]) df.to_pickle('pickled_setup')
def process_image(image_path, threshold): # Read image img, _, _ = pcv.readimage(filename=image_path) # If image is not in Portrait rotate to ensure center of mass splits the plant correctly if img.shape[0] < img.shape[1]: img = np.array(Image.fromarray(img).transpose(Image.ROTATE_270)) # Convert RGB to HSV and extract the saturation channel s = pcv.rgb2gray_hsv(rgb_img=img, channel='s') # Threshold the saturation image s_thresh = pcv.threshold.binary(gray_img=s, threshold=85, max_value=255, object_type='light') # Median Blur s_mblur = pcv.median_blur(gray_img=s_thresh, ksize=5) # Convert RGB to LAB and extract the Blue channel b = pcv.rgb2gray_lab(rgb_img=img, channel='b') # Threshold the blue image b_cnt = pcv.threshold.binary(gray_img=b, threshold=160, max_value=255, object_type='light') # Join the thresholded saturation and blue-yellow images bs = pcv.logical_or(bin_img1=s_mblur, bin_img2=b_cnt) # Apply Mask (for VIS images, mask_color=white) masked = pcv.apply_mask(img=img, mask=bs, mask_color='white') # Convert RGB to LAB and extract the Green-Magenta and Blue-Yellow channels masked_a = pcv.rgb2gray_lab(rgb_img=masked, channel='a') masked_b = pcv.rgb2gray_lab(rgb_img=masked, channel='b') # Threshold the green-magenta and blue images maskeda_thresh = pcv.threshold.binary(gray_img=masked_a, threshold=115, max_value=255, object_type='dark') maskeda_thresh1 = pcv.threshold.binary(gray_img=masked_a, threshold=135, max_value=255, object_type='light') maskedb_thresh = pcv.threshold.binary(gray_img=masked_b, threshold=128, max_value=255, object_type='light') # Join the thresholded saturation and blue-yellow images (OR) ab1 = pcv.logical_or(bin_img1=maskeda_thresh, bin_img2=maskedb_thresh) ab = pcv.logical_or(bin_img1=maskeda_thresh1, bin_img2=ab1) # Fill small objects ab_fill = pcv.fill(bin_img=ab, size=200) # Apply mask (for VIS images, mask_color=white) masked2 = pcv.apply_mask(img=masked, mask=ab_fill, mask_color='white') # Identify objects id_objects, obj_hierarchy = pcv.find_objects(img=masked2, mask=ab_fill) # Define ROI roi1, roi_hierarchy = pcv.roi.rectangle(img=masked2, x=300, y=300, h=img.shape[0] - 600, w=img.shape[1] - 600) # Decide which objects to keep roi_objects, hierarchy3, _, _ = pcv.roi_objects( img=img, roi_contour=roi1, roi_hierarchy=roi_hierarchy, object_contour=id_objects, obj_hierarchy=obj_hierarchy, roi_type='partial') # Object combine kept objects obj, mask = pcv.object_composition(img=img, contours=roi_objects, hierarchy=hierarchy3) # ---------------- Analysis ---------------- # Find shape properties, output shape image (optional) _ = pcv.analyze_object(img=img, obj=obj, mask=mask, label="default") x, y = pcv.outputs.observations['default']['center_of_mass']['value'] width = pcv.outputs.observations['default']['width']['value'] height = pcv.outputs.observations['default']['height']['value'] x = int(x) y = int(y) top = max(int(y - (height / 2)), 0) bottom = min(int(y + (height / 2)), img.shape[0]) left = max(int(x - (width / 2)), 0) right = min(int(x + (width / 2)), img.shape[1]) left_half = mask[top:bottom, left:x] right_half = mask[top:bottom, x:right] left_half_count = cv2.countNonZero(left_half) right_half_count = cv2.countNonZero(right_half) left_percent = (left_half_count / (left_half_count + right_half_count)) right_percent = 1 - left_percent print('Left Percentage: {:.2%} Right Percentage: {:.2%}'.format( left_percent, right_percent)) if abs(left_percent - right_percent) > threshold: print('Rotate plant') else: print('Do NOT rotate plant')
def main(): # Get options args = options() pcv.params.debug = args.debug # set debug mode pcv.params.debug_outdir = args.outdir # set output directory # Read metadata with open(args.metadata, 'r', encoding='utf-8') as f: md = json.load(f) camera_label = md['camera_label'] # Read image img, path, filename = pcv.readimage(filename=args.image) # Convert RGB to HSV and extract the value channel s = pcv.rgb2gray_hsv(rgb_img=img, channel='v') # Threshold the saturation image removing highs and lows and join s_thresh_1 = pcv.threshold.binary(gray_img=s, threshold=10, max_value=255, object_type='light') s_thresh_2 = pcv.threshold.binary(gray_img=s, threshold=245, max_value=255, object_type='dark') s_thresh = pcv.logical_and(bin_img1=s_thresh_1, bin_img2=s_thresh_2) # Median Blur s_mblur = pcv.median_blur(gray_img=s_thresh, ksize=5) # Convert RGB to LAB and extract the Blue channel b = pcv.rgb2gray_lab(rgb_img=img, channel='b') # Threshold the blue image b_cnt = pcv.threshold.binary(gray_img=b, threshold=128, max_value=255, object_type='light') # Fill small objects b_fill = pcv.fill(b_cnt, 10) # Join the thresholded saturation and blue-yellow images bs = pcv.logical_or(bin_img1=s_mblur, bin_img2=b_fill) # Apply Mask (for VIS images, mask_color=white) masked = pcv.apply_mask(rgb_img=img, mask=bs, mask_color='white') # Convert RGB to LAB and extract the Green-Magenta and Blue-Yellow channels # Threshold the green-magenta and blue images masked_a = pcv.rgb2gray_lab(rgb_img=masked, channel='a') maskeda_thresh = pcv.threshold.binary(gray_img=masked_a, threshold=127, max_value=255, object_type='dark') # Convert RGB to LAB and extract the Green-Magenta and Blue-Yellow channels # Threshold the green-magenta and blue images masked_b = pcv.rgb2gray_lab(rgb_img=masked, channel='b') maskedb_thresh = pcv.threshold.binary(gray_img=masked_b, threshold=128, max_value=255, object_type='light') # Join the thresholded saturation and blue-yellow images (OR) ab = pcv.logical_or(bin_img1=maskeda_thresh, bin_img2=maskedb_thresh) # Fill small objects ab_fill = pcv.fill(bin_img=ab, size=200) # Apply mask (for VIS images, mask_color=white) masked2 = pcv.apply_mask(rgb_img=masked, mask=ab_fill, mask_color='white') # Identify objects id_objects, obj_hierarchy = pcv.find_objects(img=masked2, mask=ab_fill) # Define ROI W = 2472 H = 3296 if "far" in camera_label: # SIDE FAR w = 1600 h = 1200 pot = 230 #340 roi1, roi_hierarchy = pcv.roi.rectangle(img=masked2, x=(W - w) / 2, y=(H - h - pot), h=h, w=w) elif "lower" in camera_label: # SIDE LOWER w = 800 h = 2400 pot = 340 roi1, roi_hierarchy = pcv.roi.rectangle(img=masked2, x=1000 - w / 2, y=(H - h - pot), h=h, w=w) elif "upper" in camera_label: # SIDE UPPER w = 600 h = 800 pot = 550 roi1, roi_hierarchy = pcv.roi.rectangle(img=masked2, x=1400 - w / 2, y=(H - h - pot), h=h, w=w) elif "top" in camera_label: # TOP w = 450 h = 450 roi1, roi_hierarchy = pcv.roi.rectangle(img=masked2, x=(H - h) / 2, y=(W - w) / 2, h=h, w=w) # Decide which objects to keep roi_objects, hierarchy3, kept_mask, obj_area = pcv.roi_objects( img=img, roi_contour=roi1, roi_hierarchy=roi_hierarchy, object_contour=id_objects, obj_hierarchy=obj_hierarchy, roi_type='partial') # Object combine kept objects obj, mask = pcv.object_composition(img=img, contours=roi_objects, hierarchy=hierarchy3) #TODO: Update for plantCV metadata import for key in md.keys(): if str(md[key]).isdigit(): pcv.outputs.add_observation(variable=key, trait=key, method='', scale='', datatype=int, value=md[key], label='') else: pcv.outputs.add_observation(variable=key, trait=key, method='', scale='', datatype=str, value=md[key], label='') if obj is not None: # Find shape properties, output shape image (optional) shape_imgs = pcv.analyze_object(img=img, obj=obj, mask=mask) # Shape properties relative to user boundary line (optional) #boundary_img1 = pcv.analyze_bound_horizontal(img=img, obj=obj, mask=mask, line_position=1680) # 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') # Pseudocolor the grayscale image #pseudocolored_img = pcv.visualize.pseudocolor(gray_img=s, mask=kept_mask, cmap='jet') #print(pcv.outputs.images) if args.writeimg == True: for idx, item in enumerate(pcv.outputs.images[0]): pcv.print_image(item, "{}_{}.png".format(args.result[:-5], idx)) # Write shape and color data to results file pcv.print_results(filename=args.result)
for frac in rm_fracs: if np.abs((frac[0] - 1) * 100) <= rm_perc: if np.abs((frac[1] - 1) * 100) <= rm_perc: if np.abs((frac[2] - 1) * 100) <= rm_perc: rm_match = True break if keep_match == False or rm_match == True: filtered[y, x] = (255, 255, 255) pcv.plot_image(filtered) # Threshold using the 'a' lab channel to pick out green leaves channel_a = pcv.rgb2gray_lab(filtered, 'a') thresh = pcv.threshold.binary(channel_a, 123, 255, 'dark') # Clean up the noise from the mask by opening and blurring pixels together. opened = pcv.opening(thresh) mask2 = pcv.median_blur(opened, 3) # Apply the new mask to the VIS image masked = pcv.apply_mask(filtered, mask2, 'white') #-------------------------------------------------------------------------------------------------------------------# # It is very important to note that we want to avoid having extract the 'a' lab colour channel, as this is only # effective if the plant is green. This step is included temporarily, as we search for an alternative that works # universally, for plants of any colour. One suggestion is to find the average RGB values of the pixels in filtered, # and remove pixels if their RGB values are not similar to this average. This should work, as by this point MOST of # what is left should be the plant. #-------------------------------------------------------------------------------------------------------------------#
def main(): # Get options args = options() pcv.params.debug = args.debug # set debug mode pcv.params.debug_outdir = args.outdir # set output directory # Read image img, path, filename = pcv.readimage(filename=args.image) # Convert RGB to HSV and extract the saturation channel h = pcv.rgb2gray_hsv(rgb_img=img, channel='h') # Threshold the saturation image h_thresh = pcv.threshold.binary(gray_img=h, threshold=85, max_value=255, object_type='dark') # Median Blur h_mblur = pcv.median_blur(gray_img=h_thresh, ksize=20) h_cnt = pcv.median_blur(gray_img=h_thresh, ksize=20) # Convert RGB to LAB and extract the Blue channel b = pcv.rgb2gray_lab(rgb_img=img, channel='b') # Threshold the blue image b_thresh = pcv.threshold.binary(gray_img=b, threshold=160, max_value=255, object_type='light') b_cnt = pcv.threshold.binary(gray_img=b, threshold=160, max_value=255, object_type='light') # Fill small objects # b_fill = pcv.fill(b_thresh, 10) # Join the thresholded saturation and blue-yellow images bs = pcv.logical_or(bin_img1=h_mblur, bin_img2=b_cnt) # Apply Mask (for VIS images, mask_color=white) masked = pcv.apply_mask(img=img, mask=bs, mask_color='white') # Convert RGB to LAB and extract the Green-Magenta and Blue-Yellow channels masked_a = pcv.rgb2gray_lab(rgb_img=masked, channel='a') masked_b = pcv.rgb2gray_lab(rgb_img=masked, channel='b') # Threshold the green-magenta and blue images maskeda_thresh = pcv.threshold.binary(gray_img=masked_a, threshold=115, max_value=255, object_type='dark') maskeda_thresh1 = pcv.threshold.binary(gray_img=masked_a, threshold=135, max_value=255, object_type='light') maskedb_thresh = pcv.threshold.binary(gray_img=masked_b, threshold=128, max_value=255, object_type='light') # Join the thresholded saturation and blue-yellow images (OR) ab1 = pcv.logical_or(bin_img1=maskeda_thresh, bin_img2=maskedb_thresh) ab = pcv.logical_or(bin_img1=maskeda_thresh1, bin_img2=ab1) # Fill small objects ab_fill = pcv.fill(bin_img=ab, size=200) # Apply mask (for VIS images, mask_color=white) masked2 = pcv.apply_mask(img=masked, mask=ab_fill, mask_color='white') # Identify objects id_objects, obj_hierarchy = pcv.find_objects(img=masked2, mask=ab_fill) # Define ROI roi1, roi_hierarchy = pcv.roi.rectangle(img=masked2, x=400, y=400, h=200, w=200) # Decide which objects to keep roi_objects, hierarchy3, kept_mask, obj_area = pcv.roi_objects( img=img, roi_contour=roi1, roi_hierarchy=roi_hierarchy, object_contour=id_objects, obj_hierarchy=obj_hierarchy, roi_type='partial') # Object combine kept objects obj, mask = pcv.object_composition(img=img, contours=roi_objects, hierarchy=hierarchy3) ############### Analysis ################ outfile = False if args.writeimg == True: outfile = args.outdir + "/" + filename # Find shape properties, output shape image (optional) shape_imgs = pcv.analyze_object(img=img, obj=obj, mask=mask) # Shape properties relative to user boundary line (optional) boundary_img1 = pcv.analyze_bound_horizontal(img=img, obj=obj, mask=mask, line_position=600) # 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') # Pseudocolor the grayscale image pseudocolored_img = pcv.visualize.pseudocolor(gray_img=h, mask=kept_mask, cmap='jet') # Write shape and color data to results file pcv.print_results(filename=args.result)
def main(): # Get options args = options() # Read image img, path, filename = pcv.readimage(args.image) pcv.params.debug = args.debug #set debug mode # STEP 1: white balance (for comparison across images) # inputs: # img = image object, RGB colorspace # roi = region for white reference (position of ColorChecker Passport) img1 = pcv.white_balance(img, roi=(910, 3555, 30, 30)) # STEP 2: Mask out color card and stake # inputs: # img = grayscale image ('a' channel) # p1 = (x,y) coordinates for top left corner of rectangle # p2 = (x,y) coordinates for bottom right corner of rectangle # color = color to make the mask (white here to match background) masked, binary, contours, hierarchy = pcv.rectangle_mask(img1, (0, 2000), (1300, 4000), color="white") masked2, binary, contours, hierarchy = pcv.rectangle_mask(masked, (0, 3600), (4000, 4000), color="white") # STEP 3: Convert from RGB colorspace to LAB colorspace # Keep green-magenta channel (a) # inputs: # img = image object, RGB colorspace # channel = color subchannel ('l' = lightness, 'a' = green-magenta, 'b' = blue-yellow) a = pcv.rgb2gray_lab(masked2, 'l') # STEP 4: Set a binary threshold on the saturation channel image # inputs: # img = img object, grayscale # threshold = treshold value (0-255) - need to adjust this # max_value = value to apply above treshold (255 = white) # object_type = light or dark img_binary = pcv.threshold.binary(a, 118, 255, object_type="dark") # STEP 5: Apply Gaussian blur to binary image (reduced noise) # inputs: # img = img object, binary # ksize = tuple of kernel dimensions, e.g. (5,5) blur_image = pcv.median_blur(img_binary, 10) # STEP 6: Fill small objects (speckles) # inputs: # img = img object, binary # size = minimum object area size in pixels fill_image1 = pcv.fill(blur_image, 150000) # STEP 7: Invert image to fill gaps # inputs: # img = img object, binary inv_image = pcv.invert(fill_image1) # rerun fill on inverted image inv_fill = pcv.fill(inv_image, 25000) # invert image again fill_image = pcv.invert(inv_fill) # STEP 8: Dilate to avoid losing detail # inputs: # img = img object, binary # ksize = kernel size # i = iterations (number of consecutive filtering passes) dilated = pcv.dilate(fill_image, 2, 1) # STEP 9: Find objects (contours: black-white boundaries) # inputs: # img = img object, RGB colorspace # mask = binary image used for object detection id_objects, obj_hierarchy = pcv.find_objects(img1, dilated) # STEP 10: Define region of interest (ROI) # inputs: # img = img object to overlay ROI # x = x-coordinate of upper left corner for rectangle # y = y-coordinate of upper left corner for rectangle # h = height of rectangle # w = width of rectangle roi_contour, roi_hierarchy = pcv.roi.rectangle(img=img1, x=20, y=10, h=3000, w=3000) # STEP 11: Keep objects that overlap with the ROI # inputs: # img = img where selected objects will be displayed # roi_type = options are 'cutto', 'partial' (objects are partially inside roi), or 'largest' (keep only the biggest boi) # roi_countour = contour of roi, output from 'view and adjust roi' function (STEP 10) # roi_hierarchy = contour of roi, output from 'view and adjust roi' function (STEP 10) # object_contour = contours of objects, output from 'identifying objects' function (STEP 9) # obj_hierarchy = hierarchy of objects, output from 'identifying objects' function (STEP 9) roi_objects, roi_obj_hierarchy, kept_mask, obj_area = pcv.roi_objects( img1, 'partial', roi_contour, roi_hierarchy, id_objects, obj_hierarchy) # STEP 12: Cluster multiple contours in an image based on user input of rows/columns # inputs: # img = img object (RGB colorspace) # roi_objects = object contours in an image that will be clustered (output from STEP 11) # roi_obj_hierarchy = object hierarchy (also from STEP 11) # nrow = number of rows for clustering (desired rows in image even if no leaf present in all) # ncol = number of columns to cluster (desired columns in image even if no leaf present in all) clusters_i, contours, hierarchies = pcv.cluster_contours( img1, roi_objects, roi_obj_hierarchy, 3, 3) # STEP 13: select and split clustered contours to export into multiple images # also checks if number of inputted filenames matches number of clustered contours # if no filenames, objects are numbered in order # inputs: # img = masked RGB image # grouped_contour_indexes = indexes of clustered contours, output of 'cluster_contours' (STEP 12) # contours = contours of cluster, output of 'cluster_contours' (STEP 12) # hierarchy = object hierarchy (from STEP 12) # outdir = directory to export output images # file = name of input image to use as basename (uses filename from 'readimage') # filenames = (optional) txt file with list of filenames ordered from top to bottom/left to right # Set global debug behavior to None (default), "print" (to file), or "plot" (Jupyter Notebooks or X11) pcv.params.debug = None out = args.outdir # names = args.namesout = "./" output_path, imgs, masks = pcv.cluster_contour_splitimg(img1, clusters_i, contours, hierarchies, out, file=filename, filenames=None)
mask_image_label, path, filename = pcv.readimage( '1_naive_bayes_labels_mask.jpg') mask_image = mask_image_plant + mask_image_label device, mask_image = pcv.rgb2gray_lab(mask_image, 'l', device) #clean the mask up device, img_binary = pcv.binary_threshold(mask_image, 50, 255, 'light', device) pcv.print_image(img_binary, 'img_binary.tif') device, blur_img = pcv.erode( img_binary, 3, 1, device, debug='print' ) # Erode to remove soil and Dilate so that you don't lose leaves (just in case) mask = np.copy(blur_img) device, fill_image = pcv.fill(blur_img, mask, 100, device) pcv.print_image(fill_image, 'fill_image.tif') device, binary_image = pcv.median_blur(fill_image, 1, device) pcv.print_image(binary_image, 'binary_image.tif') device, masked_image = device, dilate_image = pcv.dilate( fill_image, 3, 3, device) ############################################ ########### Create Output ############# ############################################ #Print grid of images for QC # from https://stackoverflow.com/questions/30227466/combine-several-images-horizontally-with-python #Different steps created here list_masked = [ 'mask_image.tif', 'img_binary.tif', 'blur_img.tif', 'fill_image.tif', 'binary_image.tif', outfile
def plot_hotspots(directory, filename,convex_hull_flag): # Read image in_full_path = os.path.join(directory, filename) img, path, filename = pcv.readimage(in_full_path, mode="rgb") img_thermal = img.copy() # Convert RGB to HSV and extract the saturation channel s = pcv.rgb2gray_hsv(rgb_img=img, channel='s') # Threshold the saturation image s_thresh = pcv.threshold.binary(gray_img=s, threshold=85, max_value=255, object_type='light') # Median Blur s_mblur = pcv.median_blur(gray_img=s_thresh, ksize=5) edge = cv2.Canny(s_mblur, 60, 180) outfile = 'Gray_' + filename out_full_path = os.path.join(directory, outfile) cv2.imwrite(out_full_path, edge) # Contours extraction contours, hierarchy = cv2.findContours(edge.copy(), cv2.RETR_TREE, cv2.CHAIN_APPROX_SIMPLE)[-2:] #contours = sorted(contours, key=cv2.contourArea, reverse=True) hull_list = [] if (convex_hull_flag == True): for i in range(len(contours)): hull = cv2.convexHull(contours[i]) hull_list.append(hull) contours = hull_list mask = np.zeros(edge.shape, np.uint8) hiers = hierarchy[0] for i in range(len(contours)): if hiers[i][3] != -1: continue cv2.drawContours(mask, contours, i,255, cv2.LINE_AA) ## Find all inner contours and draw ch = hiers[i][2] while ch != -1: cv2.drawContours(mask, contours, ch, (255,0,255), -1, cv2.LINE_AA) ch = hiers[ch][0] thermal = thermal_image(img_thermal, mask) if (convex_hull_flag == True): outfile = 'Thermal_tree_CH_' + filename else: outfile = 'Thermal_tree_' + filename out_full_path = os.path.join(directory, outfile) cv2.imwrite(out_full_path, thermal) centroids = [] if (convex_hull_flag == True): area_threshold = 30 else: area_threshold = 10 for i, cnt in enumerate(contours): cv2.drawContours(mask, contours, i,255, cv2.FILLED) if (cv2.contourArea(cnt) > area_threshold ): moment = cv2.moments(contours[i]) Cx = int(moment["m10"]/moment["m00"]) Cy = int(moment["m01"]/moment["m00"]) center = (Cx, Cy) centroids.append((contours, center, moment["m00"], 0)) #cv2.circle(img, (Cx, Cy), 5, (255, 255, 255), -1) coordinate = '(' + str(Cx) + ',' + str(Cy) + ')' cv2.putText(img, coordinate, (Cx,Cy), cv2.FONT_HERSHEY_SIMPLEX, 0.5, RED, 1, cv2.LINE_AA) print(cv2.contourArea(cnt),Cx, Cy) if Debug == True: fig, ax = plt.subplots(1, figsize=(12,8)) plt.imshow(mask, cmap='Greys') if (convex_hull_flag == True): outfile = 'Hotspots_CH_' + filename else: outfile = 'Hotspots_' + filename out_full_path = os.path.join(directory, outfile) cv2.imwrite(out_full_path, img) return
def main(): # Get options args = options() pcv.params.debug = args.debug # set debug mode pcv.params.debug_outdir = args.outdir # set output directory # Read image img, path, filename = pcv.readimage(filename=args.image) # Convert RGB to HSV and extract the value channel s = pcv.rgb2gray_hsv(rgb_img=img, channel='v') # Threshold the saturation image removing highs and lows and join s_thresh_1 = pcv.threshold.binary(gray_img=s, threshold=10, max_value=255, object_type='light') s_thresh_2 = pcv.threshold.binary(gray_img=s, threshold=245, max_value=255, object_type='dark') s_thresh = pcv.logical_and(bin_img1=s_thresh_1, bin_img2=s_thresh_2) # Median Blur s_mblur = pcv.median_blur(gray_img=s_thresh, ksize=5) # Convert RGB to LAB and extract the Blue channel b = pcv.rgb2gray_lab(rgb_img=img, channel='b') # Threshold the blue image b_cnt = pcv.threshold.binary(gray_img=b, threshold=128, max_value=255, object_type='light') # Fill small objects b_fill = pcv.fill(b_cnt, 10) # Join the thresholded saturation and blue-yellow images bs = pcv.logical_or(bin_img1=s_mblur, bin_img2=b_fill) # Apply Mask (for VIS images, mask_color=white) masked = pcv.apply_mask(rgb_img=img, mask=bs, mask_color='white') # Convert RGB to LAB and extract the Green-Magenta and Blue-Yellow channels masked_a = pcv.rgb2gray_lab(rgb_img=masked, channel='a') masked_b = pcv.rgb2gray_lab(rgb_img=masked, channel='b') # Threshold the green-magenta and blue images maskeda_thresh = pcv.threshold.binary(gray_img=masked_a, threshold=127, max_value=255, object_type='dark') maskedb_thresh = pcv.threshold.binary(gray_img=masked_b, threshold=128, max_value=255, object_type='light') # Join the thresholded saturation and blue-yellow images (OR) ab = pcv.logical_or(bin_img1=maskeda_thresh, bin_img2=maskedb_thresh) # Fill small objects ab_fill = pcv.fill(bin_img=ab, size=200) # Apply mask (for VIS images, mask_color=white) masked2 = pcv.apply_mask(rgb_img=masked, mask=ab_fill, mask_color='white') # Identify objects id_objects, obj_hierarchy = pcv.find_objects(img=masked2, mask=ab_fill) # Define ROI w = 1600 h = 1200 pot = 230 #340 roi1, roi_hierarchy = pcv.roi.rectangle(img=masked2, x=(2472 - w) / 2, y=(3296 - h - pot), h=h, w=w) # Decide which objects to keep roi_objects, hierarchy3, kept_mask, obj_area = pcv.roi_objects( img=img, roi_contour=roi1, roi_hierarchy=roi_hierarchy, object_contour=id_objects, obj_hierarchy=obj_hierarchy, roi_type='partial') # Object combine kept objects obj, mask = pcv.object_composition(img=img, contours=roi_objects, hierarchy=hierarchy3) # Find shape properties, output shape image (optional) shape_imgs = pcv.analyze_object(img=img, obj=obj, mask=mask) if args.writeimg == True: pcv.print_image(img=shape_imgs, filename="{}_shape.png".format(args.result[:-5])) pcv.print_image(img=masked2, filename="{}_obj_on_img.png".format(args.result[:-5])) # Shape properties relative to user boundary line (optional) #boundary_img1 = pcv.analyze_bound_horizontal(img=img, obj=obj, mask=mask, line_position=1680) # 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') # Pseudocolor the grayscale image pseudocolored_img = pcv.visualize.pseudocolor(gray_img=s, mask=kept_mask, cmap='jet') # Write shape and color data to results file pcv.print_results(filename=args.result)
def plantCVProcess(img, x, y, w, h): # Convert RGB to HSV and extract the saturation channel s = pcv.rgb2gray_hsv(rgb_img=img, channel='s') # Threshold the saturation image s_thresh = pcv.threshold.binary(gray_img=s, threshold=85, max_value=255, object_type='light') # Median Blur s_mblur = pcv.median_blur(gray_img=s_thresh, ksize=5) s_cnt = pcv.median_blur(gray_img=s_thresh, ksize=5) # Convert RGB to LAB and extract the Blue channel b = pcv.rgb2gray_lab(rgb_img=img, channel='b') # Threshold the blue image b_thresh = pcv.threshold.binary(gray_img=b, threshold=160, max_value=255, object_type='light') b_cnt = pcv.threshold.binary(gray_img=b, threshold=160, max_value=255, object_type='light') # Fill small objects # b_fill = pcv.fill(b_thresh, 10) # Join the thresholded saturation and blue-yellow images bs = pcv.logical_or(bin_img1=s_mblur, bin_img2=b_cnt) # Apply Mask (for VIS images, mask_color=white) masked = pcv.apply_mask(img=img, mask=bs, mask_color='white') # Convert RGB to LAB and extract the Green-Magenta and Blue-Yellow channels masked_a = pcv.rgb2gray_lab(rgb_img=masked, channel='a') masked_b = pcv.rgb2gray_lab(rgb_img=masked, channel='b') # Threshold the green-magenta and blue images maskeda_thresh = pcv.threshold.binary(gray_img=masked_a, threshold=115, max_value=255, object_type='dark') maskeda_thresh1 = pcv.threshold.binary(gray_img=masked_a, threshold=135, max_value=255, object_type='light') maskedb_thresh = pcv.threshold.binary(gray_img=masked_b, threshold=128, max_value=255, object_type='light') # Join the thresholded saturation and blue-yellow images (OR) ab1 = pcv.logical_or(bin_img1=maskeda_thresh, bin_img2=maskedb_thresh) ab = pcv.logical_or(bin_img1=maskeda_thresh1, bin_img2=ab1) # Fill small objects ab_fill = pcv.fill(bin_img=ab, size=200) # Apply mask (for VIS images, mask_color=white) masked2 = pcv.apply_mask(img=masked, mask=ab_fill, mask_color='white') # Identify objects id_objects, obj_hierarchy = pcv.find_objects(img=masked2, mask=ab_fill) # Define ROI roi1, roi_hierarchy = pcv.roi.rectangle(img=masked2, x=x, y=y, h=h, w=w) # Decide which objects to keep roi_objects, hierarchy3, kept_mask, obj_area = pcv.roi_objects(img=img, roi_contour=roi1, roi_hierarchy=roi_hierarchy, object_contour=id_objects, obj_hierarchy=obj_hierarchy, roi_type='partial') # Object combine kept objects obj, mask = pcv.object_composition(img=img, contours=roi_objects, hierarchy=hierarchy3) ############### Analysis ################ # Find shape properties, output shape image (optional) shape_imgs = pcv.analyze_object(img=img, obj=obj, mask=mask) # Shape properties relative to user boundary line (optional) boundary_img1 = pcv.analyze_bound_horizontal(img=img, obj=obj, mask=mask, line_position=1680) # 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') # Pseudocolor the grayscale image pseudocolored_img = pcv.visualize.pseudocolor(gray_img=s, mask=mask, cmap='jet') return print_results()
def shoot(): uploaded_file = st.file_uploader("Choose an image...", type="jpg") if uploaded_file is not None: inp = Image.open(uploaded_file) inp.save('input.jpg') img, path, filename = pcv.readimage(filename='input.jpg') image = Image.open('input.jpg') st.image(image, caption='Original Image',use_column_width=True) # Convert RGB to HSV and extract the saturation channel # Inputs: # rgb_image - RGB image data # channel - Split by 'h' (hue), 's' (saturation), or 'v' (value) channel s = pcv.rgb2gray_hsv(rgb_img=img, channel='s') pcv.print_image(s, "plant/rgbtohsv.png") image = Image.open('plant/rgbtohsv.png') st.image(image, caption='RGB to HSV', use_column_width=True) s_thresh = pcv.threshold.binary(gray_img=s, threshold=85, max_value=255, object_type='light') pcv.print_image(s_thresh, "plant/binary_threshold.png") image = Image.open('plant/binary_threshold.png') st.image(image, caption='Binary Threshold',use_column_width=True) # Median Blur to clean noise # Inputs: # gray_img - Grayscale image data # ksize - Kernel size (integer or tuple), (ksize, ksize) box if integer input, # (n, m) box if tuple input s_mblur = pcv.median_blur(gray_img=s_thresh, ksize=5) pcv.print_image(s_mblur, "plant/Median_blur.png") image = Image.open('plant/Median_blur.png') st.image(image, caption='Median Blur',use_column_width=True) # An alternative to using median_blur is gaussian_blur, which applies # a gaussian blur filter to the image. Depending on the image, one # technique may be more effective than others. # Inputs: # img - RGB or grayscale image data # ksize - Tuple of kernel size # sigma_x - Standard deviation in X direction; if 0 (default), # calculated from kernel size # sigma_y - Standard deviation in Y direction; if sigmaY is # None (default), sigmaY is taken to equal sigmaX gaussian_img = pcv.gaussian_blur(img=s_thresh, ksize=(5, 5), sigma_x=0, sigma_y=None) # Convert RGB to LAB and extract the blue channel ('b') # Input: # rgb_img - RGB image data # channel- Split by 'l' (lightness), 'a' (green-magenta), or 'b' (blue-yellow) channel b = pcv.rgb2gray_lab(rgb_img=img, channel='b') b_thresh = pcv.threshold.binary(gray_img=b, threshold=160, max_value=255, object_type='light') # Join the threshold saturation and blue-yellow images with a logical or operation # Inputs: # bin_img1 - Binary image data to be compared to bin_img2 # bin_img2 - Binary image data to be compared to bin_img1 bs = pcv.logical_or(bin_img1=s_mblur, bin_img2=b_thresh) pcv.print_image(bs, "plant/threshold comparison.png") image = Image.open('plant/threshold comparison.png') st.image(image, caption='Threshold Comparision',use_column_width=True) # Appy Mask (for VIS images, mask_color='white') # Inputs: # img - RGB or grayscale image data # mask - Binary mask image data # mask_color - 'white' or 'black' masked = pcv.apply_mask(img=img, mask=bs, mask_color='white') pcv.print_image(masked, "plant/Apply_mask.png") image = Image.open('plant/Apply_mask.png') st.image(image, caption='Applied Mask',use_column_width=True) # Convert RGB to LAB and extract the Green-Magenta and Blue-Yellow channels masked_a = pcv.rgb2gray_lab(rgb_img=masked, channel='a') masked_b = pcv.rgb2gray_lab(rgb_img=masked, channel='b') # Threshold the green-magenta and blue images maskeda_thresh = pcv.threshold.binary(gray_img=masked_a, threshold=115, max_value=255, object_type='dark') maskeda_thresh1 = pcv.threshold.binary(gray_img=masked_a, threshold=135,max_value=255, object_type='light') maskedb_thresh = pcv.threshold.binary(gray_img=masked_b, threshold=128, max_value=255, object_type='light') pcv.print_image( maskeda_thresh, "plant/maskeda_thresh.png") pcv.print_image(maskeda_thresh1, "plant/maskeda_thresh1.png") pcv.print_image(maskedb_thresh, "plant/maskedb_thresh1.png") image = Image.open('plant/maskeda_thresh.png') st.image(image, caption='Threshold green-magneta and blue image',use_column_width=True) # Join the thresholded saturation and blue-yellow images (OR) ab1 = pcv.logical_or(bin_img1=maskeda_thresh, bin_img2=maskedb_thresh) ab = pcv.logical_or(bin_img1=maskeda_thresh1, bin_img2=ab1)
def initcrop(imagePath): dire = dir path = dire + '/Classifyer_dump' try: os.makedirs(path) except OSError: pass image = cv2.imread(imagePath) blue_image = pcv.rgb2gray_lab(image, 'l') Gaussian_blue = cv2.adaptiveThreshold(blue_image, 255, cv2.ADAPTIVE_THRESH_GAUSSIAN_C, cv2.THRESH_BINARY, 981, -1) # 241 is good 981 cv2.imwrite(os.path.join(path, "blue_test.png"), Gaussian_blue) fill = pcv.fill_holes(Gaussian_blue) fill_again = pcv.fill(fill, 100000) id_objects, obj_hierarchy = pcv.find_objects( img=image, mask=fill_again) # lazy way to findContours and draw them roi1, roi_hierarchy = pcv.roi.rectangle(img=image, x=3000, y=1000, h=200, w=300) roi_objects, hierarchy3, kept_mask, obj_area = pcv.roi_objects( img=image, roi_contour=roi1, roi_hierarchy=roi_hierarchy, object_contour=id_objects, obj_hierarchy=obj_hierarchy, roi_type='partial') cv2.imwrite(os.path.join(path, "plate_mask.png"), kept_mask) mask = cv2.imread(os.path.join(path, "plate_mask.png")) result = image * (mask.astype(image.dtype)) result = cv2.bitwise_not(result) cv2.imwrite(os.path.join(path, "AutoCrop.png"), result) output = cv2.connectedComponentsWithStats(kept_mask, connectivity=8) stats = output[2] left = (stats[1, cv2.CC_STAT_LEFT]) # print(stats[1, cv2.CC_STAT_TOP]) # print(stats[1, cv2.CC_STAT_HEIGHT]) # exit(2) L, a, b = cv2.split(result) # cv2.imwrite("gray_scale.png", L) plate_threshold = cv2.adaptiveThreshold(b, 255, cv2.ADAPTIVE_THRESH_GAUSSIAN_C, cv2.THRESH_BINARY, 87, -1) # 867 is good 241 cv2.imwrite(os.path.join(path, "plate_threshold.png"), plate_threshold) fill_again2 = pcv.fill(plate_threshold, 1000) cv2.imwrite(os.path.join(path, "fill_test.png"), fill_again2) # fill = pcv.fill_holes(fill_again2) # cv2.imwrite(os.path.join(path, "fill_test2.png"), fill) blur_image = pcv.median_blur(fill_again2, 10) nb_components, output, stats, centroids = cv2.connectedComponentsWithStats( blur_image, connectivity=8) sizes = stats[1:, -1] nb_components = nb_components - 1 min_size = 20000 img2 = np.zeros((output.shape)) for i in range(0, nb_components): if sizes[i] <= min_size: img2[output == i + 1] = 255 cv2.imwrite(os.path.join(path, "remove_20000.png"), img2) # this can be made better to speed it up thresh_image = img2.astype( np.uint8) # maybe crop to the roi below then do it thresh_image = pcv.fill_holes(thresh_image) cv2.imwrite("NEWTEST.jpg", thresh_image) id_objects, obj_hierarchy = pcv.find_objects(img=image, mask=thresh_image) roi1, roi_hierarchy = pcv.roi.rectangle(img=image, x=(left + 380), y=750, h=175, w=100) try: where_cell = 0 roi_objects, hierarchy3, kept_mask, obj_area = pcv.roi_objects( img=image, roi_contour=roi1, roi_hierarchy=roi_hierarchy, object_contour=id_objects, obj_hierarchy=obj_hierarchy, roi_type='partial') cv2.imwrite(os.path.join(path, "test_mask.png"), kept_mask) mask = cv2.imread(os.path.join(path, "test_mask.png")) result = image * (mask.astype(image.dtype)) result = cv2.bitwise_not(result) cv2.imwrite(os.path.join(path, "TEST.png"), result) output = cv2.connectedComponentsWithStats(kept_mask, connectivity=8) stats = output[2] centroids = output[3] centroids_x = (int(centroids[1][0])) centroids_y = (int(centroids[1][1])) except: where_cell = 1 print("did this work?") roi1, roi_hierarchy = pcv.roi.rectangle(img=image, x=(left + 380), y=3200, h=100, w=100) roi_objects, hierarchy3, kept_mask, obj_area = pcv.roi_objects( img=image, roi_contour=roi1, roi_hierarchy=roi_hierarchy, object_contour=id_objects, obj_hierarchy=obj_hierarchy, roi_type='partial') cv2.imwrite(os.path.join(path, "test_mask.png"), kept_mask) mask = cv2.imread(os.path.join(path, "test_mask.png")) result = image * (mask.astype(image.dtype)) result = cv2.bitwise_not(result) cv2.imwrite(os.path.join(path, "TEST.png"), result) output = cv2.connectedComponentsWithStats(kept_mask, connectivity=8) stats = output[2] centroids = output[3] centroids_x = (int(centroids[1][0])) centroids_y = (int(centroids[1][1])) flag = 0 # print(stats[1, cv2.CC_STAT_AREA]) if ((stats[1, cv2.CC_STAT_AREA]) > 4000): flag = 30 # print(centroids_x) # print(centroids_y) # print(centroids) if (where_cell == 0): left = (centroids_x - 70) right = (centroids_x + 3695 + flag) # was 3715 top = (centroids_y - 80) bottom = (centroids_y + 2462) if (where_cell == 1): left = (centroids_x - 70) right = (centroids_x + 3715 + flag) top = (centroids_y - 2480) bottom = (centroids_y + 62) # print(top) # print(bottom) image = Image.open(imagePath) img_crop = image.crop((left, top, right, bottom)) # img_crop.show() img_crop.save(os.path.join(path, 'Cropped_full_yeast.png')) circle_me = cv2.imread(os.path.join(path, "Cropped_full_yeast.png")) cropped_img = cv2.imread( os.path.join(path, "Cropped_full_yeast.png" )) # changed from Yeast_Cluster.%d.png %counter L, a, b = cv2.split(cropped_img) # can do l a or b Gaussian_blue = cv2.adaptiveThreshold(b, 255, cv2.ADAPTIVE_THRESH_GAUSSIAN_C, cv2.THRESH_BINARY, 241, -1) # For liz's pictures 241 cv2.imwrite(os.path.join(path, "blue_test.png"), Gaussian_blue) blur_image = pcv.median_blur(Gaussian_blue, 10) heavy_fill_blue = pcv.fill(blur_image, 1000) # value 400 hole_fill = pcv.fill_holes(heavy_fill_blue) cv2.imwrite(os.path.join(path, "Cropped_Threshold.png"), hole_fill)
def root(): uploaded_file = st.file_uploader("Choose an image...", type="jpg") if uploaded_file is not None: inp = Image.open(uploaded_file) inp.save('input.jpg') img, path, filename = pcv.readimage(filename='input.jpg') image = Image.open('input.jpg') st.image(image, caption='Original Image',use_column_width=True) # Convert RGB to HSV and extract the saturation channel # Inputs: # rgb_image - RGB image data # channel - Split by 'h' (hue), 's' (saturation), or 'v' (value) channel s = pcv.rgb2gray_hsv(rgb_img=img, channel='s') pcv.print_image(s, "plant/rgbtohsv.png") image = Image.open('plant/rgbtohsv.png') st.image(image, caption='RGB to HSV', use_column_width=True) s_thresh = pcv.threshold.binary(gray_img=s, threshold=85, max_value=255, object_type='light') pcv.print_image(s_thresh, "plant/binary_threshold.png") image = Image.open('plant/binary_threshold.png') st.image(image, caption='Binary Threshold',use_column_width=True) # Median Blur to clean noise # Inputs: # gray_img - Grayscale image data # ksize - Kernel size (integer or tuple), (ksize, ksize) box if integer input, # (n, m) box if tuple input s_mblur = pcv.median_blur(gray_img=s_thresh, ksize=5) pcv.print_image(s_mblur, "plant/Median_blur.png") image = Image.open('plant/Median_blur.png') st.image(image, caption='Median Blur',use_column_width=True) # An alternative to using median_blur is gaussian_blur, which applies # a gaussian blur filter to the image. Depending on the image, one # technique may be more effective than others. # Inputs: # img - RGB or grayscale image data # ksize - Tuple of kernel size # sigma_x - Standard deviation in X direction; if 0 (default), # calculated from kernel size # sigma_y - Standard deviation in Y direction; if sigmaY is # None (default), sigmaY is taken to equal sigmaX gaussian_img = pcv.gaussian_blur(img=s_thresh, ksize=(5, 5), sigma_x=0, sigma_y=None) # Convert RGB to LAB and extract the blue channel ('b') # Input: # rgb_img - RGB image data # channel- Split by 'l' (lightness), 'a' (green-magenta), or 'b' (blue-yellow) channel b = pcv.rgb2gray_lab(rgb_img=img, channel='b') b_thresh = pcv.threshold.binary(gray_img=b, threshold=160, max_value=255, object_type='light') # Join the threshold saturation and blue-yellow images with a logical or operation # Inputs: # bin_img1 - Binary image data to be compared to bin_img2 # bin_img2 - Binary image data to be compared to bin_img1 bs = pcv.logical_or(bin_img1=s_mblur, bin_img2=b_thresh) pcv.print_image(bs, "plant/threshold comparison.png") image = Image.open('plant/threshold comparison.png') st.image(image, caption='Threshold Comparision',use_column_width=True) # Appy Mask (for VIS images, mask_color='white') # Inputs: # img - RGB or grayscale image data # mask - Binary mask image data # mask_color - 'white' or 'black' masked = pcv.apply_mask(img=img, mask=bs, mask_color='white') pcv.print_image(masked, "plant/Apply_mask.png") image = Image.open('plant/Apply_mask.png') st.image(image, caption='Applied Mask',use_column_width=True) # Convert RGB to LAB and extract the Green-Magenta and Blue-Yellow channels masked_a = pcv.rgb2gray_lab(rgb_img=masked, channel='a') masked_b = pcv.rgb2gray_lab(rgb_img=masked, channel='b') # Threshold the green-magenta and blue images maskeda_thresh = pcv.threshold.binary(gray_img=masked_a, threshold=115, max_value=255, object_type='dark') maskeda_thresh1 = pcv.threshold.binary(gray_img=masked_a, threshold=135,max_value=255, object_type='light') maskedb_thresh = pcv.threshold.binary(gray_img=masked_b, threshold=128, max_value=255, object_type='light') pcv.print_image( maskeda_thresh, "plant/maskeda_thresh.png") pcv.print_image(maskeda_thresh1, "plant/maskeda_thresh1.png") pcv.print_image(maskedb_thresh, "plant/maskedb_thresh1.png") image = Image.open('plant/maskeda_thresh.png') st.image(image, caption='Threshold green-magneta and blue image',use_column_width=True) # Join the thresholded saturation and blue-yellow images (OR) ab1 = pcv.logical_or(bin_img1=maskeda_thresh, bin_img2=maskedb_thresh) ab = pcv.logical_or(bin_img1=maskeda_thresh1, bin_img2=ab1) # Opening filters out bright noise from an image. # Inputs: # gray_img - Grayscale or binary image data # kernel - Optional neighborhood, expressed as an array of 1's and 0's. If None (default), # uses cross-shaped structuring element. opened_ab = pcv.opening(gray_img=ab) # Depending on the situation it might be useful to use the # exclusive or (pcv.logical_xor) function. # Inputs: # bin_img1 - Binary image data to be compared to bin_img2 # bin_img2 - Binary image data to be compared to bin_img1 xor_img = pcv.logical_xor(bin_img1=maskeda_thresh, bin_img2=maskedb_thresh) # Fill small objects (reduce image noise) # Inputs: # bin_img - Binary image data # size - Minimum object area size in pixels (must be an integer), and smaller objects will be filled ab_fill = pcv.fill(bin_img=ab, size=200) # Closing filters out dark noise from an image. # Inputs: # gray_img - Grayscale or binary image data # kernel - Optional neighborhood, expressed as an array of 1's and 0's. If None (default), # uses cross-shaped structuring element. closed_ab = pcv.closing(gray_img=ab_fill) # Apply mask (for VIS images, mask_color=white) masked2 = pcv.apply_mask(img=masked, mask=ab_fill, mask_color='white') # Identify objects # Inputs: # img - RGB or grayscale image data for plotting # mask - Binary mask used for detecting contours id_objects, obj_hierarchy = pcv.find_objects(img=masked2, mask=ab_fill) # Define the region of interest (ROI) # Inputs: # img - RGB or grayscale image to plot the ROI on # x - The x-coordinate of the upper left corner of the rectangle # y - The y-coordinate of the upper left corner of the rectangle # h - The height of the rectangle # w - The width of the rectangle roi1, roi_hierarchy= pcv.roi.rectangle(img=masked2, x=50, y=50, h=100, w=100) # Decide which objects to keep # Inputs: # img = img to display kept objects # roi_contour = contour of roi, output from any ROI function # roi_hierarchy = contour of roi, output from any ROI function # object_contour = contours of objects, output from pcv.find_objects function # obj_hierarchy = hierarchy of objects, output from pcv.find_objects function # roi_type = 'partial' (default, for partially inside the ROI), 'cutto', or # 'largest' (keep only largest contour) roi_objects, hierarchy3, kept_mask, obj_area = pcv.roi_objects(img=img, roi_contour=roi1, roi_hierarchy=roi_hierarchy, object_contour=id_objects, obj_hierarchy=obj_hierarchy, roi_type='partial') # Object combine kept objects # Inputs: # img - RGB or grayscale image data for plotting # contours - Contour list # hierarchy - Contour hierarchy array obj, mask = pcv.object_composition(img=img, contours=roi_objects, hierarchy=hierarchy3) ############### Analysis ################ # Find shape properties, data gets stored to an Outputs class automatically # Inputs: # img - RGB or grayscale image data # obj- Single or grouped contour object # mask - Binary image mask to use as mask for moments analysis analysis_image = pcv.analyze_object(img=img, obj=obj, mask=mask) pcv.print_image(analysis_image, "plant/analysis_image.png") image = Image.open('plant/analysis_image.png') st.image(image, caption='Analysis_image',use_column_width=True) # Shape properties relative to user boundary line (optional) # Inputs: # img - RGB or grayscale image data # 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) boundary_image2 = pcv.analyze_bound_horizontal(img=img, obj=obj, mask=mask, line_position=370) pcv.print_image(boundary_image2, "plant/boundary_image2.png") image = Image.open('plant/boundary_image2.png') st.image(image, caption='Boundary Image',use_column_width=True) # Determine color properties: Histograms, Color Slices and Pseudocolored Images, output color analyzed images (optional) # Inputs: # 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=kept_mask, hist_plot_type='all') # Print the histogram out to save it pcv.print_image(img=color_histogram, filename="plant/vis_tutorial_color_hist.jpg") image = Image.open('plant/vis_tutorial_color_hist.jpg') st.image(image, caption='Color Histogram',use_column_width=True) # 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. # Inputs: # img - RGB or grayscale image data # obj - Single or grouped contour object # mask - Binary mask of selected contours top_x, bottom_x, center_v_x = pcv.x_axis_pseudolandmarks(img=img, obj=obj, mask=mask) top_y, bottom_y, center_v_y = pcv.y_axis_pseudolandmarks(img=img, obj=obj, mask=mask) # The print_results function will take the measurements stored when running any (or all) of these functions, format, # and print an output text file for data analysis. The Outputs class stores data whenever any of the following functions # are ran: analyze_bound_horizontal, analyze_bound_vertical, analyze_color, analyze_nir_intensity, analyze_object, # fluor_fvfm, report_size_marker_area, watershed. If no functions have been run, it will print an empty text file pcv.print_results(filename='vis_tutorial_results.txt')
def main(): # Get options args = options() pcv.params.debug = args.debug # set debug mode pcv.params.debug_outdir = args.outdir # set output directory # Read image img, path, filename = pcv.readimage(filename=args.image) # Convert RGB to HSV and extract the saturation channel s = pcv.rgb2gray_hsv(rgb_img=img, channel='s') # Threshold the saturation image s_thresh = pcv.threshold.binary(gray_img=s, threshold=85, max_value=255, object_type='light') # Median Blur s_mblur = pcv.median_blur(gray_img=s_thresh, ksize=5) s_cnt = pcv.median_blur(gray_img=s_thresh, ksize=5) # Convert RGB to LAB and extract the Blue channel b = pcv.rgb2gray_lab(rgb_img=img, channel='b') # Threshold the blue image b_thresh = pcv.threshold.binary(gray_img=b, threshold=160, max_value=255, object_type='light') b_cnt = pcv.threshold.binary(gray_img=b, threshold=160, max_value=255, object_type='light') # Fill small objects # b_fill = pcv.fill(b_thresh, 10) # Join the thresholded saturation and blue-yellow images bs = pcv.logical_or(bin_img1=s_mblur, bin_img2=b_cnt) # Apply Mask (for VIS images, mask_color=white) masked = pcv.apply_mask(img=img, mask=bs, mask_color='white') # Convert RGB to LAB and extract the Green-Magenta and Blue-Yellow channels masked_a = pcv.rgb2gray_lab(rgb_img=masked, channel='a') masked_b = pcv.rgb2gray_lab(rgb_img=masked, channel='b') cv2.imwrite("masked.jpeg", masked) # Threshold the green-magenta and blue images maskeda_thresh = pcv.threshold.binary(gray_img=masked_a, threshold=115, max_value=255, object_type='dark') maskeda_thresh1 = pcv.threshold.binary(gray_img=masked_a, threshold=135, max_value=255, object_type='light') maskedb_thresh = pcv.threshold.binary(gray_img=masked_b, threshold=128, max_value=255, object_type='light') # Join the thresholded saturation and blue-yellow images (OR) ab1 = pcv.logical_or(bin_img1=maskeda_thresh, bin_img2=maskedb_thresh) ab = pcv.logical_or(bin_img1=maskeda_thresh1, bin_img2=ab1) # Fill small objects ab_fill = pcv.fill(bin_img=ab, size=200) # Apply mask (for VIS images, mask_color=white) masked2 = pcv.apply_mask(img=masked, mask=ab_fill, mask_color='white') cv2.imwrite("masked2.jpeg", masked2)
def main_side(): # Setting "args" # Get options pcv.params.debug = args.debug #set debug mode pcv.params.debug_outdir = args.outdir #set output directory # Read image (readimage mode defaults to native but if image is RGBA then specify mode='rgb') # Inputs: # filename - Image file to be read in # mode - Return mode of image; either 'native' (default), 'rgb', 'gray', or 'csv' filename = args.image img = cv2.imread(args.image, flags=0) #img = pcv.invert(img) path, img_name = os.path.split(args.image) img_bkgrd = cv2.imread("background.png", flags=0) #print(img) #print(img_bkgrd) bkg_sub_img = pcv.image_subtract(img_bkgrd, img) bkg_sub_thres_img, masked_img = pcv.threshold.custom_range( rgb_img=bkg_sub_img, lower_thresh=[50], upper_thresh=[255], channel='gray') # Laplace filtering (identify edges based on 2nd derivative) # Inputs: # gray_img - Grayscale image data # ksize - Aperture size used to calculate the second derivative filter, # specifies the size of the kernel (must be an odd integer) # scale - Scaling factor applied (multiplied) to computed Laplacian values # (scale = 1 is unscaled) lp_img = pcv.laplace_filter(gray_img=img, ksize=1, scale=1) # Plot histogram of grayscale values pcv.visualize.histogram(gray_img=lp_img) # Lapacian image sharpening, this step will enhance the darkness of the edges detected lp_shrp_img = pcv.image_subtract(gray_img1=img, gray_img2=lp_img) # Plot histogram of grayscale values, this helps to determine thresholding value pcv.visualize.histogram(gray_img=lp_shrp_img) # Sobel filtering # 1st derivative sobel filtering along horizontal axis, kernel = 1) # Inputs: # gray_img - Grayscale image data # dx - Derivative of x to analyze # dy - Derivative of y to analyze # ksize - Aperture size used to calculate 2nd derivative, specifies the size of the kernel and must be an odd integer # NOTE: Aperture size must be greater than the largest derivative (ksize > dx & ksize > dy) sbx_img = pcv.sobel_filter(gray_img=img, dx=1, dy=0, ksize=1) # 1st derivative sobel filtering along vertical axis, kernel = 1) sby_img = pcv.sobel_filter(gray_img=img, dx=0, dy=1, ksize=1) # Combine the effects of both x and y filters through matrix addition # This will capture edges identified within each plane and emphasize edges found in both images # Inputs: # gray_img1 - Grayscale image data to be added to gray_img2 # gray_img2 - Grayscale image data to be added to gray_img1 sb_img = pcv.image_add(gray_img1=sbx_img, gray_img2=sby_img) # Use a lowpass (blurring) filter to smooth sobel image # Inputs: # gray_img - Grayscale image data # ksize - Kernel size (integer or tuple), (ksize, ksize) box if integer input, # (n, m) box if tuple input mblur_img = pcv.median_blur(gray_img=sb_img, ksize=1) # Inputs: # gray_img - Grayscale image data mblur_invert_img = pcv.invert(gray_img=mblur_img) # combine the smoothed sobel image with the laplacian sharpened image # combines the best features of both methods as described in "Digital Image Processing" by Gonzalez and Woods pg. 169 edge_shrp_img = pcv.image_add(gray_img1=mblur_invert_img, gray_img2=lp_shrp_img) # Perform thresholding to generate a binary image tr_es_img = pcv.threshold.binary(gray_img=edge_shrp_img, threshold=145, max_value=255, object_type='dark') # Do erosion with a 3x3 kernel (ksize=3) # Inputs: # gray_img - Grayscale (usually binary) image data # ksize - The size used to build a ksize x ksize # matrix using np.ones. Must be greater than 1 to have an effect # i - An integer for the number of iterations e1_img = pcv.erode(gray_img=tr_es_img, ksize=3, i=1) # Bring the two object identification approaches together. # Using a logical OR combine object identified by background subtraction and the object identified by derivative filter. # Inputs: # bin_img1 - Binary image data to be compared in bin_img2 # bin_img2 - Binary image data to be compared in bin_img1 comb_img = pcv.logical_or(bin_img1=e1_img, bin_img2=bkg_sub_thres_img) # Get masked image, Essentially identify pixels corresponding to plant and keep those. # Inputs: # rgb_img - RGB image data # mask - Binary mask image data # mask_color - 'black' or 'white' masked_erd = pcv.apply_mask(rgb_img=img, mask=comb_img, mask_color='black') # Need to remove the edges of the image, we did that by generating a set of rectangles to mask the edges # img is (1280 X 960) # mask for the bottom of the image # Inputs: # img - RGB or grayscale image data # p1 - Point at the top left corner of the rectangle (tuple) # p2 - Point at the bottom right corner of the rectangle (tuple) # color 'black' (default), 'gray', or 'white' # masked1, box1_img, rect_contour1, hierarchy1 = pcv.rectangle_mask(img=img, p1=(500, 875), p2=(720, 960)) # mask the edges masked2, box2_img, rect_contour2, hierarchy2 = pcv.rectangle_mask(img=img, p1=(1, 1), p2=(1279, 959)) bx12_img = pcv.logical_or(bin_img1=box1_img, bin_img2=box2_img) inv_bx1234_img = bx12_img # we dont invert inv_bx1234_img = bx12_img #inv_bx1234_img = pcv.invert(gray_img=bx12_img) edge_masked_img = pcv.apply_mask(rgb_img=masked_erd, mask=inv_bx1234_img, mask_color='black') #print("here we create a mask") mask, masked = pcv.threshold.custom_range(rgb_img=edge_masked_img, lower_thresh=[25], upper_thresh=[175], channel='gray') masked = pcv.apply_mask(rgb_img=masked, mask=mask, mask_color='white') #print("end") # Identify objects # Inputs: # img - RGB or grayscale image data for plotting # mask - Binary mask used for detecting contours id_objects, obj_hierarchy = pcv.find_objects(img=edge_masked_img, mask=mask) # Define ROI # Inputs: # img - RGB or grayscale image to plot the ROI on # x - The x-coordinate of the upper left corner of the rectangle # y - The y-coordinate of the upper left corner of the rectangle # h - The height of the rectangle # w - The width of the rectangle roi1, roi_hierarchy = pcv.roi.rectangle(img=edge_masked_img, x=100, y=100, h=800, w=1000) # Decide which objects to keep # Inputs: # img = img to display kept objects # roi_contour = contour of roi, output from any ROI function # roi_hierarchy = contour of roi, output from any ROI function # object_contour = contours of objects, output from pcv.find_objects function # obj_hierarchy = hierarchy of objects, output from pcv.find_objects function # roi_type = 'partial' (default, for partially inside), 'cutto', or # 'largest' (keep only largest contour) with HiddenPrints(): roi_objects, hierarchy5, kept_mask, obj_area = pcv.roi_objects( img=edge_masked_img, roi_contour=roi1, roi_hierarchy=roi_hierarchy, object_contour=id_objects, obj_hierarchy=obj_hierarchy, roi_type='largest') rgb_img = cv2.cvtColor(img, cv2.COLOR_GRAY2RGB) # Inputs: # img - RGB or grayscale image data for plotting # contours - Contour list # hierarchy - Contour hierarchy array o, m = pcv.object_composition(img=rgb_img, contours=roi_objects, hierarchy=hierarchy5) ### Analysis ### outfile = False if args.writeimg == True: outfile = args.outdir + "/" + filename # Perform signal analysis # 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=o, mask=m) new_im = Image.fromarray(shape_img) new_im.save("output//" + args.filename + "shape_img_side.png") # Inputs: # gray_img - 8 or 16-bit grayscale image data # 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 nir_hist = pcv.analyze_nir_intensity(gray_img=img, mask=kept_mask, bins=256, histplot=True) # Pseudocolor the grayscale image to a colormap # Inputs: # gray_img - Grayscale image data # obj - Single or grouped contour object (optional), if provided the pseudocolored image gets cropped down to the region of interest. # mask - Binary mask (optional) # background - Background color/type. Options are "image" (gray_img), "white", or "black". A mask must be supplied. # cmap - Colormap # min_value - Minimum value for range of interest # max_value - Maximum value for range of interest # dpi - Dots per inch for image if printed out (optional, if dpi=None then the default is set to 100 dpi). # axes - If False then the title, x-axis, and y-axis won't be displayed (default axes=True). # colorbar - If False then the colorbar won't be displayed (default colorbar=True) pseudocolored_img = pcv.visualize.pseudocolor(gray_img=img, mask=kept_mask, cmap='viridis') # Perform shape analysis # 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_imgs = pcv.analyze_object(img=rgb_img, obj=o, mask=m) # Write shape and nir data to results file pcv.print_results(filename=args.result)
def main(): # Set variables args = options() pcv.params.debug = args.debug # Read and rotate image img, path, filename = pcv.readimage(filename=args.image) img = pcv.rotate(img, -90, False) # Create mask from LAB b channel l = pcv.rgb2gray_lab(rgb_img=img, channel='b') l_thresh = pcv.threshold.binary(gray_img=l, threshold=115, max_value=255, object_type='dark') l_mblur = pcv.median_blur(gray_img=l_thresh, ksize=5) # Apply mask to image masked = pcv.apply_mask(img=img, mask=l_mblur, mask_color='white') ab_fill = pcv.fill(bin_img=l_mblur, size=50) # Extract plant object from image id_objects, obj_hierarchy = pcv.find_objects(img=img, mask=ab_fill) roi1, roi_hierarchy = pcv.roi.rectangle(img=masked, x=150, y=270, h=100, w=100) roi_objects, hierarchy3, kept_mask, obj_area = pcv.roi_objects( img=img, roi_contour=roi1, roi_hierarchy=roi_hierarchy, object_contour=id_objects, obj_hierarchy=obj_hierarchy, roi_type='partial') obj, mask = pcv.object_composition(img=img, contours=roi_objects, hierarchy=hierarchy3) ############### Analysis ################ # Analyze shape properties analysis_image = pcv.analyze_object(img=img, obj=obj, mask=mask) boundary_image2 = pcv.analyze_bound_horizontal(img=img, obj=obj, mask=mask, line_position=370) # Analyze colour properties color_histogram = pcv.analyze_color(rgb_img=img, mask=kept_mask, hist_plot_type='all') # Analyze shape independent of size top_x, bottom_x, center_v_x = pcv.x_axis_pseudolandmarks(img=img, obj=obj, mask=mask) top_y, bottom_y, center_v_y = pcv.y_axis_pseudolandmarks(img=img, obj=obj, mask=mask) # Print results pcv.print_results(filename='{}'.format(args.result)) pcv.print_image(img=color_histogram, filename='{}_color_hist.jpg'.format(args.outdir)) pcv.print_image(img=kept_mask, filename='{}_mask.jpg'.format(args.outdir))
def main(): # Get options pcv.params.debug = args.debug #set debug mode pcv.params.debug_outdir = args.outdir #set output directory # Read image (readimage mode defaults to native but if image is RGBA then specify mode='rgb') # Inputs: # filename - Image file to be read in # mode - Return mode of image; either 'native' (default), 'rgb', 'gray', or 'csv' img, path, filename = pcv.readimage(filename=args.image, mode='rgb') ### SELECTING THE PLANT ### Attempt 5 combineren # Parameters hue_lower_tresh = 22 # 24 hue_higher_tresh = 50 # 50 saturation_lower_tresh = 138 # 140 saturation_higher_tresh = 230 # 230 value_lower_tresh = 120 # 125 value_higher_tresh = 255 # 255 # RGB color space green_lower_tresh = 105 # 110 green_higher_tresh = 255 # 255 red_lower_tresh = 22 # 24 red_higher_thresh = 98 # 98 blue_lower_tresh = 85 # 85 blue_higher_tresh = 253 # 255 # CIELAB color space #lab_blue_lower_tresh = 0 # Blue yellow channel #lab_blue_higher_tresh = 255 s = pcv.rgb2gray_hsv(rgb_img=img, channel='h') mask, masked_image = pcv.threshold.custom_range( rgb_img=s, lower_thresh=[hue_lower_tresh], upper_thresh=[hue_higher_tresh], channel='gray') masked = pcv.apply_mask(rgb_img=img, mask=mask, mask_color='white') # Filtered on Hue s = pcv.rgb2gray_hsv(rgb_img=masked, channel='s') mask, masked_image = pcv.threshold.custom_range( rgb_img=s, lower_thresh=[saturation_lower_tresh], upper_thresh=[saturation_higher_tresh], channel='gray') masked = pcv.apply_mask(rgb_img=masked, mask=mask, mask_color='white') #filtered on saturation s = pcv.rgb2gray_hsv(rgb_img=masked, channel='v') mask, masked_image = pcv.threshold.custom_range( rgb_img=s, lower_thresh=[value_lower_tresh], upper_thresh=[value_higher_tresh], channel='gray') masked = pcv.apply_mask(rgb_img=masked, mask=mask, mask_color='white') #filtered on value mask, masked = pcv.threshold.custom_range( rgb_img=masked, lower_thresh=[0, green_lower_tresh, 0], upper_thresh=[255, green_higher_tresh, 255], channel='RGB') masked = pcv.apply_mask(rgb_img=masked, mask=mask, mask_color='white') #filtered on green mask, masked = pcv.threshold.custom_range( rgb_img=masked, lower_thresh=[red_lower_tresh, 0, 0], upper_thresh=[red_higher_thresh, 255, 255], channel='RGB') masked = pcv.apply_mask(rgb_img=masked, mask=mask, mask_color='white') #filtered on red mask_old, masked_old = pcv.threshold.custom_range( rgb_img=masked, lower_thresh=[0, 0, blue_lower_tresh], upper_thresh=[255, 255, blue_higher_tresh], channel='RGB') masked = pcv.apply_mask(rgb_img=masked_old, mask=mask_old, mask_color='white') #filtered on blue #b = pcv.rgb2gray_lab(rgb_img = masked, channel = 'b') # Converting toe CIElab blue_yellow image #b_thresh =pcv.threshold.binary(gray_img = b, threshold=lab_blue_lower_tresh, max_value = lab_blue_higher_tresh) ###_____________________________________ Now to identify objects masked_a = pcv.rgb2gray_lab(rgb_img=masked, channel='a') masked_b = pcv.rgb2gray_lab(rgb_img=masked, channel='b') # Threshold the green-magenta and blue images maskeda_thresh = pcv.threshold.binary( gray_img=masked_a, threshold=125, # original 115 max_value=255, object_type='dark') maskeda_thresh1 = pcv.threshold.binary( gray_img=masked_a, threshold=140, # original 135 max_value=255, object_type='light') maskedb_thresh = pcv.threshold.binary(gray_img=masked_b, threshold=128, max_value=255, object_type='light') ab1 = pcv.logical_or(bin_img1=maskeda_thresh, bin_img2=maskedb_thresh) ab = pcv.logical_or(bin_img1=maskeda_thresh1, bin_img2=ab1) # Fill small objects # Inputs: # bin_img - Binary image data # size - Minimum object area size in pixels (must be an integer), and smaller objects will be filled ab = pcv.median_blur(gray_img=ab, ksize=3) ab_fill = pcv.fill(bin_img=ab, size=1000) #print("filled") # Apply mask (for VIS images, mask_color=white) masked2 = pcv.apply_mask(rgb_img=masked, mask=ab_fill, mask_color='white') # ID the objects id_objects, obj_hierarchy = pcv.find_objects(masked2, ab_fill) # Let's just take the largest roi1, roi_hierarchy = pcv.roi.rectangle(img=masked2, x=0, y=0, h=960, w=1280) # Currently hardcoded # Decide which objects to keep # Inputs: # img = img to display kept objects # roi_contour = contour of roi, output from any ROI function # roi_hierarchy = contour of roi, output from any ROI function # object_contour = contours of objects, output from pcv.find_objects function # obj_hierarchy = hierarchy of objects, output from pcv.find_objects function # roi_type = 'partial' (default, for partially inside), 'cutto', or # 'largest' (keep only largest contour) with HiddenPrints(): roi_objects, hierarchy3, kept_mask, obj_area = pcv.roi_objects( img=img, roi_contour=roi1, roi_hierarchy=roi_hierarchy, object_contour=id_objects, obj_hierarchy=obj_hierarchy, roi_type='partial') # Object combine kept objects # Inputs: # img - RGB or grayscale image data for plotting # contours - Contour list # hierarchy - Contour hierarchy array obj, mask = pcv.object_composition(img=img, contours=roi_objects, hierarchy=hierarchy3) #print("final plant") new_im = Image.fromarray(masked2) new_im.save("output//" + args.filename + "last_masked.png") ##################_________________ Analysis outfile = args.outdir + "/" + filename # Here come all the analyse functions. # pcv.acute_vertex(img, obj, 30, 15, 100) color_img = pcv.analyze_color(rgb_img=img, mask=kept_mask, hist_plot_type=None) #new_im = Image.fromarray(color_img) #new_im.save(args.filename + "color_img.png") # Find shape properties, output shape image (optional) # 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) new_im = Image.fromarray(shape_img) new_im.save("output//" + args.filename + "shape_img.png") # Shape properties relative to user boundary line (optional) # Inputs: # img - RGB or grayscale image data # 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) boundary_img1 = pcv.analyze_bound_horizontal(img=img, obj=obj, mask=mask, line_position=1680) new_im = Image.fromarray(boundary_img1) new_im.save("output//" + args.filename + "boundary_img.png") # Determine color properties: Histograms, Color Slices, output color analyzed histogram (optional) # Inputs: # 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=kept_mask, hist_plot_type='all') #new_im = Image.fromarray(color_histogram) #new_im.save(args.filename + "color_histogram_img.png") # Pseudocolor the grayscale image # Inputs: # gray_img - Grayscale image data # obj - Single or grouped contour object (optional), if provided the pseudocolored image gets # cropped down to the region of interest. # mask - Binary mask (optional) # background - Background color/type. Options are "image" (gray_img, default), "white", or "black". A mask # must be supplied. # cmap - Colormap # min_value - Minimum value for range of interest # max_value - Maximum value for range of interest # dpi - Dots per inch for image if printed out (optional, if dpi=None then the default is set to 100 dpi). # axes - If False then the title, x-axis, and y-axis won't be displayed (default axes=True). # colorbar - If False then the colorbar won't be displayed (default colorbar=True) pseudocolored_img = pcv.visualize.pseudocolor(gray_img=s, mask=kept_mask, cmap='jet') #new_im = Image.fromarray(pseudocolored_img) #new_im.save(args.filename + "pseudocolored.png") # Write shape and color data to results file pcv.print_results(filename=args.result)
def main(): # Get options args = options() # Set variables device = 0 pcv.params.debug = args.debug img_file = args.image # Read image img, path, filename = pcv.readimage(filename=img_file, mode='rgb') # Process saturation channel from HSV colour space s = pcv.rgb2gray_hsv(rgb_img=img, channel='s') lp_s = pcv.laplace_filter(s, 1, 1) shrp_s = pcv.image_subtract(s, lp_s) s_eq = pcv.hist_equalization(shrp_s) s_thresh = pcv.threshold.binary(gray_img=s_eq, threshold=215, max_value=255, object_type='light') s_mblur = pcv.median_blur(gray_img=s_thresh, ksize=5) # Process green-magenta channel from LAB colour space b = pcv.rgb2gray_lab(rgb_img=img, channel='a') b_lp = pcv.laplace_filter(b, 1, 1) b_shrp = pcv.image_subtract(b, b_lp) b_thresh = pcv.threshold.otsu(b_shrp, 255, object_type='dark') # Create and apply mask bs = pcv.logical_or(bin_img1=s_mblur, bin_img2=b_thresh) filled = pcv.fill_holes(bs) masked = pcv.apply_mask(img=img, mask=filled, mask_color='white') # Extract colour channels from masked image masked_a = pcv.rgb2gray_lab(rgb_img=masked, channel='a') masked_b = pcv.rgb2gray_lab(rgb_img=masked, channel='b') # Threshold the green-magenta and blue images maskeda_thresh = pcv.threshold.binary(gray_img=masked_a, threshold=115, max_value=255, object_type='dark') maskeda_thresh1 = pcv.threshold.binary(gray_img=masked_a, threshold=140, max_value=255, object_type='light') maskedb_thresh = pcv.threshold.binary(gray_img=masked_b, threshold=128, max_value=255, object_type='light') # Join the thresholded saturation and blue-yellow images (OR) ab1 = pcv.logical_or(bin_img1=maskeda_thresh, bin_img2=maskedb_thresh) ab = pcv.logical_or(bin_img1=maskeda_thresh1, bin_img2=ab1) # Produce and apply a mask opened_ab = pcv.opening(gray_img=ab) ab_fill = pcv.fill(bin_img=ab, size=200) closed_ab = pcv.closing(gray_img=ab_fill) masked2 = pcv.apply_mask(img=masked, mask=bs, mask_color='white') # Identify objects id_objects, obj_hierarchy = pcv.find_objects(img=masked2, mask=ab_fill) # Define region of interest (ROI) roi1, roi_hierarchy = pcv.roi.rectangle(img=masked2, x=250, y=100, h=200, w=200) # Decide what objects to keep roi_objects, hierarchy3, kept_mask, obj_area = pcv.roi_objects( img=img, roi_contour=roi1, roi_hierarchy=roi_hierarchy, object_contour=id_objects, obj_hierarchy=obj_hierarchy, roi_type='partial') # Object combine kept objects obj, mask = pcv.object_composition(img=img, contours=roi_objects, hierarchy=hierarchy3) ############### Analysis ################ outfile = False if args.writeimg == True: outfile = args.outdir + "/" + filename # Analyze the plant analysis_image = pcv.analyze_object(img=img, obj=obj, mask=mask) color_histogram = pcv.analyze_color(rgb_img=img, mask=kept_mask, hist_plot_type='all') top_x, bottom_x, center_v_x = pcv.x_axis_pseudolandmarks(img=img, obj=obj, mask=mask) top_y, bottom_y, center_v_y = pcv.y_axis_pseudolandmarks(img=img, obj=obj, mask=mask) # Print results of the analysis pcv.print_results(filename=args.result) pcv.output_mask(img, kept_mask, filename, outdir=args.outdir, mask_only=True)
def generateMask(input, output, maskType=MASK_TYPES['BW']): pcv.params.debug = True #set debug mode # pcv.params.debug_outdir="./output.txt" #set output directory # Read image (readimage mode defaults to native but if image is RGBA then specify mode='rgb') # Inputs: # filename - Image file to be read in # mode - Return mode of image; either 'native' (default), 'rgb', 'gray', 'envi', or 'csv' img, path, filename = pcv.readimage(filename=input, mode='rgb') s = pcv.rgb2gray_hsv(rgb_img=img, channel='s') # Threshold the saturation image s_thresh = pcv.threshold.binary(gray_img=s, threshold=85, max_value=255, object_type='light') # Median Blur s_mblur = pcv.median_blur(gray_img=s_thresh, ksize=5) s_cnt = pcv.median_blur(gray_img=s_thresh, ksize=5) # Convert RGB to LAB and extract the Blue channel b = pcv.rgb2gray_lab(rgb_img=img, channel='b') # Threshold the blue image b_thresh = pcv.threshold.binary(gray_img=b, threshold=160, max_value=255, object_type='light') b_cnt = pcv.threshold.binary(gray_img=b, threshold=160, max_value=255, object_type='light') # Fill small objects # b_fill = pcv.fill(b_thresh, 10) # Join the thresholded saturation and blue-yellow images bs = pcv.logical_or(bin_img1=s_mblur, bin_img2=b_cnt) # Apply Mask (for VIS images, mask_color=white) masked = pcv.apply_mask(img=img, mask=bs, mask_color='white') # Convert RGB to LAB and extract the Green-Magenta and Blue-Yellow channels masked_a = pcv.rgb2gray_lab(rgb_img=masked, channel='a') masked_b = pcv.rgb2gray_lab(rgb_img=masked, channel='b') # Threshold the green-magenta and blue images maskeda_thresh = pcv.threshold.binary(gray_img=masked_a, threshold=115, max_value=255, object_type='dark') maskeda_thresh1 = pcv.threshold.binary(gray_img=masked_a, threshold=135, max_value=255, object_type='light') maskedb_thresh = pcv.threshold.binary(gray_img=masked_b, threshold=128, max_value=255, object_type='light') # Join the thresholded saturation and blue-yellow images (OR) ab1 = pcv.logical_or(bin_img1=maskeda_thresh, bin_img2=maskedb_thresh) ab = pcv.logical_or(bin_img1=maskeda_thresh1, bin_img2=ab1) if maskType == MASK_TYPES['BW']: pcv.print_image(ab, filename=output) return (True, None) # Fill small objects ab_fill = pcv.fill(bin_img=ab, size=200) # Apply mask (for VIS images, mask_color=white) masked2 = pcv.apply_mask(img=masked, mask=ab_fill, mask_color='black') if maskType == MASK_TYPES['COLORED']: pcv.print_image(masked2, filename=output) return (True, None) return (False, 'Unknown mask type.') """
# In[109]: # Convert RGB to HSV and extract the saturation channel # Then set threshold for saturation s = pcv.rgb2gray_hsv(rgb_img=img1, channel='s') s_thresh = pcv.threshold.binary(gray_img=s, threshold=122, max_value=255, object_type='dark') # In[110]: # Set Median Blur #Input box size "ksize" s_mblur = pcv.median_blur(gray_img=s_thresh, ksize=2) s_cnt = pcv.median_blur(gray_img=s_thresh, ksize=2) # In[111]: # Convert RGB to LAB and extract the blue channel #Then threshold the image b = pcv.rgb2gray_lab(rgb_img=img1, channel='b') b_thresh = pcv.threshold.binary(gray_img=b, threshold=135, max_value=255, object_type='light') #Setting threshold continued b_cnt = pcv.threshold.binary(gray_img=b, threshold=135,
def test(true_positive_file, test_parameters): saturation_lower_tresh = test_parameters[0] saturation_higher_tresh = test_parameters[1] hue_lower_tresh = test_parameters[2] hue_higher_tresh = test_parameters[3] value_lower_tresh = test_parameters[4] value_higher_tresh = test_parameters[5] l_lower_thresh = test_parameters[6] a_lower_thresh_1 = test_parameters[7] a_lower_thresh_2 = test_parameters[8] b_lower_thresh_1 = test_parameters[9] b_higher_thresh_1 = test_parameters[10] b_lower_thresh_2 = test_parameters[11] b_higher_thresh_2 = test_parameters[12] HSV_blur_k = test_parameters[13] LAB_blur_k = test_parameters[14] b_fill_k = test_parameters[15] LAB_fill_k = test_parameters[16] class args: #image = "C:\\Users\\RensD\\OneDrive\\studie\\Master\\The_big_project\\top_perspective\\0214_2018-03-07 08.55 - 26_cam9.png" image = true_positive_file outdir = "C:\\Users\\RensD\\OneDrive\\studie\\Master\\The_big_project\\top_perspective\\output" debug = debug_setting result = "results.txt" # Get options pcv.params.debug = args.debug #set debug mode pcv.params.debug_outdir = args.outdir #set output directory pcv.params.debug = args.debug # set debug mode pcv.params.debug_outdir = args.outdir # set output directory # Read image img, path, filename = pcv.readimage(filename=args.image) #______________________________________________________________#### BEGIN HSV COLORSPACE WORKFLOW ### # Convert RGB to HSV and extract the saturation channel # Threshold the saturation s = pcv.rgb2gray_hsv(rgb_img=img, channel='s') s_thresh, maskeds_image = pcv.threshold.custom_range( rgb_img=s, lower_thresh=[saturation_lower_tresh], upper_thresh=[saturation_higher_tresh], channel='gray') # Threshold the hue h = pcv.rgb2gray_hsv(rgb_img=img, channel='h') h_thresh, maskedh_image = pcv.threshold.custom_range( rgb_img=h, lower_thresh=[hue_lower_tresh], upper_thresh=[hue_higher_tresh], channel='gray') v = pcv.rgb2gray_hsv(rgb_img=img, channel='v') v_thresh, maskedv_image = pcv.threshold.custom_range( rgb_img=v, lower_thresh=[value_lower_tresh], upper_thresh=[value_higher_tresh], channel='gray') # Join saturation, Hue and Value sh = pcv.logical_and(bin_img1=s_thresh, bin_img2=h_thresh) hsv = pcv.logical_and(bin_img1=sh, bin_img2=v_thresh) # Median Blur s_mblur = pcv.median_blur(gray_img=hsv, ksize=HSV_blur_k) #s_cnt = pcv.median_blur(gray_img=s_thresh, ksize=5) #______________________________________________________________#### END HSV COLORSPACE WORKFLOW ### #______________________________________________________________#### BEGIN CIELAB COLORSPACE WORKFLOW ### # Convert RGB to LAB and extract the Blue channel b = pcv.rgb2gray_lab(rgb_img=img, channel='b') # Threshold the blue image b_thresh = pcv.threshold.binary(gray_img=b, threshold=b_lower_thresh_1, max_value=b_higher_thresh_1, object_type='light') b_cnt = pcv.threshold.binary(gray_img=b, threshold=b_lower_thresh_1, max_value=b_higher_thresh_1, object_type='light') # Fill small objects b_cnt = pcv.fill( b_thresh, b_fill_k ) # If the fill step fails because of small objects try a smaller fill, else abort. # Join the thresholded saturation and blue-yellow images bs = pcv.logical_and(bin_img1=s_mblur, bin_img2=b_cnt) # CHANGER OR TO AND # Apply Mask (for VIS images, mask_color=white) masked = pcv.apply_mask(rgb_img=img, mask=bs, mask_color='white') #Now the background is filtered away. Next step is to capture the plant. # Convert RGB to LAB and extract the Green-Magenta and Blue-Yellow channels masked_l = pcv.rgb2gray_lab(rgb_img=masked, channel='l') masked_a = pcv.rgb2gray_lab(rgb_img=masked, channel='a') masked_b = pcv.rgb2gray_lab(rgb_img=masked, channel='b') # Threshold the green-magenta and blue images maskedl_thresh, maskedl_image = pcv.threshold.custom_range( rgb_img=masked_l, lower_thresh=[120], upper_thresh=[247], channel='gray') maskeda_thresh, maskeda_image = pcv.threshold.custom_range( rgb_img=masked_a, lower_thresh=[0], upper_thresh=[114], channel='gray') maskedb_thresh, maskedb_image = pcv.threshold.custom_range( rgb_img=masked_b, lower_thresh=[130], upper_thresh=[240], channel='gray') # Join the thresholded saturation and blue-yellow images (OR) ab1 = pcv.logical_and(bin_img1=maskeda_thresh, bin_img2=maskedb_thresh) ab = pcv.logical_and(bin_img1=maskedl_thresh, bin_img2=ab1) # Fill small objects ab_fill = pcv.median_blur(gray_img=ab, ksize=LAB_blur_k) ab_fill = pcv.fill(bin_img=ab_fill, size=LAB_fill_k) # Apply mask (for VIS images, mask_color=white) masked2 = pcv.apply_mask(rgb_img=masked, mask=ab_fill, mask_color='white') # Identify objects id_objects, obj_hierarchy = pcv.find_objects(img=masked2, mask=ab_fill) # Define ROI roi1, roi_hierarchy = pcv.roi.rectangle(img=masked2, x=0, y=0, h=960, w=1280) # Decide which objects to keep roi_objects, hierarchy3, kept_mask, obj_area = pcv.roi_objects( img=img, roi_contour=roi1, roi_hierarchy=roi_hierarchy, object_contour=id_objects, obj_hierarchy=obj_hierarchy, roi_type='partial') # Object combine kept objects obj, mask = pcv.object_composition(img=img, contours=roi_objects, hierarchy=hierarchy3) if use_mask == True: return (mask) else: masked2 = pcv.apply_mask(rgb_img=masked, mask=mask, mask_color='white') return (masked2)