Repository: Project-MONAI/MONAI

Issue:
Add more properties in DecathlonDataset
**Is your feature request related to a problem? Please describe.**
We can load properties from the JSON config file of DecathlonDataset, for example: number of classes.



Discussion:

Patch:
diff --git a/monai/apps/datasets.py b/monai/apps/datasets.py
--- a/monai/apps/datasets.py
+++ b/monai/apps/datasets.py
@@ -14,8 +14,9 @@
 from typing import Any, Callable, Dict, List, Optional, Sequence, Union
 
 from monai.apps.utils import download_and_extract
-from monai.data import CacheDataset, load_decathlon_datalist
+from monai.data import CacheDataset, load_decathlon_datalist, load_decathlon_properties
 from monai.transforms import LoadNiftid, LoadPNGd, Randomizable
+from monai.utils import ensure_tuple
 
 
 class MedNISTDataset(Randomizable, CacheDataset):
@@ -135,6 +136,8 @@ class DecathlonDataset(Randomizable, CacheDataset):
     """
     The Dataset to automatically download the data of Medical Segmentation Decathlon challenge
     (http://medicaldecathlon.com/) and generate items for training, validation or test.
+    It will also load these properties from the JSON config file of dataset. user can call `get_properties()`
+    to get specified properties or all the properties loaded.
     It's based on :py:class:`monai.data.CacheDataset` to accelerate the training process.
 
     Args:
@@ -241,11 +244,37 @@ def __init__(
                 f"Cannot find dataset directory: {dataset_dir}, please use download=True to download it."
             )
         data = self._generate_data_list(dataset_dir)
+        property_keys = [
+            "name",
+            "description",
+            "reference",
+            "licence",
+            "relase",
+            "tensorImageSize",
+            "modality",
+            "labels",
+            "numTraining",
+            "numTest",
+        ]
+        self._properties = load_decathlon_properties(os.path.join(dataset_dir, "dataset.json"), property_keys)
         super().__init__(data, transform, cache_num=cache_num, cache_rate=cache_rate, num_workers=num_workers)
 
     def randomize(self, data: Optional[Any] = None) -> None:
         self.rann = self.R.random()
 
+    def get_properties(self, keys: Optional[Union[Sequence[str], str]] = None):
+        """
+        Get the loaded properties of dataset with specified keys.
+        If no keys specified, return all the loaded properties.
+
+        """
+        if keys is None:
+            return self._properties
+        elif self._properties is not None:
+            return {key: self._properties[key] for key in ensure_tuple(keys)}
+        else:
+            return {}
+
     def _generate_data_list(self, dataset_dir: str) -> List[Dict]:
         section = "training" if self.section in ["training", "validation"] else "test"
         datalist = load_decathlon_datalist(os.path.join(dataset_dir, "dataset.json"), True, section)
diff --git a/monai/data/__init__.py b/monai/data/__init__.py
--- a/monai/data/__init__.py
+++ b/monai/data/__init__.py
@@ -12,7 +12,7 @@
 from .csv_saver import CSVSaver
 from .dataloader import DataLoader
 from .dataset import ArrayDataset, CacheDataset, Dataset, PersistentDataset, SmartCacheDataset, ZipDataset
-from .decathlon_datalist import load_decathlon_datalist
+from .decathlon_datalist import load_decathlon_datalist, load_decathlon_properties
 from .grid_dataset import GridPatchDataset
 from .image_reader import *
 from .nifti_reader import NiftiDataset
diff --git a/monai/data/decathlon_datalist.py b/monai/data/decathlon_datalist.py
--- a/monai/data/decathlon_datalist.py
+++ b/monai/data/decathlon_datalist.py
@@ -11,7 +11,9 @@
 
 import json
 import os
-from typing import Dict, List, Optional, overload
+from typing import Dict, List, Optional, Sequence, Union, overload
+
+from monai.utils import ensure_tuple
 
 
 @overload
@@ -113,3 +115,30 @@ def load_decathlon_datalist(
         base_dir = os.path.dirname(data_list_file_path)
 
     return _append_paths(base_dir, is_segmentation, expected_data)
+
+
+def load_decathlon_properties(
+    data_property_file_path: str,
+    property_keys: Union[Sequence[str], str],
+) -> Dict:
+    """Load the properties from the JSON file contains data property with specified `property_keys`.
+
+    Args:
+        data_property_file_path: the path to the JSON file of data properties.
+        property_keys: expected keys to load from the JSON file, for example, we have these keys
+            in the decathlon challenge:
+            `name`, `description`, `reference`, `licence`, `relase`, `tensorImageSize`,
+            `modality`, `labels`, `numTraining`, `numTest`, etc.
+
+    """
+    if not os.path.isfile(data_property_file_path):
+        raise ValueError(f"Data property file {data_property_file_path} does not exist.")
+    with open(data_property_file_path) as json_file:
+        json_data = json.load(json_file)
+
+    properties = dict()
+    for key in ensure_tuple(property_keys):
+        if key not in json_data:
+            raise KeyError(f"key {key} is not in the data property file.")
+        properties[key] = json_data[key]
+    return properties


Test patch:
diff --git a/tests/test_decathlondataset.py b/tests/test_decathlondataset.py
--- a/tests/test_decathlondataset.py
+++ b/tests/test_decathlondataset.py
@@ -61,6 +61,16 @@ def _test_dataset(dataset):
         _test_dataset(data)
         data = DecathlonDataset(root_dir=testing_dir, task="Task04_Hippocampus", section="validation", download=False)
         self.assertTupleEqual(data[0]["image"].shape, (33, 47, 34))
+
+        data = DecathlonDataset(
+            root_dir=testing_dir,
+            task="Task04_Hippocampus",
+            section="validation",
+            download=False,
+        )
+        properties = data.get_properties(keys="labels")
+        self.assertDictEqual(properties["labels"], {"0": "background", "1": "Anterior", "2": "Posterior"})
+
         shutil.rmtree(os.path.join(testing_dir, "Task04_Hippocampus"))
         try:
             data = DecathlonDataset(