Beispiel #1
0
def _hist_gray(gray_img, bins, lower_bound, upper_bound, mask=None):
    """ Prepare the ready to plot histogram data

    Inputs:
    gray_img       = grayscale image to analyze
    bins           = divide the data into n evenly spaced bins
    lower_bound    = the lower bound of the bins (x-axis min value)
    upper_bound    = the upper bound of the bins (x-axis max value)
    mask           = binary mask, calculate histogram from masked area only (default=None)

    Returns:
    bin_labels     = an array of histogram bin labels
    hist_percent   = an array of histogram represented by percent values
    hist_gray_data = an array of histogram (original values)

    :param gray_img: numpy.ndarray
    :param bins: int
    :param lower_bound: int
    :param upper_bound: int
    :param mask: numpy.ndarray
    :return bin_labels: numpy.ndarray
    :return hist_percent: numpy.ndarray
    :return hist_gray_data: numpy.ndarray
    """

    params.device += 1
    debug = params.debug

    # Apply mask if one is supplied
    if mask is not None:
        min_val = np.min(gray_img)
        pixels = len(np.where(mask > 0)[0])
        # apply plant shaped mask to image
        params.debug = None
        mask1 = binary_threshold(mask, 0, 255, 'light')
        mask1 = (mask1 / 255)
        masked = np.where(mask1 != 0, gray_img, min_val - 5000)

    else:
        pixels = gray_img.shape[0] * gray_img.shape[1]
        masked = gray_img

    params.debug = debug

    # Store histogram data
    hist_gray_data, hist_bins = np.histogram(masked, bins,
                                             (lower_bound, upper_bound))

    # make hist percentage for plotting
    hist_percent = (hist_gray_data / float(pixels)) * 100
    # use middle value of every bin as bin label
    bin_labels = np.array([
        np.average([hist_bins[i], hist_bins[i + 1]])
        for i in range(0,
                       len(hist_bins) - 1)
    ])

    return bin_labels, hist_percent, hist_gray_data
def report_size_marker_area(img,
                            roi_contour,
                            roi_hierarchy,
                            marker='define',
                            objcolor='dark',
                            thresh_channel=None,
                            thresh=None):
    """Detects a size marker in a specified region and reports its size and eccentricity

    Inputs:
    img             = An RGB or grayscale image to plot the marker object on
    roi_contour     = A region of interest contour (e.g. output from pcv.roi.rectangle or other methods)
    roi_hierarchy   = A region of interest contour hierarchy (e.g. output from pcv.roi.rectangle or other methods)
    marker          = 'define' or 'detect'. If define it means you set an area, if detect it means you want to
                      detect within an area
    objcolor        = Object color is 'dark' or 'light' (is the marker darker or lighter than the background)
    thresh_channel  = 'h', 's', or 'v' for hue, saturation or value
    thresh          = Binary threshold value (integer)

    Returns:
    analysis_images = List of output images

    :param img: numpy.ndarray
    :param roi_contour: list
    :param roi_hierarchy: numpy.ndarray
    :param marker: str
    :param objcolor: str
    :param thresh_channel: str
    :param thresh: int
    :return: analysis_images: list
    """
    # Store debug
    debug = params.debug
    params.debug = None

    params.device += 1
    # Make a copy of the reference image
    ref_img = np.copy(img)
    # If the reference image is grayscale convert it to color
    if len(np.shape(ref_img)) == 2:
        ref_img = cv2.cvtColor(ref_img, cv2.COLOR_GRAY2BGR)

    # Marker components
    # If the marker type is "defined" then the marker_mask and marker_contours are equal to the input ROI
    # Initialize a binary image
    roi_mask = np.zeros(np.shape(img)[:2], dtype=np.uint8)
    # Draw the filled ROI on the mask
    cv2.drawContours(roi_mask, roi_contour, -1, (255), -1)
    marker_mask = []
    marker_contour = []

    # If the marker type is "detect" then we will use the ROI to isolate marker contours from the input image
    if marker.upper() == 'DETECT':
        # We need to convert the input image into an one of the HSV channels and then threshold it
        if thresh_channel is not None and thresh is not None:
            # Mask the input image
            masked = apply_mask(rgb_img=ref_img,
                                mask=roi_mask,
                                mask_color="black")
            # Convert the masked image to hue, saturation, or value
            marker_hsv = rgb2gray_hsv(rgb_img=masked, channel=thresh_channel)
            # Threshold the HSV image
            marker_bin = binary_threshold(gray_img=marker_hsv,
                                          threshold=thresh,
                                          max_value=255,
                                          object_type=objcolor)
            # Identify contours in the masked image
            contours, hierarchy = find_objects(img=ref_img, mask=marker_bin)
            # Filter marker contours using the input ROI
            kept_contours, kept_hierarchy, kept_mask, obj_area = roi_objects(
                img=ref_img,
                object_contour=contours,
                obj_hierarchy=hierarchy,
                roi_contour=roi_contour,
                roi_hierarchy=roi_hierarchy,
                roi_type="partial")
            # If there are more than one contour detected, combine them into one
            # These become the marker contour and mask
            marker_contour, marker_mask = object_composition(
                img=ref_img, contours=kept_contours, hierarchy=kept_hierarchy)
        else:
            fatal_error(
                'thresh_channel and thresh must be defined in detect mode')
    elif marker.upper() == "DEFINE":
        # Identify contours in the masked image
        contours, hierarchy = find_objects(img=ref_img, mask=roi_mask)
        # If there are more than one contour detected, combine them into one
        # These become the marker contour and mask
        marker_contour, marker_mask = object_composition(img=ref_img,
                                                         contours=contours,
                                                         hierarchy=hierarchy)
    else:
        fatal_error(
            "marker must be either 'define' or 'detect' but {0} was provided.".
            format(marker))

    # Calculate the moments of the defined marker region
    m = cv2.moments(marker_mask, binaryImage=True)
    # Calculate the marker area
    marker_area = m['m00']

    # Fit a bounding ellipse to the marker
    center, axes, angle = cv2.fitEllipse(marker_contour)
    major_axis = np.argmax(axes)
    minor_axis = 1 - major_axis
    major_axis_length = axes[major_axis]
    minor_axis_length = axes[minor_axis]
    # Calculate the bounding ellipse eccentricity
    eccentricity = np.sqrt(1 - (axes[minor_axis] / axes[major_axis])**2)

    cv2.drawContours(ref_img, marker_contour, -1, (255, 0, 0), 5)
    analysis_image = ref_img

    # Reset debug mode
    params.debug = debug

    if params.debug is 'print':
        print_image(
            ref_img,
            os.path.join(params.debug_outdir,
                         str(params.device) + '_marker_shape.png'))
    elif params.debug is 'plot':
        plot_image(ref_img)

    outputs.add_observation(variable='marker_area',
                            trait='marker area',
                            method='plantcv.plantcv.report_size_marker_area',
                            scale='pixels',
                            datatype=int,
                            value=marker_area,
                            label='pixels')
    outputs.add_observation(variable='marker_ellipse_major_axis',
                            trait='marker ellipse major axis length',
                            method='plantcv.plantcv.report_size_marker_area',
                            scale='pixels',
                            datatype=int,
                            value=major_axis_length,
                            label='pixels')
    outputs.add_observation(variable='marker_ellipse_minor_axis',
                            trait='marker ellipse minor axis length',
                            method='plantcv.plantcv.report_size_marker_area',
                            scale='pixels',
                            datatype=int,
                            value=minor_axis_length,
                            label='pixels')
    outputs.add_observation(variable='marker_ellipse_eccentricity',
                            trait='marker ellipse eccentricity',
                            method='plantcv.plantcv.report_size_marker_area',
                            scale='none',
                            datatype=float,
                            value=eccentricity,
                            label='none')

    # Store images
    outputs.images.append(analysis_image)

    return analysis_image
def report_size_marker_area(img, roi_contour, roi_hierarchy, marker='define', objcolor='dark', thresh_channel=None,
                            thresh=None):
    """Detects a size marker in a specified region and reports its size and eccentricity

    Inputs:
    img             = An RGB or grayscale image to plot the marker object on
    roi_contour     = A region of interest contour (e.g. output from pcv.roi.rectangle or other methods)
    roi_hierarchy   = A region of interest contour hierarchy (e.g. output from pcv.roi.rectangle or other methods)
    marker          = 'define' or 'detect'. If define it means you set an area, if detect it means you want to
                      detect within an area
    objcolor        = Object color is 'dark' or 'light' (is the marker darker or lighter than the background)
    thresh_channel  = 'h', 's', or 'v' for hue, saturation or value
    thresh          = Binary threshold value (integer)

    Returns:
    analysis_images = List of output images

    :param img: numpy.ndarray
    :param roi_contour: list
    :param roi_hierarchy: numpy.ndarray
    :param marker: str
    :param objcolor: str
    :param thresh_channel: str
    :param thresh: int
    :return: analysis_images: list
    """

    params.device += 1
    # Make a copy of the reference image
    ref_img = np.copy(img)
    # If the reference image is grayscale convert it to color
    if len(np.shape(ref_img)) == 2:
        ref_img = cv2.cvtColor(ref_img, cv2.COLOR_GRAY2BGR)

    # Marker components
    # If the marker type is "defined" then the marker_mask and marker_contours are equal to the input ROI
    # Initialize a binary image
    roi_mask = np.zeros(np.shape(img)[:2], dtype=np.uint8)
    # Draw the filled ROI on the mask
    cv2.drawContours(roi_mask, roi_contour, -1, (255), -1)
    marker_mask = []
    marker_contour = []

    # If the marker type is "detect" then we will use the ROI to isolate marker contours from the input image
    if marker.upper() == 'DETECT':
        # We need to convert the input image into an one of the HSV channels and then threshold it
        if thresh_channel is not None and thresh is not None:
            # Mask the input image
            masked = apply_mask(rgb_img=ref_img, mask=roi_mask, mask_color="black")
            # Convert the masked image to hue, saturation, or value
            marker_hsv = rgb2gray_hsv(rgb_img=masked, channel=thresh_channel)
            # Threshold the HSV image
            marker_bin = binary_threshold(gray_img=marker_hsv, threshold=thresh, max_value=255, object_type=objcolor)
            # Identify contours in the masked image
            contours, hierarchy = find_objects(img=ref_img, mask=marker_bin)
            # Filter marker contours using the input ROI
            kept_contours, kept_hierarchy, kept_mask, obj_area = roi_objects(img=ref_img, object_contour=contours,
                                                                             obj_hierarchy=hierarchy,
                                                                             roi_contour=roi_contour,
                                                                             roi_hierarchy=roi_hierarchy,
                                                                             roi_type="partial")
            # If there are more than one contour detected, combine them into one
            # These become the marker contour and mask
            marker_contour, marker_mask = object_composition(img=ref_img, contours=kept_contours,
                                                             hierarchy=kept_hierarchy)
        else:
            fatal_error('thresh_channel and thresh must be defined in detect mode')
    elif marker.upper() == "DEFINE":
        # Identify contours in the masked image
        contours, hierarchy = find_objects(img=ref_img, mask=roi_mask)
        # If there are more than one contour detected, combine them into one
        # These become the marker contour and mask
        marker_contour, marker_mask = object_composition(img=ref_img, contours=contours, hierarchy=hierarchy)
    else:
        fatal_error("marker must be either 'define' or 'detect' but {0} was provided.".format(marker))

    # Calculate the moments of the defined marker region
    m = cv2.moments(marker_mask, binaryImage=True)
    # Calculate the marker area
    marker_area = m['m00']

    # Fit a bounding ellipse to the marker
    center, axes, angle = cv2.fitEllipse(marker_contour)
    major_axis = np.argmax(axes)
    minor_axis = 1 - major_axis
    major_axis_length = axes[major_axis]
    minor_axis_length = axes[minor_axis]
    # Calculate the bounding ellipse eccentricity
    eccentricity = np.sqrt(1 - (axes[minor_axis] / axes[major_axis]) ** 2)

    # Make a list to store output images
    analysis_image = []
    cv2.drawContours(ref_img, marker_contour, -1, (255, 0, 0), 5)
    # out_file = os.path.splitext(filename)[0] + '_sizemarker.jpg'
    # print_image(ref_img, out_file)
    analysis_image.append(ref_img)
    if params.debug is 'print':
        print_image(ref_img, os.path.join(params.debug_outdir, str(params.device) + '_marker_shape.png'))
    elif params.debug is 'plot':
        plot_image(ref_img)

    outputs.add_observation(variable='marker_area', trait='marker area',
                            method='plantcv.plantcv.report_size_marker_area', scale='pixels', datatype=int,
                            value=marker_area, label='pixels')
    outputs.add_observation(variable='marker_ellipse_major_axis', trait='marker ellipse major axis length',
                            method='plantcv.plantcv.report_size_marker_area', scale='pixels', datatype=int,
                            value=major_axis_length, label='pixels')
    outputs.add_observation(variable='marker_ellipse_minor_axis', trait='marker ellipse minor axis length',
                            method='plantcv.plantcv.report_size_marker_area', scale='pixels', datatype=int,
                            value=minor_axis_length, label='pixels')
    outputs.add_observation(variable='marker_ellipse_eccentricity', trait='marker ellipse eccentricity',
                            method='plantcv.plantcv.report_size_marker_area', scale='none', datatype=float,
                            value=eccentricity, label='none')

    # Store images
    outputs.images.append(analysis_image)

    return analysis_image
def analyze_nir_intensity(gray_img, mask, bins, histplot=False):
    """This function calculates the intensity of each pixel associated with the plant and writes the values out to
       a file. It can also print out a histogram plot of pixel intensity and a pseudocolor image of the plant.

    Inputs:
    gray_img     = 8- or 16-bit grayscale image data
    mask         = Binary mask made from selected contours
    bins         = number of classes to divide spectrum into
    histplot     = if True plots histogram of intensity values

    Returns:
    hist_header  = NIR histogram data table headers
    hist_data    = NIR histogram data table values
    nir_hist     = NIR histogram image

    :param gray_img: numpy array
    :param mask: numpy array
    :param bins: int
    :param histplot: bool
    :return hist_header: list
    :return hist_data: list
    :return nir_hist: str
    """
    import matplotlib
    matplotlib.use('Agg', warn=False)
    from plotnine import ggplot, aes, geom_line, scale_x_continuous
    # from matplotlib import pyplot as plt

    params.device += 1

    # apply plant shaped mask to image
    mask1 = binary_threshold(mask, 0, 255, 'light')
    mask1 = (mask1 / 255)
    masked = np.multiply(gray_img, mask1)

    # calculate histogram
    if gray_img.dtype == 'uint16':
        maxval = 65536
    else:
        maxval = 256

    # Make a pseudo-RGB image
    rgbimg = cv2.cvtColor(gray_img, cv2.COLOR_GRAY2BGR)

    hist_nir, hist_bins = np.histogram(masked, bins, (1, maxval), False, None,
                                       None)

    hist_bins1 = hist_bins[:-1]
    hist_bins2 = [l for l in hist_bins1]

    hist_nir1 = [l for l in hist_nir]

    # make hist percentage for plotting
    pixels = cv2.countNonZero(mask1)
    hist_percent = (hist_nir / float(pixels)) * 100

    # report histogram data
    hist_header = ['HEADER_HISTOGRAM', 'bin-number', 'bin-values', 'nir']

    hist_data = ['HISTOGRAM_DATA', bins, hist_bins2, hist_nir1]

    # No longer returning a pseudocolored image
    # make mask to select the background
    # mask_inv = cv2.bitwise_not(mask)
    # img_back = cv2.bitwise_and(rgbimg, rgbimg, mask=mask_inv)
    # img_back1 = cv2.applyColorMap(img_back, colormap=1)

    # mask the background and color the plant with color scheme 'jet'
    # cplant = cv2.applyColorMap(rgbimg, colormap=2)
    # masked1 = apply_mask(cplant, mask, 'black')
    masked1 = cv2.bitwise_and(rgbimg, rgbimg, mask=mask)
    # cplant_back = cv2.add(masked1, img_back1)
    if params.debug is not None:
        if params.debug == "print":
            print_image(
                masked1,
                os.path.join(params.debug_outdir,
                             str(params.device) + "_masked_nir_plant.jpg"))
        if params.debug == "plot":
            plot_image(masked1)

    nir_hist = []

    if histplot is True:
        hist_x = hist_percent
        bin_labels = np.arange(0, bins)
        dataset = pd.DataFrame({
            'Grayscale pixel intensity': bin_labels,
            'Proportion of pixels (%)': hist_x
        })
        fig_hist = (ggplot(data=dataset,
                           mapping=aes(x='Grayscale pixel intensity',
                                       y='Proportion of pixels (%)')) +
                    geom_line(color='red') +
                    scale_x_continuous(breaks=list(range(0, bins, 25))))
        # plot hist percent
        #         plt.plot(hist_percent, color='green', label='Signal Intensity')
        #         plt.xlim([0, (bins - 1)])
        #         plt.xlabel(('Grayscale pixel intensity (0-' + str(bins) + ")"))
        #         plt.ylabel('Proportion of pixels (%)')

        #         fig_name_hist = (os.path.splitext(filename)[0] + '_nir_hist.svg')
        #         plt.savefig(fig_name_hist)
        nir_hist.append(fig_hist)
        if params.debug is not None:
            if params.debug == "print":
                fig_hist.save(
                    os.path.join(params.debug_outdir,
                                 str(params.device) + '_nir_hist.png'))
            if params.debug == "plot":
                print(fig_hist)

    return hist_header, hist_data, nir_hist
def histogram(gray_img, mask=None, bins=256, color='red', title=None):
    """Plot a histogram using ggplot.

    Inputs:
    gray_img = grayscale image to analyze
    mask     = binary mask made from selected contours
    bins     = number of classes to divide spectrum into
    color    = color of the line drawn
    title    = custom title for the plot gets drawn if title is not None

    :param gray_img: numpy.ndarray
    :param mask: numpy.ndarray
    :param bins: int
    :param color: str
    :param title: str
    :return fig_hist: ggplot
    """

    params.device += 1
    debug = params.debug
    # Apply mask if one is supplied
    if mask is not None:
        # apply plant shaped mask to image
        params.debug = None
        mask1 = binary_threshold(mask, 0, 255, 'light')
        mask1 = (mask1 / 255)
        masked = np.multiply(gray_img, mask1)
    else:
        masked = gray_img

    params.debug = debug

    if gray_img.dtype == 'uint16':
        maxval = 65536
    else:
        maxval = 256

    # Store histogram data
    hist_gray_data, hist_bins = np.histogram(masked, bins, (1, maxval))
    # make hist percentage for plotting
    pixels = cv2.countNonZero(masked)
    hist_percent = (hist_gray_data / float(pixels)) * 100

    hist_x = hist_percent
    bin_labels = np.arange(0, bins)
    dataset = pd.DataFrame({
        'Grayscale pixel intensity': bin_labels,
        'Proportion of pixels (%)': hist_x
    })
    if title is None:
        fig_hist = (ggplot(data=dataset,
                           mapping=aes(x='Grayscale pixel intensity',
                                       y='Proportion of pixels (%)')) +
                    geom_line(color=color) +
                    scale_x_continuous(breaks=list(range(0, bins, 25))))
    elif title is not None:
        fig_hist = (ggplot(data=dataset,
                           mapping=aes(x='Grayscale pixel intensity',
                                       y='Proportion of pixels (%)')) +
                    geom_line(color=color) +
                    scale_x_continuous(breaks=list(range(0, bins, 25))) +
                    labels.ggtitle(title))

    if params.debug is not None:
        if params.debug == "print":
            fig_hist.save(
                os.path.join(params.debug_outdir,
                             str(params.device) + '_hist.png'))
        if params.debug == "plot":
            print(fig_hist)

    return fig_hist
Beispiel #6
0
def plot_hist(gray_img, mask=None, bins=256):
    """Plot a histogram using ggplot.

    Inputs:
    gray_img = grayscale image to analyze
    mask     = binary mask made from selected contours
    bins     = number of classes to divide spectrum into

    :param gray_img: numpy.ndarray
    :param mask: numpy.ndarray
    :param bins: int
    :return bins: list
    :return hist: list
    :return fig_hist: ggplot
    """

    params.device += 1
    debug = params.debug
    # Apply mask if one is supplied
    if mask is not None:
        # apply plant shaped mask to image
        params.debug=None
        mask1 = binary_threshold(mask, 0, 255, 'light')
        mask1 = (mask1 / 255)
        masked = np.multiply(gray_img, mask1)
    else:
        masked = gray_img

    if gray_img.dtype == 'uint16':
        maxval = 65536
    else:
        maxval = 256

    # Store histogram data
    hist_gray_data, hist_bins = np.histogram(masked, bins, (1, maxval), False, None, None)
    hist_bins1 = hist_bins[:-1]
    hist_bins2 = [l for l in hist_bins1]
    hist_gray = [l for l in hist_gray_data]
    # make hist percentage for plotting
    pixels = cv2.countNonZero(masked)
    hist_percent = (hist_gray_data / float(pixels)) * 100

    # report histogram data
    hist_header = [
        'HEADER_HISTOGRAM',
        'bin-number',
        'bin-values',
        'gray_img'
    ]

    hist_data = [
        'HISTOGRAM_DATA',
        bins,
        hist_bins2,
        hist_gray
    ]
    hist_x = hist_percent
    bin_labels = np.arange(0, bins)
    dataset = pd.DataFrame({'Grayscale pixel intensity': bin_labels,
                            'Proportion of pixels (%)': hist_x})
    fig_hist = (ggplot(data=dataset,
                       mapping=aes(x='Grayscale pixel intensity',
                                   y='Proportion of pixels (%)'))
                + geom_line(color='red')
                + scale_x_continuous(breaks=list(range(0, bins, 25))))
    params.debug=debug
    if params.debug is not None:
        if params.debug == "print":
            fig_hist.save(os.path.join(params.debug_outdir, str(params.device) + '_hist.png'))
        if params.debug == "plot":
            print(fig_hist)

    return hist_header, hist_data, fig_hist
def analyze_nir_intensity(gray_img, mask, bins=256, histplot=False):
    """This function calculates the intensity of each pixel associated with the plant and writes the values out to
       a file. It can also print out a histogram plot of pixel intensity and a pseudocolor image of the plant.

    Inputs:
    gray_img     = 8- or 16-bit grayscale image data
    mask         = Binary mask made from selected contours
    bins         = number of classes to divide spectrum into
    histplot     = if True plots histogram of intensity values

    Returns:
    analysis_images = NIR histogram image

    :param gray_img: numpy array
    :param mask: numpy array
    :param bins: int
    :param histplot: bool
    :return analysis_images: list
    """

    params.device += 1

    # apply plant shaped mask to image
    mask1 = binary_threshold(mask, 0, 255, 'light')
    mask1 = (mask1 / 255)
    masked = np.multiply(gray_img, mask1)

    # calculate histogram
    if gray_img.dtype == 'uint16':
        maxval = 65536
    else:
        maxval = 256

    # Make a pseudo-RGB image
    rgbimg = cv2.cvtColor(gray_img, cv2.COLOR_GRAY2BGR)

    hist_nir, hist_bins = np.histogram(masked, bins, (1, maxval))

    hist_bins1 = hist_bins[:-1]
    hist_bins2 = [float(round(l, 2)) for l in hist_bins1]

    hist_nir1 = [float(l) for l in hist_nir]

    # make hist percentage for plotting
    pixels = cv2.countNonZero(mask1)
    hist_percent = (hist_nir / float(pixels)) * 100

    # No longer returning a pseudocolored image
    # make mask to select the background
    # mask_inv = cv2.bitwise_not(mask)
    # img_back = cv2.bitwise_and(rgbimg, rgbimg, mask=mask_inv)
    # img_back1 = cv2.applyColorMap(img_back, colormap=1)

    # mask the background and color the plant with color scheme 'jet'
    # cplant = cv2.applyColorMap(rgbimg, colormap=2)
    # masked1 = apply_mask(cplant, mask, 'black')
    masked1 = cv2.bitwise_and(rgbimg, rgbimg, mask=mask)
    # cplant_back = cv2.add(masked1, img_back1)
    if params.debug is not None:
        if params.debug == "print":
            print_image(masked1, os.path.join(params.debug_outdir, str(params.device) + "_masked_nir_plant.jpg"))
        if params.debug == "plot":
            plot_image(masked1)

    analysis_images = []

    if histplot is True:
        hist_x = hist_percent
        bin_labels = np.arange(0, bins)
        dataset = pd.DataFrame({'Grayscale pixel intensity': bin_labels,
                                'Proportion of pixels (%)': hist_x})
        fig_hist = (ggplot(data=dataset,
                           mapping=aes(x='Grayscale pixel intensity',
                                       y='Proportion of pixels (%)'))
                    + geom_line(color='red')
                    + scale_x_continuous(breaks=list(range(0, bins, 25))))

        analysis_images.append(fig_hist)
        if params.debug == "print":
            fig_hist.save(os.path.join(params.debug_outdir, str(params.device) + '_nir_hist.png'))
        elif params.debug == "plot":
            print(fig_hist)

    outputs.add_observation(variable='nir_frequencies', trait='near-infrared frequencies',
                            method='plantcv.plantcv.analyze_nir_intensity', scale='frequency', datatype=list,
                            value=hist_nir1, label=hist_bins2)

    # Store images
    outputs.images.append(analysis_images)

    return analysis_images
def analyze_nir_intensity(gray_img, mask, bins=256, histplot=False):
    """This function calculates the intensity of each pixel associated with the plant and writes the values out to
       a file. It can also print out a histogram plot of pixel intensity and a pseudocolor image of the plant.

    Inputs:
    gray_img     = 8- or 16-bit grayscale image data
    mask         = Binary mask made from selected contours
    bins         = number of classes to divide spectrum into
    histplot     = if True plots histogram of intensity values

    Returns:
    analysis_images = NIR histogram image

    :param gray_img: numpy array
    :param mask: numpy array
    :param bins: int
    :param histplot: bool
    :return analysis_images: plotnine ggplot
    """
    # apply plant shaped mask to image
    mask1 = binary_threshold(mask, 0, 255, 'light')
    mask1 = (mask1 / 255)
    # masked = np.multiply(gray_img, mask1)

    # calculate histogram
    if gray_img.dtype == 'uint16':
        maxval = 65536
    else:
        maxval = 256

    masked_array = gray_img[np.where(mask > 0)]
    masked_nir_mean = np.average(masked_array)
    masked_nir_median = np.median(masked_array)
    masked_nir_std = np.std(masked_array)

    # Make a pseudo-RGB image
    rgbimg = cv2.cvtColor(gray_img, cv2.COLOR_GRAY2BGR)

    # Calculate histogram
    hist_nir = [
        float(i[0])
        for i in cv2.calcHist([gray_img], [0], mask, [bins], [0, maxval])
    ]
    # Create list of bin labels
    bin_width = maxval / float(bins)
    b = 0
    bin_labels = [float(b)]
    for i in range(bins - 1):
        b += bin_width
        bin_labels.append(b)

    # make hist percentage for plotting
    pixels = cv2.countNonZero(mask1)
    hist_percent = [(p / float(pixels)) * 100 for p in hist_nir]

    masked1 = cv2.bitwise_and(rgbimg, rgbimg, mask=mask)
    if params.debug is not None:
        params.device += 1
        if params.debug == "print":
            print_image(
                masked1,
                os.path.join(params.debug_outdir,
                             str(params.device) + "_masked_nir_plant.png"))
        if params.debug == "plot":
            plot_image(masked1)

    analysis_image = None

    if histplot is True:
        hist_x = hist_percent
        # bin_labels = np.arange(0, bins)
        dataset = pd.DataFrame({
            'Grayscale pixel intensity': bin_labels,
            'Proportion of pixels (%)': hist_x
        })
        fig_hist = (ggplot(data=dataset,
                           mapping=aes(x='Grayscale pixel intensity',
                                       y='Proportion of pixels (%)')) +
                    geom_line(color='red') +
                    scale_x_continuous(breaks=list(range(0, maxval, 25))))

        analysis_image = fig_hist
        if params.debug == "print":
            fig_hist.save(os.path.join(params.debug_outdir,
                                       str(params.device) + '_nir_hist.png'),
                          verbose=False)
        elif params.debug == "plot":
            print(fig_hist)

    outputs.add_observation(variable='nir_frequencies',
                            trait='near-infrared frequencies',
                            method='plantcv.plantcv.analyze_nir_intensity',
                            scale='frequency',
                            datatype=list,
                            value=hist_nir,
                            label=bin_labels)
    outputs.add_observation(variable='nir_mean',
                            trait='near-infrared mean',
                            method='plantcv.plantcv.analyze_nir_intensity',
                            scale='none',
                            datatype=float,
                            value=masked_nir_mean,
                            label='none')
    outputs.add_observation(variable='nir_median',
                            trait='near-infrared median',
                            method='plantcv.plantcv.analyze_nir_intensity',
                            scale='none',
                            datatype=float,
                            value=masked_nir_median,
                            label='none')
    outputs.add_observation(variable='nir_stdev',
                            trait='near-infrared standard deviation',
                            method='plantcv.plantcv.analyze_nir_intensity',
                            scale='none',
                            datatype=float,
                            value=masked_nir_std,
                            label='none')

    # Store images
    outputs.images.append(analysis_image)

    return analysis_image
def analyze_nir_intensity(gray_img,
                          mask,
                          bins,
                          histplot=False,
                          filename=False):
    """This function calculates the intensity of each pixel associated with the plant and writes the values out to
       a file. It can also print out a histogram plot of pixel intensity and a pseudocolor image of the plant.

    Inputs:
    gray_img     = 8- or 16-bit grayscale image data
    mask         = Binary mask made from selected contours
    bins         = number of classes to divide spectrum into
    histplot     = if True plots histogram of intensity values
    filename     = False or image name. If defined print image

    Returns:
    hist_header  = NIR histogram data table headers
    hist_data    = NIR histogram data table values
    analysis_img = output image

    :param gray_img: numpy array
    :param mask: numpy array
    :param bins: int
    :param histplot: bool
    :param filename: str
    :return hist_header: list
    :return hist_data: list
    :return analysis_img: str
    """
    params.device += 1

    # apply plant shaped mask to image
    mask1 = binary_threshold(mask, 0, 255, 'light')
    mask1 = (mask1 / 255)
    masked = np.multiply(gray_img, mask1)

    # calculate histogram
    if gray_img.dtype == 'uint16':
        maxval = 65536
    else:
        maxval = 256

    # Make a pseudo-RGB image
    rgbimg = cv2.cvtColor(gray_img, cv2.COLOR_GRAY2BGR)

    hist_nir, hist_bins = np.histogram(masked, bins, (1, maxval), False, None,
                                       None)

    hist_bins1 = hist_bins[:-1]
    hist_bins2 = [l for l in hist_bins1]

    hist_nir1 = [l for l in hist_nir]

    # make hist percentage for plotting
    pixels = cv2.countNonZero(mask1)
    hist_percent = (hist_nir / float(pixels)) * 100

    # report histogram data
    hist_header = ['HEADER_HISTOGRAM', 'bin-number', 'bin-values', 'nir']

    hist_data = ['HISTOGRAM_DATA', bins, hist_bins2, hist_nir1]

    analysis_img = []

    # make mask to select the background
    mask_inv = cv2.bitwise_not(mask)
    img_back = cv2.bitwise_and(rgbimg, rgbimg, mask=mask_inv)
    img_back1 = cv2.applyColorMap(img_back, colormap=1)

    # mask the background and color the plant with color scheme 'jet'
    cplant = cv2.applyColorMap(rgbimg, colormap=2)
    masked1 = apply_mask(cplant, mask, 'black')
    cplant_back = cv2.add(masked1, img_back1)

    if filename:
        path = os.path.dirname(filename)
        fig_name = 'NIR_pseudocolor_colorbar.svg'
        if not os.path.isfile(path + '/' + fig_name):
            plot_colorbar(path, fig_name, bins)

        fig_name_pseudo = (os.path.splitext(filename)[0] +
                           '_nir_pseudo_col.jpg')
        print_image(cplant_back, fig_name_pseudo)
        analysis_img.append(['IMAGE', 'pseudo', fig_name_pseudo])

    if params.debug is not None:
        if params.debug == "print":
            print_image(
                masked1,
                os.path.join(params.debug_outdir,
                             str(params.device) + "_nir_pseudo_plant.jpg"))
            print_image(
                cplant_back,
                os.path.join(params.debug_outdir,
                             str(params.device) +
                             "_nir_pseudo_plant_back.jpg"))
        if params.debug == "plot":
            plot_image(masked1)
            plot_image(cplant_back)

    if histplot is True:
        import matplotlib
        matplotlib.use('Agg', warn=False)
        from matplotlib import pyplot as plt

        # plot hist percent
        plt.plot(hist_percent, color='green', label='Signal Intensity')
        plt.xlim([0, (bins - 1)])
        plt.xlabel(('Grayscale pixel intensity (0-' + str(bins) + ")"))
        plt.ylabel('Proportion of pixels (%)')

        if filename:
            fig_name_hist = (os.path.splitext(filename)[0] + '_nir_hist.svg')
            plt.savefig(fig_name_hist)
            analysis_img.append(['IMAGE', 'hist', fig_name_hist])
        if params.debug == "print":
            plt.savefig(
                os.path.join(params.debug_outdir,
                             str(params.device) + "_nir_histogram.png"))
        if params.debug == "plot":
            plt.figure()
        plt.clf()

    return hist_header, hist_data, analysis_img
def analyze_thermal_values(thermal_array, mask, histplot=False):
    """This extracts the thermal values of each pixel writes the values out to
       a file. It can also print out a histogram plot of pixel intensity
       and a pseudocolor image of the plant.

    Inputs:
    array        = numpy array of thermal values
    mask         = Binary mask made from selected contours
    histplot     = if True plots histogram of intensity values

    Returns:
    analysis_img = output image

    :param thermal_array: numpy.ndarray
    :param mask: numpy.ndarray
    :param histplot: bool
    :return analysis_img: ggplot
    """
    max_value = np.amax(thermal_array)
    # Calculate histogram
    hist_thermal = [
        float(i[0]) for i in cv2.calcHist([np.float32(thermal_array)], [0],
                                          mask, [256], [0, max_value])
    ]
    bin_width = max_value / 256.
    b = 0
    bin_labels = [float(b)]
    for i in range(255):
        b += bin_width
        bin_labels.append(b)

    # Store debug mode
    debug = params.debug
    params.debug = None

    # apply plant shaped mask to image
    mask1 = binary_threshold(mask, 0, 255, 'light')
    params.debug = debug

    mask1 = (mask1 / 255)
    masked_thermal = thermal_array[np.where(mask > 0)]

    pixels = cv2.countNonZero(mask1)
    hist_percent = [(p / float(pixels)) * 100 for p in hist_thermal]

    maxtemp = np.amax(masked_thermal)
    mintemp = np.amin(masked_thermal)
    avgtemp = np.average(masked_thermal)
    mediantemp = np.median(masked_thermal)

    # Store data into outputs class
    outputs.add_observation(variable='max_temp',
                            trait='maximum temperature',
                            method='plantcv.plantcv.analyze_thermal_values',
                            scale='degrees',
                            datatype=float,
                            value=maxtemp,
                            label='degrees')
    outputs.add_observation(variable='min_temp',
                            trait='minimum temperature',
                            method='plantcv.plantcv.analyze_thermal_values',
                            scale='degrees',
                            datatype=float,
                            value=mintemp,
                            label='degrees')
    outputs.add_observation(variable='mean_temp',
                            trait='mean temperature',
                            method='plantcv.plantcv.analyze_thermal_values',
                            scale='degrees',
                            datatype=float,
                            value=avgtemp,
                            label='degrees')
    outputs.add_observation(variable='median_temp',
                            trait='median temperature',
                            method='plantcv.plantcv.analyze_thermal_values',
                            scale='degrees',
                            datatype=float,
                            value=mediantemp,
                            label='degrees')
    outputs.add_observation(variable='thermal_frequencies',
                            trait='thermal frequencies',
                            method='plantcv.plantcv.analyze_thermal_values',
                            scale='frequency',
                            datatype=list,
                            value=hist_percent,
                            label=bin_labels)
    analysis_img = None

    if histplot is True:
        params.device += 1

        dataset = pd.DataFrame({
            'Temperature C': bin_labels,
            'Proportion of pixels (%)': hist_percent
        })
        fig_hist = (ggplot(data=dataset,
                           mapping=aes(x='Temperature C',
                                       y='Proportion of pixels (%)')) +
                    geom_line(color='green'))

        analysis_img = fig_hist
        if params.debug == "print":
            fig_hist.save(os.path.join(
                params.debug_outdir,
                str(params.device) + '_therm_histogram.png'),
                          verbose=False)
        elif params.debug == "plot":
            print(fig_hist)

    return analysis_img
Beispiel #11
0
def analyze_nir_intensity(gray_img, mask, bins, histplot=False):
    """This function calculates the intensity of each pixel associated with the plant and writes the values out to
       a file. It can also print out a histogram plot of pixel intensity and a pseudocolor image of the plant.

    Inputs:
    gray_img     = 8- or 16-bit grayscale image data
    mask         = Binary mask made from selected contours
    bins         = number of classes to divide spectrum into
    histplot     = if True plots histogram of intensity values

    Returns:
    hist_header     = NIR histogram data table headers
    hist_data       = NIR histogram data table values
    analysis_images = NIR histogram image

    :param gray_img: numpy array
    :param mask: numpy array
    :param bins: int
    :param histplot: bool
    :return hist_header: list
    :return hist_data: list
    :return analysis_images: list
    """

    params.device += 1

    # apply plant shaped mask to image
    mask1 = binary_threshold(mask, 0, 255, 'light')
    mask1 = (mask1 / 255)
    masked = np.multiply(gray_img, mask1)

    # calculate histogram
    if gray_img.dtype == 'uint16':
        maxval = 65536
    else:
        maxval = 256

    # Make a pseudo-RGB image
    rgbimg = cv2.cvtColor(gray_img, cv2.COLOR_GRAY2BGR)

    hist_nir, hist_bins = np.histogram(masked, bins, (1, maxval))

    hist_bins1 = hist_bins[:-1]
    hist_bins2 = [round(l, 2) for l in hist_bins1]

    hist_nir1 = [l for l in hist_nir]

    # make hist percentage for plotting
    pixels = cv2.countNonZero(mask1)
    hist_percent = (hist_nir / float(pixels)) * 100

    # report histogram data
    hist_header = ['HEADER_HISTOGRAM', 'bin-number', 'bin-values', 'nir']

    hist_data = ['HISTOGRAM_DATA', bins, hist_bins2, hist_nir1]

    # No longer returning a pseudocolored image
    # make mask to select the background
    # mask_inv = cv2.bitwise_not(mask)
    # img_back = cv2.bitwise_and(rgbimg, rgbimg, mask=mask_inv)
    # img_back1 = cv2.applyColorMap(img_back, colormap=1)

    # mask the background and color the plant with color scheme 'jet'
    # cplant = cv2.applyColorMap(rgbimg, colormap=2)
    # masked1 = apply_mask(cplant, mask, 'black')
    masked1 = cv2.bitwise_and(rgbimg, rgbimg, mask=mask)
    # cplant_back = cv2.add(masked1, img_back1)
    if params.debug is not None:
        if params.debug == "print":
            print_image(
                masked1,
                os.path.join(params.debug_outdir,
                             str(params.device) + "_masked_nir_plant.jpg"))
        if params.debug == "plot":
            plot_image(masked1)

    analysis_images = []

    if histplot is True:
        hist_x = hist_percent
        bin_labels = np.arange(0, bins)
        dataset = pd.DataFrame({
            'Grayscale pixel intensity': bin_labels,
            'Proportion of pixels (%)': hist_x
        })
        fig_hist = (ggplot(data=dataset,
                           mapping=aes(x='Grayscale pixel intensity',
                                       y='Proportion of pixels (%)')) +
                    geom_line(color='red') +
                    scale_x_continuous(breaks=list(range(0, bins, 25))))

        analysis_images.append(fig_hist)
        if params.debug == "print":
            fig_hist.save(
                os.path.join(params.debug_outdir,
                             str(params.device) + '_nir_hist.png'))
        elif params.debug == "plot":
            print(fig_hist)

    # Store into global measurements
    if not 'nir_histogram' in outputs.measurements:
        outputs.measurements['nir_histogram'] = {}
    outputs.measurements['nir_histogram']['signal_values'] = hist_bins2
    outputs.measurements['nir_histogram']['frequency'] = hist_nir1

    # Store images
    outputs.images.append(analysis_images)

    return hist_header, hist_data, analysis_images