Skip to content

Commit

Permalink
Merge branch 'master' into cluster_functions
Browse files Browse the repository at this point in the history
  • Loading branch information
HaleySchuhl committed Mar 8, 2019
2 parents 9f3f59a + d41d46a commit f65e65f
Show file tree
Hide file tree
Showing 13 changed files with 129 additions and 92 deletions.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added docs/img/documentation_images/plot_hist/hist.jpg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added docs/img/documentation_images/plot_hist/mask.jpg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
36 changes: 18 additions & 18 deletions docs/multi-plant_tutorial.md
Original file line number Diff line number Diff line change
Expand Up @@ -178,7 +178,7 @@ Convert the image from [RGB to LAB](rgb2lab.md) and select single color channel
# STEP 5: Convert image from RGB colorspace to LAB colorspace
# Keep only the green-magenta channel (grayscale)
# Inputs:
# img = image object, RGB colorspace
# rgb_img = image object, RGB colorspace
# channel = color subchannel ('l' = lightness, 'a' = green-magenta , 'b' = blue-yellow)

a = pcv.rgb2gray_lab(img1, 'a')
Expand All @@ -194,7 +194,7 @@ Use the [binary threshold](binary_threshold.md) function to threshold green-mage

# STEP 6: Set a binary threshold on the saturation channel image
# Inputs:
# img = img object, grayscale
# gray_img = img object, grayscale
# threshold = threshold value (0-255)
# maxValue = value to apply above threshold (usually 255 = white)
# object_type = light or dark
Expand All @@ -217,8 +217,8 @@ img_binary = pcv.threshold.binary(a, 120, 255, 'dark')

# STEP 7: Fill in small objects (speckles)
# Inputs:
# img = image object, grayscale. img will be returned after filling
# size = minimum object area size in pixels (integer)
# bin_img = image object, grayscale. img will be returned after filling
# size = minimum object area size in pixels (integer)

fill_image = pcv.fill(img_binary, 100)
# ^
Expand All @@ -236,9 +236,9 @@ fill_image = pcv.fill(img_binary, 100)

# STEP 8: Dilate so that you don't lose leaves (just in case)
# Inputs:
# img = input image
# kernel = integer
# i = iterations, i.e. number of consecutive filtering passes
# gray_img = input image
# ksize = kernel size, integer
# i = iterations, i.e. number of consecutive filtering passes

dilated = pcv.dilate(fill_image, 1, 1)
```
Expand Down Expand Up @@ -269,17 +269,17 @@ Define a [rectangular region of interest](roi_rectangle.md) in the image.

# STEP 10: Define region of interest (ROI)
# Inputs:
# img = img to overlay roi
# x_adj = adjust center along x axis
# y_adj = adjust center along y axis
# w_adj = adjust width
# h_adj = adjust height
# img = img to overlay roi
# roi_contour, roi_hierarchy = pcv.roi.rectangle(10, 500, -10, -100, img1)
# ^ ^
# |________________|
# roi_contour, roi_hierarchy = pcv.roi.rectangle(img1, 10, 500, -10, -100)
# ^ ^
# |________________|
# adjust these four values

roi_contour, roi_hierarchy = pcv.roi.rectangle(10, 500, -10, -100, img1)
roi_contour, roi_hierarchy = pcv.roi.rectangle(img1, 10, 500, -10, -100)
```

**Figure 10.** Define ROI.
Expand Down Expand Up @@ -320,7 +320,7 @@ roi_objects, roi_obj_hierarchy, kept_mask, obj_area = pcv.roi_objects(img1, 'par
# clusters them based on user input of rows and columns

# Inputs:
# img = An RGB image
# img = An RGB or grayscale image
# roi_objects = object contours in an image that are needed to be clustered.
# roi_obj_hierarchy = object hierarchy
# nrow = number of rows to cluster (this should be the approximate number of desired rows in the entire image even if there isn't a literal row of plants)
Expand Down Expand Up @@ -530,17 +530,17 @@ def main():

# STEP 10: Define region of interest (ROI)
# Inputs:
# img = img to overlay roi
# x_adj = adjust center along x axis
# y_adj = adjust center along y axis
# w_adj = adjust width
# h_adj = adjust height
# img = img to overlay roi
# roi_contour, roi_hierarchy = pcv.roi.rectangle(10, 500, -10, -100, img1)
# ^ ^
# |________________|
# roi_contour, roi_hierarchy = pcv.roi.rectangle(img1, 10, 500, -10, -100)
# ^ ^
# |________________|
# adjust these four values

roi_contour, roi_hierarchy = pcv.roi.rectangle(10, 500, -10, -100, img1)
roi_contour, roi_hierarchy = pcv.roi.rectangle(img1, 10, 500, -10, -100)

# STEP 11: Keep objects that overlap with the ROI
# Inputs:
Expand Down
14 changes: 6 additions & 8 deletions docs/nir_tutorial.md
Original file line number Diff line number Diff line change
Expand Up @@ -136,13 +136,13 @@ the amount of plant material captured, and it is particularly useful if estimati
```python
# Laplace filtering (identify edges based on 2nd derivative)
lp_img = pcv.laplace_filter(img, 1, 1)
if args.debug:
pcv.plot_hist(lp_img, 'hist_lp')
# Plot histogram of grayscale values
pcv.plot_hist(lp_img)

# Lapacian image sharpening, this step will enhance the darkness of the edges detected
lp_shrp_img = pcv.image_subtract(img, lp_img)
if args.debug:
pcv.plot_hist(lp_sharp_img, 'hist_lp_sharp')
# Plot histogram of grayscale values, this helps to determine thresholding value
pcv.plot_hist(lp_sharp_img)
```

**Figure 3.** (Top) Result after second derivative Laplacian filter is applied to the original grayscale image.
Expand Down Expand Up @@ -439,13 +439,11 @@ def main():

# Laplace filtering (identify edges based on 2nd derivative)
lp_img = pcv.laplace_filter(img, 1, 1)
if args.debug:
pcv.plot_hist(lp_img, 'hist_lp')
pcv.plot_hist(lp_img)

# Lapacian image sharpening, this step will enhance the darkness of the edges detected
lp_shrp_img = pcv.image_subtract(img, lp_img)
if args.debug:
pcv.plot_hist(lp_shrp_img, 'hist_lp_sharp')
pcv.plot_hist(lp_shrp_img)

# Sobel filtering
# 1st derivative sobel filtering along horizontal axis, kernel = 1)
Expand Down
19 changes: 12 additions & 7 deletions docs/plot_hist.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,31 +2,36 @@

This is a plotting method used to examine the distribution of signal within an image.

**plantcv.plot_hist**(*img, name=False*)
**plantcv.plot_hist**(*gray_img, mask=None, bins=256*)

**returns** bins, hist

- **Parameters:**
- img - RGB or grayscale image data, the original image for analysis.
- name - the name of the output plot as a string (default: name=False)
- gray_img - Grayscale image data, the original image for analysis.
- mask - Optional binary mask made from selected contours (default mask=None)
- bins - Number of class to divide spectrum into
- **Context:**
- Examine the distribution of the signal, this help you select a value for binary thresholding.
- Examine the distribution of the signal, this helps you select a value for binary thresholding.
- **Example use:**
- [Use In NIR Tutorial](nir_tutorial.md)

**Grayscale image**

![Screenshot](img/documentation_images/plot_hist/grayscale_image.jpg)
![Screenshot](img/documentation_images/plot_hist/01_hsv_saturation.jpg)

**Mask**

![Screenshot](img/documentation_images/plot_hist/mask.jpg)

```python

from plantcv import plantcv as pcv

# Examine signal distribution within an image
# prints out an image histogram of signal within image
bins, hist = pcv.plot_hist(img, 'histogram')
header, hist_data, hist_figure = pcv.plot_hist(gray_img, mask=mask, bins=256)
```

**Histogram of signal intensity**

![Screenshot](img/documentation_images/plot_hist/histogram.jpg)
![Screenshot](img/documentation_images/plot_hist/hist.jpg)
2 changes: 1 addition & 1 deletion docs/roi_multi.md
Original file line number Diff line number Diff line change
Expand Up @@ -67,7 +67,7 @@ for i in range(0, len(rois1)):
plant_contour, plant_mask = pcv.object_composition(img=img, contours=filtered_contours, hierarchy=filtered_hierarchy)

# Analyze the shape of each plant
shape_data_headers, shape_data, analysis_images = pcv.analyze_object(img=img_copy, obj=obj, mask=img_mask)
shape_data_headers, shape_data, analysis_images = pcv.analyze_object(img=img_copy, obj=plant_contour, mask=plant_mask)

# Save the image with shape characteristics
img_copy = analysis_images[0]
Expand Down
2 changes: 1 addition & 1 deletion docs/updating.md
Original file line number Diff line number Diff line change
Expand Up @@ -361,7 +361,7 @@ post v3.0: new_img = **plantcv.image_subtract**(*gray_img1, gray_img2*)

* pre v3.0dev2: bins, hist = **plantcv.plot_hist**(*img, name=False*)
* post v3.0dev2: bins, hist = **plantcv.plot_hist**(*img, name=False*)
* post v3.2: header, hist_data, hist_figure = **pcv.plot_hist**(*gray_img, mask=None, bins=256*)
* post v3.2: hist_header, hist_data, fig_hist = **plantcv.plot_hist**(*gray_img, mask=None, bins=256*)

#### plantcv.plot_image

Expand Down
6 changes: 3 additions & 3 deletions docs/vis_nir_tutorial.md
Original file line number Diff line number Diff line change
Expand Up @@ -207,7 +207,7 @@ Next, a [rectangular region of interest](roi_rectangle.md) is defined (this can
```python

# Define ROI
roi1, roi_hierarchy= pcv.roi.rectangle(600,450,-600,-700, img)
roi1, roi_hierarchy= pcv.roi.rectangle(img,600,450,-600,-700)
```

**Figure 9.** Region of interest drawn onto image.
Expand Down Expand Up @@ -350,7 +350,7 @@ Write co-result data out to a file.
pcv.print_result(filename=args.coresult)

if __name__ == '__main__':
main()
main()
```

To deploy a pipeline over a full image set please see tutorial on
Expand Down Expand Up @@ -426,7 +426,7 @@ def main():
id_objects,obj_hierarchy = pcv.find_objects(masked, bs)

# Define ROI
roi1, roi_hierarchy= pcv.roi.rectangle(600,450,-600,-700, img)
roi1, roi_hierarchy= pcv.roi.rectangle(img,600,450,-600,-700)

# Decide which objects to keep
roi_objects, hierarchy, kept_mask, obj_area = pcv.roi_objects(img,'partial',roi1,roi_hierarchy,id_objects,obj_hierarchy)
Expand Down
2 changes: 1 addition & 1 deletion docs/vis_tutorial.md
Original file line number Diff line number Diff line change
Expand Up @@ -265,7 +265,7 @@ Next a [rectangular region of interest](roi_rectangle.md) is defined (this can b
```python

# Define ROI
roi1, roi_hierarchy= pcv.roi.rectangle(x=100, y=100, h=200, w=200, img=masked2)
roi1, roi_hierarchy= pcv.roi.rectangle(img=masked2, x=100, y=100, h=200, w=200)
```

**Figure 12.** Region of interest drawn onto image.
Expand Down
17 changes: 8 additions & 9 deletions plantcv/plantcv/analyze_nir_intensity.py
Original file line number Diff line number Diff line change
Expand Up @@ -23,17 +23,17 @@ def analyze_nir_intensity(gray_img, mask, bins, histplot=False):
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
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 nir_hist: str
:return analysis_images: list
"""

params.device += 1
Expand Down Expand Up @@ -109,11 +109,10 @@ def analyze_nir_intensity(gray_img, mask, bins, histplot=False):
+ scale_x_continuous(breaks=list(range(0, bins, 25))))

analysis_images.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)
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:
Expand Down
107 changes: 70 additions & 37 deletions plantcv/plantcv/plot_hist.py
Original file line number Diff line number Diff line change
@@ -1,52 +1,85 @@
# Plot histogram

import cv2
import os
import numpy as np
from matplotlib import pyplot as plt
from plantcv.plantcv.threshold import binary as binary_threshold
from plantcv.plantcv import params
import pandas as pd
from plotnine import ggplot, aes, geom_line, scale_x_continuous


def plot_hist(img, name=False):
"""Plot a histogram using the pyplot library.

def plot_hist(gray_img, mask=None, bins=256):
"""Plot a histogram using ggplot.
Inputs:
img = image to analyze
name = name for plot output
gray_img = image to analyze
mask = binary mask made from selected contours
bins = number of classes to divide spectrum into
:param img: numpy.ndarray
:param name: str
:param gray_img: numpy.ndarray
:param mask: numpy.ndarray
:param bins: int
:return bins: list
:return hist: list
:return fig_hist: ggplot
"""

# get histogram
if img.dtype == 'uint8':
hist = cv2.calcHist([img], [0], None, [256], [0, 255])
bins = range(0, 256, 1)

if name is not False:
# open pyplot plotting window using hist data
plt.plot(hist)
# set range of x-axis
xaxis = plt.xlim([0, 255])
fig_name = name + '.png'
# write the figure to current directory
plt.savefig(fig_name)
# close pyplot plotting window
plt.clf()
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:
hist, bins = np.histogram(img, bins='auto')

if name is not False:
# open pyplot plotting window using hist data
plt.plot(bins[:-1], hist)
plt.xticks(bins[:-1], rotation='vertical', fontsize=4)
# set range of x-axis
# xaxis = plt.xlim([0, bins.max()])
fig_name = name + '.png'
# write the figure to current directory
plt.savefig(fig_name)
# close pyplot plotting window
plt.clf()

return bins, hist
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
Loading

0 comments on commit f65e65f

Please sign in to comment.