diff --git a/py-client/client_api.py b/py-client/client_api.py index 8404cdb..c1b8d6d 100644 --- a/py-client/client_api.py +++ b/py-client/client_api.py @@ -217,7 +217,7 @@ def segmentation(self, model, image_in, image_out, session_id=None): selector += '&session_id=' + AIAAUtils.urllib_quote_plus(session_id) in_fields = {'params': '{}'} - in_files = {'image': image_in} if not session_id else {} + in_files = {'datapoint': image_in} if not session_id else {} logger.debug('Using Selector: {}'.format(selector)) logger.debug('Using Fields: {}'.format(in_fields)) @@ -231,6 +231,9 @@ def segmentation(self, model, image_in, image_out, session_id=None): form = json.loads(form) if isinstance(form, str) else form params = form.get('params') + if params is None: # v1 backward compatibility + points = json.loads(form.get('points')) + params = {'points': (json.loads(points) if isinstance(points, str) else points)} params = json.loads(params) if isinstance(params, str) else params AIAAUtils.save_result(files, image_out) @@ -272,7 +275,7 @@ def dextr3d(self, model, point_set, image_in, image_out, pad=20, roi_size='128x1 selector += '&session_id=' + AIAAUtils.urllib_quote_plus(session_id) in_fields = {'params': json.dumps({'points': json.dumps(points)})} - in_files = {'image': cropped_file} if not use_session_input else {} + in_files = {'datapoint': cropped_file} if not use_session_input else {} logger.debug('Using Selector: {}'.format(selector)) logger.debug('Using Fields: {}'.format(in_fields)) @@ -322,7 +325,7 @@ def deepgrow(self, model, foreground, background, image_in, image_out, session_i selector += '&session_id=' + AIAAUtils.urllib_quote_plus(session_id) in_fields = {'params': json.dumps({'foreground': foreground, 'background': background})} - in_files = {'image': image_in} if not session_id else {} + in_files = {'datapoint': image_in} if not session_id else {} logger.debug('Using Selector: {}'.format(selector)) logger.debug('Using Fields: {}'.format(in_fields)) @@ -358,7 +361,7 @@ def mask2polygon(self, image_in, point_ratio): params['more_points'] = point_ratio fields = {'params': json.dumps(params)} - files = {'image': image_in} + files = {'datapoint': image_in} status, response = AIAAUtils.http_multipart('POST', self._server_url, selector, fields, files, multipart_response=False) @@ -411,7 +414,7 @@ def fixpolygon(self, image_in, image_out, polygons, index, vertex_offset, propag params['propagate_neighbor'] = propagate_neighbor fields = {'params': json.dumps(params)} - files = {'image': image_in} + files = {'datapoint': image_in} status, form, files = AIAAUtils.http_multipart('POST', self._server_url, selector, fields, files) if status != 200: diff --git a/slicer-plugin/NvidiaAIAA/SegmentEditorNvidiaAIAA.py b/slicer-plugin/NvidiaAIAA/SegmentEditorNvidiaAIAA.py index 6e4e334..9883550 100644 --- a/slicer-plugin/NvidiaAIAA/SegmentEditorNvidiaAIAA.py +++ b/slicer-plugin/NvidiaAIAA/SegmentEditorNvidiaAIAA.py @@ -83,6 +83,16 @@ def __init__(self, parent): "NVIDIA-AIAA/compressData", compressDataMapper, "valueAsInt", str(qt.SIGNAL("valueAsIntChanged(int)"))) + useSessionCheckBox = qt.QCheckBox() + useSessionCheckBox.checked = False + useSessionCheckBox.toolTip = ("Enable this option to make use of AIAA sessions." + " Volume is uploaded to AIAA as part of session once and it makes segmentation/dextr3d/deepgrow operations faster.") + aiaaGroupLayout.addRow("AIAA Session:", useSessionCheckBox) + useSessionMapper = ctk.ctkBooleanMapper(useSessionCheckBox, "checked", str(qt.SIGNAL("toggled(bool)"))) + parent.registerProperty( + "NVIDIA-AIAA/aiaaSession", useSessionMapper, + "valueAsInt", str(qt.SIGNAL("valueAsIntChanged(int)"))) + vBoxLayout.addWidget(aiaaGroupBox) vBoxLayout.addStretch(1) diff --git a/slicer-plugin/NvidiaAIAA/SegmentEditorNvidiaAIAALib/SegmentEditorEffect.py b/slicer-plugin/NvidiaAIAA/SegmentEditorNvidiaAIAALib/SegmentEditorEffect.py index b8c3b32..0ad0a9f 100644 --- a/slicer-plugin/NvidiaAIAA/SegmentEditorNvidiaAIAALib/SegmentEditorEffect.py +++ b/slicer-plugin/NvidiaAIAA/SegmentEditorNvidiaAIAALib/SegmentEditorEffect.py @@ -13,7 +13,7 @@ import vtk from SegmentEditorEffects import * -from NvidiaAIAAClientAPI.client_api import AIAAClient, AIAAException, urlparse +from NvidiaAIAAClientAPI.client_api import AIAAClient, AIAAException, AIAAError, urlparse class SegmentEditorEffect(AbstractScriptedSegmentEditorEffect): @@ -82,10 +82,7 @@ def serverUrl(self): serverUrl = self.ui.serverComboBox.currentText if not serverUrl: # Default Slicer AIAA server - # serverUrl = "http://skull.cs.queensu.ca:8123" - return slicer.util.settingsValue("NVIDIA-AIAA/serverUrl", "http://0.0.0.0:5000") - - self.saveServerUrl() + serverUrl = "http://skull.cs.queensu.ca:8123" return serverUrl def setupOptionsFrame(self): @@ -102,6 +99,8 @@ def setupOptionsFrame(self): # Set icons and tune widget properties + self.ui.serverComboBox.lineEdit().setPlaceholderText("enter server address or leave empty to use default") + self.ui.fetchModelsButton.setIcon(self.icon('refresh-icon.png')) self.ui.segmentationButton.setIcon(self.icon('nvidia-icon.png')) self.ui.annotationModelFilterPushButton.setIcon(self.icon('filter-icon.png')) @@ -127,6 +126,7 @@ def setupOptionsFrame(self): # Connections self.ui.fetchModelsButton.connect('clicked(bool)', self.onClickFetchModels) + self.ui.serverComboBox.connect('currentIndexChanged(int)', self.onClickFetchModels) self.ui.segmentationModelSelector.connect("currentIndexChanged(int)", self.updateMRMLFromGUI) self.ui.segmentationButton.connect('clicked(bool)', self.onClickSegmentation) self.ui.annotationModelSelector.connect("currentIndexChanged(int)", self.updateMRMLFromGUI) @@ -149,9 +149,13 @@ def currentSegmentID(self): def updateServerSettings(self): self.logic.setServer(self.serverUrl()) - self.logic.setUseCompression(slicer.util.settingsValue("NVIDIA-AIAA/compressData", - True, - converter=slicer.util.toBool)) + self.logic.setUseCompression(slicer.util.settingsValue( + "NVIDIA-AIAA/compressData", + True, converter=slicer.util.toBool)) + self.logic.setUseSession(slicer.util.settingsValue( + "NVIDIA-AIAA/aiaaSession", + False, converter=slicer.util.toBool)) + self.saveServerUrl() def saveServerUrl(self): @@ -180,8 +184,7 @@ def saveServerUrl(self): self.updateServerUrlGUIFromSettings() def onClickFetchModels(self): - self.fetchAIAAModels(showInfo=True) - self.saveServerUrl() + self.fetchAIAAModels(showInfo=False) def fetchAIAAModels(self, showInfo=False): if not self.logic: @@ -193,8 +196,8 @@ def fetchAIAAModels(self, showInfo=False): models = self.logic.list_models() except: slicer.util.errorDisplay("Failed to fetch models from remote server. " - "Make sure server address is correct and {}/v1/models " - "is accessible in browser".format(self.serverUrl()), + "Make sure server address is correct and /v1/models " + "is accessible in browser", detailedText=traceback.format_exc()) return @@ -344,7 +347,7 @@ def createAiaaSessionIfNotExists(self): inputVolume = self.scriptedEffect.parameterSetNode().GetMasterVolumeNode() in_file, session_id = self.logic.getSession(inputVolume) - if session_id: + if in_file or session_id: return in_file, session_id if not self.getPermissionForImageDataUpload(): @@ -368,7 +371,7 @@ def createAiaaSessionIfNotExists(self): def onClickSegmentation(self): in_file, session_id = self.createAiaaSessionIfNotExists() - if session_id is None: + if in_file is None and session_id is None: return start = time.time() @@ -389,13 +392,17 @@ def onClickSegmentation(self): if self.updateSegmentationMask(extreme_points, result_file, modelInfo): result = 'SUCCESS' self.updateGUIFromMRML() - except AIAAException: - self.closeAiaaSession() - slicer.util.warningDisplay(operationDescription + " - session expired. Retry Again!") - return + self.onClickEditAnnotationFiducialPoints() + except AIAAException as ae: + logging.exception("AIAA Exception") + if ae.error == AIAAError.SESSION_EXPIRED: + self.closeAiaaSession() + slicer.util.warningDisplay(operationDescription + " - session expired. Retry Again!") + else: + slicer.util.errorDisplay(operationDescription + " - " + ae.msg, detailedText=traceback.format_exc()) except: + logging.exception("Unknown Exception") slicer.util.errorDisplay(operationDescription + " - unexpected error.", detailedText=traceback.format_exc()) - return finally: qt.QApplication.restoreOverrideCursor() self.progressBar.hide() @@ -403,7 +410,6 @@ def onClickSegmentation(self): msg = 'Run segmentation for ({0}): {1}\t\n' \ 'Time Consumed: {2:3.1f} (sec)'.format(model, result, (time.time() - start)) logging.info(msg) - self.onClickEditAnnotationFiducialPoints() def getFiducialPointsXYZ(self, fiducialNode): v = self.scriptedEffect.parameterSetNode().GetMasterVolumeNode() @@ -449,7 +455,7 @@ def getFiducialPointXYZ(self, fiducialNode, index): def onClickAnnotation(self): in_file, session_id = self.createAiaaSessionIfNotExists() - if session_id is None: + if in_file is None and session_id is None: return start = time.time() @@ -468,13 +474,16 @@ def onClickAnnotation(self): if self.updateSegmentationMask(pointSet, result_file, None, overwriteCurrentSegment=True): result = 'SUCCESS' self.updateGUIFromMRML() - except AIAAException: - self.closeAiaaSession() - slicer.util.warningDisplay(operationDescription + " - session expired. Retry Again!") - return + except AIAAException as ae: + logging.exception("AIAA Exception") + if ae.error == AIAAError.SESSION_EXPIRED: + self.closeAiaaSession() + slicer.util.warningDisplay(operationDescription + " - session expired. Retry Again!") + else: + logging.exception("Unknown Exception") + slicer.util.errorDisplay(operationDescription + " - " + ae.msg, detailedText=traceback.format_exc()) except: slicer.util.errorDisplay(operationDescription + " - unexpected error.", detailedText=traceback.format_exc()) - return finally: qt.QApplication.restoreOverrideCursor() @@ -483,22 +492,28 @@ def onClickAnnotation(self): logging.info(msg) def onClickDeepgrow(self, current_point): + model = self.ui.deepgrowModelSelector.currentText + if not model: + slicer.util.warningDisplay("Please select a deepgrow model") + return + segment = self.currentSegment() if not segment: slicer.util.warningDisplay("Please add/select a segment to run deepgrow") return + foreground_all = self.getFiducialPointsXYZ(self.dgPositiveFiducialNode) + background_all = self.getFiducialPointsXYZ(self.dgNegativeFiducialNode) + + segment.SetTag("AIAA.ForegroundPoints", json.dumps(foreground_all)) + segment.SetTag("AIAA.BackgroundPoints", json.dumps(background_all)) + in_file, session_id = self.createAiaaSessionIfNotExists() - if session_id is None: + if in_file is None and session_id is None: return start = time.time() - model = self.ui.deepgrowModelSelector.currentText - if not model: - slicer.util.warningDisplay("Please select a deepgrow model") - return - label = self.currentSegment().GetName() operationDescription = 'Run Deepgrow for segment: {}; model: {}'.format(label, model) logging.debug(operationDescription) @@ -506,12 +521,6 @@ def onClickDeepgrow(self, current_point): try: qt.QApplication.setOverrideCursor(qt.Qt.WaitCursor) - foreground_all = self.getFiducialPointsXYZ(self.dgPositiveFiducialNode) - background_all = self.getFiducialPointsXYZ(self.dgNegativeFiducialNode) - - segment.SetTag("AIAA.ForegroundPoints", json.dumps(foreground_all)) - segment.SetTag("AIAA.BackgroundPoints", json.dumps(background_all)) - sliceIndex = current_point[2] logging.debug('Slice Index: {}'.format(sliceIndex)) @@ -529,13 +538,16 @@ def onClickDeepgrow(self, current_point): sliceIndex=sliceIndex): result = 'SUCCESS' self.updateGUIFromMRML() - except AIAAException: - self.closeAiaaSession() - slicer.util.warningDisplay(operationDescription + " - session expired. Retry Again!") - return + except AIAAException as ae: + logging.exception("AIAA Exception") + if ae.error == AIAAError.SESSION_EXPIRED: + self.closeAiaaSession() + slicer.util.warningDisplay(operationDescription + " - session expired. Retry Again!") + else: + slicer.util.errorDisplay(operationDescription + " - " + ae.msg, detailedText=traceback.format_exc()) except: + logging.exception("Unknown Exception") slicer.util.errorDisplay(operationDescription + " - unexpected error.", detailedText=traceback.format_exc()) - return finally: qt.QApplication.restoreOverrideCursor() @@ -614,7 +626,7 @@ def activate(self): self.annotationFiducialNode, self.annotationFiducialNodeObservers = self.createFiducialNode( 'A', self.onAnnotationFiducialNodeModified, - [1,0.5,0.5]) + [1, 0.5, 0.5]) self.ui.annotationFiducialPlacementWidget.setCurrentNode(self.annotationFiducialNode) self.ui.annotationFiducialPlacementWidget.setPlaceModeEnabled(False) @@ -623,7 +635,7 @@ def activate(self): self.dgPositiveFiducialNode, self.dgPositiveFiducialNodeObservers = self.createFiducialNode( 'P', self.onDeepGrowFiducialNodeModified, - [0.5,1,0.5]) + [0.5, 1, 0.5]) self.ui.dgPositiveFiducialPlacementWidget.setCurrentNode(self.dgPositiveFiducialNode) self.ui.dgPositiveFiducialPlacementWidget.setPlaceModeEnabled(False) @@ -631,7 +643,7 @@ def activate(self): self.dgNegativeFiducialNode, self.dgNegativeFiducialNodeObservers = self.createFiducialNode( 'N', self.onDeepGrowFiducialNodeModified, - [0.5,0.5,1]) + [0.5, 0.5, 1]) self.ui.dgNegativeFiducialPlacementWidget.setCurrentNode(self.dgNegativeFiducialNode) self.ui.dgNegativeFiducialPlacementWidget.setPlaceModeEnabled(False) @@ -660,7 +672,7 @@ def setMRMLDefaults(self): self.scriptedEffect.setParameterDefault("ModelFilterLabel", "") self.scriptedEffect.setParameterDefault("SegmentationModel", "") self.scriptedEffect.setParameterDefault("AnnotationModel", "") - self.scriptedEffect.setParameterDefault("AnnotationModelFiltered", 1) + self.scriptedEffect.setParameterDefault("AnnotationModelFiltered", 0) def observeParameterNode(self, observationEnabled): parameterSetNode = self.scriptedEffect.parameterSetNode() @@ -741,7 +753,7 @@ def updateServerUrlGUIFromSettings(self): self.ui.serverComboBox.setCurrentText(settings.value("NVIDIA-AIAA/serverUrl")) self.ui.serverComboBox.blockSignals(wasBlocked) - def updateSelector(self, selector, model_type, param, filtered): + def updateSelector(self, selector, model_type, param, filtered, defaultIndex=0): wasSelectorBlocked = selector.blockSignals(True) selector.clear() @@ -761,7 +773,7 @@ def updateSelector(self, selector, model_type, param, filtered): currentSegment.GetTag(param, model) modelIndex = selector.findText(model) - modelIndex = 0 if modelIndex < 0 < selector.count else modelIndex + modelIndex = defaultIndex if modelIndex < 0 < selector.count else modelIndex selector.setCurrentIndex(modelIndex) try: @@ -777,17 +789,17 @@ def updateGUIFromMRML(self): self.ui.annotationModelFilterPushButton.checked = annotationModelFiltered self.ui.annotationModelFilterPushButton.blockSignals(wasBlocked) - self.updateSelector(self.ui.segmentationModelSelector, 'segmentation', 'SegmentationModel', False) + self.updateSelector(self.ui.segmentationModelSelector, 'segmentation', 'SegmentationModel', False, 0) self.updateSelector(self.ui.annotationModelSelector, 'annotation', 'AIAA.AnnotationModel', - annotationModelFiltered) - self.updateSelector(self.ui.deepgrowModelSelector, 'deepgrow', 'DeepgrowModel', False) + annotationModelFiltered, -1) + self.updateSelector(self.ui.deepgrowModelSelector, 'deepgrow', 'DeepgrowModel', False, 0) # Enable/Disable self.ui.segmentationButton.setEnabled(self.ui.segmentationModelSelector.currentText) currentSegment = self.currentSegment() if currentSegment: - self.ui.dgNegativeFiducialPlacementWidget.setEnabled(self.ui.deepgrowModelSelector.currentText) + self.ui.dgPositiveFiducialPlacementWidget.setEnabled(self.ui.deepgrowModelSelector.currentText) self.ui.dgNegativeFiducialPlacementWidget.setEnabled(self.ui.deepgrowModelSelector.currentText) if currentSegment and self.annotationFiducialNode and self.ui.annotationModelSelector.currentText: @@ -862,6 +874,7 @@ def onAnnotationFiducialNodeModified(self, observer, eventid): def onDeepGrowFiducialNodeModified(self, observer, eventid): self.updateGUIFromMRML() + logging.debug('Deepgrow Point Event!!') if self.ignoreFiducialNodeAddEvent: return @@ -875,6 +888,11 @@ def onDeepGrowFiducialNodeModified(self, observer, eventid): self.onClickDeepgrow(current_point) + self.ignoreFiducialNodeAddEvent = True + self.onEditFiducialPoints(self.dgPositiveFiducialNode, "AIAA.ForegroundPoints") + self.onEditFiducialPoints(self.dgNegativeFiducialNode, "AIAA.BackgroundPoints") + self.ignoreFiducialNodeAddEvent = False + def updateModelFromSegmentMarkupNode(self): self.updateGUIFromMRML() @@ -891,6 +909,7 @@ def __init__(self, server_url=None, progress_callback=None): self.server_url = server_url self.useCompression = True + self.useSession = False def __del__(self): shutil.rmtree(self.aiaa_tmpdir, ignore_errors=True) @@ -903,12 +922,15 @@ def outputFileExtension(self): def setServer(self, server_url=None): if not server_url: - server_url = 'http://0.0.0.0:5000' + server_url = "http://skull.cs.queensu.ca:8123" self.server_url = server_url def setUseCompression(self, useCompression): self.useCompression = useCompression + def setUseSession(self, useSession): + self.useSession = useSession + def setProgressCallback(self, progress_callback=None): self.progress_callback = progress_callback @@ -923,6 +945,9 @@ def getSession(self, inputVolume): session_id = t[1] server_url = t[2] + if not self.useSession: + return in_file, session_id + parsed_uri1 = urlparse(server_url) result1 = '{uri.scheme}://{uri.netloc}/'.format(uri=parsed_uri1) @@ -944,8 +969,9 @@ def closeSession(self, inputVolume): session_id = t[1] server_url = t[2] - aiaaClient = AIAAClient(server_url) - aiaaClient.close_session(session_id) + if self.useSession: + aiaaClient = AIAAClient(server_url) + aiaaClient.close_session(session_id) self.volumeToAiaaSessions.pop(self.nodeCacheKey(inputVolume)) def createSession(self, inputVolume): @@ -961,12 +987,14 @@ def createSession(self, inputVolume): in_file = t[0] self.reportProgress(30) - aiaaClient = AIAAClient(self.server_url) - response = aiaaClient.create_session(in_file) - logging.info('AIAA Session Response Json: {}'.format(response)) + session_id = None + if self.useSession: + aiaaClient = AIAAClient(self.server_url) + response = aiaaClient.create_session(in_file) + logging.info('AIAA Session Response Json: {}'.format(response)) - session_id = response.get('session_id') - logging.info('Created AIAA session ({0}) in {1:3.1f}s'.format(session_id, time.time() - start)) + session_id = response.get('session_id') + logging.info('Created AIAA session ({0}) in {1:3.1f}s'.format(session_id, time.time() - start)) self.volumeToAiaaSessions[self.nodeCacheKey(inputVolume)] = (in_file, session_id, self.server_url) self.reportProgress(100) @@ -979,8 +1007,9 @@ def closeAllSessions(self): session_id = t[1] server_url = t[2] - aiaaClient = AIAAClient(server_url) - aiaaClient.close_session(session_id) + if self.useSession: + aiaaClient = AIAAClient(server_url) + aiaaClient.close_session(session_id) if os.path.exists(in_file): os.unlink(in_file) @@ -1013,7 +1042,9 @@ def dextr3d(self, image_in, session_id, model, pointset): result_file = tempfile.NamedTemporaryFile(suffix=self.outputFileExtension(), dir=self.aiaa_tmpdir).name aiaaClient = AIAAClient(self.server_url) - aiaaClient.dextr3d(model, pointset, image_in, result_file, pre_process=False, session_id=session_id) + aiaaClient.dextr3d(model, pointset, image_in, result_file, + pre_process=(not self.useSession), + session_id=session_id) return result_file def deepgrow(self, image_in, session_id, model, foreground_point_set, background_point_set): diff --git a/slicer-plugin/NvidiaAIAA/SegmentEditorNvidiaAIAALib/SegmentEditorNvidiaAIAA.ui b/slicer-plugin/NvidiaAIAA/SegmentEditorNvidiaAIAALib/SegmentEditorNvidiaAIAA.ui index 44f19ea..3f07344 100644 --- a/slicer-plugin/NvidiaAIAA/SegmentEditorNvidiaAIAALib/SegmentEditorNvidiaAIAA.ui +++ b/slicer-plugin/NvidiaAIAA/SegmentEditorNvidiaAIAALib/SegmentEditorNvidiaAIAA.ui @@ -121,7 +121,7 @@ Segment from boundary points (DExtr3D) - true + false 9 @@ -140,6 +140,9 @@ filter-icon.pngfilter-icon.png + + false + true @@ -227,7 +230,10 @@ DeepGrow - + + true + + 9 diff --git a/slicer-plugin/README.md b/slicer-plugin/README.md index 14931cd..0c9cd85 100644 --- a/slicer-plugin/README.md +++ b/slicer-plugin/README.md @@ -2,9 +2,10 @@ Nvidia AI-assisted segmentation is available in [3D Slicer](https://www.slicer.org), a popular free, open-source medical image visualization and analysis application. The tool is available in Segment Editor module of the application. -The tool has two modes: -- Fully automatic segmentation: no user inputs required. In "Auto-segmentation" section, choose model, and click Start. Segmentation process may take several minutes (up to about 5-10 minutes for large data sets on computers with slow network upload speed). -- Boundary-points based segmentation: requires user to specify input points near the edge of the structure of interest, one on each side. Segmentation typcally takes less than a minute. +The tool has three modes: +- **Fully automatic segmentation:** no user inputs required. In "Auto-segmentation" section, choose model, and click Start. Segmentation process may take several minutes (up to about 5-10 minutes for large data sets on computers with slow network upload speed). +- **Boundary-points based segmentation:** requires user to specify input points near the edge of the structure of interest, one on each side. Segmentation typcally takes less than a minute. +- **DeepGrow segmentation:** requires user to specify few input points (foreground/background) on the structure of interest. This is a 2D operation and Segmentation happens slice by slicer over every point added. Each click operation typically takes about 1-2 seconds. Example result of automatic segmentation: ![](snapshot.jpg?raw=true "Example segmentation result") @@ -67,10 +68,31 @@ The computer running 3D Slicer does not have any special requirements to run AI- ![](snapshot-segmentation-result-liver.jpg?raw=true "Automatic liver and tumor segmentation results") +### DeepGrow based segmentation of liver on CT: + +- Download Task03_Liver\imagesTr\liver_102.nii.gz data set from http://medicaldecathlon.com/ and load it into 3D Slicer +- Go to **Segment Editor** +- Create a new segment +- Click "Nvidia AIAA" effect +- Expand "Deepgrow" section and possibly select a deepgrow model provided by NVIDIA AIAA +- Click "Foreground mark point" button to add foreground points anywhere on liver (Left+Top window only) +- If the image is already saved in session, the segmentation of Liver for the current slice appears in a second +- Add more points if required for the liver section which are not part of segmentation mask +- If there is any overlap of mask to other regions (background) and needs to be corrected (removed), click "Background mark point" to add background points +- Go to next slice and repeat the process to annotate Liver section (slice-by-slice) + + +> Enable *AIAA session* in **Edit** -> **Application Settings** -> **Nvidia** to save the current volume as part of AIAA session. +> This will help to run DeepGrow actions faster and more interactive over every click points. + +![](snapshot-deepgrow-result-liver.jpg?raw=true "DeepGrow liver results") + + ## Advanced - For locally set up servers or computers with fast upload speed, disable compression in Application Settings / NVidia (since compression may take more time than the time saved by transferring less data) - To filter models based on labels attached to them, set label text in "Models" section of Nvidia AIAA effect user interface. +- Enable AIAA Session to reduce network data transfer between Slicer and AIAA Server in **Edit** -> **Application Settings** -> **Nvidia** (NOTE:: This Option is available only if you are using NVIDIA Clara AIAA Server version 3.0 and above) ## For developers The plugin can be downloaded and installed directly from GitHub: diff --git a/slicer-plugin/snapshot-deepgrow-result-liver.jpg b/slicer-plugin/snapshot-deepgrow-result-liver.jpg new file mode 100644 index 0000000..2d64769 Binary files /dev/null and b/slicer-plugin/snapshot-deepgrow-result-liver.jpg differ