From 7eeba94a2077a21fd6387a5f132bf075b49c382b Mon Sep 17 00:00:00 2001 From: Malia Gehan Date: Tue, 20 Aug 2024 14:04:41 -0500 Subject: [PATCH 01/14] added function and test added function to extract rgb values and format it for use in naive bayes --- plantcv/annotate/__init__.py | 4 +- plantcv/annotate/napari_naive_bayes_data.py | 40 ++++++++++++++++++ tests/conftest.py | 5 +++ tests/test_napari_naive_bayes.py | 16 +++++++ .../testdata/08_02_16-QTHJ-RIL-019_zoomed.png | Bin 0 -> 139514 bytes tests/testdata/my_maskdict.npy | Bin 0 -> 605382 bytes 6 files changed, 64 insertions(+), 1 deletion(-) create mode 100755 plantcv/annotate/napari_naive_bayes_data.py create mode 100644 tests/test_napari_naive_bayes.py create mode 100755 tests/testdata/08_02_16-QTHJ-RIL-019_zoomed.png create mode 100644 tests/testdata/my_maskdict.npy diff --git a/plantcv/annotate/__init__.py b/plantcv/annotate/__init__.py index 83ad404..381fc73 100644 --- a/plantcv/annotate/__init__.py +++ b/plantcv/annotate/__init__.py @@ -5,6 +5,7 @@ from plantcv.annotate.napari_save_coor import napari_save_coor from plantcv.annotate.napari_read_coor import napari_read_coor from plantcv.annotate.napari_points_mask import napari_points_mask +from plantcv.annotate.napari_naive_bayes_data import napari_naive_bayes_colors __all__ = [ @@ -14,5 +15,6 @@ "napari_join_labels", "napari_save_coor", "napari_read_coor", - "napari_points_mask" + "napari_points_mask", + "napari_naive_bayes_colors" ] diff --git a/plantcv/annotate/napari_naive_bayes_data.py b/plantcv/annotate/napari_naive_bayes_data.py new file mode 100755 index 0000000..48d258a --- /dev/null +++ b/plantcv/annotate/napari_naive_bayes_data.py @@ -0,0 +1,40 @@ +# Get Data from Dictionary of Masks and Format for Naive Bayes + +import pandas as pd +import numpy as np + + +def napari_naive_bayes_colors(img, maskdict, filename): + """ + get names of napari keys + + Inputs: + img = rgb image + maskdict = dictionary of masks, output of napari_points_mask for example + filename = name/path of file to save data + + Returns: + dataarray = pandas data array + + :param img: RGB image + :param maskdict = dictionary of masks + :param filename = str + :return dataarray: pandas dataframe + """ + keys = list(maskdict.keys()) + datadict = {} + for key in keys: + mask = maskdict[key] + nonzero = np.transpose(np.nonzero(mask)) + keydata = [] + for x, y in nonzero: + rgbdata = list(img[x][y]) + rgblist = ", ".join(repr(int(e)) for e in rgbdata) + keydata.append(rgblist) + dict1 = {key: keydata} + datadict.update(dict1) + dataarray = pd.DataFrame.from_dict(datadict, orient='index') + datatranspose = dataarray.transpose() + datatranspose.to_csv(filename, sep="\t", index=False) + + return datatranspose diff --git a/tests/conftest.py b/tests/conftest.py index 75e0997..493493a 100644 --- a/tests/conftest.py +++ b/tests/conftest.py @@ -25,6 +25,11 @@ def __init__(self): # Coordinates File filename_coor = "germinated.txt" self.coor_data = os.path.join(self.datadir, filename_coor) + # Naive Bayes Data + filename_nbrgb = "08_02_16-QTHJ-RIL-019_zoomed.png" + self.nb_rgb = os.path.join(self.datadir, filename_nbrgb) + filename_nbmask = "my_maskdict.npy" + self.nb_mask = os.path.join(self.datadir, filename_nbmask) @pytest.fixture(scope="session") diff --git a/tests/test_napari_naive_bayes.py b/tests/test_napari_naive_bayes.py new file mode 100644 index 0000000..98284df --- /dev/null +++ b/tests/test_napari_naive_bayes.py @@ -0,0 +1,16 @@ +import os +import numpy as np +from plantcv.plantcv import readimage +from plantcv.annotate import napari_naive_bayes_colors + + +def test_napari_join_labels(test_data, tmpdir): + """Test for PlantCV.Annotate""" + # Read in test data + cache_dir = tmpdir.mkdir("cache") + img, _, _ = readimage(test_data.nb_rgb) + maskdict = np.load(test_data.nb_mask, allow_pickle='TRUE').item() + filename = os.path.join(cache_dir, 'tempfile.txt') + data = napari_naive_bayes_colors(img, maskdict, filename) + + assert data.shape == (16, 1) diff --git a/tests/testdata/08_02_16-QTHJ-RIL-019_zoomed.png b/tests/testdata/08_02_16-QTHJ-RIL-019_zoomed.png new file mode 100755 index 0000000000000000000000000000000000000000..f4bcea3db25933bbdff4da477696af2b44dcc5e5 GIT binary patch literal 139514 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