Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
10 changes: 5 additions & 5 deletions docs/quick_color_check.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ be better off excluded from analysis . A quick way to examine this is by plottin
masked in the color card.


**plantcv.transform.quick_color_check**(*source_matrix, target_matrix, num_chips*)
**plantcv.qc.quick_color_check**(*source_matrix, target_matrix, num_chips*)

**returns** Altair chart

Expand All @@ -23,9 +23,9 @@ masked in the color card.

from plantcv import plantcv as pcv

chart = pcv.transform.quick_color_check(source_matrix=s_matrix,
target_matrix=t_matrix,
num_chips=24)
chart = pcv.qc.quick_color_check(source_matrix=s_matrix,
target_matrix=t_matrix,
num_chips=24)

```
**Perfect Color Correlation**
Expand All @@ -36,4 +36,4 @@ chart = pcv.transform.quick_color_check(source_matrix=s_matrix,

![Screenshot](img/documentation_images/quick_color_check/quick_color_plot2.png)

**Source Code:** [Here](https://github.com/danforthcenter/plantcv/blob/main/plantcv/plantcv/transform/color_correction.py)
**Source Code:** [Here](https://github.com/danforthcenter/plantcv/blob/main/plantcv/plantcv/qc/quick_color_check.py)
6 changes: 6 additions & 0 deletions docs/updating.md
Original file line number Diff line number Diff line change
Expand Up @@ -994,6 +994,11 @@ pages for more details on the input and output variable types.
* pre v4.3.1: NA
* post v4.3.1: chart = **plantcv.qc.exposure**(*rgb_img, warning_threshold=0.05*)

#### plantcv.qc.quick_color_check

* pre v5.0: NA, see `plantcv.transform.quick_color_check`
* post v5.0: chart = **plantcv.transform.quick_color_check**(*target_matrix, source_matrix, num_chips*)

#### plantcv.readbayer

* pre v3.0: NA
Expand Down Expand Up @@ -1497,6 +1502,7 @@ pages for more details on the input and output variable types.
* pre v3.0: NA
* post v3.0: **plantcv.transform.quick_color_check**(*target_matrix, source_matrix, num_chips*)
* post v4.0: chart = **plantcv.transform.quick_color_check**(*target_matrix, source_matrix, num_chips*)
* post v5.0: NA, moved to `plantcv.qc.quick_color_check`

#### plantcv.transform.save_matrix

Expand Down
2 changes: 1 addition & 1 deletion mkdocs.yml
Original file line number Diff line number Diff line change
Expand Up @@ -145,6 +145,7 @@ nav:
- 'Plot Image': plot_image.md
- "Quality Control Tools":
- "Exposure": qc_exposure.md
- "Quick Color Check": quick_color_check.md
- 'Read Image': read_image.md
- 'Read Bayer Raw Image': read_bayer.md
- 'Report Size Marker': report_size_marker.md
Expand Down Expand Up @@ -187,7 +188,6 @@ nav:
- 'Create Color Card Mask': create_color_card_mask.md
- 'Convert Color Card to Matrix': get_color_matrix.md
- 'Color Correction Workflow': transform_correct_color.md
- 'Quick Color Check': quick_color_check.md
- 'Affine Color Correction': transform_affine_color_correction.md
- 'Standard Color Matrix': std_color_matrix.md
- 'Gamma Correction': transform_gamma_correct.md
Expand Down
4 changes: 3 additions & 1 deletion plantcv/plantcv/qc/__init__.py
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
from plantcv.plantcv.qc.exposure import exposure
from plantcv.plantcv.qc.quick_color_check import quick_color_check

__all__ = ["exposure"]

__all__ = ["exposure", "quick_color_check"]
77 changes: 77 additions & 0 deletions plantcv/plantcv/qc/quick_color_check.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,77 @@
# Plot the color values of a target and source color matrix
import os
import numpy as np
import pandas as pd
import altair as alt
from plantcv.plantcv._debug import _debug
from plantcv.plantcv._globals import params


def quick_color_check(target_matrix, source_matrix, num_chips):
"""Plot the color values of a target and source color card matrix.

Quickly plot target matrix values against source matrix values to determine
over saturated color chips or other issues.

Inputs:
source_matrix = an nrowsXncols matrix containing the avg red, green, and blue values for each color chip
of the source image
target_matrix = an nrowsXncols matrix containing the avg red, green, and blue values for each color chip
of the target image
num_chips = number of color card chips included in th # Test data directory
self.datadir = os.path.join(os.path.dirname(os.path.abspath(__file__)), "..", "..", "testdata")e matrices (integer)

Returns:
p1 = an altair plot of the target and source color values

:param source_matrix: numpy.ndarray
:param target_matrix: numpy.ndarray
:param num_chips: int
:return p1: altair.vegalite.v5.api.Chart
"""
# Scale matrices to 0-255
target_matrix = 255*target_matrix
source_matrix = 255*source_matrix

# Extract and organize matrix info
tr = target_matrix[:num_chips, 1:2]
tg = target_matrix[:num_chips, 2:3]
tb = target_matrix[:num_chips, 3:4]
sr = source_matrix[:num_chips, 1:2]
sg = source_matrix[:num_chips, 2:3]
sb = source_matrix[:num_chips, 3:4]

# Create columns of color labels
red = ["red"] * num_chips
blue = ["blue"] * num_chips
green = ["green"] * num_chips

# Make a column of chip numbers
chip = np.arange(0, num_chips).reshape((num_chips, 1))
chips = np.vstack((chip, chip, chip))

# Combine info
color_data_r = np.column_stack((sr, tr, red))
color_data_g = np.column_stack((sg, tg, green))
color_data_b = np.column_stack((sb, tb, blue))
all_color_data = np.vstack((color_data_b, color_data_g, color_data_r))

# Create a dataframe with headers
dataset = pd.DataFrame({'source': all_color_data[:, 0], 'target': all_color_data[:, 1],
'color': all_color_data[:, 2]})

# Add chip numbers to the dataframe
dataset['chip'] = chips
dataset = dataset.astype({'color': str, 'chip': str, 'target': float, 'source': float})

# Make the plot
p1 = alt.Chart(dataset).mark_point(point=True).encode(
x="target",
y="source",
color=alt.Color("color").scale(range=["blue", "green", "red"]),
column="color"
)

_debug(visual=p1, filename=os.path.join(params.debug_outdir, 'color_quick_check.png'))

return p1.interactive()
3 changes: 1 addition & 2 deletions plantcv/plantcv/transform/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,6 @@
from plantcv.plantcv.transform.color_correction import load_matrix
from plantcv.plantcv.transform.color_correction import correct_color
from plantcv.plantcv.transform.color_correction import create_color_card_mask
from plantcv.plantcv.transform.color_correction import quick_color_check
from plantcv.plantcv.transform.color_correction import std_color_matrix
from plantcv.plantcv.transform.color_correction import astro_color_matrix
from plantcv.plantcv.transform.color_correction import affine_color_correction
Expand All @@ -24,7 +23,7 @@
from plantcv.plantcv.transform.auto_correct_color import auto_correct_color_nonlinear

__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",
"save_matrix", "load_matrix", "correct_color", "create_color_card_mask",
"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", "auto_correct_color", "mask_color_card", "auto_correct_color_nonlinear",
Expand Down
71 changes: 0 additions & 71 deletions plantcv/plantcv/transform/color_correction.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,6 @@
import math
import cv2
import numpy as np
import altair as alt
import pandas as pd
from plantcv.plantcv import params, fatal_error
from plantcv.plantcv.roi import circle
from plantcv.plantcv._debug import _debug
Expand Down Expand Up @@ -597,72 +595,3 @@ def create_color_card_mask(rgb_img, radius, start_coord, spacing, nrows, ncols,
_debug(visual=canvas, filename=os.path.join(params.debug_outdir, str(params.device) + '_color_card_mask_rois.png'))
_debug(visual=mask, filename=os.path.join(params.debug_outdir, str(params.device) + '_color_card_mask.png'))
return mask


def quick_color_check(target_matrix, source_matrix, num_chips):
"""Plot the color values of a target and source color card matrix.

Quickly plot target matrix values against source matrix values to determine
over saturated color chips or other issues.

Inputs:
source_matrix = an nrowsXncols matrix containing the avg red, green, and blue values for each color chip
of the source image
target_matrix = an nrowsXncols matrix containing the avg red, green, and blue values for each color chip
of the target image
num_chips = number of color card chips included in the matrices (integer)

Returns:
p1 = an altair plot of the target and source color values

:param source_matrix: numpy.ndarray
:param target_matrix: numpy.ndarray
:param num_chips: int
:return p1: altair.vegalite.v5.api.Chart
"""
# Scale matrices to 0-255
target_matrix = 255*target_matrix
source_matrix = 255*source_matrix

# Extract and organize matrix info
tr = target_matrix[:num_chips, 1:2]
tg = target_matrix[:num_chips, 2:3]
tb = target_matrix[:num_chips, 3:4]
sr = source_matrix[:num_chips, 1:2]
sg = source_matrix[:num_chips, 2:3]
sb = source_matrix[:num_chips, 3:4]

# Create columns of color labels
red = ["red"] * num_chips
blue = ["blue"] * num_chips
green = ["green"] * num_chips

# Make a column of chip numbers
chip = np.arange(0, num_chips).reshape((num_chips, 1))
chips = np.vstack((chip, chip, chip))

# Combine info
color_data_r = np.column_stack((sr, tr, red))
color_data_g = np.column_stack((sg, tg, green))
color_data_b = np.column_stack((sb, tb, blue))
all_color_data = np.vstack((color_data_b, color_data_g, color_data_r))

# Create a dataframe with headers
dataset = pd.DataFrame({'source': all_color_data[:, 0], 'target': all_color_data[:, 1],
'color': all_color_data[:, 2]})

# Add chip numbers to the dataframe
dataset['chip'] = chips
dataset = dataset.astype({'color': str, 'chip': str, 'target': float, 'source': float})

# Make the plot
p1 = alt.Chart(dataset).mark_point(point=True).encode(
x="target",
y="source",
color=alt.Color("color").scale(range=["blue", "green", "red"]),
column="color"
)

_debug(visual=p1, filename=os.path.join(params.debug_outdir, 'color_quick_check.png'))

return p1.interactive()
29 changes: 29 additions & 0 deletions tests/plantcv/qc/conftest.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
import pytest
import os
import numpy as np
import matplotlib

# Disable plotting
matplotlib.use("Template")


class QCTestData:
def __init__(self):
"""Initialize simple variables."""
# Test data directory
self.datadir = os.path.join(os.path.dirname(os.path.abspath(__file__)), "..", "..", "testdata")
# Target matrix file
self.target_matrix_file = os.path.join(self.datadir, "target_matrix.npz")
# Source 1 matrix file
self.source1_matrix_file = os.path.join(self.datadir, "source1_matrix.npz")

@staticmethod
def load_npz(npz_file):
"""Load data saved in a NumPy .npz file."""
data = np.load(npz_file, encoding="latin1")
return data['arr_0']

@pytest.fixture(scope="session")
def qc_test_data():
"""Test data object for the PlantCV transform submodule."""
return QCTestData()
11 changes: 11 additions & 0 deletions tests/plantcv/qc/test_quick_color_check.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
from altair.vegalite.v5.api import Chart
from plantcv.plantcv.qc.quick_color_check import quick_color_check


def test_quick_color_check(qc_test_data):
"""Test for PlantCV."""
# Load target image
target_matrix = qc_test_data.load_npz(qc_test_data.target_matrix_file)
source_matrix = qc_test_data.load_npz(qc_test_data.source1_matrix_file)
chart = quick_color_check(target_matrix, source_matrix, num_chips=22)
assert isinstance(chart, Chart)
12 changes: 1 addition & 11 deletions tests/plantcv/transform/test_color_correction.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,10 +3,9 @@
import os
import cv2
import numpy as np
from altair.vegalite.v5.api import Chart
from plantcv.plantcv.transform.color_correction import (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, std_color_matrix,
create_color_card_mask, std_color_matrix,
astro_color_matrix, affine_color_correction)
from plantcv.plantcv.transform.detect_color_card import detect_color_card

Expand Down Expand Up @@ -303,15 +302,6 @@ def test_create_color_card_mask(transform_test_data):
220], dtype=np.uint8)))


def test_quick_color_check(transform_test_data):
"""Test for PlantCV."""
# Load target image
target_matrix = transform_test_data.load_npz(transform_test_data.target_matrix_file)
source_matrix = transform_test_data.load_npz(transform_test_data.source1_matrix_file)
chart = quick_color_check(target_matrix, source_matrix, num_chips=22)
assert isinstance(chart, Chart)


def test_cameratrax_and_astro_consistent_color_calibration(transform_test_data):
"""Test for PlantCV."""
# Load rgb image
Expand Down