Skip to content

Commit 3016e0b

Browse files
bilalcodehubbilalcodehubpre-commit-ci[bot]
authored
Add cvat_labels_file conf parameter to support CSV label definitions with attributes (#1824)
* Added read_labels_from_file and changed init_datastore to parse CSV labels with JSON attributes passed via cvat_labels_file * [pre-commit.ci] auto fixes from pre-commit.com hooks for more information, see https://pre-commit.ci * Fix: corrected issues from previous PR submission related to imports Signed-off-by: Muhammad Bilal <bilalcodehub> * Fix: corrected issues from previous PR submission Signed-off-by: Muhammad Bilal <[email protected]> * Fix: Add setuptools>=61 for Windows build compatibility with girder-client Signed-off-by: bilalcodehub <[email protected]> * [pre-commit.ci] auto fixes from pre-commit.com hooks for more information, see https://pre-commit.ci * Fix: upgrade setuptools early in CI to avoid girder-client error on Windows Signed-off-by: bilalcodehub <[email protected]> * Fix: resolve mypy type error in endoscopy main.py Signed-off-by: bilalcodehub <[email protected]> --------- Signed-off-by: Muhammad Bilal <bilalcodehub> Signed-off-by: Muhammad Bilal <[email protected]> Signed-off-by: bilalcodehub <[email protected]> Co-authored-by: bilalcodehub <[email protected]> Co-authored-by: pre-commit-ci[bot] <66853113+pre-commit-ci[bot]@users.noreply.github.com>
1 parent 83cc1c6 commit 3016e0b

File tree

3 files changed

+62
-3
lines changed

3 files changed

+62
-3
lines changed

.github/workflows/pythonapp.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -45,7 +45,7 @@ jobs:
4545
rm -rf /opt/hostedtoolcache
4646
- name: Install dependencies
4747
run: |
48-
python -m pip install --upgrade pip wheel
48+
python -m pip install --upgrade pip setuptools wheel
4949
pip install -r requirements.txt
5050
5151
build:

requirements.txt

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,8 @@ pydicom-seg==0.4.1
2929
pynetdicom==2.0.2
3030
pynrrd==1.0.0
3131
numpymaxflow==0.0.7
32+
setuptools>=61
33+
setuptools-scm<8.0.0
3234
girder-client==3.2.3
3335
ninja==1.11.1.1
3436
einops==0.7.0

sample-apps/endoscopy/main.py

Lines changed: 59 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -9,10 +9,12 @@
99
# See the License for the specific language governing permissions and
1010
# limitations under the License.
1111

12+
import csv
13+
import json
1214
import logging
1315
import os
1416
from datetime import timedelta
15-
from typing import Dict
17+
from typing import Dict, List, Union
1618

1719
import lib.configs
1820
import numpy as np
@@ -96,9 +98,64 @@ def __init__(self, app_dir, studies, conf):
9698
)
9799
self.downloading = False
98100

101+
def read_labels_from_file(self, file_path: str) -> List[Dict[str, Union[str, int, list]]]:
102+
labels = []
103+
104+
try:
105+
with open(file_path) as csvfile:
106+
reader = csv.DictReader(csvfile)
107+
108+
for row in reader:
109+
# Check for required fields
110+
if "name" in row and "id" in row and "color" in row:
111+
attributes = []
112+
# Process the attributes if they exist and are not empty
113+
if "attributes" in row and row["attributes"].strip():
114+
try:
115+
attributes = json.loads(row["attributes"].strip())
116+
except json.JSONDecodeError as e:
117+
logger.warning(f"Could not parse attributes JSON for row {row}: {e}")
118+
119+
entry = {
120+
"name": row["name"],
121+
"id": int(row["id"]),
122+
"color": row["color"],
123+
"type": "any",
124+
"attributes": attributes,
125+
}
126+
labels.append(entry)
127+
else:
128+
logger.warning(f"Skipping row due to missing fields: {row}")
129+
130+
logger.info(f"Loaded {len(labels)} labels from {file_path}")
131+
except FileNotFoundError:
132+
logger.error(f"Label file {file_path} not found!")
133+
except Exception as e:
134+
logger.error(f"Error reading label file {file_path}: {e}")
135+
136+
return labels
137+
99138
def init_datastore(self) -> Datastore:
100139
if settings.MONAI_LABEL_DATASTORE_URL and settings.MONAI_LABEL_DATASTORE.lower() == "cvat":
101140
logger.info(f"Using CVAT: {self.studies}")
141+
142+
labels: List[Dict[str, Union[str, int, list]]] = []
143+
144+
# If cvat_labels_file is specified and not null, read labels from that file
145+
cvat_labels_file = self.conf.get("cvat_labels_file")
146+
if cvat_labels_file:
147+
try:
148+
labels = self.read_labels_from_file(cvat_labels_file)
149+
except Exception as e:
150+
logger.error(f"Error reading CVAT labels file {cvat_labels_file}: {e}")
151+
else:
152+
label_str = self.conf.get("cvat_labels")
153+
if label_str:
154+
try:
155+
labels = json.loads(label_str)
156+
except Exception as e:
157+
logger.error(f"Error parsing cvat_labels config: {e}")
158+
102159
return CVATDatastore(
103160
datastore_path=self.studies,
104161
api_url=settings.MONAI_LABEL_DATASTORE_URL,
@@ -107,7 +164,7 @@ def init_datastore(self) -> Datastore:
107164
project=self.conf.get("cvat_project", "MONAILabel"),
108165
task_prefix=self.conf.get("cvat_task_prefix", "ActiveLearning_Iteration"),
109166
image_quality=int(self.conf.get("cvat_image_quality", "70")),
110-
labels=self.conf.get("cvat_labels"),
167+
labels=labels,
111168
normalize_label=strtobool(self.conf.get("cvat_normalize_label", "true")),
112169
segment_size=int(self.conf.get("cvat_segment_size", "1")),
113170
extensions=settings.MONAI_LABEL_DATASTORE_FILE_EXT,

0 commit comments

Comments
 (0)