Skip to content

Commit

Permalink
Merge pull request #1325 from danforthcenter/rename_to_ksize
Browse files Browse the repository at this point in the history
Rename to ksize in adaptive thresholding methods
  • Loading branch information
nfahlgren authored Aug 10, 2023
2 parents 3cad879 + 7ce560a commit 95dffb5
Show file tree
Hide file tree
Showing 5 changed files with 40 additions and 41 deletions.
12 changes: 6 additions & 6 deletions docs/gaussian_threshold.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,17 +4,17 @@ Creates a binary image from a grayscale image using the Gaussian adaptive thresh

Adaptive thresholds use a threshold value that varies across the image.
This local threshold depends on the local average, computed in a squared portion of the image of
*block_size* by *block_size* pixels, and on the *offset* relative to that local average.
*ksize* by *ksize* pixels, and on the *offset* relative to that local average.

In the Gaussian adaptive threshold, the local average is a weighted average of the pixel values in the block, where the weights are a 2D Gaussian centered in the middle.

**plantcv.threshold.gaussian**(*gray_img, block_size, offset, object_type="light"*)
**plantcv.threshold.gaussian**(*gray_img, ksize, offset, object_type="light"*)

**returns** thresholded/binary image

- **Parameters:**
- gray_img - Grayscale image data.
- block_size - Size of the block of pixels used to compute the local average.
- ksize - Size of the block of pixels used to compute the local average.
- offset - Value substracted from the local average to compute the local threshold.
A negative offset sets the local threshold above the local average.
- object_type - "light" or "dark" (default: "light").
Expand All @@ -40,13 +40,13 @@ from plantcv import plantcv as pcv
pcv.params.debug = "plot"

# Adaptive threshold with different parameters
bin_gauss1 = pcv.threshold.gaussian(gray_img=gray_img, block_size=250, offset=15,
bin_gauss1 = pcv.threshold.gaussian(gray_img=gray_img, ksize=250, offset=15,
object_type='dark')

bin_gauss1 = pcv.threshold.gaussian(gray_img=gray_img, block_size=25, offset=5,
bin_gauss1 = pcv.threshold.gaussian(gray_img=gray_img, ksize=25, offset=5,
object_type='dark')

bin_gauss1 = pcv.threshold.gaussian(gray_img=gray_img, block_size=2000, offset=15,
bin_gauss1 = pcv.threshold.gaussian(gray_img=gray_img, ksize=2000, offset=15,
object_type='dark')

```
Expand Down
12 changes: 6 additions & 6 deletions docs/mean_threshold.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,17 +4,17 @@ Creates a binary image from a grayscale image using the mean adaptive thresholdi

Adaptive thresholds use a threshold value that varies across the image.
This local threshold depends on the local average, computed in a squared portion of the image of
*block_size* by *block_size* pixels, and on the *offset* relative to that local average.
*ksize* by *ksize* pixels, and on the *offset* relative to that local average.

In the mean adaptive threshold, the local average is the average of the pixel values in the block.

**plantcv.threshold.mean**(*gray_img, block_size, offset, object_type="light"*)
**plantcv.threshold.mean**(*gray_img, ksize, offset, object_type="light"*)

**returns** thresholded/binary image

- **Parameters:**
- gray_img - Grayscale image data
- block_size - Size of the block of pixels used to compute the local average
- ksize - Size of the block of pixels used to compute the local average
- offset - Value substracted from the local average to compute the local threshold.
A negative offset sets the local threshold above the local average.
- object_type - "light" or "dark" (default: "light").
Expand All @@ -39,13 +39,13 @@ from plantcv import plantcv as pcv
pcv.params.debug = "plot"

# Adaptive threshold with different parameters
threshold_mean1 = pcv.threshold.mean(gray_img=gray_img, block_size=250, offset=25,
threshold_mean1 = pcv.threshold.mean(gray_img=gray_img, ksize=250, offset=25,
object_type='dark')

threshold_mean2 = pcv.threshold.mean(gray_img=gray_img, block_size=15, offset=5,
threshold_mean2 = pcv.threshold.mean(gray_img=gray_img, ksize=15, offset=5,
object_type='dark')

threshold_mean3 = pcv.threshold.mean(gray_img=gray_img, block_size=2000, offset=25,
threshold_mean3 = pcv.threshold.mean(gray_img=gray_img, ksize=2000, offset=25,
object_type='dark')
```

Expand Down
6 changes: 3 additions & 3 deletions docs/updating.md
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,7 @@ If conda does not update your PlantCV installation, you can try installing a spe
```bash
conda install -n plantcv -c conda-forge plantcv=4.0

```
```

You can find the version you have installed with:

Expand Down Expand Up @@ -1084,13 +1084,13 @@ pages for more details on the input and output variable types.

* pre v3.0dev2: NA
* post v3.0dev2: bin_img = **plantcv.threshold.gaussian**(*gray_img, max_value, object_type="light"*)
* post v4.0: bin_img = **plantcv.threshold.gaussian**(*gray_img, block_size, offset, object_type="light"*)
* post v4.0: bin_img = **plantcv.threshold.gaussian**(*gray_img, ksize, offset, object_type="light"*)

#### plantcv.threshold.mean

* pre v3.0dev2: NA
* post v3.0dev2: bin_img = **plantcv.threshold.mean**(*gray_img, max_value, object_type="light"*)
* post v4.0: bin_img = **plantcv.threshold.mean**(*gray_img, block_size, offset, object_type="light"*)
* post v4.0: bin_img = **plantcv.threshold.mean**(*gray_img, ksize, offset, object_type="light"*)

#### plantcv.threshold.otsu

Expand Down
39 changes: 19 additions & 20 deletions plantcv/plantcv/threshold/threshold_methods.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
# Threshold functions

"""Threshold functions."""
import os
import cv2
import math
Expand Down Expand Up @@ -52,19 +51,19 @@ def binary(gray_img, threshold, object_type="light"):


# Gaussian adaptive threshold
def gaussian(gray_img, block_size, offset, object_type="light"):
def gaussian(gray_img, ksize, offset, object_type="light"):
"""Creates a binary image from a grayscale image based on the Gaussian adaptive threshold method.
Adaptive thresholds use a threshold value that varies across the image.
This local threshold depends on the local average, computed in a squared portion of the image of
block_size by block_size pixels, and on the offset relative to that local average.
ksize by ksize pixels, and on the offset relative to that local average.
In the Gaussian adaptive threshold, the local average is a weighed average of the pixel values
in the block, where the weights are a 2D Gaussian centered in the middle.
Inputs:
gray_img = Grayscale image data
block_size = Size of the block of pixels used to compute the local average
ksize = Size of the block of pixels used to compute the local average
offset = Value substracted from the local average to compute the local threshold.
A negative offset sets the local threshold above the local average.
object_type = "light" or "dark" (default: "light")
Expand All @@ -77,7 +76,7 @@ def gaussian(gray_img, block_size, offset, object_type="light"):
bin_img = Thresholded, binary image
:param gray_img: numpy.ndarray
:param block_size: int
:param ksize: int
:param offset: float
:param object_type: str
:return bin_img: numpy.ndarray
Expand All @@ -93,25 +92,25 @@ def gaussian(gray_img, block_size, offset, object_type="light"):

params.device += 1

bin_img = _call_adaptive_threshold(gray_img, block_size, offset, cv2.ADAPTIVE_THRESH_GAUSSIAN_C,
bin_img = _call_adaptive_threshold(gray_img, ksize, offset, cv2.ADAPTIVE_THRESH_GAUSSIAN_C,
threshold_method, "_gaussian_threshold_")

return bin_img


# Mean adaptive threshold
def mean(gray_img, block_size, offset, object_type="light"):
def mean(gray_img, ksize, offset, object_type="light"):
"""Creates a binary image from a grayscale image based on the mean adaptive threshold method.
Adaptive thresholds use a threshold value that varies across the image.
This local threshold depends on the local average, computed in a squared portion of the image of
block_size by block_size pixels, and on the offset relative to that local average.
ksize by ksize pixels, and on the offset relative to that local average.
In the mean adaptive threshold, the local average is the average of the pixel values in the block.
Inputs:
gray_img = Grayscale image data
block_size = Size of the block of pixels used to compute the local average
ksize = Size of the block of pixels used to compute the local average
offset = Value substracted from the local average to compute the local threshold.
A negative offset sets the local threshold above the local average.
object_type = "light" or "dark" (default: "light")
Expand All @@ -124,7 +123,7 @@ def mean(gray_img, block_size, offset, object_type="light"):
bin_img = Thresholded, binary image
:param gray_img: numpy.ndarray
:param block_size: int
:param ksize: int
:param offset: float
:param object_type: str
:return bin_img: numpy.ndarray
Expand All @@ -140,7 +139,7 @@ def mean(gray_img, block_size, offset, object_type="light"):

params.device += 1

bin_img = _call_adaptive_threshold(gray_img, block_size, offset, cv2.ADAPTIVE_THRESH_MEAN_C,
bin_img = _call_adaptive_threshold(gray_img, ksize, offset, cv2.ADAPTIVE_THRESH_MEAN_C,
threshold_method, "_mean_threshold_")

return bin_img
Expand Down Expand Up @@ -491,18 +490,18 @@ def _call_threshold(gray_img, threshold, threshold_method, method_name):


# Internal method for calling the OpenCV adaptiveThreshold function to reduce code duplication
def _call_adaptive_threshold(gray_img, block_size, offset, adaptive_method, threshold_method, method_name):
def _call_adaptive_threshold(gray_img, ksize, offset, adaptive_method, threshold_method, method_name):

if block_size < 3:
fatal_error("block_size must be >= 3")
if ksize < 3:
fatal_error("ksize must be >= 3")

# Force block_size to be odd number
block_size = int(block_size)
if (block_size % 2) != 1:
block_size = block_size + 1
# Force ksize to be odd number
ksize = int(ksize)
if (ksize % 2) != 1:
ksize = ksize + 1

# Threshold the image
bin_img = cv2.adaptiveThreshold(gray_img, 255, adaptive_method, threshold_method, block_size, offset)
bin_img = cv2.adaptiveThreshold(gray_img, 255, adaptive_method, threshold_method, ksize, offset)

# Print or plot the binary image if debug is on
_debug(visual=bin_img, filename=os.path.join(params.debug_outdir, str(params.device) + method_name + '.png'))
Expand Down
12 changes: 6 additions & 6 deletions tests/plantcv/threshold/test_threshold_methods.py
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@ def test_gaussian(objtype, threshold_test_data):
"""Test for PlantCV."""
# Read in test data
gray_img = cv2.imread(threshold_test_data.small_gray_img, -1)
binary_img = gaussian(gray_img=gray_img, block_size=11, offset=2, object_type=objtype)
binary_img = gaussian(gray_img=gray_img, ksize=11, offset=2, object_type=objtype)
# Assert that the output image has the dimensions of the input image and is binary
assert gray_img.shape == binary_img.shape and np.array_equal(np.unique(binary_img), np.array([0, 255]))

Expand All @@ -39,15 +39,15 @@ def test_gaussian_incorrect_object_type(threshold_test_data):
# Read in test data
gray_img = cv2.imread(threshold_test_data.small_gray_img, -1)
with pytest.raises(RuntimeError):
_ = gaussian(gray_img=gray_img, block_size=11, offset=2, object_type="lite")
_ = gaussian(gray_img=gray_img, ksize=11, offset=2, object_type="lite")


@pytest.mark.parametrize("objtype, size", [["dark", 11], ["light", 10]])
def test_mean(objtype, size, threshold_test_data):
"""Test for PlantCV."""
# Read in test data
gray_img = cv2.imread(threshold_test_data.small_gray_img, -1)
binary_img = mean(gray_img=gray_img, block_size=size, offset=2, object_type=objtype)
binary_img = mean(gray_img=gray_img, ksize=size, offset=2, object_type=objtype)
# Assert that the output image has the dimensions of the input image and is binary
assert gray_img.shape == binary_img.shape and np.array_equal(np.unique(binary_img), np.array([0, 255]))

Expand All @@ -57,15 +57,15 @@ def test_mean_incorrect_object_type(threshold_test_data):
# Read in test data
gray_img = cv2.imread(threshold_test_data.small_gray_img, -1)
with pytest.raises(RuntimeError):
_ = mean(gray_img=gray_img, block_size=11, offset=2, object_type="lite")
_ = mean(gray_img=gray_img, ksize=11, offset=2, object_type="lite")


def test_mean_incorrect_block_size(threshold_test_data):
def test_mean_incorrect_ksize(threshold_test_data):
"""Test for PlantCV."""
# Read in test data
gray_img = cv2.imread(threshold_test_data.small_gray_img, -1)
with pytest.raises(RuntimeError):
_ = mean(gray_img=gray_img, block_size=1, offset=2, object_type="dark")
_ = mean(gray_img=gray_img, ksize=1, offset=2, object_type="dark")


@pytest.mark.parametrize("objtype", ["dark", "light"])
Expand Down

0 comments on commit 95dffb5

Please sign in to comment.