Project-MONAI / Project-MONAI/MONAILabel

Add ability to load different label to current image

Open
#1,436 1 comment 0 reactions 0 assignees View on GitHub

Nobody has claimed this yet.

Dominant language
Python
Stars
891
Forks
269
Avg merge
15h 41m
Merged PRs (30d)
1

Description

Describe the solution you'd like
clicking next image would load 'orignal' label when that setting is enabled. If would be nice to have a user select the tag in the active learning strategy options, then slicer would only call server to get the label with that tag.

image

Describe alternatives you've considered
I managed to get it to work after modifying slicer code. It may be a bit hacky as I assume a cmd name in the strategy to skip calling the main image

    def onNextSampleButton(self):
        if not self.logic:
            return
            
        curr_image_id = self.ui.inputSelector.currentText  # aeh avoid unneeded reload 
        curr_image_id = curr_image_id[:curr_image_id.find(".nii")] if curr_image_id else ""
        print(f"========{curr_image_id}")

        loadNewImage=True
        try:  ## moved code up  duplicate to check command and keep same image 
            # qt.QApplication.setOverrideCursor(qt.Qt.WaitCursor)
            #self.updateServerSettings()
            strategy = self.ui.strategyBox.currentText
            if not strategy:
                slicer.util.errorDisplay("No Strategy Found/Selected\t")
                return
            strategyParams=self.getParamsFromConfig("activelearning", strategy)
            label_tag2get = strategyParams.get('label_tag',"original")
            cmd=strategyParams.get("cmd", None)
            if cmd=="LoadLabelTag" and len(curr_image_id)>0:
                loadNewImage=False
        except BaseException as e:
            msg = f" aeh new code Message:: {e.msg}" if hasattr(e, "msg") else ""
            slicer.util.errorDisplay(
                f"Failed to fetch Sample from MONAI Label Server.\n{msg}",
                detailedText=traceback.format_exc(),
            )
        print(f"========{curr_image_id} {loadNewImage=}")
        
        if loadNewImage and (self._volumeNode or len(slicer.util.getNodesByClass("vtkMRMLScalarVolumeNode")) ):
            if not slicer.util.confirmOkCancelDisplay(
                "This will close current scene.  Please make sure you have saved your current work.\n"
                "Are you sure to continue?"
            ):
                return
            self.onResetScribbles()
            slicer.mrmlScene.Clear(0)

        start = time.time()
        try:
            qt.QApplication.setOverrideCursor(qt.Qt.WaitCursor)

            self.updateServerSettings()
            #strategy = self.ui.strategyBox.currentText  # moved up 
            #if not strategy:
            #    slicer.util.errorDisplay("No Strategy Found/Selected\t")
            #    return
 
            #strategyParams=self.getParamsFromConfig("activelearning", strategy)  #moved up
            #strategyParams["current_loaded_image_id"] = curr_image_id ## will use this id when asking to compare models 

            if not loadNewImage: #aeh avoid un needed reload 
                image_id = curr_image_id
                print(f" keeping same sample {image_id}")
            else:                    

                sample = self.logic.next_sample(strategy, strategyParams )
                logging.debug(sample)
                if not sample.get("id"):
                    slicer.util.warningDisplay(
                        "Unlabled Samples/Images Not Found at server.  Instead you can load your own image."
                    )
                    return

                if loadNewImage and self.samples.get(sample["id"]) is not None:
                    self.current_sample = self.samples[sample["id"]]
                    name = self.current_sample["VolumeNodeName"]
                    index = self.ui.inputSelector.findText(name)
                    self.ui.inputSelector.setCurrentIndex(index)
                    return

                logging.info(sample)
                image_id = sample["id"]
                image_file = sample.get("path")
                image_name = sample.get("name", image_id)
                node_name = sample.get("PatientID", sample.get("name", image_id))
                checksum = sample.get("checksum")
                local_exists = image_file and os.path.exists(image_file)
                
                print(f"------- aeh next sample id is {image_id} labeltag= {label_tag2get} ")
                logging.info(f"Check if file exists/shared locally: {image_file} => {local_exists}")
                if local_exists:
                    self._volumeNode = slicer.util.loadVolume(image_file)
                    self._volumeNode.SetName(node_name)
                else:
                    download_uri = f"{self.serverUrl()}/datastore/image?image={quote_plus(image_id)}"
                    logging.info(download_uri)

                    sampleDataLogic = SampleData.SampleDataLogic()
                    self._volumeNode = sampleDataLogic.downloadFromURL(
                        nodeNames=node_name, fileNames=image_name, uris=download_uri, checksums=checksum
                    )[0]

            if slicer.util.settingsValue("MONAILabel/originalLabel", True, converter=slicer.util.toBool):
                try:
                    datastore = self.logic.datastore()
                    label_info = datastore["objects"][image_id]["labels"][label_tag2get]["info"]
                    labels = label_info.get("params", {}).get("label_names", {})

                    if labels:
                        # labels are available in original label info
                        labels = labels.keys()
                    else:
                        # labels not available
                        # assume labels in app info are valid for original label file
                        labels = self.logic.info().get("labels")

                    # ext = datastore['objects'][image_id]['labels']['original']['ext']
                    maskFile = self.logic.download_label(image_id, label_tag2get)
                    self.updateSegmentationMask(maskFile, list(labels))   ## aeh copied above
                    print(f"label tag {label_tag2get} label loaded! ")
                except:
                    print(f"label tag {label_tag2get} label not found /errors ... ")
            
            if loadNewImage: ## aeh added condition
                self.initSample(sample)

        except BaseException as e:
            msg = f"Message:: {e.msg}" if hasattr(e, "msg") else ""
            slicer.util.errorDisplay(f"Failed to fetch Sample from MONAI Label Server.\n{msg}",detailedText=traceback.format_exc(), )
        finally:
            qt.QApplication.restoreOverrideCursor()

        self.updateGUIFromParameterNode()
        logging.info(f"Time consumed by next_sample: {time.time() - start:3.1f}")

Contributor guide

Open the contributing guide

First steps

  1. Read the whole issue, then the project's contributing guide.
  2. Comment on the issue to say you are picking it up — it saves two people doing the same work.
  3. Fork the repository and make your change on a branch.
  4. Open a pull request that references the issue number.

Research direction

Start at the Slicer-side onNextSampleButton entry point and trace its calls to next_sample, datastore, download_label, and updateSegmentationMask. Review how active-learning strategy parameters are read, then make selecting a label tag load that tag without unnecessarily reloading the current image. Done means the selected tag is loaded when advancing images and the existing image-loading behavior still works.

Written by the indexing model from the issue text.

Assessment

Tech stack
python
Domain
desktop, machine-learning
Issue type
Feature
Difficulty
4/5
Estimated time
3-5 days
Activity status
Stale
Clarity
Mostly clear
Newbie friendliness
38/100

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.