Beispiel #1
0
def prepare(rgb_img, gray_low, gray_high):
    logger.debug('received rbg image')
    gray_img = pcv.rgb2gray(rgb_img=rgb_img)
    logger.debug('converted rbg image to grayscale image')
    masked_img = cv2.inRange(gray_img, gray_low, gray_high)
    logger.debug('filtered grayscale image')
    fill_image = pcv.fill_holes(masked_img)
    logger.debug('filled holes in binary mask')
    logger.debug('returned binary image mask')
    return fill_image
Beispiel #2
0
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")
Beispiel #3
0
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)
Beispiel #4
0
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 main():
    # Initialize options
    args = options()
    # Set PlantCV debug mode to input debug method
    pcv.params.debug = args.debug

    # Use PlantCV to read in the input image. The function outputs an image as a NumPy array, the path to the file,
    # and the image filename
    img, path, filename = pcv.readimage(filename=args.image)

    # ## Segmentation

    # ### Saturation channel
    # Convert the RGB image to HSV colorspace and extract the saturation channel
    s = pcv.rgb2gray_hsv(rgb_img=img, channel='s')

    # Use a binary threshold to set an inflection value where all pixels in the grayscale saturation image below the
    # threshold get set to zero (pure black) and all pixels at or above the threshold get set to 255 (pure white)
    s_thresh = pcv.threshold.binary(gray_img=s, threshold=80, max_value=255, object_type='light')

    # ### Blue-yellow channel
    # Convert the RGB image to LAB colorspace and extract the blue-yellow channel
    b = pcv.rgb2gray_lab(rgb_img=img, channel='b')

    # Use a binary threshold to set an inflection value where all pixels in the grayscale blue-yellow image below the
    # threshold get set to zero (pure black) and all pixels at or above the threshold get set to 255 (pure white)
    b_thresh = pcv.threshold.binary(gray_img=b, threshold=134, max_value=255, object_type='light')

    # ### Green-magenta channel
    # Convert the RGB image to LAB colorspace and extract the green-magenta channel
    a = pcv.rgb2gray_lab(rgb_img=img, channel='a')

    # In the green-magenta image the plant pixels are darker than the background. Setting object_type="dark" will
    # invert the image first and then use a binary threshold to set an inflection value where all pixels in the
    # grayscale green-magenta image below the threshold get set to zero (pure black) and all pixels at or above the
    # threshold get set to 255 (pure white)
    a_thresh = pcv.threshold.binary(gray_img=a, threshold=122, max_value=255, object_type='dark')

    # Combine the binary images for the saturation and blue-yellow channels. The "or" operator returns a binary image
    # that is white when a pixel was white in either or both input images
    bs = pcv.logical_or(bin_img1=s_thresh, bin_img2=b_thresh)

    # Combine the binary images for the combined saturation and blue-yellow channels and the green-magenta channel.
    # The "or" operator returns a binary image that is white when a pixel was white in either or both input images
    bsa = pcv.logical_or(bin_img1=bs, bin_img2=a_thresh)

    # The combined binary image labels plant pixels well but the background still has pixels labeled as foreground.
    # Small white noise (salt) in the background can be removed by filtering white objects in the image by size and
    # setting a size threshold where smaller objects can be removed
    bsa_fill1 = pcv.fill(bin_img=bsa, size=15)  # Fill small noise

    # Before more stringent size filtering is done we want to connect plant parts that may still be disconnected from
    # the main plant. Use a dilation to expand the boundary of white regions. Ksize is the size of a box scanned
    # across the image and i is the number of times a scan is done
    bsa_fill2 = pcv.dilate(gray_img=bsa_fill1, ksize=3, i=3)

    # Remove small objects by size again but use a higher threshold
    bsa_fill3 = pcv.fill(bin_img=bsa_fill2, size=250)

    # Use the binary image to identify objects or connected components.
    id_objects, obj_hierarchy = pcv.find_objects(img=img, mask=bsa_fill3)

    # Because the background still contains pixels labeled as foreground, the object list contains background.
    # Because these images were collected in an automated system the plant is always centered in the image at the
    # same position each time. Define a region of interest (ROI) to set the area where we expect to find plant
    # pixels. PlantCV can make simple ROI shapes like rectangles, circles, etc. but here we use a custom ROI to fit a
    # polygon around the plant area
    roi_custom, roi_hier_custom = pcv.roi.custom(img=img, vertices=[[1085, 1560], [1395, 1560], [1395, 1685],
                                                                    [1890, 1744], [1890, 25], [600, 25], [615, 1744],
                                                                    [1085, 1685]])

    # Use the ROI to filter out objects found outside the ROI. When `roi_type = "cutto"` objects outside the ROI are
    # cropped out. The default `roi_type` is "partial" which allows objects to overlap the ROI and be retained
    roi_objects, hierarchy, kept_mask, obj_area = pcv.roi_objects(img=img, roi_contour=roi_custom,
                                                                  roi_hierarchy=roi_hier_custom,
                                                                  object_contour=id_objects,
                                                                  obj_hierarchy=obj_hierarchy, roi_type='cutto')

    # Filter remaining objects by size again to remove any remaining background objects
    filled_mask1 = pcv.fill(bin_img=kept_mask, size=350)

    # Use a closing operation to first dilate (expand) and then erode (shrink) the plant to fill in any additional
    # gaps in leaves or stems
    filled_mask2 = pcv.closing(gray_img=filled_mask1)

    # Remove holes or dark spot noise (pepper) in the plant binary image
    filled_mask3 = pcv.fill_holes(filled_mask2)

    # With the clean binary image identify the contour of the plant
    id_objects, obj_hierarchy = pcv.find_objects(img=img, mask=filled_mask3)

    # Because a plant or object of interest may be composed of multiple contours, it is required to combine all
    # remaining contours into a single contour before measurements can be done
    obj, mask = pcv.object_composition(img=img, contours=id_objects, hierarchy=obj_hierarchy)

    # ## Measurements PlantCV has several built-in measurement or analysis methods. Here, basic measurements of size
    # and shape are done. Additional typical modules would include plant height (`pcv.analyze_bound_horizontal`) and
    # color (`pcv.analyze_color`)
    shape_img = pcv.analyze_object(img=img, obj=obj, mask=mask)

    # Save the shape image if requested
    if args.writeimg:
        outfile = os.path.join(args.outdir, filename[:-4] + "_shapes.png")
        pcv.print_image(img=shape_img, filename=outfile)

    # ## Morphology workflow

    # Update a few PlantCV parameters for plotting purposes
    pcv.params.text_size = 1.5
    pcv.params.text_thickness = 5
    pcv.params.line_thickness = 15

    # Convert the plant mask into a "skeletonized" image where each path along the stem and leaves are a single pixel
    # wide
    skel = pcv.morphology.skeletonize(mask=mask)

    # Sometimes wide parts of leaves or stems are skeletonized in the direction perpendicular to the main path. These
    # "barbs" or "spurs" can be removed by pruning the skeleton to remove small paths. Pruning will also separate the
    # individual path segments (leaves and stem parts)
    pruned, segmented_img, segment_objects = pcv.morphology.prune(skel_img=skel, size=30, mask=mask)
    pruned, segmented_img, segment_objects = pcv.morphology.prune(skel_img=pruned, size=3, mask=mask)

    # Leaf and stem segments above are separated but only into individual paths. We can sort the segments into stem
    # and leaf paths by identifying primary segments (stems; those that end in a branch point) and secondary segments
    # (leaves; those that begin at a branch point and end at a tip point)
    leaf_objects, other_objects = pcv.morphology.segment_sort(skel_img=pruned, objects=segment_objects, mask=mask)

    # Label the segment unique IDs
    segmented_img, labeled_id_img = pcv.morphology.segment_id(skel_img=pruned, objects=leaf_objects, mask=mask)

    # Measure leaf insertion angles. Measures the angle between a line fit through the stem paths and a line fit
    # through the first `size` points of each leaf path
    labeled_angle_img = pcv.morphology.segment_insertion_angle(skel_img=pruned, segmented_img=segmented_img,
                                                               leaf_objects=leaf_objects, stem_objects=other_objects,
                                                               size=22)

    # Save leaf angle image if requested
    if args.writeimg:
        outfile = os.path.join(args.outdir, filename[:-4] + "_leaf_insertion_angles.png")
        pcv.print_image(img=labeled_angle_img, filename=outfile)

    # ## Other potential morphological measurements There are many other functions that extract data from within the
    # morphology sub-package of PlantCV. For our purposes, we are most interested in the relative angle between each
    # leaf and the stem which we measure with `plantcv.morphology.segment_insertion_angle`. However, the following
    # cells show some of the other traits that we are able to measure from images that can be succesfully sorted into
    # primary and secondary segments.

    # Segment the plant binary mask using the leaf and stem segments. Allows for the measurement of individual leaf
    # areas
    # filled_img = pcv.morphology.fill_segments(mask=mask, objects=leaf_objects)

    # Measure the path length of each leaf (geodesic distance)
    # labeled_img2 = pcv.morphology.segment_path_length(segmented_img=segmented_img, objects=leaf_objects)

    # Measure the straight-line, branch point to tip distance (Euclidean) for each leaf
    # labeled_img3 = pcv.morphology.segment_euclidean_length(segmented_img=segmented_img, objects=leaf_objects)

    # Measure the curvature of each leaf (Values closer to 1 indicate that a segment is a straight line while larger
    # values indicate the segment has more curvature)
    # labeled_img4 = pcv.morphology.segment_curvature(segmented_img=segmented_img, objects=leaf_objects)

    # Measure absolute leaf angles (angle of linear regression line fit to each leaf object) Note: negative values
    # signify leaves to the left of the stem, positive values signify leaves to the right of the stem
    # labeled_img5 = pcv.morphology.segment_angle(segmented_img=segmented_img, objects=leaf_objects)

    # Measure leaf curvature in degrees
    # labeled_img6 = pcv.morphology.segment_tangent_angle(segmented_img=segmented_img, objects=leaf_objects, size=35)

    # Measure stem characteristics like stem angle and length
    # stem_img = pcv.morphology.analyze_stem(rgb_img=img, stem_objects=other_objects)

    # Remove unneeded observations (hack)
    _ = pcv.outputs.observations.pop("tips")
    _ = pcv.outputs.observations.pop("branch_pts")
    angles = pcv.outputs.observations["segment_insertion_angle"]["value"]
    remove_indices = []
    for i, value in enumerate(angles):
        if value == "NA":
            remove_indices.append(i)
    remove_indices.sort(reverse=True)
    for i in remove_indices:
        _ = pcv.outputs.observations["segment_insertion_angle"]["value"].pop(i)

    # ## Save the results out to file for downsteam analysis
    pcv.print_results(filename=args.result)
    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 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 main():
    # Get options
    args = options()

    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)

    # pixel_resolution
    # mm
    # see pixel_resolution.xlsx for calibration curve for pixel to mm translation
    pixelresolution = 0.052

    # The result file should exist if plantcv-workflow.py was run
    if os.path.exists(args.result):
        # Open the result file
        results = open(args.result, "r")
        # The result file would have image metadata in it from plantcv-workflow.py, read it into memory
        metadata = json.load(results)
        # Close the file
        results.close()
        # Delete the file, we will create new ones
        os.remove(args.result)
        plantbarcode = metadata['metadata']['plantbarcode']['value']
        print(plantbarcode,
              metadata['metadata']['timestamp']['value'],
              sep=' - ')

    else:
        # If the file did not exist (for testing), initialize metadata as an empty string
        metadata = "{}"
        regpat = re.compile(args.regex)
        plantbarcode = re.search(regpat, args.image).groups()[0]

    # read images and create mask
    img, _, fn = pcv.readimage(args.image)
    imagename = os.path.splitext(fn)[0]

    # create mask

    # taf=filters.try_all_threshold(s_img)
    ## remove background
    s_img = pcv.rgb2gray_hsv(img, 's')
    min_s = filters.threshold_minimum(s_img)
    thresh_s = pcv.threshold.binary(s_img, min_s, 255, 'light')
    rm_bkgrd = pcv.fill_holes(thresh_s)

    ## low greenness
    thresh_s = pcv.threshold.binary(s_img, min_s + 15, 255, 'dark')
    # taf = filters.try_all_threshold(s_img)
    c = pcv.logical_xor(rm_bkgrd, thresh_s)
    cinv = pcv.invert(c)
    cinv_f = pcv.fill(cinv, 500)
    cinv_f_c = pcv.closing(cinv_f, np.ones((5, 5)))
    cinv_f_c_e = pcv.erode(cinv_f_c, 2, 1)

    ## high greenness
    a_img = pcv.rgb2gray_lab(img, channel='a')
    # taf = filters.try_all_threshold(a_img)
    t_a = filters.threshold_isodata(a_img)
    thresh_a = pcv.threshold.binary(a_img, t_a, 255, 'dark')
    thresh_a = pcv.closing(thresh_a, np.ones((5, 5)))
    thresh_a_f = pcv.fill(thresh_a, 500)
    ## combined mask
    lor = pcv.logical_or(cinv_f_c_e, thresh_a_f)
    close = pcv.closing(lor, np.ones((2, 2)))
    fill = pcv.fill(close, 800)
    erode = pcv.erode(fill, 3, 1)
    fill2 = pcv.fill(erode, 1200)
    # dilate = pcv.dilate(fill2,2,2)
    mask = fill2

    final_mask = np.zeros_like(mask)

    # Compute greenness
    # split color channels
    b, g, r = cv2.split(img)
    # print green intensity
    # g_img = pcv.visualize.pseudocolor(g, cmap='Greens', background='white', min_value=0, max_value=255, mask=mask, axes=False)

    # convert color channels to int16 so we can add them (values will be greater than 255 which is max of current uint8 format)
    g = g.astype('uint16')
    r = r.astype('uint16')
    b = b.astype('uint16')
    denom = g + r + b

    # greenness index
    out_flt = np.zeros_like(denom, dtype='float32')
    # divide green by sum of channels to compute greenness index with values 0-1
    gi = np.divide(g,
                   denom,
                   out=out_flt,
                   where=np.logical_and(denom != 0, mask > 0))

    # find objects
    c, h = pcv.find_objects(img, mask)
    rc, rh = pcv.roi.multi(img, coord=[(1300, 900), (1300, 2400)], radius=350)
    # Turn off debug temporarily, otherwise there will be a lot of plots
    pcv.params.debug = None
    # Loop over each region of interest
    i = 0
    rc_i = rc[i]
    for i, rc_i in enumerate(rc):
        rh_i = rh[i]

        # Add ROI number to output. Before roi_objects so result has NA if no object.
        pcv.outputs.add_observation(variable='roi',
                                    trait='roi',
                                    method='roi',
                                    scale='int',
                                    datatype=int,
                                    value=i,
                                    label='#')

        roi_obj, hierarchy_obj, submask, obj_area = pcv.roi_objects(
            img,
            roi_contour=rc_i,
            roi_hierarchy=rh_i,
            object_contour=c,
            obj_hierarchy=h,
            roi_type='partial')

        if obj_area == 0:

            print('\t!!! No object found in ROI', str(i))
            pcv.outputs.add_observation(
                variable='plantarea',
                trait='plant area in sq mm',
                method='observations.area*pixelresolution^2',
                scale=pixelresolution,
                datatype="<class 'float'>",
                value=0,
                label='sq mm')

        else:

            # Combine multiple objects
            # ple plant objects within an roi together
            plant_object, plant_mask = pcv.object_composition(
                img=img, contours=roi_obj, hierarchy=hierarchy_obj)

            final_mask = pcv.image_add(final_mask, plant_mask)

            # Save greenness for individual ROI
            grnindex = np.mean(gi[np.where(plant_mask > 0)])
            pcv.outputs.add_observation(
                variable='greenness_index',
                trait='mean normalized greenness index',
                method='g/sum(b+g+r)',
                scale='[0,1]',
                datatype="<class 'float'>",
                value=float(grnindex),
                label='/1')

            # Analyze all colors
            hist = pcv.analyze_color(img, plant_mask, 'all')

            # Analyze the shape of the current plant
            shape_img = pcv.analyze_object(img, plant_object, plant_mask)
            plant_area = pcv.outputs.observations['area'][
                'value'] * pixelresolution**2
            pcv.outputs.add_observation(
                variable='plantarea',
                trait='plant area in sq mm',
                method='observations.area*pixelresolution^2',
                scale=pixelresolution,
                datatype="<class 'float'>",
                value=plant_area,
                label='sq mm')

        # end if-else

        # At this point we have observations for one plant
        # We can write these out to a unique results file
        # Here I will name the results file with the ROI ID combined with the original result filename
        basename, ext = os.path.splitext(args.result)
        filename = basename + "-roi" + str(i) + ext
        # Save the existing metadata to the new file
        with open(filename, "w") as r:
            json.dump(metadata, r)
        pcv.print_results(filename=filename)
        # The results are saved, now clear out the observations so the next loop adds new ones for the next plant
        pcv.outputs.clear()

        if args.writeimg and obj_area != 0:
            imgdir = os.path.join(args.outdir, 'shape_images', plantbarcode)
            os.makedirs(imgdir, exist_ok=True)
            pcv.print_image(
                shape_img,
                os.path.join(imgdir,
                             imagename + '-roi' + str(i) + '-shape.png'))

            imgdir = os.path.join(args.outdir, 'colorhist_images',
                                  plantbarcode)
            os.makedirs(imgdir, exist_ok=True)
            pcv.print_image(
                hist,
                os.path.join(imgdir,
                             imagename + '-roi' + str(i) + '-colorhist.png'))

# end roi loop

    if args.writeimg:
        # save grnness image of entire tray
        imgdir = os.path.join(args.outdir, 'pseudocolor_images', plantbarcode)
        os.makedirs(imgdir, exist_ok=True)
        gi_img = pcv.visualize.pseudocolor(gi,
                                           obj=None,
                                           mask=final_mask,
                                           cmap='viridis',
                                           axes=False,
                                           min_value=0.3,
                                           max_value=0.6,
                                           background='black',
                                           obj_padding=0)
        gi_img = add_scalebar(gi_img,
                              pixelresolution=pixelresolution,
                              barwidth=20,
                              barlocation='lower left')
        gi_img.set_size_inches(6, 6, forward=False)
        gi_img.savefig(os.path.join(imgdir, imagename + '-greenness.png'),
                       bbox_inches='tight')
        gi_img.clf()