From 1db55b158c09c18cbbaa73523bdbd1f9ae0bc383 Mon Sep 17 00:00:00 2001 From: Malia Gehan Date: Fri, 30 Jan 2026 13:06:11 -0600 Subject: [PATCH 1/9] added sam format to napari read added function and tests, still need docs. --- plantcv/annotate/napari_read_coor.py | 20 ++++++++++++++++++++ tests/test_napari_read_coor.py | 15 ++++++++++++--- 2 files changed, 32 insertions(+), 3 deletions(-) diff --git a/plantcv/annotate/napari_read_coor.py b/plantcv/annotate/napari_read_coor.py index e571bac..da076c0 100755 --- a/plantcv/annotate/napari_read_coor.py +++ b/plantcv/annotate/napari_read_coor.py @@ -34,4 +34,24 @@ def napari_read_coor(coor, dataformat='yx'): data1.update({key: data2}) data = data1 + if dataformat == 'sam': + pointslist = [] + pointslabel = [] + + for i in range(len(data['pos'])): + x, y = data['pos'][i] + pointslist.append([x, y]) + pointslabel.append(1) + + for i in range(len(data['neg'])): + x, y = data['neg'][i] + pointslist.append([x, y]) + pointslabel.append(0) + + pointslist = [pointslist] + pointslabel = [pointslabel] + data1['points'] = pointslist + data1['labels'] = pointslabel + data = data1 + return data diff --git a/tests/test_napari_read_coor.py b/tests/test_napari_read_coor.py index 55be5ac..5f50d95 100644 --- a/tests/test_napari_read_coor.py +++ b/tests/test_napari_read_coor.py @@ -4,7 +4,7 @@ def test_napari_read_coor_napari(test_data): """Test for PlantCV.Annotate""" # Read in test data - data = napari_read_coor(test_data.coor_data, 'yx') + data = napari_read_coor(test_data.coor_data, dataformat='yx') assert isinstance(data, dict) @@ -12,7 +12,7 @@ def test_napari_read_coor_napari(test_data): def test_napari_read_coor_other(test_data): """Test for PlantCV.Annotate""" # Read in test data - data = napari_read_coor(test_data.coor_data, 'xy') + data = napari_read_coor(test_data.coor_data, dataformat='xy') assert data['germinated'][0] == (10, 25) @@ -21,6 +21,15 @@ def test_napari_read_coor_flip(): """Test for PlantCV.Annotate""" # Read in test data coor = {"germinated": [[25, 10]]} - data = napari_read_coor(coor, 'xy') + data = napari_read_coor(coor, dataformat='xy') assert data['germinated'][0] == (10, 25) + + +def test_napari_read_coor_sam(test_data): + """Test for PlantCV.Annotate""" + # Read in test data + coor = {'pos': [(284, 451)], 'neg': [(206, 160)]} + data = napari_read_coor(coor, dataformat='sam') + + assert data['points'][0][0][0] == 451 From 032050fd6604fe8a5067e21d034d7dad24ab01d5 Mon Sep 17 00:00:00 2001 From: Malia Gehan Date: Fri, 30 Jan 2026 13:31:23 -0600 Subject: [PATCH 2/9] Added sam docs also fixed a problem with a link in naive bayes --- docs/napari_naive_bayes_colors.md | 2 +- docs/napari_read_coor.md | 3 ++- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/docs/napari_naive_bayes_colors.md b/docs/napari_naive_bayes_colors.md index c5a5571..1c10939 100644 --- a/docs/napari_naive_bayes_colors.md +++ b/docs/napari_naive_bayes_colors.md @@ -9,7 +9,7 @@ to get data for naive bayes functions. Collect pixel training data in Napari, ra - **Parameters:** - img - RGB image to extract color information from - - maskdict - dictionary of masks, output of [`napari_points_mask`](docs/napari_points_mask.md) for example + - maskdict - dictionary of masks, output of [`napari_points_mask`](napari_points_mask.md) for example - filename - filename to save data, formatted to work with [Naive Bayes segmentation](https://plantcv.readthedocs.io/en/latest/tutorials/machine_learning_tutorial/) - **Context:** diff --git a/docs/napari_read_coor.md b/docs/napari_read_coor.md index 2d22fc9..d6c382f 100644 --- a/docs/napari_read_coor.md +++ b/docs/napari_read_coor.md @@ -8,7 +8,8 @@ Save Points Labeled in Napari to a File - **Parameters:** - coor - dictionary object of coordinates, or a path to json datafile with dictionary of point coordinates - - dataformat - either 'yx' or 'xy', Napari takes data as y,x format. If data is 'xy' data is converted from x,y to y,x + - dataformat - either 'yx', 'xy', or 'sam', Napari takes data as y,x format. If data is 'xy' data is converted from x,y to y,x. + If data is 'sam' point data is formatted for input into ultralytics sam3 functions. - **Context:** - Import previously labeled points, or points from other functions (e.g. [`pcvan.napari_read_coor`](napari_read_coor.md)) From 74b104ca4b19a919a2d992602a1c0405cb2372a9 Mon Sep 17 00:00:00 2001 From: Malia Gehan Date: Fri, 30 Jan 2026 13:32:09 -0600 Subject: [PATCH 3/9] Update napari_read_coor.py fixed whitespace --- plantcv/annotate/napari_read_coor.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/plantcv/annotate/napari_read_coor.py b/plantcv/annotate/napari_read_coor.py index da076c0..885b8ec 100755 --- a/plantcv/annotate/napari_read_coor.py +++ b/plantcv/annotate/napari_read_coor.py @@ -53,5 +53,5 @@ def napari_read_coor(coor, dataformat='yx'): data1['points'] = pointslist data1['labels'] = pointslabel data = data1 - + return data From c45e57ce8ba8421f48462bb560f1ac1f21b2d0b1 Mon Sep 17 00:00:00 2001 From: Malia Gehan Date: Fri, 30 Jan 2026 13:55:35 -0600 Subject: [PATCH 4/9] deepsource deepsource complained about using range instead of enumerate --- docs/napari_read_coor.md | 2 +- plantcv/annotate/napari_read_coor.py | 8 ++++---- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/docs/napari_read_coor.md b/docs/napari_read_coor.md index d6c382f..5937955 100644 --- a/docs/napari_read_coor.md +++ b/docs/napari_read_coor.md @@ -9,7 +9,7 @@ Save Points Labeled in Napari to a File - **Parameters:** - coor - dictionary object of coordinates, or a path to json datafile with dictionary of point coordinates - dataformat - either 'yx', 'xy', or 'sam', Napari takes data as y,x format. If data is 'xy' data is converted from x,y to y,x. - If data is 'sam' point data is formatted for input into ultralytics sam3 functions. + If data is 'sam' point data is formatted for input into ultralytics sam3 functions. If 'sam' format is selected the function does expect a dictionary with 'pos' and 'neg' points as labelled classes. - **Context:** - Import previously labeled points, or points from other functions (e.g. [`pcvan.napari_read_coor`](napari_read_coor.md)) diff --git a/plantcv/annotate/napari_read_coor.py b/plantcv/annotate/napari_read_coor.py index 885b8ec..b5fd304 100755 --- a/plantcv/annotate/napari_read_coor.py +++ b/plantcv/annotate/napari_read_coor.py @@ -38,13 +38,13 @@ def napari_read_coor(coor, dataformat='yx'): pointslist = [] pointslabel = [] - for i in range(len(data['pos'])): - x, y = data['pos'][i] + for i in enumerate(data['pos']): + x, y = i[1] pointslist.append([x, y]) pointslabel.append(1) - for i in range(len(data['neg'])): - x, y = data['neg'][i] + for i in enumerate(data['neg']): + x, y = i[1] pointslist.append([x, y]) pointslabel.append(0) From 1e92839aa83d7f8e240e7aa357172f6e9f522e36 Mon Sep 17 00:00:00 2001 From: k034b363 Date: Tue, 24 Feb 2026 11:00:43 -0600 Subject: [PATCH 5/9] Fix typos in docs --- docs/napari_read_coor.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/docs/napari_read_coor.md b/docs/napari_read_coor.md index aa706fb..dcd44f9 100644 --- a/docs/napari_read_coor.md +++ b/docs/napari_read_coor.md @@ -1,6 +1,6 @@ ## Read point data into Napari Format -Save Points Labeled in Napari to a File +Read points from a file or dictionary into Napari format **plantcv.napari_read_coor**(*coor, dataformat = 'yx'*) @@ -12,7 +12,7 @@ Save Points Labeled in Napari to a File If data is 'sam' point data is formatted for input into ultralytics sam3 functions. If 'sam' format is selected the function does expect a dictionary with 'pos' and 'neg' points as labelled classes. - **Context:** - - Import previously labeled points, or points from other functions (e.g. [`pcvan.napari_read_coor`](napari_read_coor.md)) + - Import previously labeled points, or points from other functions (e.g. [`pcvan.napari_save_coor`](napari_save_coor.md)) - **Example use:** - Below From 9f692d948ac345b967e7c82d0898fdcb622b125e Mon Sep 17 00:00:00 2001 From: k034b363 Date: Tue, 24 Feb 2026 11:32:24 -0600 Subject: [PATCH 6/9] Simplify code a little --- plantcv/annotate/napari_read_coor.py | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/plantcv/annotate/napari_read_coor.py b/plantcv/annotate/napari_read_coor.py index b5fd304..ced5545 100755 --- a/plantcv/annotate/napari_read_coor.py +++ b/plantcv/annotate/napari_read_coor.py @@ -48,10 +48,8 @@ def napari_read_coor(coor, dataformat='yx'): pointslist.append([x, y]) pointslabel.append(0) - pointslist = [pointslist] - pointslabel = [pointslabel] - data1['points'] = pointslist - data1['labels'] = pointslabel + data1['points'] = [pointslist] + data1['labels'] = [pointslabel] data = data1 return data From 844e5b51b8db6ac9c5094353e96a3b7b0120f017 Mon Sep 17 00:00:00 2001 From: k034b363 Date: Tue, 24 Feb 2026 13:48:36 -0600 Subject: [PATCH 7/9] Add SAM training example to docs --- docs/napari_read_coor.md | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/docs/napari_read_coor.md b/docs/napari_read_coor.md index dcd44f9..9bf1e9c 100644 --- a/docs/napari_read_coor.md +++ b/docs/napari_read_coor.md @@ -28,4 +28,18 @@ data = pcvan.napari_read_coor(coor ='coor.json', dataformat = 'xy') ``` +- **Example use for training Segment Anything Model:** + - Below + +```python +from ultralytics import SAM + +model = SAM("sam3.pt") +results = model.predict(source="./Example_image.jpg", + points=data["points"], + labels=data["labels"]) +results[0].show() + +``` + **Source Code:** [Here](https://github.com/danforthcenter/plantcv-annotate/blob/main/plantcv/annotate/napari_read_coor.py) From f110ac57caddfc08f8a9519d897bb7d58baf46e7 Mon Sep 17 00:00:00 2001 From: k034b363 Date: Tue, 24 Feb 2026 15:01:25 -0600 Subject: [PATCH 8/9] Update docstring --- plantcv/annotate/napari_read_coor.py | 31 ++++++++++++++-------------- 1 file changed, 15 insertions(+), 16 deletions(-) diff --git a/plantcv/annotate/napari_read_coor.py b/plantcv/annotate/napari_read_coor.py index ced5545..1af1f03 100755 --- a/plantcv/annotate/napari_read_coor.py +++ b/plantcv/annotate/napari_read_coor.py @@ -4,22 +4,21 @@ def napari_read_coor(coor, dataformat='yx'): - """ - open img in napari and label classes - - Inputs: - coor = either a dictionary of data or a path to a json file - with dictionary of point coordinates - dataformat = either 'yx' or 'xy'. Output of points function is in - x,y format and Napari is in y,x format. - - Returns: - data = dictionary of data - - :param coor: dict or str - :param dataformat: str - :return data: dictionary of data in y,x format for napari - + """Open img in napari and label classes + + Parameters + ---------- + coor : dict or str + Either a dictionary or path to json file of points and label classes. + dataformat : str + Use 'xy' for points function outputs, 'yx' for Napari outputs, and 'sam' for + Segment Anything Model, which includes "pos" and "neg" labeled classes; + defaults to 'yx'. + + Returns + ---------- + dict + Dictionary of points data. """ if isinstance(coor, dict): data = coor From d30209193e56dd11c32683fd6bcb77624397ef73 Mon Sep 17 00:00:00 2001 From: k034b363 Date: Tue, 24 Feb 2026 15:07:18 -0600 Subject: [PATCH 9/9] Remove trailing whitespace --- plantcv/annotate/napari_read_coor.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/plantcv/annotate/napari_read_coor.py b/plantcv/annotate/napari_read_coor.py index 1af1f03..64c230e 100755 --- a/plantcv/annotate/napari_read_coor.py +++ b/plantcv/annotate/napari_read_coor.py @@ -11,9 +11,9 @@ def napari_read_coor(coor, dataformat='yx'): coor : dict or str Either a dictionary or path to json file of points and label classes. dataformat : str - Use 'xy' for points function outputs, 'yx' for Napari outputs, and 'sam' for + Use 'xy' for points function outputs, 'yx' for Napari outputs, and 'sam' for Segment Anything Model, which includes "pos" and "neg" labeled classes; - defaults to 'yx'. + defaults to 'yx'. Returns ----------