Repository: danforthcenter/plantcv
Issue: NIR frequency table output range does not include zero

<!--- 
Thanks for contributing your input! Instructions are in comments, like this.
 
Please edit this template before submitting a new issue.
-->

<!--- 
Title: Please provide a descriptive title that summarizes your feature / question / issue.
-->

<!---
Labels: Please select one or more relevant tags (menu on the right).
(This only shows up for administrators.)
--->

### Description
<!---
Please provide a general summary of your feature / question / issue. 

Is there something you want to do? Is this a bug? Feature request? Discussion? 
  * Question: ask away!
  * New feature / analysis.
  * Bug: what were you trying to do? What did you expect to happen? What happened? 
-->

`plantcv.analyze_nir_intensity` outputs an NIR frequency table with somewhat odd bin labels:

```
            "observations": {
                "nir_frequencies": {
                    "trait": "near-infrared frequencies",
                    "method": "plantcv.plantcv.analyze_nir_intensity",
                    "scale": "frequency",
                    "datatype": "<class 'list'>",
                    "value": [
                        0,
                        0,
                        0,
                        0,
                        0,
                        0,
                        0,
                        0,
                        0,
                        0,
                        0,
                        0,
                        0,
                        0,
                        0,
                        0,
                        0,
                        0,
                        0,
                        0,
                        0,
                        0,
                        0,
                        0,
                        0,
                        0,
                        0,
                        0,
                        0,
                        0,
                        0,
                        0,
                        0,
                        0,
                        0,
                        0,
                        0,
                        0,
                        0,
                        0,
                        0,
                        0,
                        0,
                        0,
                        0,
                        0,
                        0,
                        0,
                        0,
                        0,
                        0,
                        0,
                        0,
                        0,
                        0,
                        1,
                        3,
                        3,
                        2,
                        8,
                        9,
                        3,
                        5,
                        2,
                        8,
                        2,
                        3,
                        3,
                        2,
                        4,
                        3,
                        2,
                        3,
                        3,
                        4,
                        4,
                        4,
                        4,
                        4,
                        1,
                        1,
                        3,
                        3,
                        3,
                        6,
                        7,
                        6,
                        13,
                        13,
                        8,
                        7,
                        8,
                        10,
                        12,
                        10,
                        11,
                        6,
                        14,
                        14,
                        14,
                        8,
                        9,
                        9,
                        9,
                        9,
                        9,
                        5,
                        7,
                        6,
                        7,
                        4,
                        5,
                        8,
                        5,
                        6,
                        3,
                        5,
                        5,
                        5,
                        5,
                        7,
                        6,
                        7,
                        5,
                        5,
                        6,
                        12,
                        7,
                        10,
                        15,
                        14,
                        12,
                        15,
                        11,
                        4,
                        9,
                        10,
                        4,
                        15,
                        10,
                        11,
                        6,
                        18,
                        11,
                        5,
                        7,
                        4,
                        5,
                        5,
                        10,
                        5,
                        10,
                        6,
                        11,
                        12,
                        8,
                        6,
                        1,
                        8,
                        9,
                        9,
                        11,
                        9,
                        9,
                        7,
                        13,
                        6,
                        4,
                        7,
                        8,
                        7,
                        8,
                        4,
                        4,
                        9,
                        3,
                        1,
                        1,
                        2,
                        5,
                        9,
                        3,
                        7,
                        10,
                        10,
                        5,
                        2,
                        5,
                        4,
                        0,
                        1,
                        1,
                        1,
                        2,
                        1,
                        0,
                        0,
                        0,
                        0,
                        1,
                        1,
                        0,
                        2,
                        1,
                        0,
                        0,
                        0,
                        0,
                        0,
                        0,
                        0,
                        0,
                        0,
                        0,
                        0,
                        0,
                        0,
                        0,
                        0,
                        0,
                        0,
                        0,
                        0,
                        0,
                        0,
                        0,
                        0,
                        0,
                        0,
                        0,
                        0,
                        0,
                        0,
                        0,
                        0,
                        0,
                        0,
                        0,
                        0,
                        0,
                        0,
                        0,
                        0,
                        0,
                        0,
                        0,
                        0,
                        0,
                        0,
                        0,
                        0,
                        0,
                        0,
                        0,
                        0,
                        0
                    ],
                    "label": [
                        1,
                        2,
                        2.99,
                        3.99,
                        4.98,
                        5.98,
                        6.98,
                        7.97,
                        8.97,
                        9.96,
                        10.96,
                        11.96,
                        12.95,
                        13.95,
                        14.95,
                        15.94,
                        16.94,
                        17.93,
                        18.93,
                        19.93,
                        20.92,
                        21.92,
                        22.91,
                        23.91,
                        24.91,
                        25.9,
                        26.9,
                        27.89,
                        28.89,
                        29.89,
                        30.88,
                        31.88,
                        32.88,
                        33.87,
                        34.87,
                        35.86,
                        36.86,
                        37.86,
                        38.85,
                        39.85,
                        40.84,
                        41.84,
                        42.84,
                        43.83,
                        44.83,
                        45.82,
                        46.82,
                        47.82,
                        48.81,
                        49.81,
                        50.8,
                        51.8,
                        52.8,
                        53.79,
                        54.79,
                        55.79,
                        56.78,
                        57.78,
                        58.77,
                        59.77,
                        60.77,
                        61.76,
                        62.76,
                        63.75,
                        64.75,
                        65.75,
                        66.74,
                        67.74,
                        68.73,
                        69.73,
                        70.73,
                        71.72,
                        72.72,
                        73.71,
                        74.71,
                        75.71,
                        76.7,
                        77.7,
                        78.7,
                        79.69,
                        80.69,
                        81.68,
                        82.68,
                        83.68,
                        84.67,
                        85.67,
                        86.66,
                        87.66,
                        88.66,
                        89.65,
                        90.65,
                        91.64,
                        92.64,
                        93.64,
                        94.63,
                        95.63,
                        96.62,
                        97.62,
                        98.62,
                        99.61,
                        100.61,
                        101.61,
                        102.6,
                        103.6,
                        104.59,
                        105.59,
                        106.59,
                        107.58,
                        108.58,
                        109.57,
                        110.57,
                        111.57,
                        112.56,
                        113.56,
                        114.55,
                        115.55,
                        116.55,
                        117.54,
                        118.54,
                        119.54,
                        120.53,
                        121.53,
                        122.52,
                        123.52,
                        124.52,
                        125.51,
                        126.51,
                        127.5,
                        128.5,
                        129.5,
                        130.49,
                        131.49,
                        132.48,
                        133.48,
                        134.48,
                        135.47,
                        136.47,
                        137.46,
                        138.46,
                        139.46,
                        140.45,
                        141.45,
                        142.45,
                        143.44,
                        144.44,
                        145.43,
                        146.43,
                        147.43,
                        148.42,
                        149.42,
                        150.41,
                        151.41,
                        152.41,
                        153.4,
                        154.4,
                        155.39,
                        156.39,
                        157.39,
                        158.38,
                        159.38,
                        160.38,
                        161.37,
                        162.37,
                        163.36,
                        164.36,
                        165.36,
                        166.35,
                        167.35,
                        168.34,
                        169.34,
                        170.34,
                        171.33,
                        172.33,
                        173.32,
                        174.32,
                        175.32,
                        176.31,
                        177.31,
                        178.3,
                        179.3,
                        180.3,
                        181.29,
                        182.29,
                        183.29,
                        184.28,
                        185.28,
                        186.27,
                        187.27,
                        188.27,
                        189.26,
                        190.26,
                        191.25,
                        192.25,
                        193.25,
                        194.24,
                        195.24,
                        196.23,
                        197.23,
                        198.23,
                        199.22,
                        200.22,
                        201.21,
                        202.21,
                        203.21,
                        204.2,
                        205.2,
                        206.2,
                        207.19,
                        208.19,
                        209.18,
                        210.18,
                        211.18,
                        212.17,
                        213.17,
                        214.16,
                        215.16,
                        216.16,
                        217.15,
                        218.15,
                        219.14,
                        220.14,
                        221.14,
                        222.13,
                        223.13,
                        224.12,
                        225.12,
                        226.12,
                        227.11,
                        228.11,
                        229.11,
                        230.1,
                        231.1,
                        232.09,
                        233.09,
                        234.09,
                        235.08,
                        236.08,
                        237.07,
                        238.07,
                        239.07,
                        240.06,
                        241.06,
                        242.05,
                        243.05,
                        244.05,
                        245.04,
                        246.04,
                        247.04,
                        248.03,
                        249.03,
                        250.02,
                        251.02,
                        252.02,
                        253.01,
                        254.01,
                        255
                    ]
```

### Details
<!--- 
How would this change help? (you, the project, the user community)?
How would it be used? 
Are there any examples (existing software / utilities)?
Please provide links, screenshots, etc.
-->

The function uses `np.histogram` to calculate the frequencies and bin labels. The problem with this approach is NumPy uses the whole (masked) image, so the most common value is zero. For this reason bin 0 was excluded, but that makes the range 1-255 instead of 0-255.

Instead we can use the OpenCV calcHist function because it has a mask input that allows you to build the histogram from pixels of interest only.

### Completion Criteria
<!---
How will we know when this is done?

Please use boxes like:

For a bug:
- [ ] Now I can [topic of question / bug]

For a discussion:
- [ ] Discuss and develop requirements docs
- [ ] Create issues for next steps

For a new feature:
- [ ] Create algorithm/method
- [ ] Write test
- [ ] Write documentation
- [ ] Add to the package (pull request)
--->

- [ ] Update function to use OpenCV calcHist
- [ ] Output labels are in the range of 0-255 (or user-specified) as expected

Changed files:
plantcv/plantcv/analyze_nir_intensity.py

diff --git a/plantcv/plantcv/analyze_nir_intensity.py b/plantcv/plantcv/analyze_nir_intensity.py
index eb03d4ce..f560cd5c 100755
--- a/plantcv/plantcv/analyze_nir_intensity.py
+++ b/plantcv/plantcv/analyze_nir_intensity.py
@@ -37,7 +37,7 @@ def analyze_nir_intensity(gray_img, mask, bins=256, histplot=False):
     # apply plant shaped mask to image
     mask1 = binary_threshold(mask, 0, 255, 'light')
     mask1 = (mask1 / 255)
-    masked = np.multiply(gray_img, mask1)
+    # masked = np.multiply(gray_img, mask1)
 
     # calculate histogram
     if gray_img.dtype == 'uint16':
@@ -48,16 +48,19 @@ def analyze_nir_intensity(gray_img, mask, bins=256, histplot=False):
     # 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]
+    # Calculate histogram
+    hist_nir = [float(l[0]) for l 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 = (hist_nir / float(pixels)) * 100
+    hist_percent = [(p / float(pixels)) * 100 for p in hist_nir]
 
     # No longer returning a pseudocolored image
     # make mask to select the background
@@ -80,14 +83,14 @@ def analyze_nir_intensity(gray_img, mask, bins=256, histplot=False):
 
     if histplot is True:
         hist_x = hist_percent
-        bin_labels = np.arange(0, bins)
+        # 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))))
+                    + scale_x_continuous(breaks=list(range(0, maxval, 25))))
 
         analysis_images.append(fig_hist)
         if params.debug == "print":
@@ -97,7 +100,7 @@ def analyze_nir_intensity(gray_img, mask, bins=256, histplot=False):
 
     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)
+                            value=hist_nir, label=bin_labels)
 
     # Store images
     outputs.images.append(analysis_images)