def nonuniform_illumination(img, ksize): """Correct for non uniform illumination i.e. spotlight correction. Inputs: img = RGB or grayscale image data ksize = (optional) new minimum value for range of interest. default = 0 Returns: corrected_img = rescaled image :param img: numpy.ndarray :param ksize: int :return corrected_img: numpy.ndarray """ if len(np.shape(img)) == 3: img = rgb2gray(img) # Fill foreground objects kernel = np.ones((ksize, ksize), np.uint8) opening = cv2.morphologyEx(img, cv2.MORPH_OPEN, kernel) # Store debug mode debug = params.debug params.debug = None # Heavily blurred image acts like a background image blurred_img = gaussian_blur(opening, ksize=(ksize, ksize)) img_mean = np.mean(blurred_img) corrected_img = img - blurred_img + img_mean corrected_img = rescale(gray_img=corrected_img, min_value=0, max_value=255) # Reset debug mode params.debug = debug # Autoincrement the device counter params.device += 1 if params.debug == 'print': print_image( corrected_img, os.path.join(params.debug_outdir, str(params.device) + '_correct_illumination' + '.png')) elif params.debug == 'plot': plot_image(corrected_img, cmap='gray') return corrected_img
def main(): # Create input arguments object args = options() # Set debug mode pcv.params.debug = args.debug # Open a single image img, imgpath, imgname = pcv.readimage(filename=args.image) # Visualize colorspaces all_cs = pcv.visualize.colorspaces(rgb_img=img) # Extract the Blue-Yellow ("b") channel from the LAB colorspace gray_img = pcv.rgb2gray_lab(rgb_img=img, channel="b") # Plot a histogram of pixel values for the Blue-Yellow ("b") channel. hist_plot = pcv.visualize.histogram(gray_img=gray_img) # Apply a binary threshold to the Blue-Yellow ("b") grayscale image. thresh_img = pcv.threshold.binary(gray_img=gray_img, threshold=140, max_value=255, object_type="light") # Apply a dilation with a 5x5 kernel and 3 iterations dil_img = pcv.dilate(gray_img=thresh_img, ksize=5, i=3) # Fill in small holes in the leaves closed_img = pcv.fill_holes(bin_img=dil_img) # Erode the plant pixels using a 5x5 kernel and 3 iterations er_img = pcv.erode(gray_img=closed_img, ksize=5, i=3) # Apply a Gaussian blur with a 5 x 5 kernel. blur_img = pcv.gaussian_blur(img=er_img, ksize=(5, 5)) # Set pixel values less than 255 to 0 blur_img[np.where(blur_img < 255)] = 0 # Fill/remove objects less than 300 pixels in area cleaned = pcv.fill(bin_img=blur_img, size=300) # Create a circular ROI roi, roi_str = pcv.roi.circle(img=img, x=1725, y=1155, r=400) # Identify objects in the binary image cnts, cnts_str = pcv.find_objects(img=img, mask=cleaned) # Filter objects by region of interest plant_cnt, plant_str, plant_mask, plant_area = pcv.roi_objects( img=img, roi_contour=roi, roi_hierarchy=roi_str, object_contour=cnts, obj_hierarchy=cnts_str) # Combine objects into one plant, mask = pcv.object_composition(img=img, contours=plant_cnt, hierarchy=plant_str) # Measure size and shape properties shape_img = pcv.analyze_object(img=img, obj=plant, mask=mask) if args.writeimg: pcv.print_image(img=shape_img, filename=os.path.join(args.outdir, "shapes_" + imgname)) # Analyze color properties color_img = pcv.analyze_color(rgb_img=img, mask=mask, hist_plot_type="hsv") if args.writeimg: pcv.print_image(img=color_img, filename=os.path.join(args.outdir, "histogram_" + imgname)) # Save the measurements to a file pcv.print_results(filename=args.result)
# In[7]: # 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) pcv.print_image(img=gaussian_img, filename="upload/output_imgs/Blur_img.jpg") # In[8]: # 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') # Threshold the blue channel image b_thresh = pcv.threshold.binary(gray_img=b, threshold=160,
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 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 segment_on_dt(a, img): #logAnd = plantcv.logical_and(a, img) #cv2.imshow('logical', logAnd) #cv2.waitKey(0) gauss = pcv.gaussian_blur(a, (5, 5), 0, 0) edges = pcv.canny_edge_detect(a, mask=None, sigma=2, low_thresh=15, high_thresh=40, thickness=2, mask_color=None, use_quantiles=False) cv2.imshow('canny', edges) cv2.waitKey(0) canny_dilate = cv2.dilate(edges, None, iterations=1) cv2.imshow("canny dilate", canny_dilate) cv2.waitKey(0) dilate = cv2.dilate(img, None, iterations=1) border = dilate - cv2.erode(dilate, None, iterations=2) cv2.imshow('border', border) cv2.waitKey(0) border = cv2.bitwise_or(border, canny_dilate, mask=dilate) cv2.imshow("border", border) cv2.waitKey(0) dt = cv2.distanceTransform(img, 1, 5) cv2.imshow('dist trans', dt) cv2.waitKey(0) dt = ((dt - dt.min()) / (dt.max() - dt.min()) * 255).astype(numpy.uint8) cv2.imshow('minmax', dt) cv2.waitKey(0) _, dt = cv2.threshold(dt, 45, 255, cv2.THRESH_BINARY) cv2.imshow('thresh', dt) cv2.waitKey(0) seg = cv2.subtract(dt, border) cv2.imshow('thresh - border', seg) cv2.waitKey(0) seg1 = cv2.erode(seg, None, iterations=2) cv2.imshow('erode', seg1) cv2.waitKey(0) fill_image = pcv.closing(seg1) cv2.imshow('Closing', fill_image) cv2.waitKey(0) lbl, ncc = label(fill_image) lbl = lbl * (255 / (ncc + 1)) # Completing the markers now. lbl[border == 255] = 255 print(ncc) lbl = lbl.astype(numpy.int32) #cv2.watershed(a, lbl) lbl[lbl == -1] = 0 lbl = lbl.astype(numpy.uint8) return 255 - lbl
def main(): # Get options args = options() # plt.rcParams["font.family"] = "Arial" # All text is Arial # pixel_resolution cppc.pixelresolution = 0.052 #mm # see pixel_resolution.xlsx for calibration curve for pixel to mm translation pcv.params.text_size = 12 pcv.params.text_thickness = 12 if args.debug: pcv.params.debug = args.debug # set debug mode if args.debugdir: pcv.params.debug_outdir = args.debugdir # set debug directory os.makedirs(args.debugdir, exist_ok=True) args = cppc.roi.copy_metadata(args) # read images and create mask img, _, fn = pcv.readimage(args.image) args.imagename = os.path.splitext(fn)[0] # cps=pcv.visualize.colorspaces(img) # create mask if args.pdfs: #if not provided in run_workflows.sh then will be False print('naive bayes classification') # Classify each pixel as plant or background (background and system components) img_blur = pcv.gaussian_blur(img, (7, 7)) masks = pcv.naive_bayes_classifier(rgb_img=img_blur, pdf_file=args.pdfs) mask = masks['Plant'] # save masks colored_img = pcv.visualize.colorize_masks( masks=[masks['Plant'], masks['Background'], masks['Blue']], colors=['green', 'black', 'blue']) # Print out the colorized figure that got created imgdir = os.path.join(args.outdir, 'bayesmask_images') os.makedirs(imgdir, exist_ok=True) pcv.print_image( colored_img, os.path.join(imgdir, args.imagename + '-bayesmask.png')) else: print('\nthreshold masking') # tray mask # _, rm, _, _ = pcv.rectangle_mask(img, (425,350), (2100,3050),'white') # img_tray = pcv.apply_mask(img, rm, 'black') # dark green # imgt_h = pcv.rgb2gray_hsv(img,'h') mask1, img1 = pcv.threshold.custom_range(img, [15, 0, 0], [60, 255, 255], 'hsv') mask1 = pcv.fill(mask1, 200) mask1 = pcv.closing(mask1, pcv.get_kernel((5, 5), 'rectangle')) mask = mask1 # img1 = pcv.apply_mask(img, mask1, 'black') # # remove faint algae # img1_a = pcv.rgb2gray_lab(img1,'b') # # img1_b = pcv.rgb2gray_lab(img1,'b') # th = filters.threshold_otsu(img1_a) # algaemask = pcv.threshold.binary(img1_a,th,255,'light') # # bmask, _ = pcv.threshold.custom_range(img1,[0,0,100],[120,120,255], 'RGB') # img2 = pcv.apply_mask(img1,algaemask,'black') # mask = pcv.rgb2gray(img2) # mask[mask > 0] = 255 # pcv.plot_image(mask) # find objects based on threshold mask c, h = pcv.find_objects(img, mask) # setup roi based on pot locations rc, rh = pcv.roi.multi(img, coord=[(1250, 1000), (1250, 2300)], radius=300) # Turn off debug temporarily if activated, otherwise there will be a lot of plots pcv.params.debug = None # Loop over each region of interest # i=0 # rc_i = rc[i] # rh_i = rh[i] final_mask = cppc.roi.iterate_rois(img, c, h, rc, rh, args=args, masked=True, gi=True, shape=True, hist=True, hue=True)