Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Auto color correct wrapper #1625

Open
wants to merge 14 commits into
base: main
Choose a base branch
from
Open
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
43 changes: 43 additions & 0 deletions docs/transform_auto_correct_color.md
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Looks like the example images for before and after color correction are different samples.

Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
# 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/auto_correct_color.png)

**Corrected Image:**

![Screenshot](img/documentation_images/transform_affine_color_corr/tobacco_leaves_corrected.jpg)

**Source Code:** [Here](https://github.com/danforthcenter/plantcv/blob/main/plantcv/plantcv/transform/auto_correct_color.py)
5 changes: 5 additions & 0 deletions docs/updating.md
Original file line number Diff line number Diff line change
Expand Up @@ -1210,6 +1210,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.r**(*rgb_img, label=None, **kwargs*)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Typo in function name


#### plantcv.transform.correct_color

* pre v3.0dev1: NA
Expand Down
1 change: 1 addition & 0 deletions mkdocs.yml
Original file line number Diff line number Diff line change
Expand Up @@ -175,6 +175,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
3 changes: 2 additions & 1 deletion plantcv/plantcv/transform/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -19,9 +19,10 @@
from plantcv.plantcv.transform.gamma_correct import gamma_correct
from plantcv.plantcv.transform.checkerboard_calib import checkerboard_calib, calibrate_camera
from plantcv.plantcv.transform.merge_images import merge_images
from plantcv.plantcv.transform.auto_correct_color import auto_correct_color

__all__ = ["get_color_matrix", "get_matrix_m", "calc_transformation_matrix", "apply_transformation_matrix",
"save_matrix", "load_matrix", "correct_color", "create_color_card_mask", "quick_color_check",
"find_color_card", "std_color_matrix", "affine_color_correction", "rescale", "nonuniform_illumination", "resize",
"resize_factor", "warp", "rotate", "warp", "warp_align", "gamma_correct", "detect_color_card", "checkerboard_calib",
"calibrate_camera", "merge_images"]
"calibrate_camera", "merge_images", "auto_correct_color"]
40 changes: 40 additions & 0 deletions plantcv/plantcv/transform/auto_correct_color.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
# Automatically detect a color card and color correct to standard chip values

from plantcv.plantcv import params
from plantcv.plantcv.transform.detect_color_card import detect_color_card
from plantcv.plantcv.transform.color_correction import get_color_matrix, std_color_matrix, affine_color_correction


def auto_correct_color(rgb_img, label=None, **kwargs):
"""Automatically detect a color card.
Parameters
----------
rgb_img : numpy.ndarray
Input RGB image data containing a color card.
label : str, optional
modifies the variable name of observations recorded (default = pcv.params.sample_label).
**kwargs
Other keyword arguments passed to cv2.adaptiveThreshold and cv2.circle.
Valid keyword arguments:
adaptive_method: 0 (mean) or 1 (Gaussian) (default = 1)
block_size: int (default = 51)
radius: int (default = 20)
min_size: int (default = 1000)
Returns
-------
numpy.ndarray
Color corrected image
"""
# Set lable to params.sample_label if None
if label is None:
label = params.sample_label

# Get keyword arguments and set defaults if not set
labeled_mask = detect_color_card(rgb_img=rgb_img, min_size=kwargs.get("min_size", 1000),
radius=kwargs.get("radius", 20),
adaptive_method=kwargs.get("adaptive_method", 1),
block_size=kwargs.get("block_size", 51))
_, card_matrix = get_color_matrix(rgb_img=rgb_img, mask=labeled_mask)
std_matrix = std_color_matrix(pos=3)
return affine_color_correction(rgb_img=rgb_img, source_matrix=card_matrix,
target_matrix=std_matrix)
11 changes: 11 additions & 0 deletions tests/plantcv/transform/test_auto_correct_color.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
"""Tests for auto_correct_color."""
import cv2
import numpy as np
from plantcv.plantcv.transform import auto_correct_color

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change

def test_auto_correct_color(transform_test_data):
"""Test for PlantCV."""
# Load rgb image
rgb_img = cv2.imread(transform_test_data.colorcard_img)
corrected_img = auto_correct_color(rgb_img=rgb_img)
assert np.shape(corrected_img) == np.shape(rgb_img) and np.sum(corrected_img) != np.sum(rgb_img)