Add CheXlocalize_Dataset for CheXpert official val/test + segmentation masks - #191
Add CheXlocalize_Dataset for CheXpert official val/test + segmentation masks#191AmlanMishra2004 wants to merge 11 commits into
Conversation
…n masks CheX_Dataset can't load CheXlocalize's data: it infers the train/valid split by string-matching the CSV path and raises NotImplementedError otherwise, and it assumes Sex/Age/Frontal-Lateral/AP-PA columns exist, which the blinded official test_labels.csv omits to prevent re-identification. CheXlocalize_Dataset handles both, and adds pathology_masks support for the 10 pathologies with radiologist ground-truth segmentations (COCO RLE via pycocotools), following the pattern in SIIM_Pneumothorax_Dataset.
|
Opened the pre-PR issue per CONTRIBUTING.md: #192 |
ieee8023
left a comment
There was a problem hiding this comment.
Thanks for the contribution! I added some initial comments. The main one is that I'd like all the dataloaders to load masks in the same format. Can you look into aligning this dataloader with that patrern? Look at objectcxr, vinbrain, nih, they all have the same pathology masks keys for each sample.
Also if you can add the license of the annotations into the docstring.
| if "Frontal/Lateral" not in self.csv.columns: | ||
| self.csv["Frontal/Lateral"] = np.where( | ||
| self.csv["Path"].str.contains("_lateral", case=False), "Lateral", "Frontal") | ||
| if "AP/PA" not in self.csv.columns: |
There was a problem hiding this comment.
Is this assumption in the dataset documentation? Otherwise setting "Unknown" is probably better.
| ``gt_segmentations_test.json``. Masks are stored as COCO RLE | ||
| (``pycocotools``) keyed by CXR id (``patientX_studyY_viewZ_frontal``). | ||
| Requires ``pycocotools`` to decode. | ||
|
|
There was a problem hiding this comment.
Can you add an example creating the dataset object, with the names of the files from the dataset set as the correct arguments. No need for paths. Just like csvpath="specialfoldername.xml"
| Cardiomediastinum, Fracture, Lung Lesion, Lung Opacity, Pleural Other, | ||
| Pneumonia, Pneumothorax, Support Devices. | ||
|
|
||
| **Segmentation masks** are available for 10 of these pathologies (all |
There was a problem hiding this comment.
Can you create a notebook do demonstrate this dataloader? The interface should be the same as the other dataloaders with pathology masks. Can you make the format of the masks the same. Can you transform the segmentations into the same format? I think there is already code to transform from the coco format in another dataloader si we can avoid the pycocotools dependency.
There was a problem hiding this comment.
Dug into this — couldn't find an existing COCO RLE mask decoder anywhere in the repo (checked NIH/VinBrain/ObjectCXR/COVID19/SIIM). SIIM's rle2mask decodes a different, incompatible format (flat start length pairs, not COCO's compressed binary counts string).
The closest match is TBX11K_Dataset, which does load a real COCO-schema JSON (images/annotations/categories), but it only reads bbox fields — it never touches compressed RLE pixel masks.
I did try writing a pure-Python decoder for COCO's compressed RLE (translated from maskApi.c), but found it produces wrong masks whenever the annotated region touches pixel (0,0) — a real, not-hypothetical case in this data — so I backed that out. Given pycocotools is only lazily imported when masks are actually requested, I'd rather keep it than risk a hand-rolled RLE codec. Happy to revisit if you can point me at the code you had in mind.
Add a pure-Python COCO RLE decoder so CheXlocalize segmentation masks no longer require pycocotools; SIIM's flat start/length RLE format is incompatible. Co-authored-by: Cursor <cursoragent@cursor.com>
This reverts commit a9caf8b.
| # the blinded test set is AP, PA, or a mix — leave it unknown | ||
| # rather than guess. `views` defaults to include "UNKNOWN" so | ||
| # these frontal images aren't silently dropped. | ||
| self.csv["AP/PA"] = "UNKNOWN" |
There was a problem hiding this comment.
Let's make the strings match other fields like this
| self.csv["AP/PA"] = "UNKNOWN" | |
| self.csv["AP/PA"] = "Unknown" |
| data_aug=None, | ||
| seed=0, | ||
| unique_patients=True, | ||
| pathology_masks=False, |
There was a problem hiding this comment.
Because this dataset is for pathology masks let's default this to true so the user doesn't need to figure it out.
| pathology_masks=False, | |
| pathology_masks=True, |
There was a problem hiding this comment.
I left a comment to run the notebook and include the images but that may be an issue with the license so disregard it.
|
Pushed fixes for the latest review round:
Notebook comment noted as disregarded (license). Let me know if there's more. |
|
Summary of everything addressed since the last review round:
Still open: whether to keep |
|
Everything looks good so far. I'm having issues downloading the cheXlocalize dataset. Once I can do that and test the code I'll approve it. |
|
Just checking in, let me know if there's anything else you need from me, or if I can help with the CheXlocalize download in any way. |
ieee8023
left a comment
There was a problem hiding this comment.
I tried it out and ran into one issue, lets remove than line and then if you can update the docstring to include counts. Then I think it is all set.
| Cardiomediastinum, Fracture, Lung Lesion, Lung Opacity, Pleural Other, | ||
| Pneumonia, Pneumothorax, Support Devices. | ||
|
|
||
| **Segmentation masks** are available for 10 of these pathologies (all |
There was a problem hiding this comment.
It would be nice to have the counts of what masks are available per pathology in both the test and valid sets in this docstring.
| # patient/view parsing below works regardless of the val/test split | ||
| self.csv["Path"] = self.csv["Path"].str.replace("CheXpert-v1.0-small/", "", regex=False) | ||
| self.csv["Path"] = self.csv["Path"].str.replace("CheXpert-v1.0/", "", regex=False) | ||
| self.csv["Path"] = self.csv["Path"].str.replace(r"^valid/", "val/", regex=True) |
There was a problem hiding this comment.
This created an issue when I tried to load the validation set and I needed to comment out this line. Lets remove it.
| self.csv["Path"] = self.csv["Path"].str.replace(r"^valid/", "val/", regex=True) |
Summary
Adds
CheXlocalize_Dataset, a loader for CheXlocalize (Saporta et al., Nature Machine Intelligence 2022, https://doi.org/10.1038/s42256-022-00536-x): the official CheXpert validation/test images and labels, plus radiologist ground-truth segmentation masks for 10 pathologies.CheX_Datasetcan't load this data as-is:Sex/Age/Frontal-Lateral/AP-PAcolumns exist. CheXlocalize's blinded officialtest_labels.csvomits them to prevent re-identification of the test set — loading it withCheX_DatasetraisesKeyError: 'Frontal/Lateral'.'train'/'valid'in the CSV path, and raises a bareNotImplementedErrorotherwise.CheXlocalize_Dataset:CheXpert-v1.0/prefix; the val CSV'svalid/prefix vs. theval/directory name on disk).pathology_masks=True+segmentation_jsonpath=...support for CheXlocalize's ground-truth segmentation JSON (COCO RLE viapycocotools), following the same pattern asSIIM_Pneumothorax_Dataset.get_pathology_mask_dict.Testing
tests/test_dataloaders.pycovering: loading the blinded test CSV (missing columns + no train/valid string match),valid/→val/path normalization, and segmentation mask decoding (including that pathologies absent from the mask JSON correctly yield an all-zero mask).tests/test_dataloaders.pysuite passes (17/17).CheX_Datasetdoes in fact fail on the realtest_labels.csvwithKeyError: 'Frontal/Lateral'.pep8.shclean on the new code.