Skip to content

Commit

Permalink
Merge branch 'main' into zeeuqsze-grayscale-colab
Browse files Browse the repository at this point in the history
  • Loading branch information
nfahlgren authored Dec 16, 2024
2 parents 4b50aa2 + 723f2c2 commit 64694f9
Show file tree
Hide file tree
Showing 22 changed files with 400 additions and 15 deletions.
13 changes: 12 additions & 1 deletion .all-contributorsrc
Original file line number Diff line number Diff line change
Expand Up @@ -627,7 +627,8 @@
"profile": "https://github.com/jbraley1107",
"contributions": [
"review",
"userTesting"
"userTesting",
"bug"
]
},
{
Expand All @@ -638,6 +639,16 @@
"contributions": [
"bug"
]
},
{
"login": "mlohbihler",
"name": "Matthew Lohbihler",
"avatar_url": "https://avatars.githubusercontent.com/u/1182059?v=4",
"profile": "https://github.com/mlohbihler",
"contributions": [
"bug",
"doc"
]
}
],
"contributorsPerLine": 7,
Expand Down
13 changes: 7 additions & 6 deletions README.md

Large diffs are not rendered by default.

Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
44 changes: 44 additions & 0 deletions docs/roi_auto_wells.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
## Autodetect Cicular Regions of Interest (ROI)

**plantcv.roi.auto_wells**(*gray_img, mindist, candec, accthresh, minradius, maxradius, nrows, ncols, radiusadjust=None*)

**returns** roi_objects

- **Parameters:**
- gray_img = Gray single channel image data
- mindist = minimum distance between detected circles
- candec = higher threshold of canny edge detector
- accthresh = accumulator threshold for the circl centers
- minradius = minimum circle radius
- maxradius = maximum circle radius
- nrows = expected number of rows
- ncols = expected number of columns
- radiusadjust = amount to adjust the average radius, this can be desirable if you want ROI to sit inside a well, for example (in that case you might set it to a negative value).
- **Context:**
- Uses a Hough Circle detector to find circular shapes, then uses a gaussian mixture model to sort found circular objects so they are ordered from
top left to bottom right. We assume that circles are of approximately equal size because we calculate an average radius of all of the found circles.
The average radius size can be adjusted with the radius adjust parameter, for example in the case that you'd like the ROI to sit inside of the well.

**Reference Image**

![Screenshot](img/documentation_images/roi_auto_wells/circle-wells.png)

```python

from plantcv import plantcv as pcv

# Set global debug behavior to None (default), "print" (to file),
# or "plot" (Jupyter Notebooks or X11)
pcv.params.debug = "plot"

# Detect Circular Shapes and Use as ROIs
rois1 = pcv.roi.auto_wells(gray_img=gray_img, mindist = 20, candec = 50,
accthresh = 30, minradius = 40, maxradius = 50, nrows=4, ncols=6, radiusadjust=-10)

```

**Grid of ROIs**

![Screenshot](img/documentation_images/roi_auto_wells/21_roi.png)

**Source Code:** [Here](https://github.com/danforthcenter/plantcv/blob/main/plantcv/plantcv/roi/roi_methods.py)
40 changes: 40 additions & 0 deletions docs/transform_auto_correct_color.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
# Automatically detect a color card and color correct in one step

Corrects the color of the input image based on the target color matrix using an affine transformation
in the RGB space after automatic detection of a color card within the image. A one-step wrapper of
[plantcv.transform.detect_color_card](transform_detect_color_card.md), [plantcv.transform.std_color_matrix](std_color_matrix.md),
[plantcv.transform.get_color_matrix](get_color_matrix.md), and [plantcv.transform.affine_color_correction](transform_affine_color_correction.md).

**plantcv.transform.auto_correct_color**(*rgb_img, label=None, \*\*kwargs*)

**returns** corrected_img

- **Parameters**
- rgb_img - Input RGB image data containing a color card.
- label - Optional label parameter, modifies the variable name of observations recorded. (default = `pcv.params.sample_label`)
- **kwargs - Other keyword arguments passed to `cv2.adaptiveThreshold` and `cv2.circle`.
- adaptive_method - Adaptive threhold method. 0 (mean) or 1 (Gaussian) (default = 1).
- block_size - Size of a pixel neighborhood that is used to calculate a threshold value (default = 51). We suggest using 127 if using `adaptive_method=0`.
- radius - Radius of circle to make the color card labeled mask (default = 20).
- min_size - Minimum chip size for filtering objects after edge detection (default = 1000)
- **Returns**
- corrected_img - Color corrected image

- **Example Use**
- Below

```python

from plantcv import plantcv as pcv

rgb_img, imgpath, imgname = pcv.readimage(filename="top_view_plant.png")

corrected_rgb = pcv.transform.auto_correct_color(rgb_img=old_card)
```

**Debug Image: automatically detected and masked the color card**

![Screenshot](img/documentation_images/correct_color_imgs/detect_color_card.png)


**Source Code:** [Here](https://github.com/danforthcenter/plantcv/blob/main/plantcv/plantcv/transform/auto_correct_color.py)
5 changes: 4 additions & 1 deletion docs/tutorials/arabidopsis_multi_plant_tutorial.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,9 @@
## Tutorial: Arabidopsis Multi-Plant Workflow

Check out our interactive Arabidopsis multi-plant tutorial!

[![Binder](https://mybinder.org/badge_logo.svg)](https://mybinder.org/v2/gh/danforthcenter/plantcv-tutorial-arabidopsis-tray/HEAD?labpath=index.ipynb) Check out our interactive arabidopsis multi-plant tutorial!
[![Binder](https://mybinder.org/badge_logo.svg)](https://mybinder.org/v2/gh/danforthcenter/plantcv-tutorial-arabidopsis-tray/HEAD?labpath=index.ipynb)
[![Colab](https://colab.research.google.com/assets/colab-badge.svg)](https://colab.research.google.com/github/danforthcenter/plantcv-tutorial-arabidopsis-tray/blob/main/index-Colab.ipynb)
[![Static Badge](https://img.shields.io/badge/Open%20on%20GitHub-black?logo=github)](https://github.com/danforthcenter/plantcv-tutorial-arabidopsis-tray.git)

<iframe src="https://nbviewer.jupyter.org/github/danforthcenter/plantcv-tutorial-arabidopsis-tray/blob/main/index.ipynb" width="100%" height="1500px"></iframe>
5 changes: 4 additions & 1 deletion docs/tutorials/morphology_tutorial.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,9 @@
## Tutorial: Morphology Functions

[![Binder](https://mybinder.org/badge_logo.svg)](https://mybinder.org/v2/gh/danforthcenter/plantcv-tutorial-morphology/HEAD?labpath=index.ipynb)
Check out our interactive morphology tutorial!

[![Binder](https://mybinder.org/badge_logo.svg)](https://mybinder.org/v2/gh/danforthcenter/plantcv-tutorial-morphology/HEAD)
[![Colab](https://colab.research.google.com/assets/colab-badge.svg)](https://colab.research.google.com/github/danforthcenter/plantcv-tutorial-morphology/blob/main/index-Colab.ipynb)
[![Static Badge](https://img.shields.io/badge/Open%20in%20GitHub-black?logo=github)](https://github.com/danforthcenter/plantcv-tutorial-morphology.git)

<iframe src="https://nbviewer.jupyter.org/github/danforthcenter/plantcv-tutorial-morphology/blob/main/index.ipynb" width="100%" height="1500px"></iframe>
5 changes: 4 additions & 1 deletion docs/tutorials/seed_analysis_tutorial.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,9 @@
## Tutorial: Seed Analysis Workflow

Check out our interactive tutorial!

[![Binder](https://mybinder.org/badge_logo.svg)](https://mybinder.org/v2/gh/danforthcenter/plantcv-tutorial-seeds/HEAD?labpath=index.ipynb) Check out our interactive seed analysis tutorial!
[![Binder](https://mybinder.org/badge_logo.svg)](https://mybinder.org/v2/gh/danforthcenter/plantcv-tutorial-seeds/HEAD)
[![Colab](https://colab.research.google.com/assets/colab-badge.svg)](https://colab.research.google.com/github/danforthcenter/plantcv-tutorial-seeds/blob/main/index-Colab.ipynb)
[![Static Badge](https://img.shields.io/badge/Open%20on%20GitHub-black?logo=github)](https://github.com/danforthcenter/plantcv-tutorial-seeds.git)

<iframe src="https://nbviewer.jupyter.org/github/danforthcenter/plantcv-tutorial-seeds/blob/main/index.ipynb" width="100%" height="1500px"></iframe>
6 changes: 5 additions & 1 deletion docs/tutorials/watershed_segmentation_tutorial.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,9 @@
## Tutorial: Watershed Segmentation Workflow

[![Binder](https://mybinder.org/badge_logo.svg)](https://mybinder.org/v2/gh/danforthcenter/plantcv-tutorial-watershed/HEAD?labpath=index.ipynb) Check out our interactive watershed tutorial!
Check out our interactive watershed tutorial! This tutorial uses the analyze watershed segmentation function to roughly segment individual leaves. In this case, the number of objects reported from the analyze watershed function is a rough estimation of the number of leaves. The Watershed Segmentation Function is a PlantCV function based on code contributed by Suxing Liu, Arkansas State University. For more information see https://github.com/lsx1980/Leaf_count.

[![Binder](https://mybinder.org/badge_logo.svg)](https://mybinder.org/v2/gh/danforthcenter/plantcv-tutorial-watershed/HEAD?labpath=index.ipynb)
[![Colab](https://colab.research.google.com/assets/colab-badge.svg)](https://colab.research.google.com/github/danforthcenter/plantcv-tutorial-watershed/blob/main/index-Colab.ipynb)
[![Static Badge](https://img.shields.io/badge/Open%20on%20GitHub-black?logo=github)](https://github.com/danforthcenter/plantcv-tutorial-watershed.git)

<iframe src="https://nbviewer.jupyter.org/github/danforthcenter/plantcv-tutorial-watershed/blob/main/index.ipynb" width="100%" height="1500px"></iframe>
12 changes: 11 additions & 1 deletion docs/updating.md
Original file line number Diff line number Diff line change
Expand Up @@ -145,7 +145,7 @@ roi = pcv.roi.rectangle(img=img, x=100, y=100, h=100, w=100)

# Filter binary image to make a clean mask based on ROI
# (no longer needs `pcv.find_objects` or `pcv.object_composition`)
mask = pcv.roi.filter(mask=bin_img, roi=roi, roi_type="partial")
mask = pcv.roi.filter(mask=bin_mask, roi=roi, roi_type="partial")

# Extract shape traits from plant
shape_img = pcv.analyze.size(img=img,labeled_mask=mask, n_labels=1)
Expand Down Expand Up @@ -934,6 +934,11 @@ pages for more details on the input and output variable types.
* pre v4.0: NA
* post v4.0: roi_objects = **pcv.roi.auto_grid**(*mask, nrows, ncols, radius=None, img=None*)

#### plantcv.roi.auto_wells

* pre v4.6: NA
* post v4.6: roi_objects = **pcv.roi.auto_wells**(*gray_img, mindist, candec, accthresh, minradius, maxradius, nrows, ncols, radiusadjust=None*)

#### plantcv.roi.multi

* pre v3.1: NA
Expand Down Expand Up @@ -1210,6 +1215,11 @@ pages for more details on the input and output variable types.
* pre v3.0dev1: NA
* post v3.0dev2: determinant, transformation_matrix = **plantcv.transform.calc_transformation_matrix**(*matrix_m, matrix_b*)

#### plantcv.transform.auto_correct_color

* pre v4.6: NA
* post v4.6: corrected_img = **plantcv.transform.auto_correct_color**(*rgb_img, label=None, **kwargs*)

#### plantcv.transform.correct_color

* pre v3.0dev1: NA
Expand Down
2 changes: 2 additions & 0 deletions mkdocs.yml
Original file line number Diff line number Diff line change
Expand Up @@ -153,6 +153,7 @@ nav:
- 'Create ROI from Binary Image': roi_from_binary_image.md
- 'Create Multi ROIs': 'roi_multi.md'
- 'Create Grid of ROIs Automatically': roi_auto_grid.md
- 'Create Grid of Circular ROIs Automatically': roi_auto_wells.md
- 'Filter a mask by ROI': roi_filter.md
- 'Filter a mask by ROI (quickly)': roi_quick_filter.md
- 'Convert ROI to Mask': roi2mask.md
Expand All @@ -175,6 +176,7 @@ nav:
- 'Transformation Methods':
- 'Auto-Detect Color Card': transform_detect_color_card.md
- 'Auto-Detect Color Card (old)': find_color_card.md
- 'Auto Correct Color': transform_auto_correct_color.md
- 'Calibrate Camera': transform_calibrate_camera.md
- 'Checkerboard Calibration': transform_checkerboard_calibration.md
- 'Create Color Card Mask': create_color_card_mask.md
Expand Down
88 changes: 88 additions & 0 deletions plantcv/plantcv/_helpers.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,94 @@
from plantcv.plantcv.logical_and import logical_and
from plantcv.plantcv import fatal_error, warn
from plantcv.plantcv import params
import pandas as pd


def _hough_circle(gray_img, mindist, candec, accthresh, minradius, maxradius, maxfound=None):
"""
Hough Circle Detection
Keyword inputs:
gray_img = gray image (np.ndarray)
mindist = minimum distance between detected circles
candec = higher threshold of canny edge detector
accthresh = accumulator threshold for the circl centers
minradius = minimum circle radius
maxradius = maximum circle radius
maxfound = maximum number of circles to find
:param gray_img: np.ndarray
:param mindist: int
:param candec: int
:param accthresh: int
:param minradius: int
:param maxradius: int
:param maxfound: None or int
:return dataframe: pandas dataframe
:return img: np.ndarray
"""
# Store debug
debug = params.debug
params.debug = None

circles = cv2.HoughCircles(gray_img, cv2.HOUGH_GRADIENT,
dp=1, minDist=mindist,
param1=candec, param2=accthresh,
minRadius=minradius, maxRadius=maxradius)

cimg = cv2.cvtColor(gray_img, cv2.COLOR_GRAY2BGR)
x = []
y = []
radius = []
if circles is None:
fatal_error('number of circles found is None with these parameters')
circles = np.uint16(np.around(circles))
if maxfound is not None:
if maxfound >= len(circles[0, :]):
for i in circles[0, :]:
# draw the outer circle
cv2.circle(cimg, (i[0], i[1]), i[2], (0, 255, 0),
params.line_thickness)
# draw the center of the circle
cv2.circle(cimg, (i[0], i[1]), 2, (0, 0, 255),
params.line_thickness)
x.append(i[0])
y.append(i[1])
radius.append(i[2])
else:
for n, i in enumerate(circles[0, :]):
if n <= (maxfound-1):
# draw the outer circle
cv2.circle(cimg, (i[0], i[1]), i[2], (0, 255, 0),
params.line_thickness)
# draw the center of the circle
cv2.circle(cimg, (i[0], i[1]), 2, (0, 0, 255),
params.line_thickness)
x.append(i[0])
y.append(i[1])
radius.append(i[2])
warn('Number of found circles is ' +
str(len(circles[0, :])) +
' Change Parameters. Only drawing first '+str(maxfound))
else:
for i in circles[0, :]:
# draw the outer circle
cv2.circle(cimg, (i[0], i[1]), i[2], (0, 255, 0),
params.line_thickness)
# draw the center of the circle
cv2.circle(cimg, (i[0], i[1]), 2, (0, 0, 255),
params.line_thickness)
x.append(i[0])
y.append(i[1])
radius.append(i[2])

data = {'x': x, 'y': y, 'radius': radius}
df = pd.DataFrame(data)

# Reset debug mode
params.debug = debug

return df, cimg


def _cv2_findcontours(bin_img):
Expand Down
4 changes: 3 additions & 1 deletion plantcv/plantcv/roi/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,8 +6,10 @@
from plantcv.plantcv.roi.roi_methods import multi
from plantcv.plantcv.roi.roi_methods import custom
from plantcv.plantcv.roi.roi_methods import filter
from plantcv.plantcv.roi.roi_methods import auto_wells
from plantcv.plantcv.roi.roi2mask import roi2mask
from plantcv.plantcv.roi.quick_filter import quick_filter

__all__ = ["circle", "ellipse", "from_binary_image", "rectangle", "auto_grid", "multi", "custom",
__all__ = ["circle", "ellipse", "from_binary_image", "rectangle", "auto_grid",
"multi", "custom", "auto_wells",
"filter", "roi2mask", "quick_filter"]
Loading

0 comments on commit 64694f9

Please sign in to comment.