def testAppletDeserialization(self): g = Graph() op = OpFake(graph=g) dataExportApplet = TrackingBaseDataExportApplet( op, "Tracking Result Export") dataExportSerializer = dataExportApplet.dataSerializers[0] with h5py.File(self.TEST_PROJECT_FILE) as testProject: # serialize TrackingBaseDataExportApplet's topLevelOperator opTrackingBaseDataExport = dataExportApplet.topLevelOperator opTrackingBaseDataExport.SelectedPlugin.setValue('Fiji-MaMuT') opTrackingBaseDataExport.SelectedExportSource.setValue('Plugin') opTrackingBaseDataExport.AdditionalPluginArguments.setValue( {'bdvFilePath': '/tmp/bdv.xml'}) dataExportSerializer.serializeToHdf5(testProject, self.TEST_PROJECT_FILE) # create new instance of TrackingBaseDataExportApplet and deserialize its topLevelOperator dataExportApplet = TrackingBaseDataExportApplet( op, "Tracking Result Export") dataExportSerializer = dataExportApplet.dataSerializers[0] dataExportSerializer.deserializeFromHdf5(testProject, self.TEST_PROJECT_FILE) # check deserialized values in applet's topLevelOperator assert dataExportSerializer.topLevelOperator.SelectedPlugin.value == 'Fiji-MaMuT' assert dataExportSerializer.topLevelOperator.SelectedExportSource.value == 'Plugin' assert dataExportSerializer.topLevelOperator.AdditionalPluginArguments.value[ 'bdvFilePath'] == '/tmp/bdv.xml'
def __init__(self, shell, headless, workflow_cmdline_args, project_creation_args, *args, **kwargs): graph = kwargs['graph'] if 'graph' in kwargs else Graph() if 'graph' in kwargs: del kwargs['graph'] super(ManualTrackingWorkflow, self).__init__(shell, headless, workflow_cmdline_args, project_creation_args, graph=graph, *args, **kwargs) data_instructions = 'Use the "Raw Data" tab to load your intensity image(s).\n\n'\ 'Use the "Prediction Maps" tab to load your pixel-wise probability image(s).' ## Create applets self.dataSelectionApplet = DataSelectionApplet( self, "Input Data", "Input Data", forceAxisOrder=['txyzc'], instructionText=data_instructions, max_lanes=1) opDataSelection = self.dataSelectionApplet.topLevelOperator opDataSelection.DatasetRoles.setValue(['Raw Data', 'Prediction Maps']) self.thresholdTwoLevelsApplet = ThresholdTwoLevelsApplet( self, "Threshold and Size Filter", "ThresholdTwoLevels") self.objectExtractionApplet = ObjectExtractionApplet( name="Object Feature Computation", workflow=self, interactive=False) self.trackingApplet = ManualTrackingApplet(workflow=self) self.default_export_filename = '{dataset_dir}/{nickname}-exported_data.csv' self.dataExportApplet = TrackingBaseDataExportApplet( self, "Tracking Result Export", default_export_filename=self.default_export_filename, ) opDataExport = self.dataExportApplet.topLevelOperator opDataExport.SelectionNames.setValue( ['Manual Tracking', 'Object Identities']) opDataExport.WorkingDirectory.connect(opDataSelection.WorkingDirectory) # Extra configuration for object export table (as CSV table or HDF5 table) opTracking = self.trackingApplet.topLevelOperator self.dataExportApplet.set_exporting_operator(opTracking) #self.dataExportApplet.post_process_lane_export = self.post_process_lane_export self._applets = [] self._applets.append(self.dataSelectionApplet) self._applets.append(self.thresholdTwoLevelsApplet) self._applets.append(self.objectExtractionApplet) self._applets.append(self.trackingApplet) self._applets.append(self.dataExportApplet)
def __init__(self, shell, headless, workflow_cmdline_args, project_creation_args, *args, **kwargs): graph = kwargs['graph'] if 'graph' in kwargs else Graph() if 'graph' in kwargs: del kwargs['graph'] super(ManualTrackingWorkflow, self).__init__(shell, headless, workflow_cmdline_args, project_creation_args, graph=graph, *args, **kwargs) data_instructions = 'Use the "Raw Data" tab to load your intensity image(s).\n\n'\ 'Use the "Prediction Maps" tab to load your pixel-wise probability image(s).' ## Create applets self.dataSelectionApplet = DataSelectionApplet( self, "Input Data", "Input Data", batchDataGui=False, force5d=True, instructionText=data_instructions, max_lanes=1) opDataSelection = self.dataSelectionApplet.topLevelOperator opDataSelection.DatasetRoles.setValue(['Raw Data', 'Prediction Maps']) self.thresholdTwoLevelsApplet = ThresholdTwoLevelsApplet( self, "Threshold and Size Filter", "ThresholdTwoLevels") self.objectExtractionApplet = ObjectExtractionApplet( name="Object Feature Computation", workflow=self, interactive=False) self.trackingApplet = ManualTrackingApplet(workflow=self) opTracking = self.trackingApplet.topLevelOperator self.dataExportApplet = TrackingBaseDataExportApplet( self, "Tracking Result Export") self.dataExportApplet.set_exporting_operator(opTracking) opDataExport = self.dataExportApplet.topLevelOperator opDataExport.SelectionNames.setValue( ['Manual Tracking', 'Object Identities']) opDataExport.WorkingDirectory.connect(opDataSelection.WorkingDirectory) self._applets = [] self._applets.append(self.dataSelectionApplet) self._applets.append(self.thresholdTwoLevelsApplet) self._applets.append(self.objectExtractionApplet) self._applets.append(self.trackingApplet) self._applets.append(self.dataExportApplet)
def testAppletSerialization(self): g = Graph() op = OpFake(graph=g) dataExportApplet = TrackingBaseDataExportApplet( op, "Tracking Result Export") dataExportSerializer = dataExportApplet.dataSerializers[0] with h5py.File(self.TEST_PROJECT_FILE) as testProject: opTrackingBaseDataExport = dataExportApplet.topLevelOperator opTrackingBaseDataExport.SelectedPlugin.setValue('Fiji-MaMuT') opTrackingBaseDataExport.SelectedExportSource.setValue('Plugin') opTrackingBaseDataExport.AdditionalPluginArguments.setValue( {'bdvFilePath': '/tmp/bdv.xml'}) dataExportSerializer.serializeToHdf5(testProject, self.TEST_PROJECT_FILE) # check serialized values with h5py.File(self.TEST_PROJECT_FILE) as testProject: assert testProject[ "Tracking Result Export/SelectedPlugin"].value.decode( ) == 'Fiji-MaMuT' assert testProject[ "Tracking Result Export/SelectedExportSource"].value.decode( ) == 'Plugin' assert testProject[ "Tracking Result Export/AdditionalPluginArguments/bdvFilePath"].value.decode( ) == '/tmp/bdv.xml'
def data_export_applet(): op = Operator(graph=Graph()) dataExportApplet = TrackingBaseDataExportApplet(op, "Tracking Result Export") opTrackingBaseDataExport = dataExportApplet.topLevelOperator opTrackingBaseDataExport.SelectedPlugin.setValue("Fiji-MaMuT") opTrackingBaseDataExport.SelectedExportSource.setValue("Plugin") opTrackingBaseDataExport.AdditionalPluginArguments.setValue( {"bdvFilePath": "/tmp/bdv.xml"}) return dataExportApplet
def __init__( self, shell, headless, workflow_cmdline_args, project_creation_args, *args, **kwargs ): graph = kwargs['graph'] if 'graph' in kwargs else Graph() if 'graph' in kwargs: del kwargs['graph'] super(ManualTrackingWorkflow, self).__init__(shell, headless, workflow_cmdline_args, project_creation_args, graph=graph, *args, **kwargs) data_instructions = 'Use the "Raw Data" tab to load your intensity image(s).\n\n'\ 'Use the "Prediction Maps" tab to load your pixel-wise probability image(s).' ## Create applets self.dataSelectionApplet = DataSelectionApplet(self, "Input Data", "Input Data", forceAxisOrder=['txyzc'], instructionText=data_instructions, max_lanes=1 ) opDataSelection = self.dataSelectionApplet.topLevelOperator opDataSelection.DatasetRoles.setValue( ['Raw Data', 'Prediction Maps'] ) self.thresholdTwoLevelsApplet = ThresholdTwoLevelsApplet( self, "Threshold and Size Filter", "ThresholdTwoLevels" ) self.objectExtractionApplet = ObjectExtractionApplet(name="Object Feature Computation", workflow=self, interactive=False) self.trackingApplet = ManualTrackingApplet( workflow=self ) self.default_export_filename = '{dataset_dir}/{nickname}-exported_data.csv' self.dataExportApplet = TrackingBaseDataExportApplet( self, "Tracking Result Export", default_export_filename=self.default_export_filename, ) opDataExport = self.dataExportApplet.topLevelOperator opDataExport.SelectionNames.setValue( ['Manual Tracking', 'Object Identities'] ) opDataExport.WorkingDirectory.connect( opDataSelection.WorkingDirectory ) # Extra configuration for object export table (as CSV table or HDF5 table) opTracking = self.trackingApplet.topLevelOperator self.dataExportApplet.set_exporting_operator(opTracking) #self.dataExportApplet.post_process_lane_export = self.post_process_lane_export self._applets = [] self._applets.append(self.dataSelectionApplet) self._applets.append(self.thresholdTwoLevelsApplet) self._applets.append(self.objectExtractionApplet) self._applets.append(self.trackingApplet) self._applets.append(self.dataExportApplet)
def test_applet_deserialization(project_path, data_export_applet): with h5py.File(project_path, "w") as project_file: data_export_applet.dataSerializers[0].serializeToHdf5( project_file, project_path) op = Operator(graph=Graph()) data_export_applet = TrackingBaseDataExportApplet( op, "Tracking Result Export") with h5py.File(project_path, "r") as project_file: data_export_applet.dataSerializers[0].deserializeFromHdf5( project_file, project_path) opTrackingBaseDataExport = data_export_applet.dataSerializers[ 0].topLevelOperator assert opTrackingBaseDataExport.SelectedPlugin.value == "Fiji-MaMuT" assert opTrackingBaseDataExport.SelectedExportSource.value == "Plugin" assert opTrackingBaseDataExport.AdditionalPluginArguments.value[ "bdvFilePath"] == "/tmp/bdv.xml"
def __init__( self, shell, headless, workflow_cmdline_args, project_creation_args, *args, **kwargs ): graph = kwargs['graph'] if 'graph' in kwargs else Graph() if 'graph' in kwargs: del kwargs['graph'] super(ManualTrackingWorkflow, self).__init__(shell, headless, workflow_cmdline_args, project_creation_args, graph=graph, *args, **kwargs) data_instructions = 'Use the "Raw Data" tab to load your intensity image(s).\n\n'\ 'Use the "Prediction Maps" tab to load your pixel-wise probability image(s).' ## Create applets self.dataSelectionApplet = DataSelectionApplet(self, "Input Data", "Input Data", batchDataGui=False, force5d=True, instructionText=data_instructions, max_lanes=1 ) opDataSelection = self.dataSelectionApplet.topLevelOperator opDataSelection.DatasetRoles.setValue( ['Raw Data', 'Prediction Maps'] ) self.thresholdTwoLevelsApplet = ThresholdTwoLevelsApplet( self, "Threshold and Size Filter", "ThresholdTwoLevels" ) self.objectExtractionApplet = ObjectExtractionApplet(name="Object Feature Computation", workflow=self, interactive=False) self.trackingApplet = ManualTrackingApplet( workflow=self ) opTracking = self.trackingApplet.topLevelOperator self.dataExportApplet = TrackingBaseDataExportApplet(self, "Tracking Result Export") self.dataExportApplet.set_exporting_operator(opTracking) opDataExport = self.dataExportApplet.topLevelOperator opDataExport.SelectionNames.setValue( ['Manual Tracking', 'Object Identities'] ) opDataExport.WorkingDirectory.connect( opDataSelection.WorkingDirectory ) self._applets = [] self._applets.append(self.dataSelectionApplet) self._applets.append(self.thresholdTwoLevelsApplet) self._applets.append(self.objectExtractionApplet) self._applets.append(self.trackingApplet) self._applets.append(self.dataExportApplet)
def __init__( self, shell, headless, workflow_cmdline_args, project_creation_args, *args, **kwargs ): graph = kwargs['graph'] if 'graph' in kwargs else Graph() if 'graph' in kwargs: del kwargs['graph'] # if 'withOptTrans' in kwargs: # self.withOptTrans = kwargs['withOptTrans'] # if 'fromBinary' in kwargs: # self.fromBinary = kwargs['fromBinary'] super(ConservationTrackingWorkflowBase, self).__init__(shell, headless, workflow_cmdline_args, project_creation_args, graph=graph, *args, **kwargs) data_instructions = 'Use the "Raw Data" tab to load your intensity image(s).\n\n' if self.fromBinary: data_instructions += 'Use the "Binary Image" tab to load your segmentation image(s).' else: data_instructions += 'Use the "Prediction Maps" tab to load your pixel-wise probability image(s).' # Variables to store division and cell classifiers to prevent retraining every-time batch processing runs self.stored_division_classifier = None self.stored_cell_classifier = None ## Create applets self.dataSelectionApplet = DataSelectionApplet(self, "Input Data", "Input Data", forceAxisOrder=['txyzc'], instructionText=data_instructions, max_lanes=None ) opDataSelection = self.dataSelectionApplet.topLevelOperator if self.fromBinary: opDataSelection.DatasetRoles.setValue( ['Raw Data', 'Segmentation Image'] ) else: opDataSelection.DatasetRoles.setValue( ['Raw Data', 'Prediction Maps'] ) if not self.fromBinary: self.thresholdTwoLevelsApplet = ThresholdTwoLevelsApplet( self, "Threshold and Size Filter", "ThresholdTwoLevels" ) self.objectExtractionApplet = TrackingFeatureExtractionApplet(workflow=self, interactive=False, name="Object Feature Computation") opObjectExtraction = self.objectExtractionApplet.topLevelOperator self.divisionDetectionApplet = self._createDivisionDetectionApplet(configConservation.selectedFeaturesDiv) # Might be None if self.divisionDetectionApplet: feature_dict_division = {} feature_dict_division[config.features_division_name] = { name: {} for name in config.division_features } opObjectExtraction.FeatureNamesDivision.setValue(feature_dict_division) selected_features_div = {} for plugin_name in list(config.selected_features_division.keys()): selected_features_div[plugin_name] = { name: {} for name in config.selected_features_division[plugin_name] } # FIXME: do not hard code this for name in [ 'SquaredDistances_' + str(i) for i in range(config.n_best_successors) ]: selected_features_div[config.features_division_name][name] = {} opDivisionDetection = self.divisionDetectionApplet.topLevelOperator opDivisionDetection.SelectedFeatures.setValue(configConservation.selectedFeaturesDiv) opDivisionDetection.LabelNames.setValue(['Not Dividing', 'Dividing']) opDivisionDetection.AllowDeleteLabels.setValue(False) opDivisionDetection.AllowAddLabel.setValue(False) opDivisionDetection.EnableLabelTransfer.setValue(False) self.cellClassificationApplet = ObjectClassificationApplet(workflow=self, name="Object Count Classification", projectFileGroupName="CountClassification", selectedFeatures=configConservation.selectedFeaturesObjectCount) selected_features_objectcount = {} for plugin_name in list(config.selected_features_objectcount.keys()): selected_features_objectcount[plugin_name] = { name: {} for name in config.selected_features_objectcount[plugin_name] } opCellClassification = self.cellClassificationApplet.topLevelOperator opCellClassification.SelectedFeatures.setValue(configConservation.selectedFeaturesObjectCount) opCellClassification.SuggestedLabelNames.setValue( ['False Detection',] + [str(1) + ' Object'] + [str(i) + ' Objects' for i in range(2,10) ] ) opCellClassification.AllowDeleteLastLabelOnly.setValue(True) opCellClassification.EnableLabelTransfer.setValue(False) self.trackingApplet = ConservationTrackingApplet( workflow=self ) self.default_export_filename = '{dataset_dir}/{nickname}-exported_data.csv' self.dataExportApplet = TrackingBaseDataExportApplet( self, "Tracking Result Export", default_export_filename=self.default_export_filename, pluginExportFunc=self._pluginExportFunc, ) opDataExport = self.dataExportApplet.topLevelOperator opDataExport.SelectionNames.setValue( ['Object-Identities', 'Tracking-Result', 'Merger-Result'] ) opDataExport.WorkingDirectory.connect( opDataSelection.WorkingDirectory ) # Extra configuration for object export table (as CSV table or HDF5 table) opTracking = self.trackingApplet.topLevelOperator self.dataExportApplet.set_exporting_operator(opTracking) self.dataExportApplet.prepare_lane_for_export = self.prepare_lane_for_export # configure export settings # settings = {'file path': self.default_export_filename, 'compression': {}, 'file type': 'csv'} # selected_features = ['Count', 'RegionCenter', 'RegionRadii', 'RegionAxes'] # opTracking.ExportSettings.setValue( (settings, selected_features) ) self._applets = [] self._applets.append(self.dataSelectionApplet) if not self.fromBinary: self._applets.append(self.thresholdTwoLevelsApplet) self._applets.append(self.objectExtractionApplet) if self.divisionDetectionApplet: self._applets.append(self.divisionDetectionApplet) self.batchProcessingApplet = BatchProcessingApplet(self, "Batch Processing", self.dataSelectionApplet, self.dataExportApplet) self._applets.append(self.cellClassificationApplet) self._applets.append(self.trackingApplet) self._applets.append(self.dataExportApplet) self._applets.append(self.batchProcessingApplet) # Parse export and batch command-line arguments for headless mode if workflow_cmdline_args: self._data_export_args, unused_args = self.dataExportApplet.parse_known_cmdline_args( workflow_cmdline_args ) self._batch_input_args, unused_args = self.batchProcessingApplet.parse_known_cmdline_args( workflow_cmdline_args ) else: unused_args = None self._data_export_args = None self._batch_input_args = None if unused_args: logger.warning("Unused command-line args: {}".format( unused_args ))
class ManualTrackingWorkflow( Workflow ): workflowName = "Manual Tracking Workflow" workflowDisplayName = "Manual Tracking Workflow [Inputs: Raw Data, Pixel Prediction Map]" workflowDescription = "Manual tracking of objects, based on Prediction Maps or (binary) Segmentation Images" @property def applets(self): return self._applets @property def imageNameListSlot(self): return self.dataSelectionApplet.topLevelOperator.ImageName def __init__( self, shell, headless, workflow_cmdline_args, project_creation_args, *args, **kwargs ): graph = kwargs['graph'] if 'graph' in kwargs else Graph() if 'graph' in kwargs: del kwargs['graph'] super(ManualTrackingWorkflow, self).__init__(shell, headless, workflow_cmdline_args, project_creation_args, graph=graph, *args, **kwargs) data_instructions = 'Use the "Raw Data" tab to load your intensity image(s).\n\n'\ 'Use the "Prediction Maps" tab to load your pixel-wise probability image(s).' ## Create applets self.dataSelectionApplet = DataSelectionApplet(self, "Input Data", "Input Data", batchDataGui=False, force5d=True, instructionText=data_instructions, max_lanes=1 ) opDataSelection = self.dataSelectionApplet.topLevelOperator opDataSelection.DatasetRoles.setValue( ['Raw Data', 'Prediction Maps'] ) self.thresholdTwoLevelsApplet = ThresholdTwoLevelsApplet( self, "Threshold and Size Filter", "ThresholdTwoLevels" ) self.objectExtractionApplet = ObjectExtractionApplet(name="Object Feature Computation", workflow=self, interactive=False) self.trackingApplet = ManualTrackingApplet( workflow=self ) opTracking = self.trackingApplet.topLevelOperator self.dataExportApplet = TrackingBaseDataExportApplet(self, "Tracking Result Export") self.dataExportApplet.set_exporting_operator(opTracking) opDataExport = self.dataExportApplet.topLevelOperator opDataExport.SelectionNames.setValue( ['Manual Tracking', 'Object Identities'] ) opDataExport.WorkingDirectory.connect( opDataSelection.WorkingDirectory ) self._applets = [] self._applets.append(self.dataSelectionApplet) self._applets.append(self.thresholdTwoLevelsApplet) self._applets.append(self.objectExtractionApplet) self._applets.append(self.trackingApplet) self._applets.append(self.dataExportApplet) def connectLane(self, laneIndex): opData = self.dataSelectionApplet.topLevelOperator.getLane(laneIndex) opObjExtraction = self.objectExtractionApplet.topLevelOperator.getLane(laneIndex) opTracking = self.trackingApplet.topLevelOperator.getLane(laneIndex) opTwoLevelThreshold = self.thresholdTwoLevelsApplet.topLevelOperator.getLane(laneIndex) opDataExport = self.dataExportApplet.topLevelOperator.getLane(laneIndex) ## Connect operators ## op5Raw = OpReorderAxes(parent=self) op5Raw.AxisOrder.setValue("txyzc") op5Raw.Input.connect(opData.ImageGroup[0]) opTwoLevelThreshold.InputImage.connect( opData.ImageGroup[1] ) opTwoLevelThreshold.RawInput.connect( opData.ImageGroup[0] ) # Used for display only # Use OpReorderAxis for both input datasets such that they are guaranteed to # have the same axis order after thresholding op5Binary = OpReorderAxes( parent=self ) op5Binary.AxisOrder.setValue("txyzc") op5Binary.Input.connect( opTwoLevelThreshold.CachedOutput ) opObjExtraction.RawImage.connect( op5Raw.Output ) opObjExtraction.BinaryImage.connect( op5Binary.Output ) opTracking.RawImage.connect( op5Raw.Output ) opTracking.BinaryImage.connect( op5Binary.Output ) opTracking.LabelImage.connect( opObjExtraction.LabelImage ) opTracking.ObjectFeatures.connect( opObjExtraction.RegionFeatures ) opTracking.ComputedFeatureNames.connect(opObjExtraction.ComputedFeatureNames) opDataExport.Inputs.resize(2) opDataExport.Inputs[0].connect( opTracking.TrackImage ) opDataExport.Inputs[1].connect( opTracking.LabelImage ) opDataExport.RawData.connect( op5Raw.Output ) opDataExport.RawDatasetInfo.connect( opData.DatasetGroup[0] ) def _inputReady(self, nRoles): slot = self.dataSelectionApplet.topLevelOperator.ImageGroup if len(slot) > 0: input_ready = True for sub in slot: input_ready = input_ready and \ all([sub[i].ready() for i in range(nRoles)]) else: input_ready = False return input_ready def handleAppletStateUpdateRequested(self): """ Overridden from Workflow base class Called when an applet has fired the :py:attr:`Applet.statusUpdateSignal` """ # If no data, nothing else is ready. input_ready = self._inputReady(2) and not self.dataSelectionApplet.busy opThresholding = self.thresholdTwoLevelsApplet.topLevelOperator thresholdingOutput = opThresholding.CachedOutput thresholding_ready = input_ready and \ len(thresholdingOutput) > 0 opObjectExtraction = self.objectExtractionApplet.topLevelOperator objectExtractionOutput = opObjectExtraction.ComputedFeatureNames features_ready = thresholding_ready and \ len(objectExtractionOutput) > 0 opTracking = self.trackingApplet.topLevelOperator tracking_ready = features_ready and \ len(opTracking.Labels) > 0 and \ opTracking.Labels.ready() and \ opTracking.TrackImage.ready() busy = False busy |= self.dataSelectionApplet.busy busy |= self.dataExportApplet.busy busy |= self.trackingApplet.busy self._shell.enableProjectChanges( not busy ) self._shell.setAppletEnabled(self.dataSelectionApplet, not busy) self._shell.setAppletEnabled(self.thresholdTwoLevelsApplet, input_ready and not busy) self._shell.setAppletEnabled(self.objectExtractionApplet, thresholding_ready and not busy) self._shell.setAppletEnabled(self.trackingApplet, features_ready and not busy) self._shell.setAppletEnabled(self.dataExportApplet, tracking_ready and not busy and \ self.dataExportApplet.topLevelOperator.Inputs[0][0].ready() )
def __init__( self, shell, headless, workflow_cmdline_args, project_creation_args, *args, **kwargs ): graph = kwargs['graph'] if 'graph' in kwargs else Graph() if 'graph' in kwargs: del kwargs['graph'] super(StructuredTrackingWorkflowBase, self).__init__(shell, headless, workflow_cmdline_args, project_creation_args, graph=graph, *args, **kwargs) data_instructions = 'Use the "Raw Data" tab to load your intensity image(s).\n\n' if self.fromBinary: data_instructions += 'Use the "Binary Image" tab to load your segmentation image(s).' else: data_instructions += 'Use the "Prediction Maps" tab to load your pixel-wise probability image(s).' # Create applets self.dataSelectionApplet = DataSelectionApplet(self, "Input Data", "Input Data", batchDataGui=False, forceAxisOrder=['txyzc'], instructionText=data_instructions, max_lanes=1) opDataSelection = self.dataSelectionApplet.topLevelOperator if self.fromBinary: opDataSelection.DatasetRoles.setValue( ['Raw Data', 'Binary Image'] ) else: opDataSelection.DatasetRoles.setValue( ['Raw Data', 'Prediction Maps'] ) if not self.fromBinary: self.thresholdTwoLevelsApplet = ThresholdTwoLevelsApplet( self,"Threshold and Size Filter","ThresholdTwoLevels" ) self.divisionDetectionApplet = ObjectClassificationApplet(workflow=self, name="Division Detection (optional)", projectFileGroupName="DivisionDetection", selectedFeatures=configStructured.selectedFeaturesDiv) self.cellClassificationApplet = ObjectClassificationApplet(workflow=self, name="Object Count Classification", projectFileGroupName="CountClassification", selectedFeatures=configStructured.selectedFeaturesObjectCount) self.cropSelectionApplet = CropSelectionApplet(self,"Crop Selection","CropSelection") self.trackingFeatureExtractionApplet = TrackingFeatureExtractionApplet(name="Object Feature Computation",workflow=self, interactive=False) self.objectExtractionApplet = ObjectExtractionApplet(name="Object Feature Computation",workflow=self, interactive=False) self.annotationsApplet = AnnotationsApplet( name="Training", workflow=self ) opAnnotations = self.annotationsApplet.topLevelOperator # self.default_training_export_filename = '{dataset_dir}/{nickname}-training_exported_data.csv' # self.dataExportAnnotationsApplet = TrackingBaseDataExportApplet(self, "Training Export",default_export_filename=self.default_training_export_filename) # opDataExportAnnotations = self.dataExportAnnotationsApplet.topLevelOperator # opDataExportAnnotations.SelectionNames.setValue( ['User Training for Tracking', 'Object Identities'] ) # opDataExportAnnotations.WorkingDirectory.connect( opDataSelection.WorkingDirectory ) # self.dataExportAnnotationsApplet.set_exporting_operator(opAnnotations) self.trackingApplet = StructuredTrackingApplet( name="Tracking - Structured Learning", workflow=self ) opStructuredTracking = self.trackingApplet.topLevelOperator self.default_tracking_export_filename = '{dataset_dir}/{nickname}-tracking_exported_data.csv' self.dataExportTrackingApplet = TrackingBaseDataExportApplet(self, "Tracking Result Export",default_export_filename=self.default_tracking_export_filename) opDataExportTracking = self.dataExportTrackingApplet.topLevelOperator opDataExportTracking.SelectionNames.setValue( ['Tracking Result', 'Merger Result', 'Object Identities'] ) opDataExportTracking.WorkingDirectory.connect( opDataSelection.WorkingDirectory ) self.dataExportTrackingApplet.set_exporting_operator(opStructuredTracking) self.dataExportTrackingApplet.post_process_lane_export = self.post_process_lane_export self._applets = [] self._applets.append(self.dataSelectionApplet) if not self.fromBinary: self._applets.append(self.thresholdTwoLevelsApplet) self._applets.append(self.trackingFeatureExtractionApplet) self._applets.append(self.divisionDetectionApplet) self._applets.append(self.cellClassificationApplet) self._applets.append(self.cropSelectionApplet) self._applets.append(self.objectExtractionApplet) self._applets.append(self.annotationsApplet) # self._applets.append(self.dataExportAnnotationsApplet) self._applets.append(self.trackingApplet) self._applets.append(self.dataExportTrackingApplet) if self.divisionDetectionApplet: opDivDetection = self.divisionDetectionApplet.topLevelOperator opDivDetection.SelectedFeatures.setValue(configConservation.selectedFeaturesDiv) opDivDetection.LabelNames.setValue(['Not Dividing', 'Dividing']) opDivDetection.AllowDeleteLabels.setValue(False) opDivDetection.AllowAddLabel.setValue(False) opDivDetection.EnableLabelTransfer.setValue(False) opCellClassification = self.cellClassificationApplet.topLevelOperator opCellClassification.SelectedFeatures.setValue(configConservation.selectedFeaturesObjectCount ) opCellClassification.SuggestedLabelNames.setValue( ['False Detection',] + [str(1) + ' Object'] + [str(i) + ' Objects' for i in range(2,10) ] ) opCellClassification.AllowDeleteLastLabelOnly.setValue(True) opCellClassification.EnableLabelTransfer.setValue(False)
class ConservationTrackingWorkflowBase( Workflow ): workflowName = "Automatic Tracking Workflow (Conservation Tracking) BASE" def __init__( self, shell, headless, workflow_cmdline_args, project_creation_args, *args, **kwargs ): graph = kwargs['graph'] if 'graph' in kwargs else Graph() if 'graph' in kwargs: del kwargs['graph'] # if 'withOptTrans' in kwargs: # self.withOptTrans = kwargs['withOptTrans'] # if 'fromBinary' in kwargs: # self.fromBinary = kwargs['fromBinary'] super(ConservationTrackingWorkflowBase, self).__init__(shell, headless, workflow_cmdline_args, project_creation_args, graph=graph, *args, **kwargs) data_instructions = 'Use the "Raw Data" tab to load your intensity image(s).\n\n' if self.fromBinary: data_instructions += 'Use the "Binary Image" tab to load your segmentation image(s).' else: data_instructions += 'Use the "Prediction Maps" tab to load your pixel-wise probability image(s).' # Variables to store division and cell classifiers to prevent retraining every-time batch processing runs self.stored_division_classifier = None self.stored_cell_classifier = None ## Create applets self.dataSelectionApplet = DataSelectionApplet(self, "Input Data", "Input Data", forceAxisOrder=['txyzc'], instructionText=data_instructions, max_lanes=None ) opDataSelection = self.dataSelectionApplet.topLevelOperator if self.fromBinary: opDataSelection.DatasetRoles.setValue( ['Raw Data', 'Segmentation Image'] ) else: opDataSelection.DatasetRoles.setValue( ['Raw Data', 'Prediction Maps'] ) if not self.fromBinary: self.thresholdTwoLevelsApplet = ThresholdTwoLevelsApplet( self, "Threshold and Size Filter", "ThresholdTwoLevels" ) self.objectExtractionApplet = TrackingFeatureExtractionApplet(workflow=self, interactive=False, name="Object Feature Computation") opObjectExtraction = self.objectExtractionApplet.topLevelOperator self.divisionDetectionApplet = self._createDivisionDetectionApplet(configConservation.selectedFeaturesDiv) # Might be None if self.divisionDetectionApplet: feature_dict_division = {} feature_dict_division[config.features_division_name] = { name: {} for name in config.division_features } opObjectExtraction.FeatureNamesDivision.setValue(feature_dict_division) selected_features_div = {} for plugin_name in list(config.selected_features_division.keys()): selected_features_div[plugin_name] = { name: {} for name in config.selected_features_division[plugin_name] } # FIXME: do not hard code this for name in [ 'SquaredDistances_' + str(i) for i in range(config.n_best_successors) ]: selected_features_div[config.features_division_name][name] = {} opDivisionDetection = self.divisionDetectionApplet.topLevelOperator opDivisionDetection.SelectedFeatures.setValue(configConservation.selectedFeaturesDiv) opDivisionDetection.LabelNames.setValue(['Not Dividing', 'Dividing']) opDivisionDetection.AllowDeleteLabels.setValue(False) opDivisionDetection.AllowAddLabel.setValue(False) opDivisionDetection.EnableLabelTransfer.setValue(False) self.cellClassificationApplet = ObjectClassificationApplet(workflow=self, name="Object Count Classification", projectFileGroupName="CountClassification", selectedFeatures=configConservation.selectedFeaturesObjectCount) selected_features_objectcount = {} for plugin_name in list(config.selected_features_objectcount.keys()): selected_features_objectcount[plugin_name] = { name: {} for name in config.selected_features_objectcount[plugin_name] } opCellClassification = self.cellClassificationApplet.topLevelOperator opCellClassification.SelectedFeatures.setValue(configConservation.selectedFeaturesObjectCount) opCellClassification.SuggestedLabelNames.setValue( ['False Detection',] + [str(1) + ' Object'] + [str(i) + ' Objects' for i in range(2,10) ] ) opCellClassification.AllowDeleteLastLabelOnly.setValue(True) opCellClassification.EnableLabelTransfer.setValue(False) self.trackingApplet = ConservationTrackingApplet( workflow=self ) self.default_export_filename = '{dataset_dir}/{nickname}-exported_data.csv' self.dataExportApplet = TrackingBaseDataExportApplet( self, "Tracking Result Export", default_export_filename=self.default_export_filename, pluginExportFunc=self._pluginExportFunc, ) opDataExport = self.dataExportApplet.topLevelOperator opDataExport.SelectionNames.setValue( ['Object-Identities', 'Tracking-Result', 'Merger-Result'] ) opDataExport.WorkingDirectory.connect( opDataSelection.WorkingDirectory ) # Extra configuration for object export table (as CSV table or HDF5 table) opTracking = self.trackingApplet.topLevelOperator self.dataExportApplet.set_exporting_operator(opTracking) self.dataExportApplet.prepare_lane_for_export = self.prepare_lane_for_export # configure export settings # settings = {'file path': self.default_export_filename, 'compression': {}, 'file type': 'csv'} # selected_features = ['Count', 'RegionCenter', 'RegionRadii', 'RegionAxes'] # opTracking.ExportSettings.setValue( (settings, selected_features) ) self._applets = [] self._applets.append(self.dataSelectionApplet) if not self.fromBinary: self._applets.append(self.thresholdTwoLevelsApplet) self._applets.append(self.objectExtractionApplet) if self.divisionDetectionApplet: self._applets.append(self.divisionDetectionApplet) self.batchProcessingApplet = BatchProcessingApplet(self, "Batch Processing", self.dataSelectionApplet, self.dataExportApplet) self._applets.append(self.cellClassificationApplet) self._applets.append(self.trackingApplet) self._applets.append(self.dataExportApplet) self._applets.append(self.batchProcessingApplet) # Parse export and batch command-line arguments for headless mode if workflow_cmdline_args: self._data_export_args, unused_args = self.dataExportApplet.parse_known_cmdline_args( workflow_cmdline_args ) self._batch_input_args, unused_args = self.batchProcessingApplet.parse_known_cmdline_args( workflow_cmdline_args ) else: unused_args = None self._data_export_args = None self._batch_input_args = None if unused_args: logger.warning("Unused command-line args: {}".format( unused_args )) @property def applets(self): return self._applets def _createDivisionDetectionApplet(self,selectedFeatures=dict()): return ObjectClassificationApplet(workflow=self, name="Division Detection (optional)", projectFileGroupName="DivisionDetection", selectedFeatures=selectedFeatures) @property def imageNameListSlot(self): return self.dataSelectionApplet.topLevelOperator.ImageName def prepareForNewLane(self, laneIndex): # Store division and cell classifiers if self.divisionDetectionApplet: opDivisionClassification = self.divisionDetectionApplet.topLevelOperator if opDivisionClassification.classifier_cache.Output.ready() and \ not opDivisionClassification.classifier_cache._dirty: self.stored_division_classifier = opDivisionClassification.classifier_cache.Output.value else: self.stored_division_classifier = None opCellClassification = self.cellClassificationApplet.topLevelOperator if opCellClassification.classifier_cache.Output.ready() and \ not opCellClassification.classifier_cache._dirty: self.stored_cell_classifier = opCellClassification.classifier_cache.Output.value else: self.stored_cell_classifier = None def handleNewLanesAdded(self): """ If new lanes were added, then we invalidated our classifiers unecessarily. Here, we can restore the classifier so it doesn't need to be retrained. """ # If we have stored division and cell classifiers, restore them into the workflow now. if self.stored_division_classifier: opDivisionClassification = self.divisionDetectionApplet.topLevelOperator opDivisionClassification.classifier_cache.forceValue(self.stored_division_classifier) # Release reference self.stored_division_classifier = None # If we have stored division and cell classifiers, restore them into the workflow now. if self.stored_cell_classifier: opCellClassification = self.cellClassificationApplet.topLevelOperator opCellClassification.classifier_cache.forceValue(self.stored_cell_classifier) # Release reference self.stored_cell_classifier = None def connectLane(self, laneIndex): opData = self.dataSelectionApplet.topLevelOperator.getLane(laneIndex) if not self.fromBinary: opTwoLevelThreshold = self.thresholdTwoLevelsApplet.topLevelOperator.getLane(laneIndex) opObjExtraction = self.objectExtractionApplet.topLevelOperator.getLane(laneIndex) opObjExtraction.setDefaultFeatures(configConservation.allFeaturesObjectCount) if self.divisionDetectionApplet: opDivDetection = self.divisionDetectionApplet.topLevelOperator.getLane(laneIndex) opCellClassification = self.cellClassificationApplet.topLevelOperator.getLane(laneIndex) opTracking = self.trackingApplet.topLevelOperator.getLane(laneIndex) opDataExport = self.dataExportApplet.topLevelOperator.getLane(laneIndex) op5Raw = OpReorderAxes(parent=self) op5Raw.AxisOrder.setValue("txyzc") op5Raw.Input.connect(opData.ImageGroup[0]) if not self.fromBinary: opTwoLevelThreshold.InputImage.connect(opData.ImageGroup[1]) opTwoLevelThreshold.RawInput.connect(opData.ImageGroup[0]) # Used for display only # opTwoLevelThreshold.Channel.setValue(1) binarySrc = opTwoLevelThreshold.CachedOutput else: binarySrc = opData.ImageGroup[1] # Use Op5ifyers for both input datasets such that they are guaranteed to # have the same axis order after thresholding op5Binary = OpReorderAxes(parent=self) op5Binary.AxisOrder.setValue("txyzc") op5Binary.Input.connect(binarySrc) # # Connect operators ## opObjExtraction.RawImage.connect(op5Raw.Output) opObjExtraction.BinaryImage.connect(op5Binary.Output) if self.divisionDetectionApplet: opDivDetection.BinaryImages.connect( op5Binary.Output ) opDivDetection.RawImages.connect( op5Raw.Output ) opDivDetection.SegmentationImages.connect(opObjExtraction.LabelImage) opDivDetection.ObjectFeatures.connect(opObjExtraction.RegionFeaturesAll) opDivDetection.ComputedFeatureNames.connect(opObjExtraction.ComputedFeatureNamesAll) opCellClassification.BinaryImages.connect( op5Binary.Output ) opCellClassification.RawImages.connect( op5Raw.Output ) opCellClassification.SegmentationImages.connect(opObjExtraction.LabelImage) opCellClassification.ObjectFeatures.connect(opObjExtraction.RegionFeaturesVigra) opCellClassification.ComputedFeatureNames.connect(opObjExtraction.FeatureNamesVigra) if self.divisionDetectionApplet: opTracking.ObjectFeaturesWithDivFeatures.connect( opObjExtraction.RegionFeaturesAll) opTracking.ComputedFeatureNamesWithDivFeatures.connect( opObjExtraction.ComputedFeatureNamesAll ) opTracking.DivisionProbabilities.connect( opDivDetection.Probabilities ) opTracking.RawImage.connect( op5Raw.Output ) opTracking.LabelImage.connect( opObjExtraction.LabelImage ) opTracking.ObjectFeatures.connect( opObjExtraction.RegionFeaturesVigra ) opTracking.ComputedFeatureNames.connect( opObjExtraction.FeatureNamesVigra) opTracking.DetectionProbabilities.connect( opCellClassification.Probabilities ) opTracking.NumLabels.connect( opCellClassification.NumLabels ) opDataExport.Inputs.resize(3) opDataExport.Inputs[0].connect( opTracking.RelabeledImage ) opDataExport.Inputs[1].connect( opTracking.Output ) opDataExport.Inputs[2].connect( opTracking.MergerOutput ) opDataExport.RawData.connect( op5Raw.Output ) opDataExport.RawDatasetInfo.connect( opData.DatasetGroup[0] ) def prepare_lane_for_export(self, lane_index): # Bypass cache on headless mode and batch processing mode self.objectExtractionApplet.topLevelOperator[lane_index].BypassModeEnabled.setValue(True) if not self.fromBinary: self.thresholdTwoLevelsApplet.topLevelOperator[lane_index].opCache.BypassModeEnabled.setValue(True) self.thresholdTwoLevelsApplet.topLevelOperator[lane_index].opSmootherCache.BypassModeEnabled.setValue(True) # Get axes info maxt = self.trackingApplet.topLevelOperator[lane_index].RawImage.meta.shape[0] maxx = self.trackingApplet.topLevelOperator[lane_index].RawImage.meta.shape[1] maxy = self.trackingApplet.topLevelOperator[lane_index].RawImage.meta.shape[2] maxz = self.trackingApplet.topLevelOperator[lane_index].RawImage.meta.shape[3] time_enum = list(range(maxt)) x_range = (0, maxx) y_range = (0, maxy) z_range = (0, maxz) ndim = 2 if ( z_range[1] - z_range[0] ) > 1: ndim = 3 parameters = self.trackingApplet.topLevelOperator.Parameters.value # Save state of axis ranges if 'time_range' in parameters: self.prev_time_range = parameters['time_range'] else: self.prev_time_range = time_enum if 'x_range' in parameters: self.prev_x_range = parameters['x_range'] else: self.prev_x_range = x_range if 'y_range' in parameters: self.prev_y_range = parameters['y_range'] else: self.prev_y_range = y_range if 'z_range' in parameters: self.prev_z_range = parameters['z_range'] else: self.prev_z_range = z_range if 'numFramesPerSplit' in parameters: numFramesPerSplit = parameters['numFramesPerSplit'] else: numFramesPerSplit = 0 self.trackingApplet.topLevelOperator[lane_index].track( time_range = time_enum, x_range = x_range, y_range = y_range, z_range = z_range, size_range = parameters['size_range'], x_scale = parameters['scales'][0], y_scale = parameters['scales'][1], z_scale = parameters['scales'][2], maxDist=parameters['maxDist'], maxObj = parameters['maxObj'], divThreshold=parameters['divThreshold'], avgSize=parameters['avgSize'], withTracklets=parameters['withTracklets'], sizeDependent=parameters['sizeDependent'], divWeight=parameters['divWeight'], transWeight=parameters['transWeight'], withDivisions=parameters['withDivisions'], withOpticalCorrection=parameters['withOpticalCorrection'], withClassifierPrior=parameters['withClassifierPrior'], ndim=ndim, withMergerResolution=parameters['withMergerResolution'], borderAwareWidth = parameters['borderAwareWidth'], withArmaCoordinates = parameters['withArmaCoordinates'], cplex_timeout = parameters['cplex_timeout'], appearance_cost = parameters['appearanceCost'], disappearance_cost = parameters['disappearanceCost'], max_nearest_neighbors = parameters['max_nearest_neighbors'], numFramesPerSplit = numFramesPerSplit, force_build_hypotheses_graph = False, withBatchProcessing = True ) def _pluginExportFunc(self, lane_index, filename, exportPlugin, checkOverwriteFiles, plugArgsSlot) -> int: return ( self.trackingApplet .topLevelOperator .getLane(lane_index) .exportPlugin( filename, exportPlugin, checkOverwriteFiles, plugArgsSlot ) ) def _inputReady(self, nRoles): slot = self.dataSelectionApplet.topLevelOperator.ImageGroup if len(slot) > 0: input_ready = True for sub in slot: input_ready = input_ready and \ all([sub[i].ready() for i in range(nRoles)]) else: input_ready = False return input_ready def onProjectLoaded(self, projectManager): """ Overridden from Workflow base class. Called by the Project Manager. If the user provided command-line arguments, use them to configure the workflow inputs and output settings. """ # Configure the data export operator. if self._data_export_args: self.dataExportApplet.configure_operator_with_parsed_args( self._data_export_args ) # Configure headless mode. if self._headless and self._batch_input_args and self._data_export_args: logger.info("Beginning Batch Processing") self.batchProcessingApplet.run_export_from_parsed_args(self._batch_input_args) logger.info("Completed Batch Processing") def handleAppletStateUpdateRequested(self): """ Overridden from Workflow base class Called when an applet has fired the :py:attr:`Applet.statusUpdateSignal` """ # If no data, nothing else is ready. opDataSelection = self.dataSelectionApplet.topLevelOperator input_ready = self._inputReady(2) and not self.dataSelectionApplet.busy if not self.fromBinary: opThresholding = self.thresholdTwoLevelsApplet.topLevelOperator thresholdingOutput = opThresholding.CachedOutput thresholding_ready = input_ready and \ len(thresholdingOutput) > 0 else: thresholding_ready = True and input_ready opObjectExtraction = self.objectExtractionApplet.topLevelOperator objectExtractionOutput = opObjectExtraction.ComputedFeatureNamesAll features_ready = thresholding_ready and \ len(objectExtractionOutput) > 0 objectCountClassifier_ready = features_ready opTracking = self.trackingApplet.topLevelOperator tracking_ready = objectCountClassifier_ready busy = False busy |= self.dataSelectionApplet.busy busy |= self.trackingApplet.busy busy |= self.dataExportApplet.busy busy |= self.batchProcessingApplet.busy self._shell.enableProjectChanges( not busy ) self._shell.setAppletEnabled(self.dataSelectionApplet, not busy) if not self.fromBinary: self._shell.setAppletEnabled(self.thresholdTwoLevelsApplet, input_ready and not busy) if self.divisionDetectionApplet: self._shell.setAppletEnabled(self.divisionDetectionApplet, features_ready and not busy) self._shell.setAppletEnabled(self.objectExtractionApplet, thresholding_ready and not busy) self._shell.setAppletEnabled(self.cellClassificationApplet, features_ready and not busy) self._shell.setAppletEnabled(self.trackingApplet, objectCountClassifier_ready and not busy) self._shell.setAppletEnabled(self.dataExportApplet, tracking_ready and not busy and \ self.dataExportApplet.topLevelOperator.Inputs[0][0].ready() ) self._shell.setAppletEnabled(self.batchProcessingApplet, tracking_ready and not busy and \ self.dataExportApplet.topLevelOperator.Inputs[0][0].ready() )
class ManualTrackingWorkflow(Workflow): workflowName = "Manual Tracking Workflow" workflowDisplayName = "Manual Tracking Workflow [Inputs: Raw Data, Pixel Prediction Map]" workflowDescription = "Manual tracking of objects, based on Prediction Maps or (binary) Segmentation Images" @property def applets(self): return self._applets @property def imageNameListSlot(self): return self.dataSelectionApplet.topLevelOperator.ImageName def __init__(self, shell, headless, workflow_cmdline_args, project_creation_args, *args, **kwargs): graph = kwargs['graph'] if 'graph' in kwargs else Graph() if 'graph' in kwargs: del kwargs['graph'] super(ManualTrackingWorkflow, self).__init__(shell, headless, workflow_cmdline_args, project_creation_args, graph=graph, *args, **kwargs) data_instructions = 'Use the "Raw Data" tab to load your intensity image(s).\n\n'\ 'Use the "Prediction Maps" tab to load your pixel-wise probability image(s).' ## Create applets self.dataSelectionApplet = DataSelectionApplet( self, "Input Data", "Input Data", forceAxisOrder='txyzc', instructionText=data_instructions, max_lanes=1) opDataSelection = self.dataSelectionApplet.topLevelOperator opDataSelection.DatasetRoles.setValue(['Raw Data', 'Prediction Maps']) self.thresholdTwoLevelsApplet = ThresholdTwoLevelsApplet( self, "Threshold and Size Filter", "ThresholdTwoLevels") self.objectExtractionApplet = ObjectExtractionApplet( name="Object Feature Computation", workflow=self, interactive=False) self.trackingApplet = ManualTrackingApplet(workflow=self) self.default_export_filename = '{dataset_dir}/{nickname}-exported_data.csv' self.dataExportApplet = TrackingBaseDataExportApplet( self, "Tracking Result Export", default_export_filename=self.default_export_filename) opDataExport = self.dataExportApplet.topLevelOperator opDataExport.SelectionNames.setValue( ['Manual Tracking', 'Object Identities']) opDataExport.WorkingDirectory.connect(opDataSelection.WorkingDirectory) # Extra configuration for object export table (as CSV table or HDF5 table) opTracking = self.trackingApplet.topLevelOperator self.dataExportApplet.set_exporting_operator(opTracking) self.dataExportApplet.post_process_lane_export = self.post_process_lane_export self._applets = [] self._applets.append(self.dataSelectionApplet) self._applets.append(self.thresholdTwoLevelsApplet) self._applets.append(self.objectExtractionApplet) self._applets.append(self.trackingApplet) self._applets.append(self.dataExportApplet) def connectLane(self, laneIndex): opData = self.dataSelectionApplet.topLevelOperator.getLane(laneIndex) opObjExtraction = self.objectExtractionApplet.topLevelOperator.getLane( laneIndex) opTracking = self.trackingApplet.topLevelOperator.getLane(laneIndex) opTwoLevelThreshold = self.thresholdTwoLevelsApplet.topLevelOperator.getLane( laneIndex) opDataExport = self.dataExportApplet.topLevelOperator.getLane( laneIndex) ## Connect operators ## op5Raw = OpReorderAxes(parent=self) op5Raw.AxisOrder.setValue("txyzc") op5Raw.Input.connect(opData.ImageGroup[0]) opTwoLevelThreshold.InputImage.connect(opData.ImageGroup[1]) opTwoLevelThreshold.RawInput.connect( opData.ImageGroup[0]) # Used for display only # Use OpReorderAxis for both input datasets such that they are guaranteed to # have the same axis order after thresholding op5Binary = OpReorderAxes(parent=self) op5Binary.AxisOrder.setValue("txyzc") op5Binary.Input.connect(opTwoLevelThreshold.CachedOutput) opObjExtraction.RawImage.connect(op5Raw.Output) opObjExtraction.BinaryImage.connect(op5Binary.Output) opTracking.RawImage.connect(op5Raw.Output) opTracking.BinaryImage.connect(op5Binary.Output) opTracking.LabelImage.connect(opObjExtraction.LabelImage) opTracking.ObjectFeatures.connect(opObjExtraction.RegionFeatures) opTracking.ComputedFeatureNames.connect(opObjExtraction.Features) opDataExport.Inputs.resize(2) opDataExport.Inputs[0].connect(opTracking.TrackImage) opDataExport.Inputs[1].connect(opTracking.LabelImage) opDataExport.RawData.connect(op5Raw.Output) opDataExport.RawDatasetInfo.connect(opData.DatasetGroup[0]) def post_process_lane_export(self, lane_index): # FIXME: This probably only works for the non-blockwise export slot. # We should assert that the user isn't using the blockwise slot. settings, selected_features = self.trackingApplet.topLevelOperator.getLane( lane_index).get_table_export_settings() if settings: raw_dataset_info = self.dataSelectionApplet.topLevelOperator.DatasetGroup[ lane_index][0].value if raw_dataset_info.location == DatasetInfo.Location.FileSystem: filename_suffix = raw_dataset_info.nickname else: filename_suffix = str(lane_index) req = self.trackingApplet.topLevelOperator.getLane( lane_index ).export_object_data( lane_index, # FIXME: Even in non-headless mode, we can't show the gui because we're running in a non-main thread. # That's not a huge deal, because there's still a progress bar for the overall export. show_gui=False, filename_suffix=filename_suffix) req.wait() def _inputReady(self, nRoles): slot = self.dataSelectionApplet.topLevelOperator.ImageGroup if len(slot) > 0: input_ready = True for sub in slot: input_ready = input_ready and \ all([sub[i].ready() for i in range(nRoles)]) else: input_ready = False return input_ready def handleAppletStateUpdateRequested(self): """ Overridden from Workflow base class Called when an applet has fired the :py:attr:`Applet.statusUpdateSignal` """ # If no data, nothing else is ready. input_ready = self._inputReady(2) and not self.dataSelectionApplet.busy opThresholding = self.thresholdTwoLevelsApplet.topLevelOperator thresholdingOutput = opThresholding.CachedOutput thresholding_ready = input_ready and \ len(thresholdingOutput) > 0 opObjectExtraction = self.objectExtractionApplet.topLevelOperator features_ready = thresholding_ready opTracking = self.trackingApplet.topLevelOperator tracking_ready = features_ready and \ len(opTracking.Labels) > 0 and \ opTracking.Labels.ready() and \ opTracking.TrackImage.ready() busy = False busy |= self.dataSelectionApplet.busy busy |= self.dataExportApplet.busy busy |= self.trackingApplet.busy self._shell.enableProjectChanges(not busy) self._shell.setAppletEnabled(self.dataSelectionApplet, not busy) self._shell.setAppletEnabled(self.thresholdTwoLevelsApplet, input_ready and not busy) self._shell.setAppletEnabled(self.objectExtractionApplet, thresholding_ready and not busy) self._shell.setAppletEnabled(self.trackingApplet, features_ready and not busy) self._shell.setAppletEnabled(self.dataExportApplet, tracking_ready and not busy and \ self.dataExportApplet.topLevelOperator.Inputs[0][0].ready() )
class StructuredTrackingWorkflowBase( Workflow ): workflowName = "Structured Learning Tracking Workflow BASE" @property def applets(self): return self._applets @property def imageNameListSlot(self): return self.dataSelectionApplet.topLevelOperator.ImageName def __init__( self, shell, headless, workflow_cmdline_args, project_creation_args, *args, **kwargs ): graph = kwargs['graph'] if 'graph' in kwargs else Graph() if 'graph' in kwargs: del kwargs['graph'] super(StructuredTrackingWorkflowBase, self).__init__(shell, headless, workflow_cmdline_args, project_creation_args, graph=graph, *args, **kwargs) data_instructions = 'Use the "Raw Data" tab to load your intensity image(s).\n\n' if self.fromBinary: data_instructions += 'Use the "Binary Image" tab to load your segmentation image(s).' else: data_instructions += 'Use the "Prediction Maps" tab to load your pixel-wise probability image(s).' # Create applets self.dataSelectionApplet = DataSelectionApplet(self, "Input Data", "Input Data", batchDataGui=False, forceAxisOrder=['txyzc'], instructionText=data_instructions, max_lanes=1) opDataSelection = self.dataSelectionApplet.topLevelOperator if self.fromBinary: opDataSelection.DatasetRoles.setValue( ['Raw Data', 'Binary Image'] ) else: opDataSelection.DatasetRoles.setValue( ['Raw Data', 'Prediction Maps'] ) if not self.fromBinary: self.thresholdTwoLevelsApplet = ThresholdTwoLevelsApplet( self,"Threshold and Size Filter","ThresholdTwoLevels" ) self.divisionDetectionApplet = ObjectClassificationApplet(workflow=self, name="Division Detection (optional)", projectFileGroupName="DivisionDetection", selectedFeatures=configConservation.selectedFeaturesDiv) self.cellClassificationApplet = ObjectClassificationApplet(workflow=self, name="Object Count Classification", projectFileGroupName="CountClassification", selectedFeatures=configConservation.selectedFeaturesObjectCount) self.trackingFeatureExtractionApplet = TrackingFeatureExtractionApplet(name="Object Feature Computation",workflow=self, interactive=False) self.objectExtractionApplet = ObjectExtractionApplet(name="Object Feature Computation",workflow=self, interactive=False) self.annotationsApplet = AnnotationsApplet( name="Training", workflow=self ) opAnnotations = self.annotationsApplet.topLevelOperator self.trackingApplet = StructuredTrackingApplet( name="Tracking - Structured Learning", workflow=self ) opStructuredTracking = self.trackingApplet.topLevelOperator if SOLVER=="CPLEX" or SOLVER=="GUROBI": self._solver="ILP" elif SOLVER=="DPCT": self._solver="Flow-based" else: self._solver=None opStructuredTracking._solver = self._solver self.default_tracking_export_filename = '{dataset_dir}/{nickname}-tracking_exported_data.csv' self.dataExportTrackingApplet = TrackingBaseDataExportApplet( self, "Tracking Result Export", default_export_filename=self.default_tracking_export_filename, pluginExportFunc=self._pluginExportFunc ) opDataExportTracking = self.dataExportTrackingApplet.topLevelOperator opDataExportTracking.SelectionNames.setValue( ['Tracking-Result', 'Merger-Result', 'Object-Identities'] ) opDataExportTracking.WorkingDirectory.connect( opDataSelection.WorkingDirectory ) self.dataExportTrackingApplet.set_exporting_operator(opStructuredTracking) self.dataExportTrackingApplet.prepare_lane_for_export = self.prepare_lane_for_export # configure export settings settings = {'file path': self.default_tracking_export_filename, 'compression': {}, 'file type': 'h5'} selected_features = ['Count', 'RegionCenter', 'RegionRadii', 'RegionAxes'] opStructuredTracking.ExportSettings.setValue( (settings, selected_features) ) self._applets = [] self._applets.append(self.dataSelectionApplet) if not self.fromBinary: self._applets.append(self.thresholdTwoLevelsApplet) self._applets.append(self.trackingFeatureExtractionApplet) self._applets.append(self.divisionDetectionApplet) self.batchProcessingApplet = BatchProcessingApplet(self, "Batch Processing", self.dataSelectionApplet, self.dataExportTrackingApplet) self._applets.append(self.cellClassificationApplet) self._applets.append(self.objectExtractionApplet) self._applets.append(self.annotationsApplet) self._applets.append(self.trackingApplet) self._applets.append(self.dataExportTrackingApplet) if self.divisionDetectionApplet: opDivDetection = self.divisionDetectionApplet.topLevelOperator opDivDetection.SelectedFeatures.setValue(configConservation.selectedFeaturesDiv) opDivDetection.LabelNames.setValue(['Not Dividing', 'Dividing']) opDivDetection.AllowDeleteLabels.setValue(False) opDivDetection.AllowAddLabel.setValue(False) opDivDetection.EnableLabelTransfer.setValue(False) opCellClassification = self.cellClassificationApplet.topLevelOperator opCellClassification.SelectedFeatures.setValue(configConservation.selectedFeaturesObjectCount ) opCellClassification.SuggestedLabelNames.setValue( ['False Detection',] + [str(1) + ' Object'] + [str(i) + ' Objects' for i in range(2,10) ] ) opCellClassification.AllowDeleteLastLabelOnly.setValue(True) opCellClassification.EnableLabelTransfer.setValue(False) if workflow_cmdline_args: if '--testFullAnnotations' in workflow_cmdline_args: self.testFullAnnotations = True else: self.testFullAnnotations = False self._data_export_args, unused_args = self.dataExportTrackingApplet.parse_known_cmdline_args( workflow_cmdline_args ) self._batch_input_args, unused_args = self.batchProcessingApplet.parse_known_cmdline_args( workflow_cmdline_args ) else: unused_args = None self._data_export_args = None self._batch_input_args = None self.testFullAnnotations = False if unused_args: logger.warning("Unused command-line args: {}".format( unused_args )) def _pluginExportFunc(self, lane_index, filename, exportPlugin, checkOverwriteFiles, plugArgsSlot) -> int: return ( self.trackingApplet .topLevelOperator .getLane(lane_index) .exportPlugin( filename, exportPlugin, checkOverwriteFiles, additionalPluginArgumentsSlot ) ) def connectLane(self, laneIndex): opData = self.dataSelectionApplet.topLevelOperator.getLane(laneIndex) opObjExtraction = self.objectExtractionApplet.topLevelOperator.getLane(laneIndex) opTrackingFeatureExtraction = self.trackingFeatureExtractionApplet.topLevelOperator.getLane(laneIndex) opAnnotations = self.annotationsApplet.topLevelOperator.getLane(laneIndex) if not self.fromBinary: opTwoLevelThreshold = self.thresholdTwoLevelsApplet.topLevelOperator.getLane(laneIndex) opStructuredTracking = self.trackingApplet.topLevelOperator.getLane(laneIndex) opDataTrackingExport = self.dataExportTrackingApplet.topLevelOperator.getLane(laneIndex) ## Connect operators ## op5Raw = OpReorderAxes(parent=self) op5Raw.AxisOrder.setValue("txyzc") op5Raw.Input.connect(opData.ImageGroup[0]) opDivDetection = self.divisionDetectionApplet.topLevelOperator.getLane(laneIndex) opCellClassification = self.cellClassificationApplet.topLevelOperator.getLane(laneIndex) if not self.fromBinary: opTwoLevelThreshold.InputImage.connect( opData.ImageGroup[1] ) opTwoLevelThreshold.RawInput.connect( opData.ImageGroup[0] ) # Used for display only binarySrc = opTwoLevelThreshold.CachedOutput else: binarySrc = opData.ImageGroup[1] # Use Op5ifyers for both input datasets such that they are guaranteed to # have the same axis order after thresholding op5Binary = OpReorderAxes(parent=self) op5Binary.AxisOrder.setValue("txyzc") op5Binary.Input.connect(binarySrc) opObjExtraction.RawImage.connect( op5Raw.Output ) opObjExtraction.BinaryImage.connect( op5Binary.Output ) opTrackingFeatureExtraction.RawImage.connect( op5Raw.Output ) opTrackingFeatureExtraction.BinaryImage.connect( op5Binary.Output ) opTrackingFeatureExtraction.setDefaultFeatures(configConservation.allFeaturesObjectCount) opTrackingFeatureExtraction.FeatureNamesVigra.setValue(configConservation.allFeaturesObjectCount) feature_dict_division = {} feature_dict_division[config.features_division_name] = { name: {} for name in config.division_features } opTrackingFeatureExtraction.FeatureNamesDivision.setValue(feature_dict_division) if self.divisionDetectionApplet: opDivDetection.BinaryImages.connect( op5Binary.Output ) opDivDetection.RawImages.connect( op5Raw.Output ) opDivDetection.SegmentationImages.connect(opTrackingFeatureExtraction.LabelImage) opDivDetection.ObjectFeatures.connect(opTrackingFeatureExtraction.RegionFeaturesAll) opDivDetection.ComputedFeatureNames.connect(opTrackingFeatureExtraction.ComputedFeatureNamesAll) opCellClassification.BinaryImages.connect( op5Binary.Output ) opCellClassification.RawImages.connect( op5Raw.Output ) opCellClassification.SegmentationImages.connect(opTrackingFeatureExtraction.LabelImage) opCellClassification.ObjectFeatures.connect(opTrackingFeatureExtraction.RegionFeaturesAll) opCellClassification.ComputedFeatureNames.connect(opTrackingFeatureExtraction.ComputedFeatureNamesNoDivisions) opAnnotations.RawImage.connect( op5Raw.Output ) opAnnotations.BinaryImage.connect( op5Binary.Output ) opAnnotations.LabelImage.connect( opObjExtraction.LabelImage ) opAnnotations.ObjectFeatures.connect( opObjExtraction.RegionFeatures ) opAnnotations.ComputedFeatureNames.connect(opObjExtraction.Features) opAnnotations.DivisionProbabilities.connect( opDivDetection.Probabilities ) opAnnotations.DetectionProbabilities.connect( opCellClassification.Probabilities ) opAnnotations.MaxNumObj.connect (opCellClassification.MaxNumObj) opStructuredTracking.RawImage.connect( op5Raw.Output ) opStructuredTracking.LabelImage.connect( opTrackingFeatureExtraction.LabelImage ) opStructuredTracking.ObjectFeatures.connect( opTrackingFeatureExtraction.RegionFeaturesVigra ) opStructuredTracking.ComputedFeatureNames.connect( opTrackingFeatureExtraction.FeatureNamesVigra ) if self.divisionDetectionApplet: opStructuredTracking.ObjectFeaturesWithDivFeatures.connect( opTrackingFeatureExtraction.RegionFeaturesAll) opStructuredTracking.ComputedFeatureNamesWithDivFeatures.connect( opTrackingFeatureExtraction.ComputedFeatureNamesAll ) opStructuredTracking.DivisionProbabilities.connect( opDivDetection.Probabilities ) opStructuredTracking.DetectionProbabilities.connect( opCellClassification.Probabilities ) opStructuredTracking.NumLabels.connect( opCellClassification.NumLabels ) opStructuredTracking.Annotations.connect (opAnnotations.Annotations) opStructuredTracking.Labels.connect (opAnnotations.Labels) opStructuredTracking.Divisions.connect (opAnnotations.Divisions) opStructuredTracking.Appearances.connect (opAnnotations.Appearances) opStructuredTracking.Disappearances.connect (opAnnotations.Disappearances) opStructuredTracking.MaxNumObj.connect (opCellClassification.MaxNumObj) opDataTrackingExport.Inputs.resize(3) opDataTrackingExport.Inputs[0].connect( opStructuredTracking.RelabeledImage ) opDataTrackingExport.Inputs[1].connect( opStructuredTracking.MergerOutput ) opDataTrackingExport.Inputs[2].connect( opStructuredTracking.LabelImage ) opDataTrackingExport.RawData.connect( op5Raw.Output ) opDataTrackingExport.RawDatasetInfo.connect( opData.DatasetGroup[0] ) def prepare_lane_for_export(self, lane_index): import logging logger = logging.getLogger(__name__) maxt = self.trackingApplet.topLevelOperator[lane_index].RawImage.meta.shape[0] maxx = self.trackingApplet.topLevelOperator[lane_index].RawImage.meta.shape[1] maxy = self.trackingApplet.topLevelOperator[lane_index].RawImage.meta.shape[2] maxz = self.trackingApplet.topLevelOperator[lane_index].RawImage.meta.shape[3] time_enum = list(range(maxt)) x_range = (0, maxx) y_range = (0, maxy) z_range = (0, maxz) ndim = 2 if ( z_range[1] - z_range[0] ) > 1: ndim = 3 parameters = self.trackingApplet.topLevelOperator.Parameters.value # Save state of axis ranges if 'time_range' in parameters: self.prev_time_range = parameters['time_range'] else: self.prev_time_range = time_enum if 'x_range' in parameters: self.prev_x_range = parameters['x_range'] else: self.prev_x_range = x_range if 'y_range' in parameters: self.prev_y_range = parameters['y_range'] else: self.prev_y_range = y_range if 'z_range' in parameters: self.prev_z_range = parameters['z_range'] else: self.prev_z_range = z_range # batch processing starts a new lane, so training data needs to be copied from the lane that loaded the project loaded_project_lane_index=0 self.annotationsApplet.topLevelOperator[lane_index].Annotations.setValue( self.trackingApplet.topLevelOperator[loaded_project_lane_index].Annotations.value) def runLearningAndTracking(withMergerResolution=True): if self.testFullAnnotations: logger.info("Test: Structured Learning") weights = self.trackingApplet.topLevelOperator[lane_index]._runStructuredLearning( z_range, parameters['maxObj'], parameters['max_nearest_neighbors'], parameters['maxDist'], parameters['divThreshold'], [parameters['scales'][0],parameters['scales'][1],parameters['scales'][2]], parameters['size_range'], parameters['withDivisions'], parameters['borderAwareWidth'], parameters['withClassifierPrior'], withBatchProcessing=True) logger.info("weights: {}".format(weights)) logger.info("Test: Tracking") result = self.trackingApplet.topLevelOperator[lane_index].track( time_range = time_enum, x_range = x_range, y_range = y_range, z_range = z_range, size_range = parameters['size_range'], x_scale = parameters['scales'][0], y_scale = parameters['scales'][1], z_scale = parameters['scales'][2], maxDist=parameters['maxDist'], maxObj = parameters['maxObj'], divThreshold=parameters['divThreshold'], avgSize=parameters['avgSize'], withTracklets=parameters['withTracklets'], sizeDependent=parameters['sizeDependent'], detWeight=parameters['detWeight'], divWeight=parameters['divWeight'], transWeight=parameters['transWeight'], withDivisions=parameters['withDivisions'], withOpticalCorrection=parameters['withOpticalCorrection'], withClassifierPrior=parameters['withClassifierPrior'], ndim=ndim, withMergerResolution=withMergerResolution, borderAwareWidth = parameters['borderAwareWidth'], withArmaCoordinates = parameters['withArmaCoordinates'], cplex_timeout = parameters['cplex_timeout'], appearance_cost = parameters['appearanceCost'], disappearance_cost = parameters['disappearanceCost'], force_build_hypotheses_graph = False, withBatchProcessing = True ) return result if self.testFullAnnotations: self.result = runLearningAndTracking(withMergerResolution=False) hypothesesGraph = self.trackingApplet.topLevelOperator[lane_index].LearningHypothesesGraph.value hypothesesGraph.insertSolution(self.result) hypothesesGraph.computeLineage() solution = hypothesesGraph.getSolutionDictionary() annotations = self.trackingApplet.topLevelOperator[lane_index].Annotations.value self.trackingApplet.topLevelOperator[lane_index].insertAnnotationsToHypothesesGraph(hypothesesGraph,annotations,misdetectionLabel=-1) hypothesesGraph.computeLineage() solutionFromAnnotations = hypothesesGraph.getSolutionDictionary() for key in list(solution.keys()): if key == 'detectionResults': detectionFlag = True for i in range(len(solution[key])): flag = False for j in range(len(solutionFromAnnotations[key])): if solution[key][i]['id'] == solutionFromAnnotations[key][j]['id'] and \ solution[key][i]['value'] == solutionFromAnnotations[key][j]['value']: flag = True break detectionFlag &= flag elif key == 'divisionResults': divisionFlag = True for i in range(len(solution[key])): flag = False for j in range(len(solutionFromAnnotations[key])): if solution[key][i]['id'] == solutionFromAnnotations[key][j]['id'] and \ solution[key][i]['value'] == solutionFromAnnotations[key][j]['value']: flag = True break divisionFlag &= flag elif key == 'linkingResults': linkingFlag = True for i in range(len(solution[key])): flag = False for j in range(len(solutionFromAnnotations[key])): if solution[key][i]['dest'] == solutionFromAnnotations[key][j]['dest'] and \ solution[key][i]['src'] == solutionFromAnnotations[key][j]['src']: if solution[key][i]['gap'] == solutionFromAnnotations[key][j]['gap'] and \ solution[key][i]['value'] == solutionFromAnnotations[key][j]['value']: flag = True break linkingFlag &= flag assert detectionFlag, "Detection results are NOT correct. They differ from your annotated detections." logger.info("Detection results are correct.") assert divisionFlag, "Division results are NOT correct. They differ from your annotated divisions." logger.info("Division results are correct.") assert linkingFlag, "Transition results are NOT correct. They differ from your annotated transitions." logger.info("Transition results are correct.") self.result = runLearningAndTracking(withMergerResolution=parameters['withMergerResolution']) def _inputReady(self, nRoles): slot = self.dataSelectionApplet.topLevelOperator.ImageGroup if len(slot) > 0: input_ready = True for sub in slot: input_ready = input_ready and \ all([sub[i].ready() for i in range(nRoles)]) else: input_ready = False return input_ready def onProjectLoaded(self, projectManager): """ Overridden from Workflow base class. Called by the Project Manager. If the user provided command-line arguments, use them to configure the workflow inputs and output settings. """ # Configure the data export operator. if self._data_export_args: self.dataExportTrackingApplet.configure_operator_with_parsed_args( self._data_export_args ) # Configure headless mode. if self._headless and self._batch_input_args and self._data_export_args: logger.info("Beginning Batch Processing") self.batchProcessingApplet.run_export_from_parsed_args(self._batch_input_args) logger.info("Completed Batch Processing") def handleAppletStateUpdateRequested(self): """ Overridden from Workflow base class Called when an applet has fired the :py:attr:`Applet.statusUpdateSignal` """ # If no data, nothing else is ready. input_ready = self._inputReady(2) and not self.dataSelectionApplet.busy if not self.fromBinary: opThresholding = self.thresholdTwoLevelsApplet.topLevelOperator thresholdingOutput = opThresholding.CachedOutput thresholding_ready = input_ready and len(thresholdingOutput) > 0 else: thresholding_ready = input_ready opTrackingFeatureExtraction = self.trackingFeatureExtractionApplet.topLevelOperator trackingFeatureExtractionOutput = opTrackingFeatureExtraction.ComputedFeatureNamesAll tracking_features_ready = thresholding_ready and len(trackingFeatureExtractionOutput) > 0 objectCountClassifier_ready = tracking_features_ready opObjectExtraction = self.objectExtractionApplet.topLevelOperator objectExtractionOutput = opObjectExtraction.RegionFeatures features_ready = thresholding_ready and \ len(objectExtractionOutput) > 0 opAnnotations = self.annotationsApplet.topLevelOperator annotations_ready = features_ready and \ len(opAnnotations.Labels) > 0 and \ opAnnotations.Labels.ready() and \ opAnnotations.TrackImage.ready() opStructuredTracking = self.trackingApplet.topLevelOperator structured_tracking_ready = objectCountClassifier_ready withIlpSolver = (self._solver=="ILP") busy = False busy |= self.dataSelectionApplet.busy busy |= self.annotationsApplet.busy # busy |= self.dataExportAnnotationsApplet.busy busy |= self.trackingApplet.busy busy |= self.dataExportTrackingApplet.busy self._shell.enableProjectChanges( not busy ) self._shell.setAppletEnabled(self.dataSelectionApplet, not busy) if not self.fromBinary: self._shell.setAppletEnabled(self.thresholdTwoLevelsApplet, input_ready and not busy) self._shell.setAppletEnabled(self.trackingFeatureExtractionApplet, thresholding_ready and not busy) self._shell.setAppletEnabled(self.cellClassificationApplet, tracking_features_ready and not busy) self._shell.setAppletEnabled(self.divisionDetectionApplet, tracking_features_ready and not busy) self._shell.setAppletEnabled(self.objectExtractionApplet, not busy) self._shell.setAppletEnabled(self.annotationsApplet, features_ready and not busy) # and withIlpSolver) # self._shell.setAppletEnabled(self.dataExportAnnotationsApplet, annotations_ready and not busy and \ # self.dataExportAnnotationsApplet.topLevelOperator.Inputs[0][0].ready() ) self._shell.setAppletEnabled(self.trackingApplet, objectCountClassifier_ready and not busy) self._shell.setAppletEnabled(self.dataExportTrackingApplet, structured_tracking_ready and not busy and \ self.dataExportTrackingApplet.topLevelOperator.Inputs[0][0].ready() )
def __init__(self, shell, headless, workflow_cmdline_args, project_creation_args, *args, **kwargs): graph = kwargs["graph"] if "graph" in kwargs else Graph() if "graph" in kwargs: del kwargs["graph"] # if 'withOptTrans' in kwargs: # self.withOptTrans = kwargs['withOptTrans'] # if 'fromBinary' in kwargs: # self.fromBinary = kwargs['fromBinary'] super(ConservationTrackingWorkflowBase, self).__init__(shell, headless, workflow_cmdline_args, project_creation_args, graph=graph, *args, **kwargs) data_instructions = 'Use the "Raw Data" tab to load your intensity image(s).\n\n' if self.fromBinary: data_instructions += 'Use the "Binary Image" tab to load your segmentation image(s).' else: data_instructions += 'Use the "Prediction Maps" tab to load your pixel-wise probability image(s).' # Variables to store division and cell classifiers to prevent retraining every-time batch processing runs self.stored_division_classifier = None self.stored_cell_classifier = None ## Create applets self.dataSelectionApplet = DataSelectionApplet( self, "Input Data", "Input Data", forceAxisOrder=["txyzc"], instructionText=data_instructions, max_lanes=None, ) opDataSelection = self.dataSelectionApplet.topLevelOperator if self.fromBinary: opDataSelection.DatasetRoles.setValue( ["Raw Data", "Segmentation Image"]) else: opDataSelection.DatasetRoles.setValue( ["Raw Data", "Prediction Maps"]) if not self.fromBinary: self.thresholdTwoLevelsApplet = ThresholdTwoLevelsApplet( self, "Threshold and Size Filter", "ThresholdTwoLevels") self.objectExtractionApplet = TrackingFeatureExtractionApplet( workflow=self, interactive=False, name="Object Feature Computation") opObjectExtraction = self.objectExtractionApplet.topLevelOperator self.divisionDetectionApplet = self._createDivisionDetectionApplet( configConservation.selectedFeaturesDiv) # Might be None if self.divisionDetectionApplet: feature_dict_division = {} feature_dict_division[config.features_division_name] = { name: {} for name in config.division_features } opObjectExtraction.FeatureNamesDivision.setValue( feature_dict_division) selected_features_div = {} for plugin_name in list(config.selected_features_division.keys()): selected_features_div[plugin_name] = { name: {} for name in config.selected_features_division[plugin_name] } # FIXME: do not hard code this for name in [ "SquaredDistances_" + str(i) for i in range(config.n_best_successors) ]: selected_features_div[config.features_division_name][name] = {} opDivisionDetection = self.divisionDetectionApplet.topLevelOperator opDivisionDetection.SelectedFeatures.setValue( configConservation.selectedFeaturesDiv) opDivisionDetection.LabelNames.setValue( ["Not Dividing", "Dividing"]) opDivisionDetection.AllowDeleteLabels.setValue(False) opDivisionDetection.AllowAddLabel.setValue(False) opDivisionDetection.EnableLabelTransfer.setValue(False) self.cellClassificationApplet = ObjectClassificationApplet( workflow=self, name="Object Count Classification", projectFileGroupName="CountClassification", selectedFeatures=configConservation.selectedFeaturesObjectCount, ) selected_features_objectcount = {} for plugin_name in list(config.selected_features_objectcount.keys()): selected_features_objectcount[plugin_name] = { name: {} for name in config.selected_features_objectcount[plugin_name] } opCellClassification = self.cellClassificationApplet.topLevelOperator opCellClassification.SelectedFeatures.setValue( configConservation.selectedFeaturesObjectCount) opCellClassification.SuggestedLabelNames.setValue( ["False Detection"] + [str(1) + " Object"] + [str(i) + " Objects" for i in range(2, 10)]) opCellClassification.AllowDeleteLastLabelOnly.setValue(True) opCellClassification.EnableLabelTransfer.setValue(False) self.trackingApplet = ConservationTrackingApplet(workflow=self) self.default_export_filename = "{dataset_dir}/{nickname}-exported_data.csv" self.dataExportApplet = TrackingBaseDataExportApplet( self, "Tracking Result Export", default_export_filename=self.default_export_filename, pluginExportFunc=self._pluginExportFunc, ) opDataExport = self.dataExportApplet.topLevelOperator opDataExport.SelectionNames.setValue( ["Object-Identities", "Tracking-Result", "Merger-Result"]) opDataExport.WorkingDirectory.connect(opDataSelection.WorkingDirectory) # Extra configuration for object export table (as CSV table or HDF5 table) opTracking = self.trackingApplet.topLevelOperator self.dataExportApplet.set_exporting_operator(opTracking) self.dataExportApplet.prepare_lane_for_export = self.prepare_lane_for_export # configure export settings # settings = {'file path': self.default_export_filename, 'compression': {}, 'file type': 'csv'} # selected_features = ['Count', 'RegionCenter', 'RegionRadii', 'RegionAxes'] # opTracking.ExportSettings.setValue( (settings, selected_features) ) self._applets = [] self._applets.append(self.dataSelectionApplet) if not self.fromBinary: self._applets.append(self.thresholdTwoLevelsApplet) self._applets.append(self.objectExtractionApplet) if self.divisionDetectionApplet: self._applets.append(self.divisionDetectionApplet) self.batchProcessingApplet = BatchProcessingApplet( self, "Batch Processing", self.dataSelectionApplet, self.dataExportApplet) self._applets.append(self.cellClassificationApplet) self._applets.append(self.trackingApplet) self._applets.append(self.dataExportApplet) self._applets.append(self.batchProcessingApplet) # Parse export and batch command-line arguments for headless mode if workflow_cmdline_args: self._data_export_args, unused_args = self.dataExportApplet.parse_known_cmdline_args( workflow_cmdline_args) self._batch_input_args, unused_args = self.batchProcessingApplet.parse_known_cmdline_args( workflow_cmdline_args) else: unused_args = None self._data_export_args = None self._batch_input_args = None if unused_args: logger.warning("Unused command-line args: {}".format(unused_args))
class StructuredTrackingWorkflowBase( Workflow ): workflowName = "Structured Learning Tracking Workflow BASE" @property def applets(self): return self._applets @property def imageNameListSlot(self): return self.dataSelectionApplet.topLevelOperator.ImageName def __init__( self, shell, headless, workflow_cmdline_args, project_creation_args, *args, **kwargs ): graph = kwargs['graph'] if 'graph' in kwargs else Graph() if 'graph' in kwargs: del kwargs['graph'] super(StructuredTrackingWorkflowBase, self).__init__(shell, headless, workflow_cmdline_args, project_creation_args, graph=graph, *args, **kwargs) data_instructions = 'Use the "Raw Data" tab to load your intensity image(s).\n\n' if self.fromBinary: data_instructions += 'Use the "Binary Image" tab to load your segmentation image(s).' else: data_instructions += 'Use the "Prediction Maps" tab to load your pixel-wise probability image(s).' # Create applets self.dataSelectionApplet = DataSelectionApplet(self, "Input Data", "Input Data", batchDataGui=False, forceAxisOrder=['txyzc'], instructionText=data_instructions, max_lanes=1) opDataSelection = self.dataSelectionApplet.topLevelOperator if self.fromBinary: opDataSelection.DatasetRoles.setValue( ['Raw Data', 'Binary Image'] ) else: opDataSelection.DatasetRoles.setValue( ['Raw Data', 'Prediction Maps'] ) if not self.fromBinary: self.thresholdTwoLevelsApplet = ThresholdTwoLevelsApplet( self,"Threshold and Size Filter","ThresholdTwoLevels" ) self.divisionDetectionApplet = ObjectClassificationApplet(workflow=self, name="Division Detection (optional)", projectFileGroupName="DivisionDetection", selectedFeatures=configConservation.selectedFeaturesDiv) self.cellClassificationApplet = ObjectClassificationApplet(workflow=self, name="Object Count Classification", projectFileGroupName="CountClassification", selectedFeatures=configConservation.selectedFeaturesObjectCount) self.trackingFeatureExtractionApplet = TrackingFeatureExtractionApplet(name="Object Feature Computation",workflow=self, interactive=False) self.objectExtractionApplet = ObjectExtractionApplet(name="Object Feature Computation",workflow=self, interactive=False) self.annotationsApplet = AnnotationsApplet( name="Training", workflow=self ) opAnnotations = self.annotationsApplet.topLevelOperator self.trackingApplet = StructuredTrackingApplet( name="Tracking - Structured Learning", workflow=self ) opStructuredTracking = self.trackingApplet.topLevelOperator if SOLVER=="CPLEX" or SOLVER=="GUROBI": self._solver="ILP" elif SOLVER=="DPCT": self._solver="Flow-based" else: self._solver=None opStructuredTracking._solver = self._solver self.default_tracking_export_filename = '{dataset_dir}/{nickname}-tracking_exported_data.csv' self.dataExportTrackingApplet = TrackingBaseDataExportApplet(self, "Tracking Result Export",default_export_filename=self.default_tracking_export_filename) opDataExportTracking = self.dataExportTrackingApplet.topLevelOperator opDataExportTracking.SelectionNames.setValue( ['Tracking-Result', 'Merger-Result', 'Object-Identities'] ) opDataExportTracking.WorkingDirectory.connect( opDataSelection.WorkingDirectory ) self.dataExportTrackingApplet.set_exporting_operator(opStructuredTracking) self.dataExportTrackingApplet.prepare_lane_for_export = self.prepare_lane_for_export self.dataExportTrackingApplet.post_process_lane_export = self.post_process_lane_export # configure export settings settings = {'file path': self.default_tracking_export_filename, 'compression': {}, 'file type': 'h5'} selected_features = ['Count', 'RegionCenter', 'RegionRadii', 'RegionAxes'] opStructuredTracking.ExportSettings.setValue( (settings, selected_features) ) self._applets = [] self._applets.append(self.dataSelectionApplet) if not self.fromBinary: self._applets.append(self.thresholdTwoLevelsApplet) self._applets.append(self.trackingFeatureExtractionApplet) self._applets.append(self.divisionDetectionApplet) self.batchProcessingApplet = BatchProcessingApplet(self, "Batch Processing", self.dataSelectionApplet, self.dataExportTrackingApplet) self._applets.append(self.cellClassificationApplet) self._applets.append(self.objectExtractionApplet) self._applets.append(self.annotationsApplet) self._applets.append(self.trackingApplet) self._applets.append(self.dataExportTrackingApplet) if self.divisionDetectionApplet: opDivDetection = self.divisionDetectionApplet.topLevelOperator opDivDetection.SelectedFeatures.setValue(configConservation.selectedFeaturesDiv) opDivDetection.LabelNames.setValue(['Not Dividing', 'Dividing']) opDivDetection.AllowDeleteLabels.setValue(False) opDivDetection.AllowAddLabel.setValue(False) opDivDetection.EnableLabelTransfer.setValue(False) opCellClassification = self.cellClassificationApplet.topLevelOperator opCellClassification.SelectedFeatures.setValue(configConservation.selectedFeaturesObjectCount ) opCellClassification.SuggestedLabelNames.setValue( ['False Detection',] + [str(1) + ' Object'] + [str(i) + ' Objects' for i in range(2,10) ] ) opCellClassification.AllowDeleteLastLabelOnly.setValue(True) opCellClassification.EnableLabelTransfer.setValue(False) if workflow_cmdline_args: if '--testFullAnnotations' in workflow_cmdline_args: self.testFullAnnotations = True else: self.testFullAnnotations = False self._data_export_args, unused_args = self.dataExportTrackingApplet.parse_known_cmdline_args( workflow_cmdline_args ) self._batch_input_args, unused_args = self.batchProcessingApplet.parse_known_cmdline_args( workflow_cmdline_args ) else: unused_args = None self._data_export_args = None self._batch_input_args = None self.testFullAnnotations = False if unused_args: logger.warning("Unused command-line args: {}".format( unused_args )) def connectLane(self, laneIndex): opData = self.dataSelectionApplet.topLevelOperator.getLane(laneIndex) opObjExtraction = self.objectExtractionApplet.topLevelOperator.getLane(laneIndex) opTrackingFeatureExtraction = self.trackingFeatureExtractionApplet.topLevelOperator.getLane(laneIndex) opAnnotations = self.annotationsApplet.topLevelOperator.getLane(laneIndex) if not self.fromBinary: opTwoLevelThreshold = self.thresholdTwoLevelsApplet.topLevelOperator.getLane(laneIndex) opStructuredTracking = self.trackingApplet.topLevelOperator.getLane(laneIndex) opDataTrackingExport = self.dataExportTrackingApplet.topLevelOperator.getLane(laneIndex) ## Connect operators ## op5Raw = OpReorderAxes(parent=self) op5Raw.AxisOrder.setValue("txyzc") op5Raw.Input.connect(opData.ImageGroup[0]) opDivDetection = self.divisionDetectionApplet.topLevelOperator.getLane(laneIndex) opCellClassification = self.cellClassificationApplet.topLevelOperator.getLane(laneIndex) if not self.fromBinary: opTwoLevelThreshold.InputImage.connect( opData.ImageGroup[1] ) opTwoLevelThreshold.RawInput.connect( opData.ImageGroup[0] ) # Used for display only binarySrc = opTwoLevelThreshold.CachedOutput else: binarySrc = opData.ImageGroup[1] # Use Op5ifyers for both input datasets such that they are guaranteed to # have the same axis order after thresholding op5Binary = OpReorderAxes(parent=self) op5Binary.AxisOrder.setValue("txyzc") op5Binary.Input.connect(binarySrc) opObjExtraction.RawImage.connect( op5Raw.Output ) opObjExtraction.BinaryImage.connect( op5Binary.Output ) opTrackingFeatureExtraction.RawImage.connect( op5Raw.Output ) opTrackingFeatureExtraction.BinaryImage.connect( op5Binary.Output ) opTrackingFeatureExtraction.setDefaultFeatures(configConservation.allFeaturesObjectCount) opTrackingFeatureExtraction.FeatureNamesVigra.setValue(configConservation.allFeaturesObjectCount) feature_dict_division = {} feature_dict_division[config.features_division_name] = { name: {} for name in config.division_features } opTrackingFeatureExtraction.FeatureNamesDivision.setValue(feature_dict_division) if self.divisionDetectionApplet: opDivDetection.BinaryImages.connect( op5Binary.Output ) opDivDetection.RawImages.connect( op5Raw.Output ) opDivDetection.SegmentationImages.connect(opTrackingFeatureExtraction.LabelImage) opDivDetection.ObjectFeatures.connect(opTrackingFeatureExtraction.RegionFeaturesAll) opDivDetection.ComputedFeatureNames.connect(opTrackingFeatureExtraction.ComputedFeatureNamesAll) opCellClassification.BinaryImages.connect( op5Binary.Output ) opCellClassification.RawImages.connect( op5Raw.Output ) opCellClassification.SegmentationImages.connect(opTrackingFeatureExtraction.LabelImage) opCellClassification.ObjectFeatures.connect(opTrackingFeatureExtraction.RegionFeaturesAll) opCellClassification.ComputedFeatureNames.connect(opTrackingFeatureExtraction.ComputedFeatureNamesNoDivisions) opAnnotations.RawImage.connect( op5Raw.Output ) opAnnotations.BinaryImage.connect( op5Binary.Output ) opAnnotations.LabelImage.connect( opObjExtraction.LabelImage ) opAnnotations.ObjectFeatures.connect( opObjExtraction.RegionFeatures ) opAnnotations.ComputedFeatureNames.connect(opObjExtraction.Features) opAnnotations.DivisionProbabilities.connect( opDivDetection.Probabilities ) opAnnotations.DetectionProbabilities.connect( opCellClassification.Probabilities ) opAnnotations.MaxNumObj.connect (opCellClassification.MaxNumObj) opStructuredTracking.RawImage.connect( op5Raw.Output ) opStructuredTracking.LabelImage.connect( opTrackingFeatureExtraction.LabelImage ) opStructuredTracking.ObjectFeatures.connect( opTrackingFeatureExtraction.RegionFeaturesVigra ) opStructuredTracking.ComputedFeatureNames.connect( opTrackingFeatureExtraction.FeatureNamesVigra ) if self.divisionDetectionApplet: opStructuredTracking.ObjectFeaturesWithDivFeatures.connect( opTrackingFeatureExtraction.RegionFeaturesAll) opStructuredTracking.ComputedFeatureNamesWithDivFeatures.connect( opTrackingFeatureExtraction.ComputedFeatureNamesAll ) opStructuredTracking.DivisionProbabilities.connect( opDivDetection.Probabilities ) opStructuredTracking.DetectionProbabilities.connect( opCellClassification.Probabilities ) opStructuredTracking.NumLabels.connect( opCellClassification.NumLabels ) opStructuredTracking.Annotations.connect (opAnnotations.Annotations) opStructuredTracking.Labels.connect (opAnnotations.Labels) opStructuredTracking.Divisions.connect (opAnnotations.Divisions) opStructuredTracking.Appearances.connect (opAnnotations.Appearances) opStructuredTracking.Disappearances.connect (opAnnotations.Disappearances) opStructuredTracking.MaxNumObj.connect (opCellClassification.MaxNumObj) opDataTrackingExport.Inputs.resize(3) opDataTrackingExport.Inputs[0].connect( opStructuredTracking.RelabeledImage ) opDataTrackingExport.Inputs[1].connect( opStructuredTracking.MergerOutput ) opDataTrackingExport.Inputs[2].connect( opStructuredTracking.LabelImage ) opDataTrackingExport.RawData.connect( op5Raw.Output ) opDataTrackingExport.RawDatasetInfo.connect( opData.DatasetGroup[0] ) def prepare_lane_for_export(self, lane_index): import logging logger = logging.getLogger(__name__) maxt = self.trackingApplet.topLevelOperator[lane_index].RawImage.meta.shape[0] maxx = self.trackingApplet.topLevelOperator[lane_index].RawImage.meta.shape[1] maxy = self.trackingApplet.topLevelOperator[lane_index].RawImage.meta.shape[2] maxz = self.trackingApplet.topLevelOperator[lane_index].RawImage.meta.shape[3] time_enum = list(range(maxt)) x_range = (0, maxx) y_range = (0, maxy) z_range = (0, maxz) ndim = 2 if ( z_range[1] - z_range[0] ) > 1: ndim = 3 parameters = self.trackingApplet.topLevelOperator.Parameters.value # Save state of axis ranges if 'time_range' in parameters: self.prev_time_range = parameters['time_range'] else: self.prev_time_range = time_enum if 'x_range' in parameters: self.prev_x_range = parameters['x_range'] else: self.prev_x_range = x_range if 'y_range' in parameters: self.prev_y_range = parameters['y_range'] else: self.prev_y_range = y_range if 'z_range' in parameters: self.prev_z_range = parameters['z_range'] else: self.prev_z_range = z_range # batch processing starts a new lane, so training data needs to be copied from the lane that loaded the project loaded_project_lane_index=0 self.annotationsApplet.topLevelOperator[lane_index].Annotations.setValue( self.trackingApplet.topLevelOperator[loaded_project_lane_index].Annotations.value) def runLearningAndTracking(withMergerResolution=True): if self.testFullAnnotations: logger.info("Test: Structured Learning") weights = self.trackingApplet.topLevelOperator[lane_index]._runStructuredLearning( z_range, parameters['maxObj'], parameters['max_nearest_neighbors'], parameters['maxDist'], parameters['divThreshold'], [parameters['scales'][0],parameters['scales'][1],parameters['scales'][2]], parameters['size_range'], parameters['withDivisions'], parameters['borderAwareWidth'], parameters['withClassifierPrior'], withBatchProcessing=True) logger.info("weights: {}".format(weights)) logger.info("Test: Tracking") result = self.trackingApplet.topLevelOperator[lane_index].track( time_range = time_enum, x_range = x_range, y_range = y_range, z_range = z_range, size_range = parameters['size_range'], x_scale = parameters['scales'][0], y_scale = parameters['scales'][1], z_scale = parameters['scales'][2], maxDist=parameters['maxDist'], maxObj = parameters['maxObj'], divThreshold=parameters['divThreshold'], avgSize=parameters['avgSize'], withTracklets=parameters['withTracklets'], sizeDependent=parameters['sizeDependent'], detWeight=parameters['detWeight'], divWeight=parameters['divWeight'], transWeight=parameters['transWeight'], withDivisions=parameters['withDivisions'], withOpticalCorrection=parameters['withOpticalCorrection'], withClassifierPrior=parameters['withClassifierPrior'], ndim=ndim, withMergerResolution=withMergerResolution, borderAwareWidth = parameters['borderAwareWidth'], withArmaCoordinates = parameters['withArmaCoordinates'], cplex_timeout = parameters['cplex_timeout'], appearance_cost = parameters['appearanceCost'], disappearance_cost = parameters['disappearanceCost'], force_build_hypotheses_graph = False, withBatchProcessing = True ) return result if self.testFullAnnotations: self.result = runLearningAndTracking(withMergerResolution=False) hypothesesGraph = self.trackingApplet.topLevelOperator[lane_index].LearningHypothesesGraph.value hypothesesGraph.insertSolution(self.result) hypothesesGraph.computeLineage() solution = hypothesesGraph.getSolutionDictionary() annotations = self.trackingApplet.topLevelOperator[lane_index].Annotations.value self.trackingApplet.topLevelOperator[lane_index].insertAnnotationsToHypothesesGraph(hypothesesGraph,annotations,misdetectionLabel=-1) hypothesesGraph.computeLineage() solutionFromAnnotations = hypothesesGraph.getSolutionDictionary() for key in list(solution.keys()): if key == 'detectionResults': detectionFlag = True for i in range(len(solution[key])): flag = False for j in range(len(solutionFromAnnotations[key])): if solution[key][i]['id'] == solutionFromAnnotations[key][j]['id'] and \ solution[key][i]['value'] == solutionFromAnnotations[key][j]['value']: flag = True break detectionFlag &= flag elif key == 'divisionResults': divisionFlag = True for i in range(len(solution[key])): flag = False for j in range(len(solutionFromAnnotations[key])): if solution[key][i]['id'] == solutionFromAnnotations[key][j]['id'] and \ solution[key][i]['value'] == solutionFromAnnotations[key][j]['value']: flag = True break divisionFlag &= flag elif key == 'linkingResults': linkingFlag = True for i in range(len(solution[key])): flag = False for j in range(len(solutionFromAnnotations[key])): if solution[key][i]['dest'] == solutionFromAnnotations[key][j]['dest'] and \ solution[key][i]['src'] == solutionFromAnnotations[key][j]['src']: if solution[key][i]['gap'] == solutionFromAnnotations[key][j]['gap'] and \ solution[key][i]['value'] == solutionFromAnnotations[key][j]['value']: flag = True break linkingFlag &= flag assert detectionFlag, "Detection results are NOT correct. They differ from your annotated detections." logger.info("Detection results are correct.") assert divisionFlag, "Division results are NOT correct. They differ from your annotated divisions." logger.info("Division results are correct.") assert linkingFlag, "Transition results are NOT correct. They differ from your annotated transitions." logger.info("Transition results are correct.") self.result = runLearningAndTracking(withMergerResolution=parameters['withMergerResolution']) def post_process_lane_export(self, lane_index, checkOverwriteFiles=False): # Plugin export if selected logger.info("Export source is: " + self.dataExportTrackingApplet.topLevelOperator.SelectedExportSource.value) print("in post_process_lane_export") if self.dataExportTrackingApplet.topLevelOperator.SelectedExportSource.value == OpTrackingBaseDataExport.PluginOnlyName: logger.info("Export source plugin selected!") selectedPlugin = self.dataExportTrackingApplet.topLevelOperator.SelectedPlugin.value additionalPluginArgumentsSlot = self.dataExportTrackingApplet.topLevelOperator.AdditionalPluginArguments exportPluginInfo = pluginManager.getPluginByName(selectedPlugin, category="TrackingExportFormats") if exportPluginInfo is None: logger.error("Could not find selected plugin %s" % exportPluginInfo) else: exportPlugin = exportPluginInfo.plugin_object logger.info("Exporting tracking result using %s" % selectedPlugin) name_format = self.dataExportTrackingApplet.topLevelOperator.getLane(lane_index).OutputFilenameFormat.value partially_formatted_name = self.getPartiallyFormattedName(lane_index, name_format) if exportPlugin.exportsToFile: filename = partially_formatted_name if os.path.basename(filename) == '': filename = os.path.join(filename, 'pluginExport.txt') else: filename = partially_formatted_name if filename is None or len(str(filename)) == 0: logger.error("Cannot export from plugin with empty output filename") return True self.dataExportTrackingApplet.progressSignal(-1) exportStatus = self.trackingApplet.topLevelOperator.getLane(lane_index).exportPlugin( filename, exportPlugin, checkOverwriteFiles, additionalPluginArgumentsSlot) self.dataExportTrackingApplet.progressSignal(100) if not exportStatus: return False logger.info("Export done") return True return True def getPartiallyFormattedName(self, lane_index, path_format_string): ''' Takes the format string for the output file, fills in the most important placeholders, and returns it ''' raw_dataset_info = self.dataSelectionApplet.topLevelOperator.DatasetGroup[lane_index][0].value project_path = self.shell.projectManager.currentProjectPath project_dir = os.path.dirname(project_path) dataset_dir = PathComponents(raw_dataset_info.filePath).externalDirectory abs_dataset_dir = make_absolute(dataset_dir, cwd=project_dir) known_keys = {} known_keys['dataset_dir'] = abs_dataset_dir nickname = raw_dataset_info.nickname.replace('*', '') if os.path.pathsep in nickname: nickname = PathComponents(nickname.split(os.path.pathsep)[0]).fileNameBase known_keys['nickname'] = nickname known_keys['result_type'] = self.dataExportTrackingApplet.topLevelOperator.SelectedPlugin._value # use partial formatting to fill in non-coordinate name fields partially_formatted_name = format_known_keys(path_format_string, known_keys) return partially_formatted_name def _inputReady(self, nRoles): slot = self.dataSelectionApplet.topLevelOperator.ImageGroup if len(slot) > 0: input_ready = True for sub in slot: input_ready = input_ready and \ all([sub[i].ready() for i in range(nRoles)]) else: input_ready = False return input_ready def onProjectLoaded(self, projectManager): """ Overridden from Workflow base class. Called by the Project Manager. If the user provided command-line arguments, use them to configure the workflow inputs and output settings. """ # Configure the data export operator. if self._data_export_args: self.dataExportTrackingApplet.configure_operator_with_parsed_args( self._data_export_args ) # Configure headless mode. if self._headless and self._batch_input_args and self._data_export_args: logger.info("Beginning Batch Processing") self.batchProcessingApplet.run_export_from_parsed_args(self._batch_input_args) logger.info("Completed Batch Processing") def handleAppletStateUpdateRequested(self): """ Overridden from Workflow base class Called when an applet has fired the :py:attr:`Applet.statusUpdateSignal` """ # If no data, nothing else is ready. input_ready = self._inputReady(2) and not self.dataSelectionApplet.busy if not self.fromBinary: opThresholding = self.thresholdTwoLevelsApplet.topLevelOperator thresholdingOutput = opThresholding.CachedOutput thresholding_ready = input_ready and len(thresholdingOutput) > 0 else: thresholding_ready = input_ready opTrackingFeatureExtraction = self.trackingFeatureExtractionApplet.topLevelOperator trackingFeatureExtractionOutput = opTrackingFeatureExtraction.ComputedFeatureNamesAll tracking_features_ready = thresholding_ready and len(trackingFeatureExtractionOutput) > 0 objectCountClassifier_ready = tracking_features_ready opObjectExtraction = self.objectExtractionApplet.topLevelOperator objectExtractionOutput = opObjectExtraction.RegionFeatures features_ready = thresholding_ready and \ len(objectExtractionOutput) > 0 opAnnotations = self.annotationsApplet.topLevelOperator annotations_ready = features_ready and \ len(opAnnotations.Labels) > 0 and \ opAnnotations.Labels.ready() and \ opAnnotations.TrackImage.ready() opStructuredTracking = self.trackingApplet.topLevelOperator structured_tracking_ready = objectCountClassifier_ready withIlpSolver = (self._solver=="ILP") busy = False busy |= self.dataSelectionApplet.busy busy |= self.annotationsApplet.busy # busy |= self.dataExportAnnotationsApplet.busy busy |= self.trackingApplet.busy busy |= self.dataExportTrackingApplet.busy self._shell.enableProjectChanges( not busy ) self._shell.setAppletEnabled(self.dataSelectionApplet, not busy) if not self.fromBinary: self._shell.setAppletEnabled(self.thresholdTwoLevelsApplet, input_ready and not busy) self._shell.setAppletEnabled(self.trackingFeatureExtractionApplet, thresholding_ready and not busy) self._shell.setAppletEnabled(self.cellClassificationApplet, tracking_features_ready and not busy) self._shell.setAppletEnabled(self.divisionDetectionApplet, tracking_features_ready and not busy) self._shell.setAppletEnabled(self.objectExtractionApplet, not busy) self._shell.setAppletEnabled(self.annotationsApplet, features_ready and not busy) # and withIlpSolver) # self._shell.setAppletEnabled(self.dataExportAnnotationsApplet, annotations_ready and not busy and \ # self.dataExportAnnotationsApplet.topLevelOperator.Inputs[0][0].ready() ) self._shell.setAppletEnabled(self.trackingApplet, objectCountClassifier_ready and not busy) self._shell.setAppletEnabled(self.dataExportTrackingApplet, structured_tracking_ready and not busy and \ self.dataExportTrackingApplet.topLevelOperator.Inputs[0][0].ready() )
class StructuredTrackingWorkflowBase(Workflow): workflowName = "Structured Learning Tracking Workflow BASE" @property def applets(self): return self._applets @property def imageNameListSlot(self): return self.dataSelectionApplet.topLevelOperator.ImageName def __init__(self, shell, headless, workflow_cmdline_args, project_creation_args, *args, **kwargs): graph = kwargs["graph"] if "graph" in kwargs else Graph() if "graph" in kwargs: del kwargs["graph"] super(StructuredTrackingWorkflowBase, self).__init__(shell, headless, workflow_cmdline_args, project_creation_args, graph=graph, *args, **kwargs) data_instructions = 'Use the "Raw Data" tab to load your intensity image(s).\n\n' if self.fromBinary: data_instructions += 'Use the "Binary Image" tab to load your segmentation image(s).' else: data_instructions += 'Use the "Prediction Maps" tab to load your pixel-wise probability image(s).' # Create applets self.dataSelectionApplet = DataSelectionApplet( self, "Input Data", "Input Data", batchDataGui=False, forceAxisOrder=["txyzc"], instructionText=data_instructions, max_lanes=1, ) opDataSelection = self.dataSelectionApplet.topLevelOperator if self.fromBinary: opDataSelection.DatasetRoles.setValue(["Raw Data", "Binary Image"]) else: opDataSelection.DatasetRoles.setValue( ["Raw Data", "Prediction Maps"]) if not self.fromBinary: self.thresholdTwoLevelsApplet = ThresholdTwoLevelsApplet( self, "Threshold and Size Filter", "ThresholdTwoLevels") self.divisionDetectionApplet = ObjectClassificationApplet( workflow=self, name="Division Detection (optional)", projectFileGroupName="DivisionDetection", selectedFeatures=configConservation.selectedFeaturesDiv, ) self.cellClassificationApplet = ObjectClassificationApplet( workflow=self, name="Object Count Classification", projectFileGroupName="CountClassification", selectedFeatures=configConservation.selectedFeaturesObjectCount, ) self.trackingFeatureExtractionApplet = TrackingFeatureExtractionApplet( name="Object Feature Computation", workflow=self, interactive=False) self.objectExtractionApplet = ObjectExtractionApplet( name="Object Feature Computation", workflow=self, interactive=False) self.annotationsApplet = AnnotationsApplet(name="Training", workflow=self) opAnnotations = self.annotationsApplet.topLevelOperator self.trackingApplet = StructuredTrackingApplet( name="Tracking - Structured Learning", workflow=self) opStructuredTracking = self.trackingApplet.topLevelOperator if SOLVER == "CPLEX" or SOLVER == "GUROBI": self._solver = "ILP" elif SOLVER == "DPCT": self._solver = "Flow-based" else: self._solver = None opStructuredTracking._solver = self._solver self.default_tracking_export_filename = "{dataset_dir}/{nickname}-tracking_exported_data.csv" self.dataExportTrackingApplet = TrackingBaseDataExportApplet( self, "Tracking Result Export", default_export_filename=self.default_tracking_export_filename, pluginExportFunc=self._pluginExportFunc, ) opDataExportTracking = self.dataExportTrackingApplet.topLevelOperator opDataExportTracking.SelectionNames.setValue( ["Tracking-Result", "Merger-Result", "Object-Identities"]) opDataExportTracking.WorkingDirectory.connect( opDataSelection.WorkingDirectory) self.dataExportTrackingApplet.set_exporting_operator( opStructuredTracking) self.dataExportTrackingApplet.prepare_lane_for_export = self.prepare_lane_for_export # configure export settings settings = { "file path": self.default_tracking_export_filename, "compression": {}, "file type": "h5" } selected_features = [ "Count", "RegionCenter", "RegionRadii", "RegionAxes" ] opStructuredTracking.ExportSettings.setValue( (settings, selected_features)) self._applets = [] self._applets.append(self.dataSelectionApplet) if not self.fromBinary: self._applets.append(self.thresholdTwoLevelsApplet) self._applets.append(self.trackingFeatureExtractionApplet) self._applets.append(self.divisionDetectionApplet) self.batchProcessingApplet = BatchProcessingApplet( self, "Batch Processing", self.dataSelectionApplet, self.dataExportTrackingApplet) self._applets.append(self.cellClassificationApplet) self._applets.append(self.objectExtractionApplet) self._applets.append(self.annotationsApplet) self._applets.append(self.trackingApplet) self._applets.append(self.dataExportTrackingApplet) if self.divisionDetectionApplet: opDivDetection = self.divisionDetectionApplet.topLevelOperator opDivDetection.SelectedFeatures.setValue( configConservation.selectedFeaturesDiv) opDivDetection.LabelNames.setValue(["Not Dividing", "Dividing"]) opDivDetection.AllowDeleteLabels.setValue(False) opDivDetection.AllowAddLabel.setValue(False) opDivDetection.EnableLabelTransfer.setValue(False) opCellClassification = self.cellClassificationApplet.topLevelOperator opCellClassification.SelectedFeatures.setValue( configConservation.selectedFeaturesObjectCount) opCellClassification.SuggestedLabelNames.setValue( ["False Detection"] + [str(1) + " Object"] + [str(i) + " Objects" for i in range(2, 10)]) opCellClassification.AllowDeleteLastLabelOnly.setValue(True) opCellClassification.EnableLabelTransfer.setValue(False) if workflow_cmdline_args: if "--testFullAnnotations" in workflow_cmdline_args: self.testFullAnnotations = True else: self.testFullAnnotations = False self._data_export_args, unused_args = self.dataExportTrackingApplet.parse_known_cmdline_args( workflow_cmdline_args) self._batch_input_args, unused_args = self.batchProcessingApplet.parse_known_cmdline_args( workflow_cmdline_args) else: unused_args = None self._data_export_args = None self._batch_input_args = None self.testFullAnnotations = False if unused_args: logger.warning("Unused command-line args: {}".format(unused_args)) def _pluginExportFunc(self, lane_index, filename, exportPlugin, checkOverwriteFiles, plugArgsSlot) -> int: return self.trackingApplet.topLevelOperator.getLane( lane_index).exportPlugin(filename, exportPlugin, checkOverwriteFiles, plugArgsSlot) def connectLane(self, laneIndex): opData = self.dataSelectionApplet.topLevelOperator.getLane(laneIndex) opObjExtraction = self.objectExtractionApplet.topLevelOperator.getLane( laneIndex) opTrackingFeatureExtraction = self.trackingFeatureExtractionApplet.topLevelOperator.getLane( laneIndex) opAnnotations = self.annotationsApplet.topLevelOperator.getLane( laneIndex) if not self.fromBinary: opTwoLevelThreshold = self.thresholdTwoLevelsApplet.topLevelOperator.getLane( laneIndex) opStructuredTracking = self.trackingApplet.topLevelOperator.getLane( laneIndex) opDataTrackingExport = self.dataExportTrackingApplet.topLevelOperator.getLane( laneIndex) ## Connect operators ## op5Raw = OpReorderAxes(parent=self) op5Raw.AxisOrder.setValue("txyzc") op5Raw.Input.connect(opData.ImageGroup[0]) opDivDetection = self.divisionDetectionApplet.topLevelOperator.getLane( laneIndex) opCellClassification = self.cellClassificationApplet.topLevelOperator.getLane( laneIndex) if not self.fromBinary: opTwoLevelThreshold.InputImage.connect(opData.ImageGroup[1]) opTwoLevelThreshold.RawInput.connect( opData.ImageGroup[0]) # Used for display only binarySrc = opTwoLevelThreshold.CachedOutput else: binarySrc = opData.ImageGroup[1] # Use Op5ifyers for both input datasets such that they are guaranteed to # have the same axis order after thresholding op5Binary = OpReorderAxes(parent=self) op5Binary.AxisOrder.setValue("txyzc") op5Binary.Input.connect(binarySrc) opObjExtraction.RawImage.connect(op5Raw.Output) opObjExtraction.BinaryImage.connect(op5Binary.Output) opTrackingFeatureExtraction.RawImage.connect(op5Raw.Output) opTrackingFeatureExtraction.BinaryImage.connect(op5Binary.Output) opTrackingFeatureExtraction.setDefaultFeatures( configConservation.allFeaturesObjectCount) opTrackingFeatureExtraction.FeatureNamesVigra.setValue( configConservation.allFeaturesObjectCount) feature_dict_division = {} feature_dict_division[config.features_division_name] = { name: {} for name in config.division_features } opTrackingFeatureExtraction.FeatureNamesDivision.setValue( feature_dict_division) if self.divisionDetectionApplet: opDivDetection.BinaryImages.connect(op5Binary.Output) opDivDetection.RawImages.connect(op5Raw.Output) opDivDetection.SegmentationImages.connect( opTrackingFeatureExtraction.LabelImage) opDivDetection.ObjectFeatures.connect( opTrackingFeatureExtraction.RegionFeaturesAll) opDivDetection.ComputedFeatureNames.connect( opTrackingFeatureExtraction.ComputedFeatureNamesAll) opCellClassification.BinaryImages.connect(op5Binary.Output) opCellClassification.RawImages.connect(op5Raw.Output) opCellClassification.SegmentationImages.connect( opTrackingFeatureExtraction.LabelImage) opCellClassification.ObjectFeatures.connect( opTrackingFeatureExtraction.RegionFeaturesAll) opCellClassification.ComputedFeatureNames.connect( opTrackingFeatureExtraction.ComputedFeatureNamesNoDivisions) opAnnotations.RawImage.connect(op5Raw.Output) opAnnotations.BinaryImage.connect(op5Binary.Output) opAnnotations.LabelImage.connect(opObjExtraction.LabelImage) opAnnotations.ObjectFeatures.connect(opObjExtraction.RegionFeatures) opAnnotations.ComputedFeatureNames.connect(opObjExtraction.Features) opAnnotations.DivisionProbabilities.connect( opDivDetection.Probabilities) opAnnotations.DetectionProbabilities.connect( opCellClassification.Probabilities) opAnnotations.MaxNumObj.connect(opCellClassification.MaxNumObj) opStructuredTracking.RawImage.connect(op5Raw.Output) opStructuredTracking.LabelImage.connect( opTrackingFeatureExtraction.LabelImage) opStructuredTracking.ObjectFeatures.connect( opTrackingFeatureExtraction.RegionFeaturesVigra) opStructuredTracking.ComputedFeatureNames.connect( opTrackingFeatureExtraction.FeatureNamesVigra) if self.divisionDetectionApplet: opStructuredTracking.ObjectFeaturesWithDivFeatures.connect( opTrackingFeatureExtraction.RegionFeaturesAll) opStructuredTracking.ComputedFeatureNamesWithDivFeatures.connect( opTrackingFeatureExtraction.ComputedFeatureNamesAll) opStructuredTracking.DivisionProbabilities.connect( opDivDetection.Probabilities) opStructuredTracking.DetectionProbabilities.connect( opCellClassification.Probabilities) opStructuredTracking.NumLabels.connect(opCellClassification.NumLabels) opStructuredTracking.Annotations.connect(opAnnotations.Annotations) opStructuredTracking.Labels.connect(opAnnotations.Labels) opStructuredTracking.Divisions.connect(opAnnotations.Divisions) opStructuredTracking.Appearances.connect(opAnnotations.Appearances) opStructuredTracking.Disappearances.connect( opAnnotations.Disappearances) opStructuredTracking.MaxNumObj.connect(opCellClassification.MaxNumObj) opDataTrackingExport.Inputs.resize(3) opDataTrackingExport.Inputs[0].connect(opStructuredTracking.Output) opDataTrackingExport.Inputs[1].connect( opStructuredTracking.MergerOutput) opDataTrackingExport.Inputs[2].connect( opStructuredTracking.RelabeledImage) opDataTrackingExport.RawData.connect(op5Raw.Output) opDataTrackingExport.RawDatasetInfo.connect(opData.DatasetGroup[0]) def prepare_lane_for_export(self, lane_index): import logging logger = logging.getLogger(__name__) maxt = self.trackingApplet.topLevelOperator[ lane_index].RawImage.meta.shape[0] maxx = self.trackingApplet.topLevelOperator[ lane_index].RawImage.meta.shape[1] maxy = self.trackingApplet.topLevelOperator[ lane_index].RawImage.meta.shape[2] maxz = self.trackingApplet.topLevelOperator[ lane_index].RawImage.meta.shape[3] time_enum = list(range(maxt)) x_range = (0, maxx) y_range = (0, maxy) z_range = (0, maxz) ndim = 2 if (z_range[1] - z_range[0]) > 1: ndim = 3 parameters = self.trackingApplet.topLevelOperator.Parameters.value # Save state of axis ranges if "time_range" in parameters: self.prev_time_range = parameters["time_range"] else: self.prev_time_range = time_enum if "x_range" in parameters: self.prev_x_range = parameters["x_range"] else: self.prev_x_range = x_range if "y_range" in parameters: self.prev_y_range = parameters["y_range"] else: self.prev_y_range = y_range if "z_range" in parameters: self.prev_z_range = parameters["z_range"] else: self.prev_z_range = z_range # batch processing starts a new lane, so training data needs to be copied from the lane that loaded the project loaded_project_lane_index = 0 self.annotationsApplet.topLevelOperator[ lane_index].Annotations.setValue( self.trackingApplet. topLevelOperator[loaded_project_lane_index].Annotations.value) def runLearningAndTracking(withMergerResolution=True): if self.testFullAnnotations: logger.info("Test: Structured Learning") weights = self.trackingApplet.topLevelOperator[ lane_index]._runStructuredLearning( z_range, parameters["maxObj"], parameters["max_nearest_neighbors"], parameters["maxDist"], parameters["divThreshold"], [ parameters["scales"][0], parameters["scales"][1], parameters["scales"][2] ], parameters["size_range"], parameters["withDivisions"], parameters["borderAwareWidth"], parameters["withClassifierPrior"], withBatchProcessing=True, ) logger.info("weights: {}".format(weights)) logger.info("Test: Tracking") result = self.trackingApplet.topLevelOperator[lane_index].track( time_range=time_enum, x_range=x_range, y_range=y_range, z_range=z_range, size_range=parameters["size_range"], x_scale=parameters["scales"][0], y_scale=parameters["scales"][1], z_scale=parameters["scales"][2], maxDist=parameters["maxDist"], maxObj=parameters["maxObj"], divThreshold=parameters["divThreshold"], avgSize=parameters["avgSize"], withTracklets=parameters["withTracklets"], sizeDependent=parameters["sizeDependent"], detWeight=parameters["detWeight"], divWeight=parameters["divWeight"], transWeight=parameters["transWeight"], withDivisions=parameters["withDivisions"], withOpticalCorrection=parameters["withOpticalCorrection"], withClassifierPrior=parameters["withClassifierPrior"], ndim=ndim, withMergerResolution=withMergerResolution, borderAwareWidth=parameters["borderAwareWidth"], withArmaCoordinates=parameters["withArmaCoordinates"], cplex_timeout=parameters["cplex_timeout"], appearance_cost=parameters["appearanceCost"], disappearance_cost=parameters["disappearanceCost"], force_build_hypotheses_graph=False, withBatchProcessing=True, ) return result if self.testFullAnnotations: self.result = runLearningAndTracking(withMergerResolution=False) hypothesesGraph = self.trackingApplet.topLevelOperator[ lane_index].LearningHypothesesGraph.value hypothesesGraph.insertSolution(self.result) hypothesesGraph.computeLineage() solution = hypothesesGraph.getSolutionDictionary() annotations = self.trackingApplet.topLevelOperator[ lane_index].Annotations.value self.trackingApplet.topLevelOperator[ lane_index].insertAnnotationsToHypothesesGraph( hypothesesGraph, annotations, misdetectionLabel=-1) hypothesesGraph.computeLineage() solutionFromAnnotations = hypothesesGraph.getSolutionDictionary() for key in list(solution.keys()): if key == "detectionResults": detectionFlag = True for i in range(len(solution[key])): flag = False for j in range(len(solutionFromAnnotations[key])): if (solution[key][i]["id"] == solutionFromAnnotations[key][j]["id"] and solution[key][i]["value"] == solutionFromAnnotations[key][j]["value"]): flag = True break detectionFlag &= flag elif key == "divisionResults": divisionFlag = True for i in range(len(solution[key])): flag = False for j in range(len(solutionFromAnnotations[key])): if (solution[key][i]["id"] == solutionFromAnnotations[key][j]["id"] and solution[key][i]["value"] == solutionFromAnnotations[key][j]["value"]): flag = True break divisionFlag &= flag elif key == "linkingResults": linkingFlag = True for i in range(len(solution[key])): flag = False for j in range(len(solutionFromAnnotations[key])): if (solution[key][i]["dest"] == solutionFromAnnotations[key][j]["dest"] and solution[key][i]["src"] == solutionFromAnnotations[key][j]["src"]): if (solution[key][i]["gap"] == solutionFromAnnotations[key][j]["gap"] and solution[key][i]["value"] == solutionFromAnnotations[key][j] ["value"]): flag = True break linkingFlag &= flag assert detectionFlag, "Detection results are NOT correct. They differ from your annotated detections." logger.info("Detection results are correct.") assert divisionFlag, "Division results are NOT correct. They differ from your annotated divisions." logger.info("Division results are correct.") assert linkingFlag, "Transition results are NOT correct. They differ from your annotated transitions." logger.info("Transition results are correct.") self.result = runLearningAndTracking( withMergerResolution=parameters["withMergerResolution"]) def _inputReady(self, nRoles): slot = self.dataSelectionApplet.topLevelOperator.ImageGroup if len(slot) > 0: input_ready = True for sub in slot: input_ready = input_ready and all( [sub[i].ready() for i in range(nRoles)]) else: input_ready = False return input_ready def onProjectLoaded(self, projectManager): """ Overridden from Workflow base class. Called by the Project Manager. If the user provided command-line arguments, use them to configure the workflow inputs and output settings. """ # Configure the data export operator. if self._data_export_args: self.dataExportTrackingApplet.configure_operator_with_parsed_args( self._data_export_args) # Configure headless mode. if self._headless and self._batch_input_args and self._data_export_args: logger.info("Beginning Batch Processing") self.batchProcessingApplet.run_export_from_parsed_args( self._batch_input_args) logger.info("Completed Batch Processing") def handleAppletStateUpdateRequested(self): """ Overridden from Workflow base class Called when an applet has fired the :py:attr:`Applet.statusUpdateSignal` """ # If no data, nothing else is ready. input_ready = self._inputReady(2) and not self.dataSelectionApplet.busy if not self.fromBinary: opThresholding = self.thresholdTwoLevelsApplet.topLevelOperator thresholdingOutput = opThresholding.CachedOutput thresholding_ready = input_ready and len(thresholdingOutput) > 0 else: thresholding_ready = input_ready opTrackingFeatureExtraction = self.trackingFeatureExtractionApplet.topLevelOperator trackingFeatureExtractionOutput = opTrackingFeatureExtraction.ComputedFeatureNamesAll tracking_features_ready = thresholding_ready and len( trackingFeatureExtractionOutput) > 0 objectCountClassifier_ready = tracking_features_ready opObjectExtraction = self.objectExtractionApplet.topLevelOperator objectExtractionOutput = opObjectExtraction.RegionFeatures features_ready = thresholding_ready and len(objectExtractionOutput) > 0 opAnnotations = self.annotationsApplet.topLevelOperator annotations_ready = (features_ready and len(opAnnotations.Labels) > 0 and opAnnotations.Labels.ready() and opAnnotations.TrackImage.ready()) opStructuredTracking = self.trackingApplet.topLevelOperator structured_tracking_ready = objectCountClassifier_ready withIlpSolver = self._solver == "ILP" busy = False busy |= self.dataSelectionApplet.busy busy |= self.annotationsApplet.busy # busy |= self.dataExportAnnotationsApplet.busy busy |= self.trackingApplet.busy busy |= self.dataExportTrackingApplet.busy self._shell.enableProjectChanges(not busy) self._shell.setAppletEnabled(self.dataSelectionApplet, not busy) if not self.fromBinary: self._shell.setAppletEnabled(self.thresholdTwoLevelsApplet, input_ready and not busy) self._shell.setAppletEnabled(self.trackingFeatureExtractionApplet, thresholding_ready and not busy) self._shell.setAppletEnabled(self.cellClassificationApplet, tracking_features_ready and not busy) self._shell.setAppletEnabled(self.divisionDetectionApplet, tracking_features_ready and not busy) self._shell.setAppletEnabled(self.objectExtractionApplet, not busy) self._shell.setAppletEnabled(self.annotationsApplet, features_ready and not busy) # and withIlpSolver) # self._shell.setAppletEnabled(self.dataExportAnnotationsApplet, annotations_ready and not busy and \ # self.dataExportAnnotationsApplet.topLevelOperator.Inputs[0][0].ready() ) self._shell.setAppletEnabled(self.trackingApplet, objectCountClassifier_ready and not busy) self._shell.setAppletEnabled( self.dataExportTrackingApplet, structured_tracking_ready and not busy and self.dataExportTrackingApplet.topLevelOperator.Inputs[0] [0].ready(), )
def __init__( self, shell, headless, workflow_cmdline_args, *args, **kwargs ): graph = kwargs['graph'] if 'graph' in kwargs else Graph() if 'graph' in kwargs: del kwargs['graph'] # if 'withOptTrans' in kwargs: # self.withOptTrans = kwargs['withOptTrans'] # if 'fromBinary' in kwargs: # self.fromBinary = kwargs['fromBinary'] super(ConservationTrackingWorkflowBase, self).__init__(shell, headless, graph=graph, *args, **kwargs) data_instructions = 'Use the "Raw Data" tab to load your intensity image(s).\n\n' if self.fromBinary: data_instructions += 'Use the "Binary Image" tab to load your segmentation image(s).' else: data_instructions += 'Use the "Prediction Maps" tab to load your pixel-wise probability image(s).' ## Create applets self.dataSelectionApplet = DataSelectionApplet(self, "Input Data", "Input Data", forceAxisOrder='txyzc', instructionText=data_instructions, max_lanes=1 ) opDataSelection = self.dataSelectionApplet.topLevelOperator if self.fromBinary: opDataSelection.DatasetRoles.setValue( ['Raw Data', 'Binary Image'] ) else: opDataSelection.DatasetRoles.setValue( ['Raw Data', 'Prediction Maps'] ) if not self.fromBinary: self.thresholdTwoLevelsApplet = ThresholdTwoLevelsApplet( self, "Threshold and Size Filter", "ThresholdTwoLevels" ) if self.withOptTrans: self.opticalTranslationApplet = OpticalTranslationApplet(workflow=self) self.objectExtractionApplet = TrackingFeatureExtractionApplet(workflow=self, interactive=False, name="Object Feature Computation") self.divisionDetectionApplet = ObjectClassificationApplet(workflow=self, name="Division Detection (optional)", projectFileGroupName="DivisionDetection") self.cellClassificationApplet = ObjectClassificationApplet(workflow=self, name="Object Count Classification (optional)", projectFileGroupName="CountClassification") self.trackingApplet = ConservationTrackingApplet( workflow=self ) self.default_export_filename = '{dataset_dir}/{nickname}-exported_data.csv' self.dataExportApplet = TrackingBaseDataExportApplet(self, "Tracking Result Export", default_export_filename=self.default_export_filename) opDataExport = self.dataExportApplet.topLevelOperator opDataExport.SelectionNames.setValue( ['Object Identities', 'Tracking Result', 'Merger Result'] ) opDataExport.WorkingDirectory.connect( opDataSelection.WorkingDirectory ) # Extra configuration for object export table (as CSV table or HDF5 table) opTracking = self.trackingApplet.topLevelOperator self.dataExportApplet.set_exporting_operator(opTracking) self.dataExportApplet.post_process_lane_export = self.post_process_lane_export self._applets = [] self._applets.append(self.dataSelectionApplet) if not self.fromBinary: self._applets.append(self.thresholdTwoLevelsApplet) if self.withOptTrans: self._applets.append(self.opticalTranslationApplet) self._applets.append(self.objectExtractionApplet) self._applets.append(self.divisionDetectionApplet) self._applets.append(self.cellClassificationApplet) self._applets.append(self.trackingApplet) self._applets.append(self.dataExportApplet)
class StructuredTrackingWorkflowBase( Workflow ): workflowName = "Structured Learning Tracking Workflow BASE" @property def applets(self): return self._applets @property def imageNameListSlot(self): return self.dataSelectionApplet.topLevelOperator.ImageName def __init__( self, shell, headless, workflow_cmdline_args, project_creation_args, *args, **kwargs ): graph = kwargs['graph'] if 'graph' in kwargs else Graph() if 'graph' in kwargs: del kwargs['graph'] super(StructuredTrackingWorkflowBase, self).__init__(shell, headless, workflow_cmdline_args, project_creation_args, graph=graph, *args, **kwargs) data_instructions = 'Use the "Raw Data" tab to load your intensity image(s).\n\n' if self.fromBinary: data_instructions += 'Use the "Binary Image" tab to load your segmentation image(s).' else: data_instructions += 'Use the "Prediction Maps" tab to load your pixel-wise probability image(s).' # Create applets self.dataSelectionApplet = DataSelectionApplet(self, "Input Data", "Input Data", batchDataGui=False, forceAxisOrder='txyzc', instructionText=data_instructions, max_lanes=1) opDataSelection = self.dataSelectionApplet.topLevelOperator if self.fromBinary: opDataSelection.DatasetRoles.setValue( ['Raw Data', 'Binary Image'] ) else: opDataSelection.DatasetRoles.setValue( ['Raw Data', 'Prediction Maps'] ) if not self.fromBinary: self.thresholdTwoLevelsApplet = ThresholdTwoLevelsApplet( self,"Threshold and Size Filter","ThresholdTwoLevels" ) self.divisionDetectionApplet = ObjectClassificationApplet(workflow=self, name="Division Detection (optional)", projectFileGroupName="DivisionDetection", selectedFeatures=configStructured.selectedFeaturesDiv) self.cellClassificationApplet = ObjectClassificationApplet(workflow=self, name="Object Count Classification", projectFileGroupName="CountClassification", selectedFeatures=configStructured.selectedFeaturesObjectCount) self.cropSelectionApplet = CropSelectionApplet(self,"Crop Selection","CropSelection") self.trackingFeatureExtractionApplet = TrackingFeatureExtractionApplet(name="Object Feature Computation",workflow=self, interactive=False) self.objectExtractionApplet = ObjectExtractionApplet(name="Object Feature Computation",workflow=self, interactive=False) self.annotationsApplet = AnnotationsApplet( name="Training", workflow=self ) opAnnotations = self.annotationsApplet.topLevelOperator # self.default_training_export_filename = '{dataset_dir}/{nickname}-training_exported_data.csv' # self.dataExportAnnotationsApplet = TrackingBaseDataExportApplet(self, "Training Export",default_export_filename=self.default_training_export_filename) # opDataExportAnnotations = self.dataExportAnnotationsApplet.topLevelOperator # opDataExportAnnotations.SelectionNames.setValue( ['User Training for Tracking', 'Object Identities'] ) # opDataExportAnnotations.WorkingDirectory.connect( opDataSelection.WorkingDirectory ) # self.dataExportAnnotationsApplet.set_exporting_operator(opAnnotations) self.trackingApplet = StructuredTrackingApplet( name="Tracking - Structured Learning", workflow=self ) opStructuredTracking = self.trackingApplet.topLevelOperator self.default_tracking_export_filename = '{dataset_dir}/{nickname}-tracking_exported_data.csv' self.dataExportTrackingApplet = TrackingBaseDataExportApplet(self, "Tracking Result Export",default_export_filename=self.default_tracking_export_filename) opDataExportTracking = self.dataExportTrackingApplet.topLevelOperator opDataExportTracking.SelectionNames.setValue( ['Tracking Result', 'Merger Result', 'Object Identities'] ) opDataExportTracking.WorkingDirectory.connect( opDataSelection.WorkingDirectory ) self.dataExportTrackingApplet.set_exporting_operator(opStructuredTracking) self.dataExportTrackingApplet.post_process_lane_export = self.post_process_lane_export self._applets = [] self._applets.append(self.dataSelectionApplet) if not self.fromBinary: self._applets.append(self.thresholdTwoLevelsApplet) self._applets.append(self.trackingFeatureExtractionApplet) self._applets.append(self.divisionDetectionApplet) self._applets.append(self.cellClassificationApplet) self._applets.append(self.cropSelectionApplet) self._applets.append(self.objectExtractionApplet) self._applets.append(self.annotationsApplet) # self._applets.append(self.dataExportAnnotationsApplet) self._applets.append(self.trackingApplet) self._applets.append(self.dataExportTrackingApplet) if self.divisionDetectionApplet: opDivDetection = self.divisionDetectionApplet.topLevelOperator opDivDetection.SelectedFeatures.setValue(configConservation.selectedFeaturesDiv) opDivDetection.LabelNames.setValue(['Not Dividing', 'Dividing']) opDivDetection.AllowDeleteLabels.setValue(False) opDivDetection.AllowAddLabel.setValue(False) opDivDetection.EnableLabelTransfer.setValue(False) opCellClassification = self.cellClassificationApplet.topLevelOperator opCellClassification.SelectedFeatures.setValue(configConservation.selectedFeaturesObjectCount ) opCellClassification.SuggestedLabelNames.setValue( ['False Detection',] + [str(1) + ' Object'] + [str(i) + ' Objects' for i in range(2,10) ] ) opCellClassification.AllowDeleteLastLabelOnly.setValue(True) opCellClassification.EnableLabelTransfer.setValue(False) def connectLane(self, laneIndex): opData = self.dataSelectionApplet.topLevelOperator.getLane(laneIndex) opObjExtraction = self.objectExtractionApplet.topLevelOperator.getLane(laneIndex) opTrackingFeatureExtraction = self.trackingFeatureExtractionApplet.topLevelOperator.getLane(laneIndex) opAnnotations = self.annotationsApplet.topLevelOperator.getLane(laneIndex) if not self.fromBinary: opTwoLevelThreshold = self.thresholdTwoLevelsApplet.topLevelOperator.getLane(laneIndex) # opDataAnnotationsExport = self.dataExportAnnotationsApplet.topLevelOperator.getLane(laneIndex) opCropSelection = self.cropSelectionApplet.topLevelOperator.getLane(laneIndex) opStructuredTracking = self.trackingApplet.topLevelOperator.getLane(laneIndex) opDataTrackingExport = self.dataExportTrackingApplet.topLevelOperator.getLane(laneIndex) ## Connect operators ## op5Raw = OpReorderAxes(parent=self) op5Raw.AxisOrder.setValue("txyzc") op5Raw.Input.connect(opData.ImageGroup[0]) opDivDetection = self.divisionDetectionApplet.topLevelOperator.getLane(laneIndex) opCellClassification = self.cellClassificationApplet.topLevelOperator.getLane(laneIndex) if not self.fromBinary: opTwoLevelThreshold.InputImage.connect( opData.ImageGroup[1] ) opTwoLevelThreshold.RawInput.connect( opData.ImageGroup[0] ) # Used for display only binarySrc = opTwoLevelThreshold.CachedOutput else: binarySrc = opData.ImageGroup[1] # Use Op5ifyers for both input datasets such that they are guaranteed to # have the same axis order after thresholding op5Binary = OpReorderAxes(parent=self) op5Binary.AxisOrder.setValue("txyzc") op5Binary.Input.connect(binarySrc) opCropSelection.InputImage.connect( opData.ImageGroup[0] ) opCropSelection.PredictionImage.connect( opData.ImageGroup[1] ) opObjExtraction.RawImage.connect( op5Raw.Output ) opObjExtraction.BinaryImage.connect( op5Binary.Output ) opTrackingFeatureExtraction.RawImage.connect( op5Raw.Output ) opTrackingFeatureExtraction.BinaryImage.connect( op5Binary.Output ) # vigra_features = list((set(config.vigra_features)).union(config.selected_features_objectcount[config.features_vigra_name])) # feature_names_vigra = {} # feature_names_vigra[config.features_vigra_name] = { name: {} for name in vigra_features } opTrackingFeatureExtraction.FeatureNamesVigra.setValue(configConservation.allFeaturesObjectCount) feature_dict_division = {} feature_dict_division[config.features_division_name] = { name: {} for name in config.division_features } opTrackingFeatureExtraction.FeatureNamesDivision.setValue(feature_dict_division) if self.divisionDetectionApplet: opDivDetection.BinaryImages.connect( op5Binary.Output ) opDivDetection.RawImages.connect( op5Raw.Output ) opDivDetection.SegmentationImages.connect(opTrackingFeatureExtraction.LabelImage) opDivDetection.ObjectFeatures.connect(opTrackingFeatureExtraction.RegionFeaturesAll) opDivDetection.ComputedFeatureNames.connect(opTrackingFeatureExtraction.ComputedFeatureNamesAll) opCellClassification.BinaryImages.connect( op5Binary.Output ) opCellClassification.RawImages.connect( op5Raw.Output ) opCellClassification.SegmentationImages.connect(opTrackingFeatureExtraction.LabelImage) opCellClassification.ObjectFeatures.connect(opTrackingFeatureExtraction.RegionFeaturesAll) opCellClassification.ComputedFeatureNames.connect(opTrackingFeatureExtraction.ComputedFeatureNamesNoDivisions) opAnnotations.RawImage.connect( op5Raw.Output ) opAnnotations.BinaryImage.connect( op5Binary.Output ) opAnnotations.LabelImage.connect( opObjExtraction.LabelImage ) opAnnotations.ObjectFeatures.connect( opObjExtraction.RegionFeatures ) opAnnotations.ComputedFeatureNames.connect(opObjExtraction.Features) opAnnotations.Crops.connect( opCropSelection.Crops) # opDataAnnotationsExport.Inputs.resize(2) # opDataAnnotationsExport.Inputs[0].connect( opAnnotations.TrackImage ) # opDataAnnotationsExport.Inputs[1].connect( opAnnotations.LabelImage ) # opDataAnnotationsExport.RawData.connect( op5Raw.Output ) # opDataAnnotationsExport.RawDatasetInfo.connect( opData.DatasetGroup[0] ) opStructuredTracking.RawImage.connect( op5Raw.Output ) opStructuredTracking.LabelImage.connect( opTrackingFeatureExtraction.LabelImage ) opStructuredTracking.ObjectFeatures.connect( opTrackingFeatureExtraction.RegionFeaturesVigra ) opStructuredTracking.ComputedFeatureNames.connect( opTrackingFeatureExtraction.FeatureNamesVigra ) if self.divisionDetectionApplet: opStructuredTracking.ObjectFeaturesWithDivFeatures.connect( opTrackingFeatureExtraction.RegionFeaturesAll) opStructuredTracking.ComputedFeatureNamesWithDivFeatures.connect( opTrackingFeatureExtraction.ComputedFeatureNamesAll ) opStructuredTracking.DivisionProbabilities.connect( opDivDetection.Probabilities ) # configure tracking export settings settings = {'file path': self.default_tracking_export_filename, 'compression': {}, 'file type': 'csv'} selected_features = ['Count', 'RegionCenter'] opStructuredTracking.configure_table_export_settings(settings, selected_features) opStructuredTracking.DetectionProbabilities.connect( opCellClassification.Probabilities ) opStructuredTracking.NumLabels.connect( opCellClassification.NumLabels ) opStructuredTracking.Crops.connect (opCropSelection.Crops) opStructuredTracking.Annotations.connect (opAnnotations.Annotations) opStructuredTracking.Labels.connect (opAnnotations.Labels) opStructuredTracking.Divisions.connect (opAnnotations.Divisions) opStructuredTracking.MaxNumObj.connect (opCellClassification.MaxNumObj) opDataTrackingExport.Inputs.resize(3) opDataTrackingExport.Inputs[0].connect( opStructuredTracking.Output ) opDataTrackingExport.Inputs[1].connect( opStructuredTracking.MergerOutput ) opDataTrackingExport.Inputs[2].connect( opStructuredTracking.LabelImage ) opDataTrackingExport.RawData.connect( op5Raw.Output ) opDataTrackingExport.RawDatasetInfo.connect( opData.DatasetGroup[0] ) def post_process_lane_export(self, lane_index): # FIXME: This probably only works for the non-blockwise export slot. # We should assert that the user isn't using the blockwise slot. settings, selected_features = self.trackingApplet.topLevelOperator.getLane(lane_index).get_table_export_settings() from lazyflow.utility import PathComponents, make_absolute, format_known_keys if settings: self.dataExportTrackingApplet.progressSignal.emit(-1) raw_dataset_info = self.dataSelectionApplet.topLevelOperator.DatasetGroup[lane_index][0].value project_path = self.shell.projectManager.currentProjectPath project_dir = os.path.dirname(project_path) dataset_dir = PathComponents(raw_dataset_info.filePath).externalDirectory abs_dataset_dir = make_absolute(dataset_dir, cwd=project_dir) known_keys = {} known_keys['dataset_dir'] = abs_dataset_dir nickname = raw_dataset_info.nickname.replace('*', '') if os.path.pathsep in nickname: nickname = PathComponents(nickname.split(os.path.pathsep)[0]).fileNameBase known_keys['nickname'] = nickname # use partial formatting to fill in non-coordinate name fields name_format = settings['file path'] partially_formatted_name = format_known_keys( name_format, known_keys ) settings['file path'] = partially_formatted_name req = self.trackingApplet.topLevelOperator.getLane(lane_index).export_object_data( lane_index, # FIXME: Even in non-headless mode, we can't show the gui because we're running in a non-main thread. # That's not a huge deal, because there's still a progress bar for the overall export. show_gui=False) req.wait() self.dataExportTrackingApplet.progressSignal.emit(100) def _inputReady(self, nRoles): slot = self.dataSelectionApplet.topLevelOperator.ImageGroup if len(slot) > 0: input_ready = True for sub in slot: input_ready = input_ready and \ all([sub[i].ready() for i in range(nRoles)]) else: input_ready = False return input_ready def handleAppletStateUpdateRequested(self): """ Overridden from Workflow base class Called when an applet has fired the :py:attr:`Applet.statusUpdateSignal` """ # If no data, nothing else is ready. input_ready = self._inputReady(2) and not self.dataSelectionApplet.busy if not self.fromBinary: opThresholding = self.thresholdTwoLevelsApplet.topLevelOperator thresholdingOutput = opThresholding.CachedOutput thresholding_ready = input_ready and len(thresholdingOutput) > 0 else: thresholding_ready = input_ready opTrackingFeatureExtraction = self.trackingFeatureExtractionApplet.topLevelOperator trackingFeatureExtractionOutput = opTrackingFeatureExtraction.ComputedFeatureNamesAll tracking_features_ready = thresholding_ready and len(trackingFeatureExtractionOutput) > 0 opCropSelection = self.cropSelectionApplet.topLevelOperator croppingOutput = opCropSelection.Crops cropping_ready = thresholding_ready and len(croppingOutput) > 0 objectCountClassifier_ready = tracking_features_ready opObjectExtraction = self.objectExtractionApplet.topLevelOperator objectExtractionOutput = opObjectExtraction.RegionFeatures features_ready = thresholding_ready and \ len(objectExtractionOutput) > 0 opAnnotations = self.annotationsApplet.topLevelOperator annotations_ready = features_ready and \ len(opAnnotations.Labels) > 0 and \ opAnnotations.Labels.ready() and \ opAnnotations.TrackImage.ready() opStructuredTracking = self.trackingApplet.topLevelOperator structured_tracking_ready = objectCountClassifier_ready and \ len(opStructuredTracking.EventsVector) > 0 busy = False busy |= self.dataSelectionApplet.busy busy |= self.annotationsApplet.busy # busy |= self.dataExportAnnotationsApplet.busy busy |= self.trackingApplet.busy busy |= self.dataExportTrackingApplet.busy self._shell.enableProjectChanges( not busy ) self._shell.setAppletEnabled(self.dataSelectionApplet, not busy) if not self.fromBinary: self._shell.setAppletEnabled(self.thresholdTwoLevelsApplet, input_ready and not busy) self._shell.setAppletEnabled(self.trackingFeatureExtractionApplet, thresholding_ready and not busy) self._shell.setAppletEnabled(self.cellClassificationApplet, tracking_features_ready and not busy) self._shell.setAppletEnabled(self.divisionDetectionApplet, tracking_features_ready and not busy) self._shell.setAppletEnabled(self.cropSelectionApplet, thresholding_ready and not busy) self._shell.setAppletEnabled(self.objectExtractionApplet, not busy) self._shell.setAppletEnabled(self.annotationsApplet, features_ready and not busy) # self._shell.setAppletEnabled(self.dataExportAnnotationsApplet, annotations_ready and not busy and \ # self.dataExportAnnotationsApplet.topLevelOperator.Inputs[0][0].ready() ) self._shell.setAppletEnabled(self.trackingApplet, objectCountClassifier_ready and not busy) self._shell.setAppletEnabled(self.dataExportTrackingApplet, structured_tracking_ready and not busy and \ self.dataExportTrackingApplet.topLevelOperator.Inputs[0][0].ready() )
def __init__( self, shell, headless, workflow_cmdline_args, project_creation_args, *args, **kwargs ): graph = kwargs['graph'] if 'graph' in kwargs else Graph() if 'graph' in kwargs: del kwargs['graph'] super(StructuredTrackingWorkflowBase, self).__init__(shell, headless, workflow_cmdline_args, project_creation_args, graph=graph, *args, **kwargs) data_instructions = 'Use the "Raw Data" tab to load your intensity image(s).\n\n' if self.fromBinary: data_instructions += 'Use the "Binary Image" tab to load your segmentation image(s).' else: data_instructions += 'Use the "Prediction Maps" tab to load your pixel-wise probability image(s).' # Create applets self.dataSelectionApplet = DataSelectionApplet(self, "Input Data", "Input Data", batchDataGui=False, forceAxisOrder='txyzc', instructionText=data_instructions, max_lanes=1) opDataSelection = self.dataSelectionApplet.topLevelOperator if self.fromBinary: opDataSelection.DatasetRoles.setValue( ['Raw Data', 'Binary Image'] ) else: opDataSelection.DatasetRoles.setValue( ['Raw Data', 'Prediction Maps'] ) if not self.fromBinary: self.thresholdTwoLevelsApplet = ThresholdTwoLevelsApplet( self,"Threshold and Size Filter","ThresholdTwoLevels" ) self.divisionDetectionApplet = ObjectClassificationApplet(workflow=self, name="Division Detection (optional)", projectFileGroupName="DivisionDetection", selectedFeatures=configStructured.selectedFeaturesDiv) self.cellClassificationApplet = ObjectClassificationApplet(workflow=self, name="Object Count Classification", projectFileGroupName="CountClassification", selectedFeatures=configStructured.selectedFeaturesObjectCount) self.cropSelectionApplet = CropSelectionApplet(self,"Crop Selection","CropSelection") self.trackingFeatureExtractionApplet = TrackingFeatureExtractionApplet(name="Object Feature Computation",workflow=self, interactive=False) self.objectExtractionApplet = ObjectExtractionApplet(name="Object Feature Computation",workflow=self, interactive=False) self.annotationsApplet = AnnotationsApplet( name="Training", workflow=self ) opAnnotations = self.annotationsApplet.topLevelOperator # self.default_training_export_filename = '{dataset_dir}/{nickname}-training_exported_data.csv' # self.dataExportAnnotationsApplet = TrackingBaseDataExportApplet(self, "Training Export",default_export_filename=self.default_training_export_filename) # opDataExportAnnotations = self.dataExportAnnotationsApplet.topLevelOperator # opDataExportAnnotations.SelectionNames.setValue( ['User Training for Tracking', 'Object Identities'] ) # opDataExportAnnotations.WorkingDirectory.connect( opDataSelection.WorkingDirectory ) # self.dataExportAnnotationsApplet.set_exporting_operator(opAnnotations) self.trackingApplet = StructuredTrackingApplet( name="Tracking - Structured Learning", workflow=self ) opStructuredTracking = self.trackingApplet.topLevelOperator self.default_tracking_export_filename = '{dataset_dir}/{nickname}-tracking_exported_data.csv' self.dataExportTrackingApplet = TrackingBaseDataExportApplet(self, "Tracking Result Export",default_export_filename=self.default_tracking_export_filename) opDataExportTracking = self.dataExportTrackingApplet.topLevelOperator opDataExportTracking.SelectionNames.setValue( ['Tracking Result', 'Merger Result', 'Object Identities'] ) opDataExportTracking.WorkingDirectory.connect( opDataSelection.WorkingDirectory ) self.dataExportTrackingApplet.set_exporting_operator(opStructuredTracking) self.dataExportTrackingApplet.post_process_lane_export = self.post_process_lane_export self._applets = [] self._applets.append(self.dataSelectionApplet) if not self.fromBinary: self._applets.append(self.thresholdTwoLevelsApplet) self._applets.append(self.trackingFeatureExtractionApplet) self._applets.append(self.divisionDetectionApplet) self._applets.append(self.cellClassificationApplet) self._applets.append(self.cropSelectionApplet) self._applets.append(self.objectExtractionApplet) self._applets.append(self.annotationsApplet) # self._applets.append(self.dataExportAnnotationsApplet) self._applets.append(self.trackingApplet) self._applets.append(self.dataExportTrackingApplet) if self.divisionDetectionApplet: opDivDetection = self.divisionDetectionApplet.topLevelOperator opDivDetection.SelectedFeatures.setValue(configConservation.selectedFeaturesDiv) opDivDetection.LabelNames.setValue(['Not Dividing', 'Dividing']) opDivDetection.AllowDeleteLabels.setValue(False) opDivDetection.AllowAddLabel.setValue(False) opDivDetection.EnableLabelTransfer.setValue(False) opCellClassification = self.cellClassificationApplet.topLevelOperator opCellClassification.SelectedFeatures.setValue(configConservation.selectedFeaturesObjectCount ) opCellClassification.SuggestedLabelNames.setValue( ['False Detection',] + [str(1) + ' Object'] + [str(i) + ' Objects' for i in range(2,10) ] ) opCellClassification.AllowDeleteLastLabelOnly.setValue(True) opCellClassification.EnableLabelTransfer.setValue(False)
def __init__( self, shell, headless, workflow_cmdline_args, project_creation_args, *args, **kwargs ): graph = kwargs['graph'] if 'graph' in kwargs else Graph() if 'graph' in kwargs: del kwargs['graph'] super(StructuredTrackingWorkflowBase, self).__init__(shell, headless, workflow_cmdline_args, project_creation_args, graph=graph, *args, **kwargs) data_instructions = 'Use the "Raw Data" tab to load your intensity image(s).\n\n' if self.fromBinary: data_instructions += 'Use the "Binary Image" tab to load your segmentation image(s).' else: data_instructions += 'Use the "Prediction Maps" tab to load your pixel-wise probability image(s).' # Create applets self.dataSelectionApplet = DataSelectionApplet(self, "Input Data", "Input Data", batchDataGui=False, forceAxisOrder=['txyzc'], instructionText=data_instructions, max_lanes=1) opDataSelection = self.dataSelectionApplet.topLevelOperator if self.fromBinary: opDataSelection.DatasetRoles.setValue( ['Raw Data', 'Binary Image'] ) else: opDataSelection.DatasetRoles.setValue( ['Raw Data', 'Prediction Maps'] ) if not self.fromBinary: self.thresholdTwoLevelsApplet = ThresholdTwoLevelsApplet( self,"Threshold and Size Filter","ThresholdTwoLevels" ) self.divisionDetectionApplet = ObjectClassificationApplet(workflow=self, name="Division Detection (optional)", projectFileGroupName="DivisionDetection", selectedFeatures=configConservation.selectedFeaturesDiv) self.cellClassificationApplet = ObjectClassificationApplet(workflow=self, name="Object Count Classification", projectFileGroupName="CountClassification", selectedFeatures=configConservation.selectedFeaturesObjectCount) self.trackingFeatureExtractionApplet = TrackingFeatureExtractionApplet(name="Object Feature Computation",workflow=self, interactive=False) self.objectExtractionApplet = ObjectExtractionApplet(name="Object Feature Computation",workflow=self, interactive=False) self.annotationsApplet = AnnotationsApplet( name="Training", workflow=self ) opAnnotations = self.annotationsApplet.topLevelOperator self.trackingApplet = StructuredTrackingApplet( name="Tracking - Structured Learning", workflow=self ) opStructuredTracking = self.trackingApplet.topLevelOperator if SOLVER=="CPLEX" or SOLVER=="GUROBI": self._solver="ILP" elif SOLVER=="DPCT": self._solver="Flow-based" else: self._solver=None opStructuredTracking._solver = self._solver self.default_tracking_export_filename = '{dataset_dir}/{nickname}-tracking_exported_data.csv' self.dataExportTrackingApplet = TrackingBaseDataExportApplet( self, "Tracking Result Export", default_export_filename=self.default_tracking_export_filename, pluginExportFunc=self._pluginExportFunc ) opDataExportTracking = self.dataExportTrackingApplet.topLevelOperator opDataExportTracking.SelectionNames.setValue( ['Tracking-Result', 'Merger-Result', 'Object-Identities'] ) opDataExportTracking.WorkingDirectory.connect( opDataSelection.WorkingDirectory ) self.dataExportTrackingApplet.set_exporting_operator(opStructuredTracking) self.dataExportTrackingApplet.prepare_lane_for_export = self.prepare_lane_for_export # configure export settings settings = {'file path': self.default_tracking_export_filename, 'compression': {}, 'file type': 'h5'} selected_features = ['Count', 'RegionCenter', 'RegionRadii', 'RegionAxes'] opStructuredTracking.ExportSettings.setValue( (settings, selected_features) ) self._applets = [] self._applets.append(self.dataSelectionApplet) if not self.fromBinary: self._applets.append(self.thresholdTwoLevelsApplet) self._applets.append(self.trackingFeatureExtractionApplet) self._applets.append(self.divisionDetectionApplet) self.batchProcessingApplet = BatchProcessingApplet(self, "Batch Processing", self.dataSelectionApplet, self.dataExportTrackingApplet) self._applets.append(self.cellClassificationApplet) self._applets.append(self.objectExtractionApplet) self._applets.append(self.annotationsApplet) self._applets.append(self.trackingApplet) self._applets.append(self.dataExportTrackingApplet) if self.divisionDetectionApplet: opDivDetection = self.divisionDetectionApplet.topLevelOperator opDivDetection.SelectedFeatures.setValue(configConservation.selectedFeaturesDiv) opDivDetection.LabelNames.setValue(['Not Dividing', 'Dividing']) opDivDetection.AllowDeleteLabels.setValue(False) opDivDetection.AllowAddLabel.setValue(False) opDivDetection.EnableLabelTransfer.setValue(False) opCellClassification = self.cellClassificationApplet.topLevelOperator opCellClassification.SelectedFeatures.setValue(configConservation.selectedFeaturesObjectCount ) opCellClassification.SuggestedLabelNames.setValue( ['False Detection',] + [str(1) + ' Object'] + [str(i) + ' Objects' for i in range(2,10) ] ) opCellClassification.AllowDeleteLastLabelOnly.setValue(True) opCellClassification.EnableLabelTransfer.setValue(False) if workflow_cmdline_args: if '--testFullAnnotations' in workflow_cmdline_args: self.testFullAnnotations = True else: self.testFullAnnotations = False self._data_export_args, unused_args = self.dataExportTrackingApplet.parse_known_cmdline_args( workflow_cmdline_args ) self._batch_input_args, unused_args = self.batchProcessingApplet.parse_known_cmdline_args( workflow_cmdline_args ) else: unused_args = None self._data_export_args = None self._batch_input_args = None self.testFullAnnotations = False if unused_args: logger.warning("Unused command-line args: {}".format( unused_args ))
class ConservationTrackingWorkflowBase(Workflow): workflowName = "Automatic Tracking Workflow (Conservation Tracking) BASE" def __init__(self, shell, headless, workflow_cmdline_args, *args, **kwargs): graph = kwargs['graph'] if 'graph' in kwargs else Graph() if 'graph' in kwargs: del kwargs['graph'] # if 'withOptTrans' in kwargs: # self.withOptTrans = kwargs['withOptTrans'] # if 'fromBinary' in kwargs: # self.fromBinary = kwargs['fromBinary'] super(ConservationTrackingWorkflowBase, self).__init__(shell, headless, graph=graph, *args, **kwargs) data_instructions = 'Use the "Raw Data" tab to load your intensity image(s).\n\n' if self.fromBinary: data_instructions += 'Use the "Binary Image" tab to load your segmentation image(s).' else: data_instructions += 'Use the "Prediction Maps" tab to load your pixel-wise probability image(s).' ## Create applets self.dataSelectionApplet = DataSelectionApplet( self, "Input Data", "Input Data", batchDataGui=False, force5d=True, instructionText=data_instructions, max_lanes=1) opDataSelection = self.dataSelectionApplet.topLevelOperator if self.fromBinary: opDataSelection.DatasetRoles.setValue(['Raw Data', 'Binary Image']) else: opDataSelection.DatasetRoles.setValue( ['Raw Data', 'Prediction Maps']) if not self.fromBinary: self.thresholdTwoLevelsApplet = ThresholdTwoLevelsApplet( self, "Threshold and Size Filter", "ThresholdTwoLevels") if self.withOptTrans: self.opticalTranslationApplet = OpticalTranslationApplet( workflow=self) self.objectExtractionApplet = TrackingFeatureExtractionApplet( workflow=self, interactive=False, name="Object Feature Computation") self.divisionDetectionApplet = ObjectClassificationApplet( workflow=self, name="Division Detection (optional)", projectFileGroupName="DivisionDetection") self.cellClassificationApplet = ObjectClassificationApplet( workflow=self, name="Object Count Classification (optional)", projectFileGroupName="CountClassification") self.trackingApplet = ConservationTrackingApplet(workflow=self) opTracking = self.trackingApplet.topLevelOperator self.dataExportApplet = TrackingBaseDataExportApplet( self, "Tracking Result Export") self.dataExportApplet.set_exporting_operator(opTracking) opDataExport = self.dataExportApplet.topLevelOperator opDataExport.SelectionNames.setValue( ['Tracking Result', 'Merger Result', 'Object Identities']) opDataExport.WorkingDirectory.connect(opDataSelection.WorkingDirectory) self._applets = [] self._applets.append(self.dataSelectionApplet) if not self.fromBinary: self._applets.append(self.thresholdTwoLevelsApplet) if self.withOptTrans: self._applets.append(self.opticalTranslationApplet) self._applets.append(self.objectExtractionApplet) self._applets.append(self.divisionDetectionApplet) self._applets.append(self.cellClassificationApplet) self._applets.append(self.trackingApplet) self._applets.append(self.dataExportApplet) @property def applets(self): return self._applets @property def imageNameListSlot(self): return self.dataSelectionApplet.topLevelOperator.ImageName def connectLane(self, laneIndex): opData = self.dataSelectionApplet.topLevelOperator.getLane(laneIndex) if not self.fromBinary: opTwoLevelThreshold = self.thresholdTwoLevelsApplet.topLevelOperator.getLane( laneIndex) if self.withOptTrans: opOptTranslation = self.opticalTranslationApplet.topLevelOperator.getLane( laneIndex) opObjExtraction = self.objectExtractionApplet.topLevelOperator.getLane( laneIndex) opDivDetection = self.divisionDetectionApplet.topLevelOperator.getLane( laneIndex) opCellClassification = self.cellClassificationApplet.topLevelOperator.getLane( laneIndex) opTracking = self.trackingApplet.topLevelOperator.getLane(laneIndex) opDataExport = self.dataExportApplet.topLevelOperator.getLane( laneIndex) op5Raw = OpReorderAxes(parent=self) op5Raw.AxisOrder.setValue("txyzc") op5Raw.Input.connect(opData.ImageGroup[0]) if not self.fromBinary: opTwoLevelThreshold.InputImage.connect(opData.ImageGroup[1]) opTwoLevelThreshold.RawInput.connect( opData.ImageGroup[0]) # Used for display only # opTwoLevelThreshold.Channel.setValue(1) binarySrc = opTwoLevelThreshold.CachedOutput else: binarySrc = opData.ImageGroup[1] # Use Op5ifyers for both input datasets such that they are guaranteed to # have the same axis order after thresholding op5Binary = OpReorderAxes(parent=self) op5Binary.AxisOrder.setValue("txyzc") op5Binary.Input.connect(binarySrc) if self.withOptTrans: opOptTranslation.RawImage.connect(op5Raw.Output) opOptTranslation.BinaryImage.connect(op5Binary.Output) # # Connect operators ## vigra_features = list((set(config.vigra_features)).union( config.selected_features_objectcount[config.features_vigra_name])) feature_names_vigra = {} feature_names_vigra[config.features_vigra_name] = { name: {} for name in vigra_features } opObjExtraction.RawImage.connect(op5Raw.Output) opObjExtraction.BinaryImage.connect(op5Binary.Output) if self.withOptTrans: opObjExtraction.TranslationVectors.connect( opOptTranslation.TranslationVectors) opObjExtraction.FeatureNamesVigra.setValue(feature_names_vigra) feature_dict_division = {} feature_dict_division[config.features_division_name] = { name: {} for name in config.division_features } opObjExtraction.FeatureNamesDivision.setValue(feature_dict_division) selected_features_div = {} for plugin_name in config.selected_features_division.keys(): selected_features_div[plugin_name] = { name: {} for name in config.selected_features_division[plugin_name] } # FIXME: do not hard code this for name in [ 'SquaredDistances_' + str(i) for i in range(config.n_best_successors) ]: selected_features_div[config.features_division_name][name] = {} opDivDetection.BinaryImages.connect(op5Binary.Output) opDivDetection.RawImages.connect(op5Raw.Output) opDivDetection.LabelsAllowedFlags.connect(opData.AllowLabels) opDivDetection.SegmentationImages.connect(opObjExtraction.LabelImage) opDivDetection.ObjectFeatures.connect( opObjExtraction.RegionFeaturesAll) opDivDetection.ComputedFeatureNames.connect( opObjExtraction.ComputedFeatureNamesAll) opDivDetection.SelectedFeatures.setValue(selected_features_div) opDivDetection.LabelNames.setValue(['Not Dividing', 'Dividing']) opDivDetection.AllowDeleteLabels.setValue(False) opDivDetection.AllowAddLabel.setValue(False) opDivDetection.EnableLabelTransfer.setValue(False) selected_features_objectcount = {} for plugin_name in config.selected_features_objectcount.keys(): selected_features_objectcount[plugin_name] = { name: {} for name in config.selected_features_objectcount[plugin_name] } opCellClassification.BinaryImages.connect(op5Binary.Output) opCellClassification.RawImages.connect(op5Raw.Output) opCellClassification.LabelsAllowedFlags.connect(opData.AllowLabels) opCellClassification.SegmentationImages.connect( opObjExtraction.LabelImage) opCellClassification.ObjectFeatures.connect( opObjExtraction.RegionFeaturesVigra) opCellClassification.ComputedFeatureNames.connect( opObjExtraction.ComputedFeatureNamesVigra) opCellClassification.SelectedFeatures.setValue( selected_features_objectcount) opCellClassification.SuggestedLabelNames.setValue([ 'false detection', ] + [str(i) + ' Objects' for i in range(1, 10)]) opCellClassification.AllowDeleteLastLabelOnly.setValue(True) opCellClassification.EnableLabelTransfer.setValue(False) opTracking.RawImage.connect(op5Raw.Output) opTracking.LabelImage.connect(opObjExtraction.LabelImage) opTracking.ObjectFeatures.connect(opObjExtraction.RegionFeaturesVigra) opTracking.ObjectFeaturesWithDivFeatures.connect( opObjExtraction.RegionFeaturesAll) opTracking.ComputedFeatureNames.connect( opObjExtraction.ComputedFeatureNamesVigra) opTracking.ComputedFeatureNamesWithDivFeatures.connect( opObjExtraction.ComputedFeatureNamesAll) opTracking.DivisionProbabilities.connect(opDivDetection.Probabilities) opTracking.DetectionProbabilities.connect( opCellClassification.Probabilities) opTracking.NumLabels.connect(opCellClassification.NumLabels) opDataExport.Inputs.resize(3) opDataExport.Inputs[0].connect(opTracking.Output) opDataExport.Inputs[1].connect(opTracking.MergerOutput) opDataExport.Inputs[2].connect(opTracking.LabelImage) opDataExport.RawData.connect(op5Raw.Output) opDataExport.RawDatasetInfo.connect(opData.DatasetGroup[0]) def _inputReady(self, nRoles): slot = self.dataSelectionApplet.topLevelOperator.ImageGroup if len(slot) > 0: input_ready = True for sub in slot: input_ready = input_ready and \ all([sub[i].ready() for i in range(nRoles)]) else: input_ready = False return input_ready def handleAppletStateUpdateRequested(self): """ Overridden from Workflow base class Called when an applet has fired the :py:attr:`Applet.statusUpdateSignal` """ # If no data, nothing else is ready. opDataSelection = self.dataSelectionApplet.topLevelOperator input_ready = self._inputReady(2) and not self.dataSelectionApplet.busy if not self.fromBinary: opThresholding = self.thresholdTwoLevelsApplet.topLevelOperator thresholdingOutput = opThresholding.CachedOutput thresholding_ready = input_ready and \ len(thresholdingOutput) > 0 else: thresholding_ready = True and input_ready opObjectExtraction = self.objectExtractionApplet.topLevelOperator objectExtractionOutput = opObjectExtraction.ComputedFeatureNamesAll features_ready = thresholding_ready and \ len(objectExtractionOutput) > 0 objectCountClassifier_ready = features_ready opTracking = self.trackingApplet.topLevelOperator tracking_ready = objectCountClassifier_ready and \ len(opTracking.EventsVector) > 0 busy = False busy |= self.dataSelectionApplet.busy busy |= self.trackingApplet.busy busy |= self.dataExportApplet.busy self._shell.enableProjectChanges(not busy) self._shell.setAppletEnabled(self.dataSelectionApplet, not busy) if not self.fromBinary: self._shell.setAppletEnabled(self.thresholdTwoLevelsApplet, input_ready and not busy) self._shell.setAppletEnabled(self.objectExtractionApplet, thresholding_ready and not busy) self._shell.setAppletEnabled(self.cellClassificationApplet, features_ready and not busy) self._shell.setAppletEnabled(self.divisionDetectionApplet, features_ready and not busy) self._shell.setAppletEnabled(self.trackingApplet, objectCountClassifier_ready and not busy) self._shell.setAppletEnabled(self.dataExportApplet, tracking_ready and not busy and \ self.dataExportApplet.topLevelOperator.Inputs[0][0].ready() )
class ManualTrackingWorkflow(Workflow): workflowName = "Manual Tracking Workflow" workflowDisplayName = "Manual Tracking Workflow [Inputs: Raw Data, Pixel Prediction Map]" workflowDescription = "Manual tracking of objects, based on Prediction Maps or (binary) Segmentation Images" @property def applets(self): return self._applets @property def imageNameListSlot(self): return self.dataSelectionApplet.topLevelOperator.ImageName def __init__(self, shell, headless, workflow_cmdline_args, project_creation_args, *args, **kwargs): graph = kwargs['graph'] if 'graph' in kwargs else Graph() if 'graph' in kwargs: del kwargs['graph'] super(ManualTrackingWorkflow, self).__init__(shell, headless, workflow_cmdline_args, project_creation_args, graph=graph, *args, **kwargs) data_instructions = 'Use the "Raw Data" tab to load your intensity image(s).\n\n'\ 'Use the "Prediction Maps" tab to load your pixel-wise probability image(s).' ## Create applets self.dataSelectionApplet = DataSelectionApplet( self, "Input Data", "Input Data", batchDataGui=False, force5d=True, instructionText=data_instructions, max_lanes=1) opDataSelection = self.dataSelectionApplet.topLevelOperator opDataSelection.DatasetRoles.setValue(['Raw Data', 'Prediction Maps']) self.thresholdTwoLevelsApplet = ThresholdTwoLevelsApplet( self, "Threshold and Size Filter", "ThresholdTwoLevels") self.objectExtractionApplet = ObjectExtractionApplet( name="Object Feature Computation", workflow=self, interactive=False) self.trackingApplet = ManualTrackingApplet(workflow=self) opTracking = self.trackingApplet.topLevelOperator self.dataExportApplet = TrackingBaseDataExportApplet( self, "Tracking Result Export") self.dataExportApplet.set_exporting_operator(opTracking) opDataExport = self.dataExportApplet.topLevelOperator opDataExport.SelectionNames.setValue( ['Manual Tracking', 'Object Identities']) opDataExport.WorkingDirectory.connect(opDataSelection.WorkingDirectory) self._applets = [] self._applets.append(self.dataSelectionApplet) self._applets.append(self.thresholdTwoLevelsApplet) self._applets.append(self.objectExtractionApplet) self._applets.append(self.trackingApplet) self._applets.append(self.dataExportApplet) def connectLane(self, laneIndex): opData = self.dataSelectionApplet.topLevelOperator.getLane(laneIndex) opObjExtraction = self.objectExtractionApplet.topLevelOperator.getLane( laneIndex) opTracking = self.trackingApplet.topLevelOperator.getLane(laneIndex) opTwoLevelThreshold = self.thresholdTwoLevelsApplet.topLevelOperator.getLane( laneIndex) opDataExport = self.dataExportApplet.topLevelOperator.getLane( laneIndex) ## Connect operators ## op5Raw = OpReorderAxes(parent=self) op5Raw.AxisOrder.setValue("txyzc") op5Raw.Input.connect(opData.ImageGroup[0]) opTwoLevelThreshold.InputImage.connect(opData.ImageGroup[1]) opTwoLevelThreshold.RawInput.connect( opData.ImageGroup[0]) # Used for display only # Use OpReorderAxis for both input datasets such that they are guaranteed to # have the same axis order after thresholding op5Binary = OpReorderAxes(parent=self) op5Binary.AxisOrder.setValue("txyzc") op5Binary.Input.connect(opTwoLevelThreshold.CachedOutput) opObjExtraction.RawImage.connect(op5Raw.Output) opObjExtraction.BinaryImage.connect(op5Binary.Output) opTracking.RawImage.connect(op5Raw.Output) opTracking.BinaryImage.connect(op5Binary.Output) opTracking.LabelImage.connect(opObjExtraction.LabelImage) opTracking.ObjectFeatures.connect(opObjExtraction.RegionFeatures) opTracking.ComputedFeatureNames.connect( opObjExtraction.ComputedFeatureNames) opDataExport.Inputs.resize(2) opDataExport.Inputs[0].connect(opTracking.TrackImage) opDataExport.Inputs[1].connect(opTracking.LabelImage) opDataExport.RawData.connect(op5Raw.Output) opDataExport.RawDatasetInfo.connect(opData.DatasetGroup[0]) def _inputReady(self, nRoles): slot = self.dataSelectionApplet.topLevelOperator.ImageGroup if len(slot) > 0: input_ready = True for sub in slot: input_ready = input_ready and \ all([sub[i].ready() for i in range(nRoles)]) else: input_ready = False return input_ready def handleAppletStateUpdateRequested(self): """ Overridden from Workflow base class Called when an applet has fired the :py:attr:`Applet.statusUpdateSignal` """ # If no data, nothing else is ready. input_ready = self._inputReady(2) and not self.dataSelectionApplet.busy opThresholding = self.thresholdTwoLevelsApplet.topLevelOperator thresholdingOutput = opThresholding.CachedOutput thresholding_ready = input_ready and \ len(thresholdingOutput) > 0 opObjectExtraction = self.objectExtractionApplet.topLevelOperator objectExtractionOutput = opObjectExtraction.ComputedFeatureNames features_ready = thresholding_ready and \ len(objectExtractionOutput) > 0 opTracking = self.trackingApplet.topLevelOperator tracking_ready = features_ready and \ len(opTracking.Labels) > 0 and \ opTracking.Labels.ready() and \ opTracking.TrackImage.ready() busy = False busy |= self.dataSelectionApplet.busy busy |= self.dataExportApplet.busy busy |= self.trackingApplet.busy self._shell.enableProjectChanges(not busy) self._shell.setAppletEnabled(self.dataSelectionApplet, not busy) self._shell.setAppletEnabled(self.thresholdTwoLevelsApplet, input_ready and not busy) self._shell.setAppletEnabled(self.objectExtractionApplet, thresholding_ready and not busy) self._shell.setAppletEnabled(self.trackingApplet, features_ready and not busy) self._shell.setAppletEnabled(self.dataExportApplet, tracking_ready and not busy and \ self.dataExportApplet.topLevelOperator.Inputs[0][0].ready() )
def __init__(self, shell, headless, workflow_cmdline_args, *args, **kwargs): graph = kwargs['graph'] if 'graph' in kwargs else Graph() if 'graph' in kwargs: del kwargs['graph'] # if 'withOptTrans' in kwargs: # self.withOptTrans = kwargs['withOptTrans'] # if 'fromBinary' in kwargs: # self.fromBinary = kwargs['fromBinary'] super(ConservationTrackingWorkflowBase, self).__init__(shell, headless, graph=graph, *args, **kwargs) data_instructions = 'Use the "Raw Data" tab to load your intensity image(s).\n\n' if self.fromBinary: data_instructions += 'Use the "Binary Image" tab to load your segmentation image(s).' else: data_instructions += 'Use the "Prediction Maps" tab to load your pixel-wise probability image(s).' ## Create applets self.dataSelectionApplet = DataSelectionApplet( self, "Input Data", "Input Data", batchDataGui=False, force5d=True, instructionText=data_instructions, max_lanes=1) opDataSelection = self.dataSelectionApplet.topLevelOperator if self.fromBinary: opDataSelection.DatasetRoles.setValue(['Raw Data', 'Binary Image']) else: opDataSelection.DatasetRoles.setValue( ['Raw Data', 'Prediction Maps']) if not self.fromBinary: self.thresholdTwoLevelsApplet = ThresholdTwoLevelsApplet( self, "Threshold and Size Filter", "ThresholdTwoLevels") if self.withOptTrans: self.opticalTranslationApplet = OpticalTranslationApplet( workflow=self) self.objectExtractionApplet = TrackingFeatureExtractionApplet( workflow=self, interactive=False, name="Object Feature Computation") self.divisionDetectionApplet = ObjectClassificationApplet( workflow=self, name="Division Detection (optional)", projectFileGroupName="DivisionDetection") self.cellClassificationApplet = ObjectClassificationApplet( workflow=self, name="Object Count Classification (optional)", projectFileGroupName="CountClassification") self.trackingApplet = ConservationTrackingApplet(workflow=self) opTracking = self.trackingApplet.topLevelOperator self.dataExportApplet = TrackingBaseDataExportApplet( self, "Tracking Result Export") self.dataExportApplet.set_exporting_operator(opTracking) opDataExport = self.dataExportApplet.topLevelOperator opDataExport.SelectionNames.setValue( ['Tracking Result', 'Merger Result', 'Object Identities']) opDataExport.WorkingDirectory.connect(opDataSelection.WorkingDirectory) self._applets = [] self._applets.append(self.dataSelectionApplet) if not self.fromBinary: self._applets.append(self.thresholdTwoLevelsApplet) if self.withOptTrans: self._applets.append(self.opticalTranslationApplet) self._applets.append(self.objectExtractionApplet) self._applets.append(self.divisionDetectionApplet) self._applets.append(self.cellClassificationApplet) self._applets.append(self.trackingApplet) self._applets.append(self.dataExportApplet)
class StructuredTrackingWorkflowBase( Workflow ): workflowName = "Structured Learning Tracking Workflow BASE" @property def applets(self): return self._applets @property def imageNameListSlot(self): return self.dataSelectionApplet.topLevelOperator.ImageName def __init__( self, shell, headless, workflow_cmdline_args, project_creation_args, *args, **kwargs ): graph = kwargs['graph'] if 'graph' in kwargs else Graph() if 'graph' in kwargs: del kwargs['graph'] super(StructuredTrackingWorkflowBase, self).__init__(shell, headless, workflow_cmdline_args, project_creation_args, graph=graph, *args, **kwargs) data_instructions = 'Use the "Raw Data" tab to load your intensity image(s).\n\n' if self.fromBinary: data_instructions += 'Use the "Binary Image" tab to load your segmentation image(s).' else: data_instructions += 'Use the "Prediction Maps" tab to load your pixel-wise probability image(s).' # Create applets self.dataSelectionApplet = DataSelectionApplet(self, "Input Data", "Input Data", batchDataGui=False, forceAxisOrder=['txyzc'], instructionText=data_instructions, max_lanes=1) opDataSelection = self.dataSelectionApplet.topLevelOperator if self.fromBinary: opDataSelection.DatasetRoles.setValue( ['Raw Data', 'Binary Image'] ) else: opDataSelection.DatasetRoles.setValue( ['Raw Data', 'Prediction Maps'] ) if not self.fromBinary: self.thresholdTwoLevelsApplet = ThresholdTwoLevelsApplet( self,"Threshold and Size Filter","ThresholdTwoLevels" ) self.divisionDetectionApplet = ObjectClassificationApplet(workflow=self, name="Division Detection (optional)", projectFileGroupName="DivisionDetection", selectedFeatures=configStructured.selectedFeaturesDiv) self.cellClassificationApplet = ObjectClassificationApplet(workflow=self, name="Object Count Classification", projectFileGroupName="CountClassification", selectedFeatures=configStructured.selectedFeaturesObjectCount) self.cropSelectionApplet = CropSelectionApplet(self,"Crop Selection","CropSelection") self.trackingFeatureExtractionApplet = TrackingFeatureExtractionApplet(name="Object Feature Computation",workflow=self, interactive=False) self.objectExtractionApplet = ObjectExtractionApplet(name="Object Feature Computation",workflow=self, interactive=False) self.annotationsApplet = AnnotationsApplet( name="Training", workflow=self ) opAnnotations = self.annotationsApplet.topLevelOperator # self.default_training_export_filename = '{dataset_dir}/{nickname}-training_exported_data.csv' # self.dataExportAnnotationsApplet = TrackingBaseDataExportApplet(self, "Training Export",default_export_filename=self.default_training_export_filename) # opDataExportAnnotations = self.dataExportAnnotationsApplet.topLevelOperator # opDataExportAnnotations.SelectionNames.setValue( ['User Training for Tracking', 'Object Identities'] ) # opDataExportAnnotations.WorkingDirectory.connect( opDataSelection.WorkingDirectory ) # self.dataExportAnnotationsApplet.set_exporting_operator(opAnnotations) self.trackingApplet = StructuredTrackingApplet( name="Tracking - Structured Learning", workflow=self ) opStructuredTracking = self.trackingApplet.topLevelOperator self.default_tracking_export_filename = '{dataset_dir}/{nickname}-tracking_exported_data.csv' self.dataExportTrackingApplet = TrackingBaseDataExportApplet(self, "Tracking Result Export",default_export_filename=self.default_tracking_export_filename) opDataExportTracking = self.dataExportTrackingApplet.topLevelOperator opDataExportTracking.SelectionNames.setValue( ['Tracking Result', 'Merger Result', 'Object Identities'] ) opDataExportTracking.WorkingDirectory.connect( opDataSelection.WorkingDirectory ) self.dataExportTrackingApplet.set_exporting_operator(opStructuredTracking) self.dataExportTrackingApplet.post_process_lane_export = self.post_process_lane_export self._applets = [] self._applets.append(self.dataSelectionApplet) if not self.fromBinary: self._applets.append(self.thresholdTwoLevelsApplet) self._applets.append(self.trackingFeatureExtractionApplet) self._applets.append(self.divisionDetectionApplet) self._applets.append(self.cellClassificationApplet) self._applets.append(self.cropSelectionApplet) self._applets.append(self.objectExtractionApplet) self._applets.append(self.annotationsApplet) # self._applets.append(self.dataExportAnnotationsApplet) self._applets.append(self.trackingApplet) self._applets.append(self.dataExportTrackingApplet) if self.divisionDetectionApplet: opDivDetection = self.divisionDetectionApplet.topLevelOperator opDivDetection.SelectedFeatures.setValue(configConservation.selectedFeaturesDiv) opDivDetection.LabelNames.setValue(['Not Dividing', 'Dividing']) opDivDetection.AllowDeleteLabels.setValue(False) opDivDetection.AllowAddLabel.setValue(False) opDivDetection.EnableLabelTransfer.setValue(False) opCellClassification = self.cellClassificationApplet.topLevelOperator opCellClassification.SelectedFeatures.setValue(configConservation.selectedFeaturesObjectCount ) opCellClassification.SuggestedLabelNames.setValue( ['False Detection',] + [str(1) + ' Object'] + [str(i) + ' Objects' for i in range(2,10) ] ) opCellClassification.AllowDeleteLastLabelOnly.setValue(True) opCellClassification.EnableLabelTransfer.setValue(False) def connectLane(self, laneIndex): opData = self.dataSelectionApplet.topLevelOperator.getLane(laneIndex) opObjExtraction = self.objectExtractionApplet.topLevelOperator.getLane(laneIndex) opTrackingFeatureExtraction = self.trackingFeatureExtractionApplet.topLevelOperator.getLane(laneIndex) opAnnotations = self.annotationsApplet.topLevelOperator.getLane(laneIndex) if not self.fromBinary: opTwoLevelThreshold = self.thresholdTwoLevelsApplet.topLevelOperator.getLane(laneIndex) # opDataAnnotationsExport = self.dataExportAnnotationsApplet.topLevelOperator.getLane(laneIndex) opCropSelection = self.cropSelectionApplet.topLevelOperator.getLane(laneIndex) opStructuredTracking = self.trackingApplet.topLevelOperator.getLane(laneIndex) opDataTrackingExport = self.dataExportTrackingApplet.topLevelOperator.getLane(laneIndex) ## Connect operators ## op5Raw = OpReorderAxes(parent=self) op5Raw.AxisOrder.setValue("txyzc") op5Raw.Input.connect(opData.ImageGroup[0]) opDivDetection = self.divisionDetectionApplet.topLevelOperator.getLane(laneIndex) opCellClassification = self.cellClassificationApplet.topLevelOperator.getLane(laneIndex) if not self.fromBinary: opTwoLevelThreshold.InputImage.connect( opData.ImageGroup[1] ) opTwoLevelThreshold.RawInput.connect( opData.ImageGroup[0] ) # Used for display only binarySrc = opTwoLevelThreshold.CachedOutput else: binarySrc = opData.ImageGroup[1] # Use Op5ifyers for both input datasets such that they are guaranteed to # have the same axis order after thresholding op5Binary = OpReorderAxes(parent=self) op5Binary.AxisOrder.setValue("txyzc") op5Binary.Input.connect(binarySrc) opCropSelection.InputImage.connect( opData.ImageGroup[0] ) opCropSelection.PredictionImage.connect( opData.ImageGroup[1] ) opObjExtraction.RawImage.connect( op5Raw.Output ) opObjExtraction.BinaryImage.connect( op5Binary.Output ) opTrackingFeatureExtraction.RawImage.connect( op5Raw.Output ) opTrackingFeatureExtraction.BinaryImage.connect( op5Binary.Output ) # vigra_features = list((set(config.vigra_features)).union(config.selected_features_objectcount[config.features_vigra_name])) # feature_names_vigra = {} # feature_names_vigra[config.features_vigra_name] = { name: {} for name in vigra_features } opTrackingFeatureExtraction.FeatureNamesVigra.setValue(configConservation.allFeaturesObjectCount) feature_dict_division = {} feature_dict_division[config.features_division_name] = { name: {} for name in config.division_features } opTrackingFeatureExtraction.FeatureNamesDivision.setValue(feature_dict_division) if self.divisionDetectionApplet: opDivDetection.BinaryImages.connect( op5Binary.Output ) opDivDetection.RawImages.connect( op5Raw.Output ) opDivDetection.SegmentationImages.connect(opTrackingFeatureExtraction.LabelImage) opDivDetection.ObjectFeatures.connect(opTrackingFeatureExtraction.RegionFeaturesAll) opDivDetection.ComputedFeatureNames.connect(opTrackingFeatureExtraction.ComputedFeatureNamesAll) opCellClassification.BinaryImages.connect( op5Binary.Output ) opCellClassification.RawImages.connect( op5Raw.Output ) opCellClassification.SegmentationImages.connect(opTrackingFeatureExtraction.LabelImage) opCellClassification.ObjectFeatures.connect(opTrackingFeatureExtraction.RegionFeaturesAll) opCellClassification.ComputedFeatureNames.connect(opTrackingFeatureExtraction.ComputedFeatureNamesNoDivisions) opAnnotations.RawImage.connect( op5Raw.Output ) opAnnotations.BinaryImage.connect( op5Binary.Output ) opAnnotations.LabelImage.connect( opObjExtraction.LabelImage ) opAnnotations.ObjectFeatures.connect( opObjExtraction.RegionFeatures ) opAnnotations.ComputedFeatureNames.connect(opObjExtraction.Features) opAnnotations.Crops.connect( opCropSelection.Crops) # opDataAnnotationsExport.Inputs.resize(2) # opDataAnnotationsExport.Inputs[0].connect( opAnnotations.TrackImage ) # opDataAnnotationsExport.Inputs[1].connect( opAnnotations.LabelImage ) # opDataAnnotationsExport.RawData.connect( op5Raw.Output ) # opDataAnnotationsExport.RawDatasetInfo.connect( opData.DatasetGroup[0] ) opStructuredTracking.RawImage.connect( op5Raw.Output ) opStructuredTracking.LabelImage.connect( opTrackingFeatureExtraction.LabelImage ) opStructuredTracking.ObjectFeatures.connect( opTrackingFeatureExtraction.RegionFeaturesVigra ) opStructuredTracking.ComputedFeatureNames.connect( opTrackingFeatureExtraction.FeatureNamesVigra ) if self.divisionDetectionApplet: opStructuredTracking.ObjectFeaturesWithDivFeatures.connect( opTrackingFeatureExtraction.RegionFeaturesAll) opStructuredTracking.ComputedFeatureNamesWithDivFeatures.connect( opTrackingFeatureExtraction.ComputedFeatureNamesAll ) opStructuredTracking.DivisionProbabilities.connect( opDivDetection.Probabilities ) # configure tracking export settings settings = {'file path': self.default_tracking_export_filename, 'compression': {}, 'file type': 'csv'} selected_features = ['Count', 'RegionCenter'] opStructuredTracking.configure_table_export_settings(settings, selected_features) opStructuredTracking.DetectionProbabilities.connect( opCellClassification.Probabilities ) opStructuredTracking.NumLabels.connect( opCellClassification.NumLabels ) opStructuredTracking.Crops.connect (opCropSelection.Crops) opStructuredTracking.Annotations.connect (opAnnotations.Annotations) opStructuredTracking.Labels.connect (opAnnotations.Labels) opStructuredTracking.Divisions.connect (opAnnotations.Divisions) opStructuredTracking.MaxNumObj.connect (opCellClassification.MaxNumObj) opDataTrackingExport.Inputs.resize(3) opDataTrackingExport.Inputs[0].connect( opStructuredTracking.Output ) opDataTrackingExport.Inputs[1].connect( opStructuredTracking.MergerOutput ) opDataTrackingExport.Inputs[2].connect( opStructuredTracking.LabelImage ) opDataTrackingExport.RawData.connect( op5Raw.Output ) opDataTrackingExport.RawDatasetInfo.connect( opData.DatasetGroup[0] ) def post_process_lane_export(self, lane_index): # FIXME: This probably only works for the non-blockwise export slot. # We should assert that the user isn't using the blockwise slot. settings, selected_features = self.trackingApplet.topLevelOperator.getLane(lane_index).get_table_export_settings() from lazyflow.utility import PathComponents, make_absolute, format_known_keys if settings: self.dataExportTrackingApplet.progressSignal.emit(-1) raw_dataset_info = self.dataSelectionApplet.topLevelOperator.DatasetGroup[lane_index][0].value project_path = self.shell.projectManager.currentProjectPath project_dir = os.path.dirname(project_path) dataset_dir = PathComponents(raw_dataset_info.filePath).externalDirectory abs_dataset_dir = make_absolute(dataset_dir, cwd=project_dir) known_keys = {} known_keys['dataset_dir'] = abs_dataset_dir nickname = raw_dataset_info.nickname.replace('*', '') if os.path.pathsep in nickname: nickname = PathComponents(nickname.split(os.path.pathsep)[0]).fileNameBase known_keys['nickname'] = nickname # use partial formatting to fill in non-coordinate name fields name_format = settings['file path'] partially_formatted_name = format_known_keys( name_format, known_keys ) settings['file path'] = partially_formatted_name req = self.trackingApplet.topLevelOperator.getLane(lane_index).export_object_data( lane_index, # FIXME: Even in non-headless mode, we can't show the gui because we're running in a non-main thread. # That's not a huge deal, because there's still a progress bar for the overall export. show_gui=False) req.wait() self.dataExportTrackingApplet.progressSignal.emit(100) def _inputReady(self, nRoles): slot = self.dataSelectionApplet.topLevelOperator.ImageGroup if len(slot) > 0: input_ready = True for sub in slot: input_ready = input_ready and \ all([sub[i].ready() for i in range(nRoles)]) else: input_ready = False return input_ready def handleAppletStateUpdateRequested(self): """ Overridden from Workflow base class Called when an applet has fired the :py:attr:`Applet.statusUpdateSignal` """ # If no data, nothing else is ready. input_ready = self._inputReady(2) and not self.dataSelectionApplet.busy if not self.fromBinary: opThresholding = self.thresholdTwoLevelsApplet.topLevelOperator thresholdingOutput = opThresholding.CachedOutput thresholding_ready = input_ready and len(thresholdingOutput) > 0 else: thresholding_ready = input_ready opTrackingFeatureExtraction = self.trackingFeatureExtractionApplet.topLevelOperator trackingFeatureExtractionOutput = opTrackingFeatureExtraction.ComputedFeatureNamesAll tracking_features_ready = thresholding_ready and len(trackingFeatureExtractionOutput) > 0 opCropSelection = self.cropSelectionApplet.topLevelOperator croppingOutput = opCropSelection.Crops cropping_ready = thresholding_ready and len(croppingOutput) > 0 objectCountClassifier_ready = tracking_features_ready opObjectExtraction = self.objectExtractionApplet.topLevelOperator objectExtractionOutput = opObjectExtraction.RegionFeatures features_ready = thresholding_ready and \ len(objectExtractionOutput) > 0 opAnnotations = self.annotationsApplet.topLevelOperator annotations_ready = features_ready and \ len(opAnnotations.Labels) > 0 and \ opAnnotations.Labels.ready() and \ opAnnotations.TrackImage.ready() opStructuredTracking = self.trackingApplet.topLevelOperator structured_tracking_ready = objectCountClassifier_ready and \ len(opStructuredTracking.EventsVector) > 0 busy = False busy |= self.dataSelectionApplet.busy busy |= self.annotationsApplet.busy # busy |= self.dataExportAnnotationsApplet.busy busy |= self.trackingApplet.busy busy |= self.dataExportTrackingApplet.busy self._shell.enableProjectChanges( not busy ) self._shell.setAppletEnabled(self.dataSelectionApplet, not busy) if not self.fromBinary: self._shell.setAppletEnabled(self.thresholdTwoLevelsApplet, input_ready and not busy) self._shell.setAppletEnabled(self.trackingFeatureExtractionApplet, thresholding_ready and not busy) self._shell.setAppletEnabled(self.cellClassificationApplet, tracking_features_ready and not busy) self._shell.setAppletEnabled(self.divisionDetectionApplet, tracking_features_ready and not busy) self._shell.setAppletEnabled(self.cropSelectionApplet, thresholding_ready and not busy) self._shell.setAppletEnabled(self.objectExtractionApplet, not busy) self._shell.setAppletEnabled(self.annotationsApplet, features_ready and not busy) # self._shell.setAppletEnabled(self.dataExportAnnotationsApplet, annotations_ready and not busy and \ # self.dataExportAnnotationsApplet.topLevelOperator.Inputs[0][0].ready() ) self._shell.setAppletEnabled(self.trackingApplet, objectCountClassifier_ready and not busy) self._shell.setAppletEnabled(self.dataExportTrackingApplet, structured_tracking_ready and not busy and \ self.dataExportTrackingApplet.topLevelOperator.Inputs[0][0].ready() )
class ConservationTrackingWorkflowBase(Workflow): workflowName = "Automatic Tracking Workflow (Conservation Tracking) BASE" def __init__(self, shell, headless, workflow_cmdline_args, project_creation_args, *args, **kwargs): graph = kwargs['graph'] if 'graph' in kwargs else Graph() if 'graph' in kwargs: del kwargs['graph'] # if 'withOptTrans' in kwargs: # self.withOptTrans = kwargs['withOptTrans'] # if 'fromBinary' in kwargs: # self.fromBinary = kwargs['fromBinary'] super(ConservationTrackingWorkflowBase, self).__init__(shell, headless, workflow_cmdline_args, project_creation_args, graph=graph, *args, **kwargs) data_instructions = 'Use the "Raw Data" tab to load your intensity image(s).\n\n' if self.fromBinary: data_instructions += 'Use the "Binary Image" tab to load your segmentation image(s).' else: data_instructions += 'Use the "Prediction Maps" tab to load your pixel-wise probability image(s).' # Variables to store division and cell classifiers to prevent retraining every-time batch processing runs self.stored_division_classifier = None self.stored_cell_classifier = None ## Create applets self.dataSelectionApplet = DataSelectionApplet( self, "Input Data", "Input Data", forceAxisOrder=['txyzc'], instructionText=data_instructions, max_lanes=None) opDataSelection = self.dataSelectionApplet.topLevelOperator if self.fromBinary: opDataSelection.DatasetRoles.setValue( ['Raw Data', 'Segmentation Image']) else: opDataSelection.DatasetRoles.setValue( ['Raw Data', 'Prediction Maps']) if not self.fromBinary: self.thresholdTwoLevelsApplet = ThresholdTwoLevelsApplet( self, "Threshold and Size Filter", "ThresholdTwoLevels") if self.withOptTrans: self.opticalTranslationApplet = OpticalTranslationApplet( workflow=self) self.objectExtractionApplet = TrackingFeatureExtractionApplet( workflow=self, interactive=False, name="Object Feature Computation") opObjectExtraction = self.objectExtractionApplet.topLevelOperator opObjectExtraction.FeatureNamesVigra.setValue( configConservation.allFeaturesObjectCount) self.divisionDetectionApplet = self._createDivisionDetectionApplet( configConservation.selectedFeaturesDiv) # Might be None if self.divisionDetectionApplet: feature_dict_division = {} feature_dict_division[config.features_division_name] = { name: {} for name in config.division_features } opObjectExtraction.FeatureNamesDivision.setValue( feature_dict_division) selected_features_div = {} for plugin_name in config.selected_features_division.keys(): selected_features_div[plugin_name] = { name: {} for name in config.selected_features_division[plugin_name] } # FIXME: do not hard code this for name in [ 'SquaredDistances_' + str(i) for i in range(config.n_best_successors) ]: selected_features_div[config.features_division_name][name] = {} opDivisionDetection = self.divisionDetectionApplet.topLevelOperator opDivisionDetection.SelectedFeatures.setValue( configConservation.selectedFeaturesDiv) opDivisionDetection.LabelNames.setValue( ['Not Dividing', 'Dividing']) opDivisionDetection.AllowDeleteLabels.setValue(False) opDivisionDetection.AllowAddLabel.setValue(False) opDivisionDetection.EnableLabelTransfer.setValue(False) self.cellClassificationApplet = ObjectClassificationApplet( workflow=self, name="Object Count Classification", projectFileGroupName="CountClassification", selectedFeatures=configConservation.selectedFeaturesObjectCount) selected_features_objectcount = {} for plugin_name in config.selected_features_objectcount.keys(): selected_features_objectcount[plugin_name] = { name: {} for name in config.selected_features_objectcount[plugin_name] } opCellClassification = self.cellClassificationApplet.topLevelOperator opCellClassification.SelectedFeatures.setValue( configConservation.selectedFeaturesObjectCount) opCellClassification.SuggestedLabelNames.setValue([ 'False Detection', ] + [str(1) + ' Object'] + [str(i) + ' Objects' for i in range(2, 10)]) opCellClassification.AllowDeleteLastLabelOnly.setValue(True) opCellClassification.EnableLabelTransfer.setValue(False) self.trackingApplet = ConservationTrackingApplet(workflow=self) self.default_export_filename = '{dataset_dir}/{nickname}-exported_data.csv' self.dataExportApplet = TrackingBaseDataExportApplet( self, "Tracking Result Export", default_export_filename=self.default_export_filename) opDataExport = self.dataExportApplet.topLevelOperator opDataExport.SelectionNames.setValue( ['Object-Identities', 'Tracking-Result', 'Merger-Result']) opDataExport.WorkingDirectory.connect(opDataSelection.WorkingDirectory) # Extra configuration for object export table (as CSV table or HDF5 table) opTracking = self.trackingApplet.topLevelOperator self.dataExportApplet.set_exporting_operator(opTracking) self.dataExportApplet.prepare_lane_for_export = self.prepare_lane_for_export self.dataExportApplet.post_process_lane_export = self.post_process_lane_export # table only export is just available for the pgmlink backend, hytra uses the CSV plugin instead try: import hytra except ImportError: self.dataExportApplet.includeTableOnlyOption( ) # Export table only, without volumes # configure export settings settings = { 'file path': self.default_export_filename, 'compression': {}, 'file type': 'csv' } selected_features = [ 'Count', 'RegionCenter', 'RegionRadii', 'RegionAxes' ] opTracking.ExportSettings.setValue((settings, selected_features)) self._applets = [] self._applets.append(self.dataSelectionApplet) if not self.fromBinary: self._applets.append(self.thresholdTwoLevelsApplet) if self.withOptTrans: self._applets.append(self.opticalTranslationApplet) self._applets.append(self.objectExtractionApplet) if self.divisionDetectionApplet: self._applets.append(self.divisionDetectionApplet) self.batchProcessingApplet = BatchProcessingApplet( self, "Batch Processing", self.dataSelectionApplet, self.dataExportApplet) self._applets.append(self.cellClassificationApplet) self._applets.append(self.trackingApplet) self._applets.append(self.dataExportApplet) self._applets.append(self.batchProcessingApplet) # Parse export and batch command-line arguments for headless mode if workflow_cmdline_args: self._data_export_args, unused_args = self.dataExportApplet.parse_known_cmdline_args( workflow_cmdline_args) self._batch_input_args, unused_args = self.batchProcessingApplet.parse_known_cmdline_args( workflow_cmdline_args) else: unused_args = None self._data_export_args = None self._batch_input_args = None if unused_args: logger.warn("Unused command-line args: {}".format(unused_args)) @property def applets(self): return self._applets def _createDivisionDetectionApplet(self, selectedFeatures=dict()): return ObjectClassificationApplet( workflow=self, name="Division Detection (optional)", projectFileGroupName="DivisionDetection", selectedFeatures=selectedFeatures) @property def imageNameListSlot(self): return self.dataSelectionApplet.topLevelOperator.ImageName def prepareForNewLane(self, laneIndex): # Store division and cell classifiers if self.divisionDetectionApplet: opDivisionClassification = self.divisionDetectionApplet.topLevelOperator if opDivisionClassification.classifier_cache.Output.ready() and \ not opDivisionClassification.classifier_cache._dirty: self.stored_division_classifier = opDivisionClassification.classifier_cache.Output.value else: self.stored_division_classifier = None opCellClassification = self.cellClassificationApplet.topLevelOperator if opCellClassification.classifier_cache.Output.ready() and \ not opCellClassification.classifier_cache._dirty: self.stored_cell_classifier = opCellClassification.classifier_cache.Output.value else: self.stored_cell_classifier = None def handleNewLanesAdded(self): """ If new lanes were added, then we invalidated our classifiers unecessarily. Here, we can restore the classifier so it doesn't need to be retrained. """ # If we have stored division and cell classifiers, restore them into the workflow now. if self.stored_division_classifier: opDivisionClassification = self.divisionDetectionApplet.topLevelOperator opDivisionClassification.classifier_cache.forceValue( self.stored_division_classifier) # Release reference self.stored_division_classifier = None # If we have stored division and cell classifiers, restore them into the workflow now. if self.stored_cell_classifier: opCellClassification = self.cellClassificationApplet.topLevelOperator opCellClassification.classifier_cache.forceValue( self.stored_cell_classifier) # Release reference self.stored_cell_classifier = None def connectLane(self, laneIndex): opData = self.dataSelectionApplet.topLevelOperator.getLane(laneIndex) if not self.fromBinary: opTwoLevelThreshold = self.thresholdTwoLevelsApplet.topLevelOperator.getLane( laneIndex) if self.withOptTrans: opOptTranslation = self.opticalTranslationApplet.topLevelOperator.getLane( laneIndex) opObjExtraction = self.objectExtractionApplet.topLevelOperator.getLane( laneIndex) if self.divisionDetectionApplet: opDivDetection = self.divisionDetectionApplet.topLevelOperator.getLane( laneIndex) opCellClassification = self.cellClassificationApplet.topLevelOperator.getLane( laneIndex) opTracking = self.trackingApplet.topLevelOperator.getLane(laneIndex) opDataExport = self.dataExportApplet.topLevelOperator.getLane( laneIndex) op5Raw = OpReorderAxes(parent=self) op5Raw.AxisOrder.setValue("txyzc") op5Raw.Input.connect(opData.ImageGroup[0]) if not self.fromBinary: opTwoLevelThreshold.InputImage.connect(opData.ImageGroup[1]) opTwoLevelThreshold.RawInput.connect( opData.ImageGroup[0]) # Used for display only # opTwoLevelThreshold.Channel.setValue(1) binarySrc = opTwoLevelThreshold.CachedOutput else: binarySrc = opData.ImageGroup[1] # Use Op5ifyers for both input datasets such that they are guaranteed to # have the same axis order after thresholding op5Binary = OpReorderAxes(parent=self) op5Binary.AxisOrder.setValue("txyzc") op5Binary.Input.connect(binarySrc) if self.withOptTrans: opOptTranslation.RawImage.connect(op5Raw.Output) opOptTranslation.BinaryImage.connect(op5Binary.Output) # # Connect operators ## opObjExtraction.RawImage.connect(op5Raw.Output) opObjExtraction.BinaryImage.connect(op5Binary.Output) if self.withOptTrans: opObjExtraction.TranslationVectors.connect( opOptTranslation.TranslationVectors) if self.divisionDetectionApplet: opDivDetection.BinaryImages.connect(op5Binary.Output) opDivDetection.RawImages.connect(op5Raw.Output) opDivDetection.SegmentationImages.connect( opObjExtraction.LabelImage) opDivDetection.ObjectFeatures.connect( opObjExtraction.RegionFeaturesAll) opDivDetection.ComputedFeatureNames.connect( opObjExtraction.ComputedFeatureNamesAll) opCellClassification.BinaryImages.connect(op5Binary.Output) opCellClassification.RawImages.connect(op5Raw.Output) opCellClassification.SegmentationImages.connect( opObjExtraction.LabelImage) opCellClassification.ObjectFeatures.connect( opObjExtraction.RegionFeaturesVigra) opCellClassification.ComputedFeatureNames.connect( opObjExtraction.FeatureNamesVigra) if self.divisionDetectionApplet: opTracking.ObjectFeaturesWithDivFeatures.connect( opObjExtraction.RegionFeaturesAll) opTracking.ComputedFeatureNamesWithDivFeatures.connect( opObjExtraction.ComputedFeatureNamesAll) opTracking.DivisionProbabilities.connect( opDivDetection.Probabilities) opTracking.RawImage.connect(op5Raw.Output) opTracking.LabelImage.connect(opObjExtraction.LabelImage) opTracking.ObjectFeatures.connect(opObjExtraction.RegionFeaturesVigra) opTracking.ComputedFeatureNames.connect( opObjExtraction.FeatureNamesVigra) opTracking.DetectionProbabilities.connect( opCellClassification.Probabilities) opTracking.NumLabels.connect(opCellClassification.NumLabels) opDataExport.Inputs.resize(3) opDataExport.Inputs[0].connect(opTracking.RelabeledImage) opDataExport.Inputs[1].connect(opTracking.Output) opDataExport.Inputs[2].connect(opTracking.MergerOutput) opDataExport.RawData.connect(op5Raw.Output) opDataExport.RawDatasetInfo.connect(opData.DatasetGroup[0]) def prepare_lane_for_export(self, lane_index): # Bypass cache on headless mode and batch processing mode self.objectExtractionApplet.topLevelOperator[ lane_index].BypassModeEnabled.setValue(True) # Get axes info maxt = self.trackingApplet.topLevelOperator[ lane_index].RawImage.meta.shape[0] maxx = self.trackingApplet.topLevelOperator[ lane_index].RawImage.meta.shape[1] maxy = self.trackingApplet.topLevelOperator[ lane_index].RawImage.meta.shape[2] maxz = self.trackingApplet.topLevelOperator[ lane_index].RawImage.meta.shape[3] time_enum = range(maxt) x_range = (0, maxx) y_range = (0, maxy) z_range = (0, maxz) ndim = 2 if (z_range[1] - z_range[0]) > 1: ndim = 3 parameters = self.trackingApplet.topLevelOperator.Parameters.value # Save state of axis ranges if 'time_range' in parameters: self.prev_time_range = parameters['time_range'] else: self.prev_time_range = time_enum if 'x_range' in parameters: self.prev_x_range = parameters['x_range'] else: self.prev_x_range = x_range if 'y_range' in parameters: self.prev_y_range = parameters['y_range'] else: self.prev_y_range = y_range if 'z_range' in parameters: self.prev_z_range = parameters['z_range'] else: self.prev_z_range = z_range self.trackingApplet.topLevelOperator[lane_index].track( time_range=time_enum, x_range=x_range, y_range=y_range, z_range=z_range, size_range=parameters['size_range'], x_scale=parameters['scales'][0], y_scale=parameters['scales'][1], z_scale=parameters['scales'][2], maxDist=parameters['maxDist'], maxObj=parameters['maxObj'], divThreshold=parameters['divThreshold'], avgSize=parameters['avgSize'], withTracklets=parameters['withTracklets'], sizeDependent=parameters['sizeDependent'], divWeight=parameters['divWeight'], transWeight=parameters['transWeight'], withDivisions=parameters['withDivisions'], withOpticalCorrection=parameters['withOpticalCorrection'], withClassifierPrior=parameters['withClassifierPrior'], ndim=ndim, withMergerResolution=parameters['withMergerResolution'], borderAwareWidth=parameters['borderAwareWidth'], withArmaCoordinates=parameters['withArmaCoordinates'], cplex_timeout=parameters['cplex_timeout'], appearance_cost=parameters['appearanceCost'], disappearance_cost=parameters['disappearanceCost'], max_nearest_neighbors=parameters['max_nearest_neighbors'], numFramesPerSplit=parameters['numFramesPerSplit'], force_build_hypotheses_graph=False, withBatchProcessing=True) def post_process_lane_export(self, lane_index, checkOverwriteFiles=False): # `time` parameter ensures we check only once for files that could be overwritten, pop up # the MessageBox and then don't export (time=0). For the next round we click the export button, # we really want it to export, so time=1. The default parameter is 1, so everything but not 0, # in order to ensure writing out even in headless mode. # FIXME: This probably only works for the non-blockwise export slot. # We should assert that the user isn't using the blockwise slot. # Plugin export if selected logger.info( "Export source is: " + self.dataExportApplet.topLevelOperator.SelectedExportSource.value) if self.dataExportApplet.topLevelOperator.SelectedExportSource.value == OpTrackingBaseDataExport.PluginOnlyName: logger.info("Export source plugin selected!") selectedPlugin = self.dataExportApplet.topLevelOperator.SelectedPlugin.value exportPluginInfo = pluginManager.getPluginByName( selectedPlugin, category="TrackingExportFormats") if exportPluginInfo is None: logger.error("Could not find selected plugin %s" % exportPluginInfo) else: exportPlugin = exportPluginInfo.plugin_object logger.info("Exporting tracking result using %s" % selectedPlugin) name_format = self.dataExportApplet.topLevelOperator.getLane( lane_index).OutputFilenameFormat.value partially_formatted_name = self.getPartiallyFormattedName( lane_index, name_format) if exportPlugin.exportsToFile: filename = partially_formatted_name if os.path.basename(filename) == '': filename = os.path.join(filename, 'pluginExport.txt') else: filename = os.path.dirname(partially_formatted_name) if filename is None or len(str(filename)) == 0: logger.error( "Cannot export from plugin with empty output filename") return exportStatus = self.trackingApplet.topLevelOperator.getLane( lane_index).exportPlugin(filename, exportPlugin, checkOverwriteFiles) if not exportStatus: return False logger.info("Export done") return # CSV Table export (only if plugin was not selected) settings, selected_features = self.trackingApplet.topLevelOperator.getLane( lane_index).get_table_export_settings() if settings: self.dataExportApplet.progressSignal.emit(0) name_format = settings['file path'] partially_formatted_name = self.getPartiallyFormattedName( lane_index, name_format) settings['file path'] = partially_formatted_name req = self.trackingApplet.topLevelOperator.getLane( lane_index ).export_object_data( lane_index, # FIXME: Even in non-headless mode, we can't show the gui because we're running in a non-main thread. # That's not a huge deal, because there's still a progress bar for the overall export. show_gui=False) req.wait() self.dataExportApplet.progressSignal.emit(100) # Restore option to bypass cache to false self.objectExtractionApplet.topLevelOperator[ lane_index].BypassModeEnabled.setValue(False) # Restore state of axis ranges parameters = self.trackingApplet.topLevelOperator.Parameters.value parameters['time_range'] = self.prev_time_range parameters['x_range'] = self.prev_x_range parameters['y_range'] = self.prev_y_range parameters['z_range'] = self.prev_z_range def getPartiallyFormattedName(self, lane_index, path_format_string): ''' Takes the format string for the output file, fills in the most important placeholders, and returns it ''' raw_dataset_info = self.dataSelectionApplet.topLevelOperator.DatasetGroup[ lane_index][0].value project_path = self.shell.projectManager.currentProjectPath project_dir = os.path.dirname(project_path) dataset_dir = PathComponents( raw_dataset_info.filePath).externalDirectory abs_dataset_dir = make_absolute(dataset_dir, cwd=project_dir) known_keys = {} known_keys['dataset_dir'] = abs_dataset_dir nickname = raw_dataset_info.nickname.replace('*', '') if os.path.pathsep in nickname: nickname = PathComponents(nickname.split( os.path.pathsep)[0]).fileNameBase known_keys['nickname'] = nickname opDataExport = self.dataExportApplet.topLevelOperator.getLane( lane_index) known_keys[ 'result_type'] = self.dataExportApplet.topLevelOperator.SelectedPlugin._value # use partial formatting to fill in non-coordinate name fields partially_formatted_name = format_known_keys(path_format_string, known_keys) return partially_formatted_name def _inputReady(self, nRoles): slot = self.dataSelectionApplet.topLevelOperator.ImageGroup if len(slot) > 0: input_ready = True for sub in slot: input_ready = input_ready and \ all([sub[i].ready() for i in range(nRoles)]) else: input_ready = False return input_ready def onProjectLoaded(self, projectManager): """ Overridden from Workflow base class. Called by the Project Manager. If the user provided command-line arguments, use them to configure the workflow inputs and output settings. """ # Configure the data export operator. if self._data_export_args: self.dataExportApplet.configure_operator_with_parsed_args( self._data_export_args) # Configure headless mode. if self._headless and self._batch_input_args and self._data_export_args: logger.info("Beginning Batch Processing") self.batchProcessingApplet.run_export_from_parsed_args( self._batch_input_args) logger.info("Completed Batch Processing") def handleAppletStateUpdateRequested(self): """ Overridden from Workflow base class Called when an applet has fired the :py:attr:`Applet.statusUpdateSignal` """ # If no data, nothing else is ready. opDataSelection = self.dataSelectionApplet.topLevelOperator input_ready = self._inputReady(2) and not self.dataSelectionApplet.busy if not self.fromBinary: opThresholding = self.thresholdTwoLevelsApplet.topLevelOperator thresholdingOutput = opThresholding.CachedOutput thresholding_ready = input_ready and \ len(thresholdingOutput) > 0 else: thresholding_ready = True and input_ready opObjectExtraction = self.objectExtractionApplet.topLevelOperator objectExtractionOutput = opObjectExtraction.ComputedFeatureNamesAll features_ready = thresholding_ready and \ len(objectExtractionOutput) > 0 objectCountClassifier_ready = features_ready opTracking = self.trackingApplet.topLevelOperator tracking_ready = objectCountClassifier_ready busy = False busy |= self.dataSelectionApplet.busy busy |= self.trackingApplet.busy busy |= self.dataExportApplet.busy busy |= self.batchProcessingApplet.busy self._shell.enableProjectChanges(not busy) self._shell.setAppletEnabled(self.dataSelectionApplet, not busy) if not self.fromBinary: self._shell.setAppletEnabled(self.thresholdTwoLevelsApplet, input_ready and not busy) if self.divisionDetectionApplet: self._shell.setAppletEnabled(self.divisionDetectionApplet, features_ready and not busy) self._shell.setAppletEnabled(self.objectExtractionApplet, thresholding_ready and not busy) self._shell.setAppletEnabled(self.cellClassificationApplet, features_ready and not busy) self._shell.setAppletEnabled(self.trackingApplet, objectCountClassifier_ready and not busy) self._shell.setAppletEnabled(self.dataExportApplet, tracking_ready and not busy and \ self.dataExportApplet.topLevelOperator.Inputs[0][0].ready() ) self._shell.setAppletEnabled(self.batchProcessingApplet, tracking_ready and not busy and \ self.dataExportApplet.topLevelOperator.Inputs[0][0].ready() )
class ConservationTrackingWorkflowBase( Workflow ): workflowName = "Automatic Tracking Workflow (Conservation Tracking) BASE" def __init__( self, shell, headless, workflow_cmdline_args, *args, **kwargs ): graph = kwargs['graph'] if 'graph' in kwargs else Graph() if 'graph' in kwargs: del kwargs['graph'] # if 'withOptTrans' in kwargs: # self.withOptTrans = kwargs['withOptTrans'] # if 'fromBinary' in kwargs: # self.fromBinary = kwargs['fromBinary'] super(ConservationTrackingWorkflowBase, self).__init__(shell, headless, graph=graph, *args, **kwargs) data_instructions = 'Use the "Raw Data" tab to load your intensity image(s).\n\n' if self.fromBinary: data_instructions += 'Use the "Binary Image" tab to load your segmentation image(s).' else: data_instructions += 'Use the "Prediction Maps" tab to load your pixel-wise probability image(s).' ## Create applets self.dataSelectionApplet = DataSelectionApplet(self, "Input Data", "Input Data", forceAxisOrder='txyzc', instructionText=data_instructions, max_lanes=1 ) opDataSelection = self.dataSelectionApplet.topLevelOperator if self.fromBinary: opDataSelection.DatasetRoles.setValue( ['Raw Data', 'Binary Image'] ) else: opDataSelection.DatasetRoles.setValue( ['Raw Data', 'Prediction Maps'] ) if not self.fromBinary: self.thresholdTwoLevelsApplet = ThresholdTwoLevelsApplet( self, "Threshold and Size Filter", "ThresholdTwoLevels" ) if self.withOptTrans: self.opticalTranslationApplet = OpticalTranslationApplet(workflow=self) self.objectExtractionApplet = TrackingFeatureExtractionApplet(workflow=self, interactive=False, name="Object Feature Computation") self.divisionDetectionApplet = ObjectClassificationApplet(workflow=self, name="Division Detection (optional)", projectFileGroupName="DivisionDetection") self.cellClassificationApplet = ObjectClassificationApplet(workflow=self, name="Object Count Classification (optional)", projectFileGroupName="CountClassification") self.trackingApplet = ConservationTrackingApplet( workflow=self ) self.dataExportApplet = TrackingBaseDataExportApplet(self, "Tracking Result Export") opDataExport = self.dataExportApplet.topLevelOperator opDataExport.SelectionNames.setValue( ['Tracking Result', 'Merger Result', 'Object Identities'] ) opDataExport.WorkingDirectory.connect( opDataSelection.WorkingDirectory ) # Extra configuration for object export table (as CSV table or HDF5 table) opTracking = self.trackingApplet.topLevelOperator self.dataExportApplet.set_exporting_operator(opTracking) self.dataExportApplet.post_process_lane_export = self.post_process_lane_export self._applets = [] self._applets.append(self.dataSelectionApplet) if not self.fromBinary: self._applets.append(self.thresholdTwoLevelsApplet) if self.withOptTrans: self._applets.append(self.opticalTranslationApplet) self._applets.append(self.objectExtractionApplet) self._applets.append(self.divisionDetectionApplet) self._applets.append(self.cellClassificationApplet) self._applets.append(self.trackingApplet) self._applets.append(self.dataExportApplet) @property def applets(self): return self._applets @property def imageNameListSlot(self): return self.dataSelectionApplet.topLevelOperator.ImageName def connectLane(self, laneIndex): opData = self.dataSelectionApplet.topLevelOperator.getLane(laneIndex) if not self.fromBinary: opTwoLevelThreshold = self.thresholdTwoLevelsApplet.topLevelOperator.getLane(laneIndex) if self.withOptTrans: opOptTranslation = self.opticalTranslationApplet.topLevelOperator.getLane(laneIndex) opObjExtraction = self.objectExtractionApplet.topLevelOperator.getLane(laneIndex) opDivDetection = self.divisionDetectionApplet.topLevelOperator.getLane(laneIndex) opCellClassification = self.cellClassificationApplet.topLevelOperator.getLane(laneIndex) opTracking = self.trackingApplet.topLevelOperator.getLane(laneIndex) opDataExport = self.dataExportApplet.topLevelOperator.getLane(laneIndex) op5Raw = OpReorderAxes(parent=self) op5Raw.AxisOrder.setValue("txyzc") op5Raw.Input.connect(opData.ImageGroup[0]) if not self.fromBinary: opTwoLevelThreshold.InputImage.connect(opData.ImageGroup[1]) opTwoLevelThreshold.RawInput.connect(opData.ImageGroup[0]) # Used for display only # opTwoLevelThreshold.Channel.setValue(1) binarySrc = opTwoLevelThreshold.CachedOutput else: binarySrc = opData.ImageGroup[1] # Use Op5ifyers for both input datasets such that they are guaranteed to # have the same axis order after thresholding op5Binary = OpReorderAxes(parent=self) op5Binary.AxisOrder.setValue("txyzc") op5Binary.Input.connect(binarySrc) if self.withOptTrans: opOptTranslation.RawImage.connect(op5Raw.Output) opOptTranslation.BinaryImage.connect(op5Binary.Output) # # Connect operators ## vigra_features = list((set(config.vigra_features)).union(config.selected_features_objectcount[config.features_vigra_name])) feature_names_vigra = {} feature_names_vigra[config.features_vigra_name] = { name: {} for name in vigra_features } opObjExtraction.RawImage.connect(op5Raw.Output) opObjExtraction.BinaryImage.connect(op5Binary.Output) if self.withOptTrans: opObjExtraction.TranslationVectors.connect(opOptTranslation.TranslationVectors) opObjExtraction.FeatureNamesVigra.setValue(feature_names_vigra) feature_dict_division = {} feature_dict_division[config.features_division_name] = { name: {} for name in config.division_features } opObjExtraction.FeatureNamesDivision.setValue(feature_dict_division) selected_features_div = {} for plugin_name in config.selected_features_division.keys(): selected_features_div[plugin_name] = { name: {} for name in config.selected_features_division[plugin_name] } # FIXME: do not hard code this for name in [ 'SquaredDistances_' + str(i) for i in range(config.n_best_successors) ]: selected_features_div[config.features_division_name][name] = {} opDivDetection.BinaryImages.connect( op5Binary.Output ) opDivDetection.RawImages.connect( op5Raw.Output ) opDivDetection.LabelsAllowedFlags.connect(opData.AllowLabels) opDivDetection.SegmentationImages.connect(opObjExtraction.LabelImage) opDivDetection.ObjectFeatures.connect(opObjExtraction.RegionFeaturesAll) opDivDetection.ComputedFeatureNames.connect(opObjExtraction.ComputedFeatureNamesAll) opDivDetection.SelectedFeatures.setValue(selected_features_div) opDivDetection.LabelNames.setValue(['Not Dividing', 'Dividing']) opDivDetection.AllowDeleteLabels.setValue(False) opDivDetection.AllowAddLabel.setValue(False) opDivDetection.EnableLabelTransfer.setValue(False) selected_features_objectcount = {} for plugin_name in config.selected_features_objectcount.keys(): selected_features_objectcount[plugin_name] = { name: {} for name in config.selected_features_objectcount[plugin_name] } opCellClassification.BinaryImages.connect( op5Binary.Output ) opCellClassification.RawImages.connect( op5Raw.Output ) opCellClassification.LabelsAllowedFlags.connect(opData.AllowLabels) opCellClassification.SegmentationImages.connect(opObjExtraction.LabelImage) opCellClassification.ObjectFeatures.connect(opObjExtraction.RegionFeaturesVigra) opCellClassification.ComputedFeatureNames.connect(opObjExtraction.ComputedFeatureNamesVigra) opCellClassification.SelectedFeatures.setValue( selected_features_objectcount ) opCellClassification.SuggestedLabelNames.setValue( ['false detection',] + [str(i) + ' Objects' for i in range(1,10) ] ) opCellClassification.AllowDeleteLastLabelOnly.setValue(True) opCellClassification.EnableLabelTransfer.setValue(False) opTracking.RawImage.connect( op5Raw.Output ) opTracking.LabelImage.connect( opObjExtraction.LabelImage ) opTracking.ObjectFeatures.connect( opObjExtraction.RegionFeaturesVigra ) opTracking.ObjectFeaturesWithDivFeatures.connect( opObjExtraction.RegionFeaturesAll) opTracking.ComputedFeatureNames.connect( opObjExtraction.ComputedFeatureNamesVigra ) opTracking.ComputedFeatureNamesWithDivFeatures.connect( opObjExtraction.ComputedFeatureNamesAll ) opTracking.DivisionProbabilities.connect( opDivDetection.Probabilities ) opTracking.DetectionProbabilities.connect( opCellClassification.Probabilities ) opTracking.NumLabels.connect( opCellClassification.NumLabels ) opDataExport.Inputs.resize(3) opDataExport.Inputs[0].connect( opTracking.Output ) opDataExport.Inputs[1].connect( opTracking.MergerOutput ) opDataExport.Inputs[2].connect( opTracking.LabelImage ) opDataExport.RawData.connect( op5Raw.Output ) opDataExport.RawDatasetInfo.connect( opData.DatasetGroup[0] ) def post_process_lane_export(self, lane_index): # FIXME: This probably only works for the non-blockwise export slot. # We should assert that the user isn't using the blockwise slot. settings, selected_features = self.trackingApplet.topLevelOperator.getLane(lane_index).get_table_export_settings() if settings: raw_dataset_info = self.dataSelectionApplet.topLevelOperator.DatasetGroup[lane_index][0].value if raw_dataset_info.location == DatasetInfo.Location.FileSystem: filename_suffix = raw_dataset_info.nickname else: filename_suffix = str(lane_index) req = self.trackingApplet.topLevelOperator.getLane(lane_index).export_object_data( lane_index, # FIXME: Even in non-headless mode, we can't show the gui because we're running in a non-main thread. # That's not a huge deal, because there's still a progress bar for the overall export. show_gui=False, filename_suffix=filename_suffix) req.wait() def _inputReady(self, nRoles): slot = self.dataSelectionApplet.topLevelOperator.ImageGroup if len(slot) > 0: input_ready = True for sub in slot: input_ready = input_ready and \ all([sub[i].ready() for i in range(nRoles)]) else: input_ready = False return input_ready def handleAppletStateUpdateRequested(self): """ Overridden from Workflow base class Called when an applet has fired the :py:attr:`Applet.statusUpdateSignal` """ # If no data, nothing else is ready. opDataSelection = self.dataSelectionApplet.topLevelOperator input_ready = self._inputReady(2) and not self.dataSelectionApplet.busy if not self.fromBinary: opThresholding = self.thresholdTwoLevelsApplet.topLevelOperator thresholdingOutput = opThresholding.CachedOutput thresholding_ready = input_ready and \ len(thresholdingOutput) > 0 else: thresholding_ready = True and input_ready opObjectExtraction = self.objectExtractionApplet.topLevelOperator objectExtractionOutput = opObjectExtraction.ComputedFeatureNamesAll features_ready = thresholding_ready and \ len(objectExtractionOutput) > 0 objectCountClassifier_ready = features_ready opTracking = self.trackingApplet.topLevelOperator tracking_ready = objectCountClassifier_ready and \ len(opTracking.EventsVector) > 0 busy = False busy |= self.dataSelectionApplet.busy busy |= self.trackingApplet.busy busy |= self.dataExportApplet.busy self._shell.enableProjectChanges( not busy ) self._shell.setAppletEnabled(self.dataSelectionApplet, not busy) if not self.fromBinary: self._shell.setAppletEnabled(self.thresholdTwoLevelsApplet, input_ready and not busy) self._shell.setAppletEnabled(self.objectExtractionApplet, thresholding_ready and not busy) self._shell.setAppletEnabled(self.cellClassificationApplet, features_ready and not busy) self._shell.setAppletEnabled(self.divisionDetectionApplet, features_ready and not busy) self._shell.setAppletEnabled(self.trackingApplet, objectCountClassifier_ready and not busy) self._shell.setAppletEnabled(self.dataExportApplet, tracking_ready and not busy and \ self.dataExportApplet.topLevelOperator.Inputs[0][0].ready() )
class ConservationTrackingWorkflowBase(Workflow): workflowName = "Automatic Tracking Workflow (Conservation Tracking) BASE" def __init__(self, shell, headless, workflow_cmdline_args, project_creation_args, *args, **kwargs): graph = kwargs["graph"] if "graph" in kwargs else Graph() if "graph" in kwargs: del kwargs["graph"] # if 'withOptTrans' in kwargs: # self.withOptTrans = kwargs['withOptTrans'] # if 'fromBinary' in kwargs: # self.fromBinary = kwargs['fromBinary'] super(ConservationTrackingWorkflowBase, self).__init__(shell, headless, workflow_cmdline_args, project_creation_args, graph=graph, *args, **kwargs) data_instructions = 'Use the "Raw Data" tab to load your intensity image(s).\n\n' if self.fromBinary: data_instructions += 'Use the "Binary Image" tab to load your segmentation image(s).' else: data_instructions += 'Use the "Prediction Maps" tab to load your pixel-wise probability image(s).' # Variables to store division and cell classifiers to prevent retraining every-time batch processing runs self.stored_division_classifier = None self.stored_cell_classifier = None ## Create applets self.dataSelectionApplet = DataSelectionApplet( self, "Input Data", "Input Data", forceAxisOrder=["txyzc"], instructionText=data_instructions, max_lanes=None, ) opDataSelection = self.dataSelectionApplet.topLevelOperator if self.fromBinary: opDataSelection.DatasetRoles.setValue( ["Raw Data", "Segmentation Image"]) else: opDataSelection.DatasetRoles.setValue( ["Raw Data", "Prediction Maps"]) if not self.fromBinary: self.thresholdTwoLevelsApplet = ThresholdTwoLevelsApplet( self, "Threshold and Size Filter", "ThresholdTwoLevels") self.objectExtractionApplet = TrackingFeatureExtractionApplet( workflow=self, interactive=False, name="Object Feature Computation") opObjectExtraction = self.objectExtractionApplet.topLevelOperator self.divisionDetectionApplet = self._createDivisionDetectionApplet( configConservation.selectedFeaturesDiv) # Might be None if self.divisionDetectionApplet: feature_dict_division = {} feature_dict_division[config.features_division_name] = { name: {} for name in config.division_features } opObjectExtraction.FeatureNamesDivision.setValue( feature_dict_division) selected_features_div = {} for plugin_name in list(config.selected_features_division.keys()): selected_features_div[plugin_name] = { name: {} for name in config.selected_features_division[plugin_name] } # FIXME: do not hard code this for name in [ "SquaredDistances_" + str(i) for i in range(config.n_best_successors) ]: selected_features_div[config.features_division_name][name] = {} opDivisionDetection = self.divisionDetectionApplet.topLevelOperator opDivisionDetection.SelectedFeatures.setValue( configConservation.selectedFeaturesDiv) opDivisionDetection.LabelNames.setValue( ["Not Dividing", "Dividing"]) opDivisionDetection.AllowDeleteLabels.setValue(False) opDivisionDetection.AllowAddLabel.setValue(False) opDivisionDetection.EnableLabelTransfer.setValue(False) self.cellClassificationApplet = ObjectClassificationApplet( workflow=self, name="Object Count Classification", projectFileGroupName="CountClassification", selectedFeatures=configConservation.selectedFeaturesObjectCount, ) selected_features_objectcount = {} for plugin_name in list(config.selected_features_objectcount.keys()): selected_features_objectcount[plugin_name] = { name: {} for name in config.selected_features_objectcount[plugin_name] } opCellClassification = self.cellClassificationApplet.topLevelOperator opCellClassification.SelectedFeatures.setValue( configConservation.selectedFeaturesObjectCount) opCellClassification.SuggestedLabelNames.setValue( ["False Detection"] + [str(1) + " Object"] + [str(i) + " Objects" for i in range(2, 10)]) opCellClassification.AllowDeleteLastLabelOnly.setValue(True) opCellClassification.EnableLabelTransfer.setValue(False) self.trackingApplet = ConservationTrackingApplet(workflow=self) self.default_export_filename = "{dataset_dir}/{nickname}-exported_data.csv" self.dataExportApplet = TrackingBaseDataExportApplet( self, "Tracking Result Export", default_export_filename=self.default_export_filename, pluginExportFunc=self._pluginExportFunc, ) opDataExport = self.dataExportApplet.topLevelOperator opDataExport.SelectionNames.setValue( ["Object-Identities", "Tracking-Result", "Merger-Result"]) opDataExport.WorkingDirectory.connect(opDataSelection.WorkingDirectory) # Extra configuration for object export table (as CSV table or HDF5 table) opTracking = self.trackingApplet.topLevelOperator self.dataExportApplet.set_exporting_operator(opTracking) self.dataExportApplet.prepare_lane_for_export = self.prepare_lane_for_export # configure export settings # settings = {'file path': self.default_export_filename, 'compression': {}, 'file type': 'csv'} # selected_features = ['Count', 'RegionCenter', 'RegionRadii', 'RegionAxes'] # opTracking.ExportSettings.setValue( (settings, selected_features) ) self._applets = [] self._applets.append(self.dataSelectionApplet) if not self.fromBinary: self._applets.append(self.thresholdTwoLevelsApplet) self._applets.append(self.objectExtractionApplet) if self.divisionDetectionApplet: self._applets.append(self.divisionDetectionApplet) self.batchProcessingApplet = BatchProcessingApplet( self, "Batch Processing", self.dataSelectionApplet, self.dataExportApplet) self._applets.append(self.cellClassificationApplet) self._applets.append(self.trackingApplet) self._applets.append(self.dataExportApplet) self._applets.append(self.batchProcessingApplet) # Parse export and batch command-line arguments for headless mode if workflow_cmdline_args: self._data_export_args, unused_args = self.dataExportApplet.parse_known_cmdline_args( workflow_cmdline_args) self._batch_input_args, unused_args = self.batchProcessingApplet.parse_known_cmdline_args( workflow_cmdline_args) else: unused_args = None self._data_export_args = None self._batch_input_args = None if unused_args: logger.warning("Unused command-line args: {}".format(unused_args)) @property def applets(self): return self._applets def _createDivisionDetectionApplet(self, selectedFeatures=dict()): return ObjectClassificationApplet( workflow=self, name="Division Detection (optional)", projectFileGroupName="DivisionDetection", selectedFeatures=selectedFeatures, ) @property def imageNameListSlot(self): return self.dataSelectionApplet.topLevelOperator.ImageName def prepareForNewLane(self, laneIndex): # Store division and cell classifiers if self.divisionDetectionApplet: opDivisionClassification = self.divisionDetectionApplet.topLevelOperator if (opDivisionClassification.classifier_cache.Output.ready() and not opDivisionClassification.classifier_cache._dirty): self.stored_division_classifier = opDivisionClassification.classifier_cache.Output.value else: self.stored_division_classifier = None opCellClassification = self.cellClassificationApplet.topLevelOperator if opCellClassification.classifier_cache.Output.ready( ) and not opCellClassification.classifier_cache._dirty: self.stored_cell_classifier = opCellClassification.classifier_cache.Output.value else: self.stored_cell_classifier = None def handleNewLanesAdded(self): """ If new lanes were added, then we invalidated our classifiers unecessarily. Here, we can restore the classifier so it doesn't need to be retrained. """ # If we have stored division and cell classifiers, restore them into the workflow now. if self.stored_division_classifier: opDivisionClassification = self.divisionDetectionApplet.topLevelOperator opDivisionClassification.classifier_cache.forceValue( self.stored_division_classifier) # Release reference self.stored_division_classifier = None # If we have stored division and cell classifiers, restore them into the workflow now. if self.stored_cell_classifier: opCellClassification = self.cellClassificationApplet.topLevelOperator opCellClassification.classifier_cache.forceValue( self.stored_cell_classifier) # Release reference self.stored_cell_classifier = None def connectLane(self, laneIndex): opData = self.dataSelectionApplet.topLevelOperator.getLane(laneIndex) if not self.fromBinary: opTwoLevelThreshold = self.thresholdTwoLevelsApplet.topLevelOperator.getLane( laneIndex) opObjExtraction = self.objectExtractionApplet.topLevelOperator.getLane( laneIndex) opObjExtraction.setDefaultFeatures( configConservation.allFeaturesObjectCount) if self.divisionDetectionApplet: opDivDetection = self.divisionDetectionApplet.topLevelOperator.getLane( laneIndex) opCellClassification = self.cellClassificationApplet.topLevelOperator.getLane( laneIndex) opTracking = self.trackingApplet.topLevelOperator.getLane(laneIndex) opDataExport = self.dataExportApplet.topLevelOperator.getLane( laneIndex) op5Raw = OpReorderAxes(parent=self) op5Raw.AxisOrder.setValue("txyzc") op5Raw.Input.connect(opData.ImageGroup[0]) if not self.fromBinary: opTwoLevelThreshold.InputImage.connect(opData.ImageGroup[1]) opTwoLevelThreshold.RawInput.connect( opData.ImageGroup[0]) # Used for display only # opTwoLevelThreshold.Channel.setValue(1) binarySrc = opTwoLevelThreshold.CachedOutput else: binarySrc = opData.ImageGroup[1] # Use Op5ifyers for both input datasets such that they are guaranteed to # have the same axis order after thresholding op5Binary = OpReorderAxes(parent=self) op5Binary.AxisOrder.setValue("txyzc") op5Binary.Input.connect(binarySrc) # # Connect operators ## opObjExtraction.RawImage.connect(op5Raw.Output) opObjExtraction.BinaryImage.connect(op5Binary.Output) if self.divisionDetectionApplet: opDivDetection.BinaryImages.connect(op5Binary.Output) opDivDetection.RawImages.connect(op5Raw.Output) opDivDetection.SegmentationImages.connect( opObjExtraction.LabelImage) opDivDetection.ObjectFeatures.connect( opObjExtraction.RegionFeaturesAll) opDivDetection.ComputedFeatureNames.connect( opObjExtraction.ComputedFeatureNamesAll) opCellClassification.BinaryImages.connect(op5Binary.Output) opCellClassification.RawImages.connect(op5Raw.Output) opCellClassification.SegmentationImages.connect( opObjExtraction.LabelImage) opCellClassification.ObjectFeatures.connect( opObjExtraction.RegionFeaturesVigra) opCellClassification.ComputedFeatureNames.connect( opObjExtraction.FeatureNamesVigra) if self.divisionDetectionApplet: opTracking.ObjectFeaturesWithDivFeatures.connect( opObjExtraction.RegionFeaturesAll) opTracking.ComputedFeatureNamesWithDivFeatures.connect( opObjExtraction.ComputedFeatureNamesAll) opTracking.DivisionProbabilities.connect( opDivDetection.Probabilities) opTracking.RawImage.connect(op5Raw.Output) opTracking.LabelImage.connect(opObjExtraction.LabelImage) opTracking.ObjectFeatures.connect(opObjExtraction.RegionFeaturesVigra) opTracking.ComputedFeatureNames.connect( opObjExtraction.FeatureNamesVigra) opTracking.DetectionProbabilities.connect( opCellClassification.Probabilities) opTracking.NumLabels.connect(opCellClassification.NumLabels) opDataExport.Inputs.resize(3) opDataExport.Inputs[0].connect(opTracking.RelabeledImage) opDataExport.Inputs[1].connect(opTracking.Output) opDataExport.Inputs[2].connect(opTracking.MergerOutput) opDataExport.RawData.connect(op5Raw.Output) opDataExport.RawDatasetInfo.connect(opData.DatasetGroup[0]) def prepare_lane_for_export(self, lane_index): # Bypass cache on headless mode and batch processing mode self.objectExtractionApplet.topLevelOperator[ lane_index].BypassModeEnabled.setValue(True) if not self.fromBinary: self.thresholdTwoLevelsApplet.topLevelOperator[ lane_index].opCache.BypassModeEnabled.setValue(True) self.thresholdTwoLevelsApplet.topLevelOperator[ lane_index].opSmootherCache.BypassModeEnabled.setValue(True) # Get axes info maxt = self.trackingApplet.topLevelOperator[ lane_index].RawImage.meta.shape[0] maxx = self.trackingApplet.topLevelOperator[ lane_index].RawImage.meta.shape[1] maxy = self.trackingApplet.topLevelOperator[ lane_index].RawImage.meta.shape[2] maxz = self.trackingApplet.topLevelOperator[ lane_index].RawImage.meta.shape[3] time_enum = list(range(maxt)) x_range = (0, maxx) y_range = (0, maxy) z_range = (0, maxz) ndim = 2 if (z_range[1] - z_range[0]) > 1: ndim = 3 parameters = self.trackingApplet.topLevelOperator.Parameters.value # Save state of axis ranges if "time_range" in parameters: self.prev_time_range = parameters["time_range"] else: self.prev_time_range = time_enum if "x_range" in parameters: self.prev_x_range = parameters["x_range"] else: self.prev_x_range = x_range if "y_range" in parameters: self.prev_y_range = parameters["y_range"] else: self.prev_y_range = y_range if "z_range" in parameters: self.prev_z_range = parameters["z_range"] else: self.prev_z_range = z_range if "numFramesPerSplit" in parameters: numFramesPerSplit = parameters["numFramesPerSplit"] else: numFramesPerSplit = 0 self.trackingApplet.topLevelOperator[lane_index].track( time_range=time_enum, x_range=x_range, y_range=y_range, z_range=z_range, size_range=parameters["size_range"], x_scale=parameters["scales"][0], y_scale=parameters["scales"][1], z_scale=parameters["scales"][2], maxDist=parameters["maxDist"], maxObj=parameters["maxObj"], divThreshold=parameters["divThreshold"], avgSize=parameters["avgSize"], withTracklets=parameters["withTracklets"], sizeDependent=parameters["sizeDependent"], divWeight=parameters["divWeight"], transWeight=parameters["transWeight"], withDivisions=parameters["withDivisions"], withOpticalCorrection=parameters["withOpticalCorrection"], withClassifierPrior=parameters["withClassifierPrior"], ndim=ndim, withMergerResolution=parameters["withMergerResolution"], borderAwareWidth=parameters["borderAwareWidth"], withArmaCoordinates=parameters["withArmaCoordinates"], cplex_timeout=parameters["cplex_timeout"], appearance_cost=parameters["appearanceCost"], disappearance_cost=parameters["disappearanceCost"], max_nearest_neighbors=parameters["max_nearest_neighbors"], numFramesPerSplit=numFramesPerSplit, force_build_hypotheses_graph=False, withBatchProcessing=True, ) def _pluginExportFunc(self, lane_index, filename, exportPlugin, checkOverwriteFiles, plugArgsSlot) -> int: return self.trackingApplet.topLevelOperator.getLane( lane_index).exportPlugin(filename, exportPlugin, checkOverwriteFiles, plugArgsSlot) def _inputReady(self, nRoles): slot = self.dataSelectionApplet.topLevelOperator.ImageGroup if len(slot) > 0: input_ready = True for sub in slot: input_ready = input_ready and all( [sub[i].ready() for i in range(nRoles)]) else: input_ready = False return input_ready def onProjectLoaded(self, projectManager): """ Overridden from Workflow base class. Called by the Project Manager. If the user provided command-line arguments, use them to configure the workflow inputs and output settings. """ # Configure the data export operator. if self._data_export_args: self.dataExportApplet.configure_operator_with_parsed_args( self._data_export_args) # Configure headless mode. if self._headless and self._batch_input_args and self._data_export_args: logger.info("Beginning Batch Processing") self.batchProcessingApplet.run_export_from_parsed_args( self._batch_input_args) logger.info("Completed Batch Processing") def handleAppletStateUpdateRequested(self): """ Overridden from Workflow base class Called when an applet has fired the :py:attr:`Applet.statusUpdateSignal` """ # If no data, nothing else is ready. opDataSelection = self.dataSelectionApplet.topLevelOperator input_ready = self._inputReady(2) and not self.dataSelectionApplet.busy if not self.fromBinary: opThresholding = self.thresholdTwoLevelsApplet.topLevelOperator thresholdingOutput = opThresholding.CachedOutput thresholding_ready = input_ready and len(thresholdingOutput) > 0 else: thresholding_ready = True and input_ready opObjectExtraction = self.objectExtractionApplet.topLevelOperator objectExtractionOutput = opObjectExtraction.ComputedFeatureNamesAll features_ready = thresholding_ready and len(objectExtractionOutput) > 0 objectCountClassifier_ready = features_ready opTracking = self.trackingApplet.topLevelOperator tracking_ready = objectCountClassifier_ready busy = False busy |= self.dataSelectionApplet.busy busy |= self.trackingApplet.busy busy |= self.dataExportApplet.busy busy |= self.batchProcessingApplet.busy self._shell.enableProjectChanges(not busy) self._shell.setAppletEnabled(self.dataSelectionApplet, not busy) if not self.fromBinary: self._shell.setAppletEnabled(self.thresholdTwoLevelsApplet, input_ready and not busy) if self.divisionDetectionApplet: self._shell.setAppletEnabled(self.divisionDetectionApplet, features_ready and not busy) self._shell.setAppletEnabled(self.objectExtractionApplet, thresholding_ready and not busy) self._shell.setAppletEnabled(self.cellClassificationApplet, features_ready and not busy) self._shell.setAppletEnabled(self.trackingApplet, objectCountClassifier_ready and not busy) self._shell.setAppletEnabled( self.dataExportApplet, tracking_ready and not busy and self.dataExportApplet.topLevelOperator.Inputs[0][0].ready(), ) self._shell.setAppletEnabled( self.batchProcessingApplet, tracking_ready and not busy and self.dataExportApplet.topLevelOperator.Inputs[0][0].ready(), )
class ConservationTrackingWorkflowBase(Workflow): workflowName = "Automatic Tracking Workflow (Conservation Tracking) BASE" def __init__(self, shell, headless, workflow_cmdline_args, *args, **kwargs): graph = kwargs["graph"] if "graph" in kwargs else Graph() if "graph" in kwargs: del kwargs["graph"] # if 'withOptTrans' in kwargs: # self.withOptTrans = kwargs['withOptTrans'] # if 'fromBinary' in kwargs: # self.fromBinary = kwargs['fromBinary'] super(ConservationTrackingWorkflowBase, self).__init__(shell, headless, graph=graph, *args, **kwargs) data_instructions = 'Use the "Raw Data" tab to load your intensity image(s).\n\n' if self.fromBinary: data_instructions += 'Use the "Binary Image" tab to load your segmentation image(s).' else: data_instructions += 'Use the "Prediction Maps" tab to load your pixel-wise probability image(s).' ## Create applets self.dataSelectionApplet = DataSelectionApplet( self, "Input Data", "Input Data", batchDataGui=False, force5d=True, instructionText=data_instructions, max_lanes=1, ) opDataSelection = self.dataSelectionApplet.topLevelOperator if self.fromBinary: opDataSelection.DatasetRoles.setValue(["Raw Data", "Binary Image"]) else: opDataSelection.DatasetRoles.setValue(["Raw Data", "Prediction Maps"]) if not self.fromBinary: self.thresholdTwoLevelsApplet = ThresholdTwoLevelsApplet( self, "Threshold and Size Filter", "ThresholdTwoLevels" ) if self.withOptTrans: self.opticalTranslationApplet = OpticalTranslationApplet(workflow=self) self.objectExtractionApplet = TrackingFeatureExtractionApplet( workflow=self, interactive=False, name="Object Feature Computation" ) self.divisionDetectionApplet = ObjectClassificationApplet( workflow=self, name="Division Detection (optional)", projectFileGroupName="DivisionDetection" ) self.cellClassificationApplet = ObjectClassificationApplet( workflow=self, name="Object Count Classification (optional)", projectFileGroupName="CountClassification" ) self.trackingApplet = ConservationTrackingApplet(workflow=self) opTracking = self.trackingApplet.topLevelOperator self.dataExportApplet = TrackingBaseDataExportApplet(self, "Tracking Result Export") self.dataExportApplet.set_exporting_operator(opTracking) opDataExport = self.dataExportApplet.topLevelOperator opDataExport.SelectionNames.setValue(["Tracking Result", "Merger Result", "Object Identities"]) opDataExport.WorkingDirectory.connect(opDataSelection.WorkingDirectory) self._applets = [] self._applets.append(self.dataSelectionApplet) if not self.fromBinary: self._applets.append(self.thresholdTwoLevelsApplet) if self.withOptTrans: self._applets.append(self.opticalTranslationApplet) self._applets.append(self.objectExtractionApplet) self._applets.append(self.divisionDetectionApplet) self._applets.append(self.cellClassificationApplet) self._applets.append(self.trackingApplet) self._applets.append(self.dataExportApplet) @property def applets(self): return self._applets @property def imageNameListSlot(self): return self.dataSelectionApplet.topLevelOperator.ImageName def connectLane(self, laneIndex): opData = self.dataSelectionApplet.topLevelOperator.getLane(laneIndex) if not self.fromBinary: opTwoLevelThreshold = self.thresholdTwoLevelsApplet.topLevelOperator.getLane(laneIndex) if self.withOptTrans: opOptTranslation = self.opticalTranslationApplet.topLevelOperator.getLane(laneIndex) opObjExtraction = self.objectExtractionApplet.topLevelOperator.getLane(laneIndex) opDivDetection = self.divisionDetectionApplet.topLevelOperator.getLane(laneIndex) opCellClassification = self.cellClassificationApplet.topLevelOperator.getLane(laneIndex) opTracking = self.trackingApplet.topLevelOperator.getLane(laneIndex) opDataExport = self.dataExportApplet.topLevelOperator.getLane(laneIndex) op5Raw = OpReorderAxes(parent=self) op5Raw.AxisOrder.setValue("txyzc") op5Raw.Input.connect(opData.ImageGroup[0]) if not self.fromBinary: opTwoLevelThreshold.InputImage.connect(opData.ImageGroup[1]) opTwoLevelThreshold.RawInput.connect(opData.ImageGroup[0]) # Used for display only # opTwoLevelThreshold.Channel.setValue(1) binarySrc = opTwoLevelThreshold.CachedOutput else: binarySrc = opData.ImageGroup[1] # Use Op5ifyers for both input datasets such that they are guaranteed to # have the same axis order after thresholding op5Binary = OpReorderAxes(parent=self) op5Binary.AxisOrder.setValue("txyzc") op5Binary.Input.connect(binarySrc) if self.withOptTrans: opOptTranslation.RawImage.connect(op5Raw.Output) opOptTranslation.BinaryImage.connect(op5Binary.Output) # # Connect operators ## vigra_features = list( (set(config.vigra_features)).union(config.selected_features_objectcount[config.features_vigra_name]) ) feature_names_vigra = {} feature_names_vigra[config.features_vigra_name] = {name: {} for name in vigra_features} opObjExtraction.RawImage.connect(op5Raw.Output) opObjExtraction.BinaryImage.connect(op5Binary.Output) if self.withOptTrans: opObjExtraction.TranslationVectors.connect(opOptTranslation.TranslationVectors) opObjExtraction.FeatureNamesVigra.setValue(feature_names_vigra) feature_dict_division = {} feature_dict_division[config.features_division_name] = {name: {} for name in config.division_features} opObjExtraction.FeatureNamesDivision.setValue(feature_dict_division) selected_features_div = {} for plugin_name in config.selected_features_division.keys(): selected_features_div[plugin_name] = {name: {} for name in config.selected_features_division[plugin_name]} # FIXME: do not hard code this for name in ["SquaredDistances_" + str(i) for i in range(config.n_best_successors)]: selected_features_div[config.features_division_name][name] = {} opDivDetection.BinaryImages.connect(op5Binary.Output) opDivDetection.RawImages.connect(op5Raw.Output) opDivDetection.LabelsAllowedFlags.connect(opData.AllowLabels) opDivDetection.SegmentationImages.connect(opObjExtraction.LabelImage) opDivDetection.ObjectFeatures.connect(opObjExtraction.RegionFeaturesAll) opDivDetection.ComputedFeatureNames.connect(opObjExtraction.ComputedFeatureNamesAll) opDivDetection.SelectedFeatures.setValue(selected_features_div) opDivDetection.LabelNames.setValue(["Not Dividing", "Dividing"]) opDivDetection.AllowDeleteLabels.setValue(False) opDivDetection.AllowAddLabel.setValue(False) opDivDetection.EnableLabelTransfer.setValue(False) selected_features_objectcount = {} for plugin_name in config.selected_features_objectcount.keys(): selected_features_objectcount[plugin_name] = { name: {} for name in config.selected_features_objectcount[plugin_name] } opCellClassification.BinaryImages.connect(op5Binary.Output) opCellClassification.RawImages.connect(op5Raw.Output) opCellClassification.LabelsAllowedFlags.connect(opData.AllowLabels) opCellClassification.SegmentationImages.connect(opObjExtraction.LabelImage) opCellClassification.ObjectFeatures.connect(opObjExtraction.RegionFeaturesVigra) opCellClassification.ComputedFeatureNames.connect(opObjExtraction.ComputedFeatureNamesVigra) opCellClassification.SelectedFeatures.setValue(selected_features_objectcount) opCellClassification.SuggestedLabelNames.setValue( ["false detection"] + [str(i) + " Objects" for i in range(1, 10)] ) opCellClassification.AllowDeleteLastLabelOnly.setValue(True) opCellClassification.EnableLabelTransfer.setValue(False) opTracking.RawImage.connect(op5Raw.Output) opTracking.LabelImage.connect(opObjExtraction.LabelImage) opTracking.ObjectFeatures.connect(opObjExtraction.RegionFeaturesVigra) opTracking.ObjectFeaturesWithDivFeatures.connect(opObjExtraction.RegionFeaturesAll) opTracking.ComputedFeatureNames.connect(opObjExtraction.ComputedFeatureNamesVigra) opTracking.ComputedFeatureNamesWithDivFeatures.connect(opObjExtraction.ComputedFeatureNamesAll) opTracking.DivisionProbabilities.connect(opDivDetection.Probabilities) opTracking.DetectionProbabilities.connect(opCellClassification.Probabilities) opTracking.NumLabels.connect(opCellClassification.NumLabels) opDataExport.Inputs.resize(3) opDataExport.Inputs[0].connect(opTracking.Output) opDataExport.Inputs[1].connect(opTracking.MergerOutput) opDataExport.Inputs[2].connect(opTracking.LabelImage) opDataExport.RawData.connect(op5Raw.Output) opDataExport.RawDatasetInfo.connect(opData.DatasetGroup[0]) def _inputReady(self, nRoles): slot = self.dataSelectionApplet.topLevelOperator.ImageGroup if len(slot) > 0: input_ready = True for sub in slot: input_ready = input_ready and all([sub[i].ready() for i in range(nRoles)]) else: input_ready = False return input_ready def handleAppletStateUpdateRequested(self): """ Overridden from Workflow base class Called when an applet has fired the :py:attr:`Applet.statusUpdateSignal` """ # If no data, nothing else is ready. opDataSelection = self.dataSelectionApplet.topLevelOperator input_ready = self._inputReady(2) and not self.dataSelectionApplet.busy if not self.fromBinary: opThresholding = self.thresholdTwoLevelsApplet.topLevelOperator thresholdingOutput = opThresholding.CachedOutput thresholding_ready = input_ready and len(thresholdingOutput) > 0 else: thresholding_ready = True and input_ready opObjectExtraction = self.objectExtractionApplet.topLevelOperator objectExtractionOutput = opObjectExtraction.ComputedFeatureNamesAll features_ready = thresholding_ready and len(objectExtractionOutput) > 0 objectCountClassifier_ready = features_ready opTracking = self.trackingApplet.topLevelOperator tracking_ready = objectCountClassifier_ready and len(opTracking.EventsVector) > 0 busy = False busy |= self.dataSelectionApplet.busy busy |= self.trackingApplet.busy busy |= self.dataExportApplet.busy self._shell.enableProjectChanges(not busy) self._shell.setAppletEnabled(self.dataSelectionApplet, not busy) if not self.fromBinary: self._shell.setAppletEnabled(self.thresholdTwoLevelsApplet, input_ready and not busy) self._shell.setAppletEnabled(self.objectExtractionApplet, thresholding_ready and not busy) self._shell.setAppletEnabled(self.cellClassificationApplet, features_ready and not busy) self._shell.setAppletEnabled(self.divisionDetectionApplet, features_ready and not busy) self._shell.setAppletEnabled(self.trackingApplet, objectCountClassifier_ready and not busy) self._shell.setAppletEnabled( self.dataExportApplet, tracking_ready and not busy and self.dataExportApplet.topLevelOperator.Inputs[0][0].ready(), )
class ManualTrackingWorkflow( Workflow ): workflowName = "Manual Tracking Workflow" workflowDisplayName = "Manual Tracking Workflow [Inputs: Raw Data, Pixel Prediction Map]" workflowDescription = "Manual tracking of objects, based on Prediction Maps or (binary) Segmentation Images" @property def applets(self): return self._applets @property def imageNameListSlot(self): return self.dataSelectionApplet.topLevelOperator.ImageName def __init__( self, shell, headless, workflow_cmdline_args, project_creation_args, *args, **kwargs ): graph = kwargs['graph'] if 'graph' in kwargs else Graph() if 'graph' in kwargs: del kwargs['graph'] super(ManualTrackingWorkflow, self).__init__(shell, headless, workflow_cmdline_args, project_creation_args, graph=graph, *args, **kwargs) data_instructions = 'Use the "Raw Data" tab to load your intensity image(s).\n\n'\ 'Use the "Prediction Maps" tab to load your pixel-wise probability image(s).' ## Create applets self.dataSelectionApplet = DataSelectionApplet(self, "Input Data", "Input Data", forceAxisOrder='txyzc', instructionText=data_instructions, max_lanes=1 ) opDataSelection = self.dataSelectionApplet.topLevelOperator opDataSelection.DatasetRoles.setValue( ['Raw Data', 'Prediction Maps'] ) self.thresholdTwoLevelsApplet = ThresholdTwoLevelsApplet( self, "Threshold and Size Filter", "ThresholdTwoLevels" ) self.objectExtractionApplet = ObjectExtractionApplet(name="Object Feature Computation", workflow=self, interactive=False) self.trackingApplet = ManualTrackingApplet( workflow=self ) self.default_export_filename = '{dataset_dir}/{nickname}-exported_data.csv' self.dataExportApplet = TrackingBaseDataExportApplet(self, "Tracking Result Export", default_export_filename=self.default_export_filename) opDataExport = self.dataExportApplet.topLevelOperator opDataExport.SelectionNames.setValue( ['Manual Tracking', 'Object Identities'] ) opDataExport.WorkingDirectory.connect( opDataSelection.WorkingDirectory ) # Extra configuration for object export table (as CSV table or HDF5 table) opTracking = self.trackingApplet.topLevelOperator self.dataExportApplet.set_exporting_operator(opTracking) self.dataExportApplet.post_process_lane_export = self.post_process_lane_export self._applets = [] self._applets.append(self.dataSelectionApplet) self._applets.append(self.thresholdTwoLevelsApplet) self._applets.append(self.objectExtractionApplet) self._applets.append(self.trackingApplet) self._applets.append(self.dataExportApplet) def connectLane(self, laneIndex): opData = self.dataSelectionApplet.topLevelOperator.getLane(laneIndex) opObjExtraction = self.objectExtractionApplet.topLevelOperator.getLane(laneIndex) opTracking = self.trackingApplet.topLevelOperator.getLane(laneIndex) opTwoLevelThreshold = self.thresholdTwoLevelsApplet.topLevelOperator.getLane(laneIndex) opDataExport = self.dataExportApplet.topLevelOperator.getLane(laneIndex) ## Connect operators ## op5Raw = OpReorderAxes(parent=self) op5Raw.AxisOrder.setValue("txyzc") op5Raw.Input.connect(opData.ImageGroup[0]) opTwoLevelThreshold.InputImage.connect( opData.ImageGroup[1] ) opTwoLevelThreshold.RawInput.connect( opData.ImageGroup[0] ) # Used for display only # Use OpReorderAxis for both input datasets such that they are guaranteed to # have the same axis order after thresholding op5Binary = OpReorderAxes( parent=self ) op5Binary.AxisOrder.setValue("txyzc") op5Binary.Input.connect( opTwoLevelThreshold.CachedOutput ) opObjExtraction.RawImage.connect( op5Raw.Output ) opObjExtraction.BinaryImage.connect( op5Binary.Output ) opTracking.RawImage.connect( op5Raw.Output ) opTracking.BinaryImage.connect( op5Binary.Output ) opTracking.LabelImage.connect( opObjExtraction.LabelImage ) opTracking.ObjectFeatures.connect( opObjExtraction.RegionFeatures ) opTracking.ComputedFeatureNames.connect(opObjExtraction.Features) opDataExport.Inputs.resize(2) opDataExport.Inputs[0].connect( opTracking.TrackImage ) opDataExport.Inputs[1].connect( opTracking.LabelImage ) opDataExport.RawData.connect( op5Raw.Output ) opDataExport.RawDatasetInfo.connect( opData.DatasetGroup[0] ) def post_process_lane_export(self, lane_index): # FIXME: This probably only works for the non-blockwise export slot. # We should assert that the user isn't using the blockwise slot. settings, selected_features = self.trackingApplet.topLevelOperator.getLane(lane_index).get_table_export_settings() if settings: raw_dataset_info = self.dataSelectionApplet.topLevelOperator.DatasetGroup[lane_index][0].value if raw_dataset_info.location == DatasetInfo.Location.FileSystem: filename_suffix = raw_dataset_info.nickname else: filename_suffix = str(lane_index) req = self.trackingApplet.topLevelOperator.getLane(lane_index).export_object_data( lane_index, # FIXME: Even in non-headless mode, we can't show the gui because we're running in a non-main thread. # That's not a huge deal, because there's still a progress bar for the overall export. show_gui=False, filename_suffix=filename_suffix) req.wait() def _inputReady(self, nRoles): slot = self.dataSelectionApplet.topLevelOperator.ImageGroup if len(slot) > 0: input_ready = True for sub in slot: input_ready = input_ready and \ all([sub[i].ready() for i in range(nRoles)]) else: input_ready = False return input_ready def handleAppletStateUpdateRequested(self): """ Overridden from Workflow base class Called when an applet has fired the :py:attr:`Applet.statusUpdateSignal` """ # If no data, nothing else is ready. input_ready = self._inputReady(2) and not self.dataSelectionApplet.busy opThresholding = self.thresholdTwoLevelsApplet.topLevelOperator thresholdingOutput = opThresholding.CachedOutput thresholding_ready = input_ready and \ len(thresholdingOutput) > 0 opObjectExtraction = self.objectExtractionApplet.topLevelOperator features_ready = thresholding_ready opTracking = self.trackingApplet.topLevelOperator tracking_ready = features_ready and \ len(opTracking.Labels) > 0 and \ opTracking.Labels.ready() and \ opTracking.TrackImage.ready() busy = False busy |= self.dataSelectionApplet.busy busy |= self.dataExportApplet.busy busy |= self.trackingApplet.busy self._shell.enableProjectChanges( not busy ) self._shell.setAppletEnabled(self.dataSelectionApplet, not busy) self._shell.setAppletEnabled(self.thresholdTwoLevelsApplet, input_ready and not busy) self._shell.setAppletEnabled(self.objectExtractionApplet, thresholding_ready and not busy) self._shell.setAppletEnabled(self.trackingApplet, features_ready and not busy) self._shell.setAppletEnabled(self.dataExportApplet, tracking_ready and not busy and \ self.dataExportApplet.topLevelOperator.Inputs[0][0].ready() )
def __init__(self, shell, headless, workflow_cmdline_args, *args, **kwargs): graph = kwargs["graph"] if "graph" in kwargs else Graph() if "graph" in kwargs: del kwargs["graph"] # if 'withOptTrans' in kwargs: # self.withOptTrans = kwargs['withOptTrans'] # if 'fromBinary' in kwargs: # self.fromBinary = kwargs['fromBinary'] super(ConservationTrackingWorkflowBase, self).__init__(shell, headless, graph=graph, *args, **kwargs) data_instructions = 'Use the "Raw Data" tab to load your intensity image(s).\n\n' if self.fromBinary: data_instructions += 'Use the "Binary Image" tab to load your segmentation image(s).' else: data_instructions += 'Use the "Prediction Maps" tab to load your pixel-wise probability image(s).' ## Create applets self.dataSelectionApplet = DataSelectionApplet( self, "Input Data", "Input Data", batchDataGui=False, force5d=True, instructionText=data_instructions, max_lanes=1, ) opDataSelection = self.dataSelectionApplet.topLevelOperator if self.fromBinary: opDataSelection.DatasetRoles.setValue(["Raw Data", "Binary Image"]) else: opDataSelection.DatasetRoles.setValue(["Raw Data", "Prediction Maps"]) if not self.fromBinary: self.thresholdTwoLevelsApplet = ThresholdTwoLevelsApplet( self, "Threshold and Size Filter", "ThresholdTwoLevels" ) if self.withOptTrans: self.opticalTranslationApplet = OpticalTranslationApplet(workflow=self) self.objectExtractionApplet = TrackingFeatureExtractionApplet( workflow=self, interactive=False, name="Object Feature Computation" ) self.divisionDetectionApplet = ObjectClassificationApplet( workflow=self, name="Division Detection (optional)", projectFileGroupName="DivisionDetection" ) self.cellClassificationApplet = ObjectClassificationApplet( workflow=self, name="Object Count Classification (optional)", projectFileGroupName="CountClassification" ) self.trackingApplet = ConservationTrackingApplet(workflow=self) opTracking = self.trackingApplet.topLevelOperator self.dataExportApplet = TrackingBaseDataExportApplet(self, "Tracking Result Export") self.dataExportApplet.set_exporting_operator(opTracking) opDataExport = self.dataExportApplet.topLevelOperator opDataExport.SelectionNames.setValue(["Tracking Result", "Merger Result", "Object Identities"]) opDataExport.WorkingDirectory.connect(opDataSelection.WorkingDirectory) self._applets = [] self._applets.append(self.dataSelectionApplet) if not self.fromBinary: self._applets.append(self.thresholdTwoLevelsApplet) if self.withOptTrans: self._applets.append(self.opticalTranslationApplet) self._applets.append(self.objectExtractionApplet) self._applets.append(self.divisionDetectionApplet) self._applets.append(self.cellClassificationApplet) self._applets.append(self.trackingApplet) self._applets.append(self.dataExportApplet)
def __init__( self, shell, headless, workflow_cmdline_args, project_creation_args, *args, **kwargs ): graph = kwargs['graph'] if 'graph' in kwargs else Graph() if 'graph' in kwargs: del kwargs['graph'] super(StructuredTrackingWorkflowBase, self).__init__(shell, headless, workflow_cmdline_args, project_creation_args, graph=graph, *args, **kwargs) data_instructions = 'Use the "Raw Data" tab to load your intensity image(s).\n\n' if self.fromBinary: data_instructions += 'Use the "Binary Image" tab to load your segmentation image(s).' else: data_instructions += 'Use the "Prediction Maps" tab to load your pixel-wise probability image(s).' # Create applets self.dataSelectionApplet = DataSelectionApplet(self, "Input Data", "Input Data", batchDataGui=False, forceAxisOrder=['txyzc'], instructionText=data_instructions, max_lanes=1) opDataSelection = self.dataSelectionApplet.topLevelOperator if self.fromBinary: opDataSelection.DatasetRoles.setValue( ['Raw Data', 'Binary Image'] ) else: opDataSelection.DatasetRoles.setValue( ['Raw Data', 'Prediction Maps'] ) if not self.fromBinary: self.thresholdTwoLevelsApplet = ThresholdTwoLevelsApplet( self,"Threshold and Size Filter","ThresholdTwoLevels" ) self.divisionDetectionApplet = ObjectClassificationApplet(workflow=self, name="Division Detection (optional)", projectFileGroupName="DivisionDetection", selectedFeatures=configConservation.selectedFeaturesDiv) self.cellClassificationApplet = ObjectClassificationApplet(workflow=self, name="Object Count Classification", projectFileGroupName="CountClassification", selectedFeatures=configConservation.selectedFeaturesObjectCount) self.trackingFeatureExtractionApplet = TrackingFeatureExtractionApplet(name="Object Feature Computation",workflow=self, interactive=False) self.objectExtractionApplet = ObjectExtractionApplet(name="Object Feature Computation",workflow=self, interactive=False) self.annotationsApplet = AnnotationsApplet( name="Training", workflow=self ) opAnnotations = self.annotationsApplet.topLevelOperator self.trackingApplet = StructuredTrackingApplet( name="Tracking - Structured Learning", workflow=self ) opStructuredTracking = self.trackingApplet.topLevelOperator if SOLVER=="CPLEX" or SOLVER=="GUROBI": self._solver="ILP" elif SOLVER=="DPCT": self._solver="Flow-based" else: self._solver=None opStructuredTracking._solver = self._solver self.default_tracking_export_filename = '{dataset_dir}/{nickname}-tracking_exported_data.csv' self.dataExportTrackingApplet = TrackingBaseDataExportApplet(self, "Tracking Result Export",default_export_filename=self.default_tracking_export_filename) opDataExportTracking = self.dataExportTrackingApplet.topLevelOperator opDataExportTracking.SelectionNames.setValue( ['Tracking-Result', 'Merger-Result', 'Object-Identities'] ) opDataExportTracking.WorkingDirectory.connect( opDataSelection.WorkingDirectory ) self.dataExportTrackingApplet.set_exporting_operator(opStructuredTracking) self.dataExportTrackingApplet.prepare_lane_for_export = self.prepare_lane_for_export self.dataExportTrackingApplet.post_process_lane_export = self.post_process_lane_export # configure export settings settings = {'file path': self.default_tracking_export_filename, 'compression': {}, 'file type': 'h5'} selected_features = ['Count', 'RegionCenter', 'RegionRadii', 'RegionAxes'] opStructuredTracking.ExportSettings.setValue( (settings, selected_features) ) self._applets = [] self._applets.append(self.dataSelectionApplet) if not self.fromBinary: self._applets.append(self.thresholdTwoLevelsApplet) self._applets.append(self.trackingFeatureExtractionApplet) self._applets.append(self.divisionDetectionApplet) self.batchProcessingApplet = BatchProcessingApplet(self, "Batch Processing", self.dataSelectionApplet, self.dataExportTrackingApplet) self._applets.append(self.cellClassificationApplet) self._applets.append(self.objectExtractionApplet) self._applets.append(self.annotationsApplet) self._applets.append(self.trackingApplet) self._applets.append(self.dataExportTrackingApplet) if self.divisionDetectionApplet: opDivDetection = self.divisionDetectionApplet.topLevelOperator opDivDetection.SelectedFeatures.setValue(configConservation.selectedFeaturesDiv) opDivDetection.LabelNames.setValue(['Not Dividing', 'Dividing']) opDivDetection.AllowDeleteLabels.setValue(False) opDivDetection.AllowAddLabel.setValue(False) opDivDetection.EnableLabelTransfer.setValue(False) opCellClassification = self.cellClassificationApplet.topLevelOperator opCellClassification.SelectedFeatures.setValue(configConservation.selectedFeaturesObjectCount ) opCellClassification.SuggestedLabelNames.setValue( ['False Detection',] + [str(1) + ' Object'] + [str(i) + ' Objects' for i in range(2,10) ] ) opCellClassification.AllowDeleteLastLabelOnly.setValue(True) opCellClassification.EnableLabelTransfer.setValue(False) if workflow_cmdline_args: if '--testFullAnnotations' in workflow_cmdline_args: self.testFullAnnotations = True else: self.testFullAnnotations = False self._data_export_args, unused_args = self.dataExportTrackingApplet.parse_known_cmdline_args( workflow_cmdline_args ) self._batch_input_args, unused_args = self.batchProcessingApplet.parse_known_cmdline_args( workflow_cmdline_args ) else: unused_args = None self._data_export_args = None self._batch_input_args = None self.testFullAnnotations = False if unused_args: logger.warning("Unused command-line args: {}".format( unused_args ))
class StructuredTrackingWorkflowBase( Workflow ): workflowName = "Structured Learning Tracking Workflow BASE" @property def applets(self): return self._applets @property def imageNameListSlot(self): return self.dataSelectionApplet.topLevelOperator.ImageName def __init__( self, shell, headless, workflow_cmdline_args, project_creation_args, *args, **kwargs ): graph = kwargs['graph'] if 'graph' in kwargs else Graph() if 'graph' in kwargs: del kwargs['graph'] super(StructuredTrackingWorkflowBase, self).__init__(shell, headless, workflow_cmdline_args, project_creation_args, graph=graph, *args, **kwargs) data_instructions = 'Use the "Raw Data" tab to load your intensity image(s).\n\n' if self.fromBinary: data_instructions += 'Use the "Binary Image" tab to load your segmentation image(s).' else: data_instructions += 'Use the "Prediction Maps" tab to load your pixel-wise probability image(s).' # Create applets self.dataSelectionApplet = DataSelectionApplet(self, "Input Data", "Input Data", batchDataGui=False, forceAxisOrder=['txyzc'], instructionText=data_instructions, max_lanes=1) opDataSelection = self.dataSelectionApplet.topLevelOperator if self.fromBinary: opDataSelection.DatasetRoles.setValue( ['Raw Data', 'Binary Image'] ) else: opDataSelection.DatasetRoles.setValue( ['Raw Data', 'Prediction Maps'] ) if not self.fromBinary: self.thresholdTwoLevelsApplet = ThresholdTwoLevelsApplet( self,"Threshold and Size Filter","ThresholdTwoLevels" ) self.divisionDetectionApplet = ObjectClassificationApplet(workflow=self, name="Division Detection (optional)", projectFileGroupName="DivisionDetection", selectedFeatures=configStructured.selectedFeaturesDiv) self.cellClassificationApplet = ObjectClassificationApplet(workflow=self, name="Object Count Classification", projectFileGroupName="CountClassification", selectedFeatures=configStructured.selectedFeaturesObjectCount) self.cropSelectionApplet = CropSelectionApplet(self,"Crop Selection","CropSelection") self.trackingFeatureExtractionApplet = TrackingFeatureExtractionApplet(name="Object Feature Computation",workflow=self, interactive=False) self.objectExtractionApplet = ObjectExtractionApplet(name="Object Feature Computation",workflow=self, interactive=False) self.annotationsApplet = AnnotationsApplet( name="Training", workflow=self ) opAnnotations = self.annotationsApplet.topLevelOperator # self.default_training_export_filename = '{dataset_dir}/{nickname}-training_exported_data.csv' # self.dataExportAnnotationsApplet = TrackingBaseDataExportApplet(self, "Training Export",default_export_filename=self.default_training_export_filename) # opDataExportAnnotations = self.dataExportAnnotationsApplet.topLevelOperator # opDataExportAnnotations.SelectionNames.setValue( ['User Training for Tracking', 'Object Identities'] ) # opDataExportAnnotations.WorkingDirectory.connect( opDataSelection.WorkingDirectory ) # self.dataExportAnnotationsApplet.set_exporting_operator(opAnnotations) self.trackingApplet = StructuredTrackingApplet( name="Tracking - Structured Learning", workflow=self ) opStructuredTracking = self.trackingApplet.topLevelOperator self.default_tracking_export_filename = '{dataset_dir}/{nickname}-tracking_exported_data.csv' self.dataExportTrackingApplet = TrackingBaseDataExportApplet(self, "Tracking Result Export",default_export_filename=self.default_tracking_export_filename) opDataExportTracking = self.dataExportTrackingApplet.topLevelOperator opDataExportTracking.SelectionNames.setValue( ['Tracking-Result', 'Merger-Result', 'Object-Identities'] ) opDataExportTracking.WorkingDirectory.connect( opDataSelection.WorkingDirectory ) self.dataExportTrackingApplet.set_exporting_operator(opStructuredTracking) self.dataExportTrackingApplet.prepare_lane_for_export = self.prepare_lane_for_export self.dataExportTrackingApplet.post_process_lane_export = self.post_process_lane_export # configure export settings settings = {'file path': self.default_tracking_export_filename, 'compression': {}, 'file type': 'h5'} selected_features = ['Count', 'RegionCenter', 'RegionRadii', 'RegionAxes'] opStructuredTracking.ExportSettings.setValue( (settings, selected_features) ) self._applets = [] self._applets.append(self.dataSelectionApplet) if not self.fromBinary: self._applets.append(self.thresholdTwoLevelsApplet) self._applets.append(self.trackingFeatureExtractionApplet) self._applets.append(self.divisionDetectionApplet) self.batchProcessingApplet = BatchProcessingApplet(self, "Batch Processing", self.dataSelectionApplet, self.dataExportTrackingApplet) self._applets.append(self.cellClassificationApplet) self._applets.append(self.cropSelectionApplet) self._applets.append(self.objectExtractionApplet) self._applets.append(self.annotationsApplet) # self._applets.append(self.dataExportAnnotationsApplet) self._applets.append(self.trackingApplet) self._applets.append(self.dataExportTrackingApplet) if self.divisionDetectionApplet: opDivDetection = self.divisionDetectionApplet.topLevelOperator opDivDetection.SelectedFeatures.setValue(configConservation.selectedFeaturesDiv) opDivDetection.LabelNames.setValue(['Not Dividing', 'Dividing']) opDivDetection.AllowDeleteLabels.setValue(False) opDivDetection.AllowAddLabel.setValue(False) opDivDetection.EnableLabelTransfer.setValue(False) opCellClassification = self.cellClassificationApplet.topLevelOperator opCellClassification.SelectedFeatures.setValue(configConservation.selectedFeaturesObjectCount ) opCellClassification.SuggestedLabelNames.setValue( ['False Detection',] + [str(1) + ' Object'] + [str(i) + ' Objects' for i in range(2,10) ] ) opCellClassification.AllowDeleteLastLabelOnly.setValue(True) opCellClassification.EnableLabelTransfer.setValue(False) if workflow_cmdline_args: self._data_export_args, unused_args = self.dataExportTrackingApplet.parse_known_cmdline_args( workflow_cmdline_args ) self._batch_input_args, unused_args = self.batchProcessingApplet.parse_known_cmdline_args( workflow_cmdline_args ) else: unused_args = None self._data_export_args = None self._batch_input_args = None if unused_args: logger.warn("Unused command-line args: {}".format( unused_args )) def connectLane(self, laneIndex): opData = self.dataSelectionApplet.topLevelOperator.getLane(laneIndex) opObjExtraction = self.objectExtractionApplet.topLevelOperator.getLane(laneIndex) opTrackingFeatureExtraction = self.trackingFeatureExtractionApplet.topLevelOperator.getLane(laneIndex) opAnnotations = self.annotationsApplet.topLevelOperator.getLane(laneIndex) if not self.fromBinary: opTwoLevelThreshold = self.thresholdTwoLevelsApplet.topLevelOperator.getLane(laneIndex) # opDataAnnotationsExport = self.dataExportAnnotationsApplet.topLevelOperator.getLane(laneIndex) opCropSelection = self.cropSelectionApplet.topLevelOperator.getLane(laneIndex) opStructuredTracking = self.trackingApplet.topLevelOperator.getLane(laneIndex) opDataTrackingExport = self.dataExportTrackingApplet.topLevelOperator.getLane(laneIndex) ## Connect operators ## op5Raw = OpReorderAxes(parent=self) op5Raw.AxisOrder.setValue("txyzc") op5Raw.Input.connect(opData.ImageGroup[0]) opDivDetection = self.divisionDetectionApplet.topLevelOperator.getLane(laneIndex) opCellClassification = self.cellClassificationApplet.topLevelOperator.getLane(laneIndex) if not self.fromBinary: opTwoLevelThreshold.InputImage.connect( opData.ImageGroup[1] ) opTwoLevelThreshold.RawInput.connect( opData.ImageGroup[0] ) # Used for display only binarySrc = opTwoLevelThreshold.CachedOutput else: binarySrc = opData.ImageGroup[1] # Use Op5ifyers for both input datasets such that they are guaranteed to # have the same axis order after thresholding op5Binary = OpReorderAxes(parent=self) op5Binary.AxisOrder.setValue("txyzc") op5Binary.Input.connect(binarySrc) opCropSelection.InputImage.connect( opData.ImageGroup[0] ) opCropSelection.PredictionImage.connect( opData.ImageGroup[1] ) opObjExtraction.RawImage.connect( op5Raw.Output ) opObjExtraction.BinaryImage.connect( op5Binary.Output ) opTrackingFeatureExtraction.RawImage.connect( op5Raw.Output ) opTrackingFeatureExtraction.BinaryImage.connect( op5Binary.Output ) # vigra_features = list((set(config.vigra_features)).union(config.selected_features_objectcount[config.features_vigra_name])) # feature_names_vigra = {} # feature_names_vigra[config.features_vigra_name] = { name: {} for name in vigra_features } opTrackingFeatureExtraction.FeatureNamesVigra.setValue(configConservation.allFeaturesObjectCount) feature_dict_division = {} feature_dict_division[config.features_division_name] = { name: {} for name in config.division_features } opTrackingFeatureExtraction.FeatureNamesDivision.setValue(feature_dict_division) if self.divisionDetectionApplet: opDivDetection.BinaryImages.connect( op5Binary.Output ) opDivDetection.RawImages.connect( op5Raw.Output ) opDivDetection.SegmentationImages.connect(opTrackingFeatureExtraction.LabelImage) opDivDetection.ObjectFeatures.connect(opTrackingFeatureExtraction.RegionFeaturesAll) opDivDetection.ComputedFeatureNames.connect(opTrackingFeatureExtraction.ComputedFeatureNamesAll) opCellClassification.BinaryImages.connect( op5Binary.Output ) opCellClassification.RawImages.connect( op5Raw.Output ) opCellClassification.SegmentationImages.connect(opTrackingFeatureExtraction.LabelImage) opCellClassification.ObjectFeatures.connect(opTrackingFeatureExtraction.RegionFeaturesAll) opCellClassification.ComputedFeatureNames.connect(opTrackingFeatureExtraction.ComputedFeatureNamesNoDivisions) opAnnotations.RawImage.connect( op5Raw.Output ) opAnnotations.BinaryImage.connect( op5Binary.Output ) opAnnotations.LabelImage.connect( opObjExtraction.LabelImage ) opAnnotations.ObjectFeatures.connect( opObjExtraction.RegionFeatures ) opAnnotations.ComputedFeatureNames.connect(opObjExtraction.Features) opAnnotations.Crops.connect( opCropSelection.Crops) opAnnotations.DivisionProbabilities.connect( opDivDetection.Probabilities ) opAnnotations.DetectionProbabilities.connect( opCellClassification.Probabilities ) opAnnotations.MaxNumObj.connect (opCellClassification.MaxNumObj) # opDataAnnotationsExport.Inputs.resize(2) # opDataAnnotationsExport.Inputs[0].connect( opAnnotations.TrackImage ) # opDataAnnotationsExport.Inputs[1].connect( opAnnotations.LabelImage ) # opDataAnnotationsExport.RawData.connect( op5Raw.Output ) # opDataAnnotationsExport.RawDatasetInfo.connect( opData.DatasetGroup[0] ) opStructuredTracking.RawImage.connect( op5Raw.Output ) opStructuredTracking.LabelImage.connect( opTrackingFeatureExtraction.LabelImage ) opStructuredTracking.ObjectFeatures.connect( opTrackingFeatureExtraction.RegionFeaturesVigra ) opStructuredTracking.ComputedFeatureNames.connect( opTrackingFeatureExtraction.FeatureNamesVigra ) if self.divisionDetectionApplet: opStructuredTracking.ObjectFeaturesWithDivFeatures.connect( opTrackingFeatureExtraction.RegionFeaturesAll) opStructuredTracking.ComputedFeatureNamesWithDivFeatures.connect( opTrackingFeatureExtraction.ComputedFeatureNamesAll ) opStructuredTracking.DivisionProbabilities.connect( opDivDetection.Probabilities ) # configure tracking export settings settings = {'file path': self.default_tracking_export_filename, 'compression': {}, 'file type': 'csv'} selected_features = ['Count', 'RegionCenter'] opStructuredTracking.configure_table_export_settings(settings, selected_features) opStructuredTracking.DetectionProbabilities.connect( opCellClassification.Probabilities ) opStructuredTracking.NumLabels.connect( opCellClassification.NumLabels ) opStructuredTracking.Crops.connect (opCropSelection.Crops) opStructuredTracking.Annotations.connect (opAnnotations.Annotations) opStructuredTracking.Labels.connect (opAnnotations.Labels) opStructuredTracking.Divisions.connect (opAnnotations.Divisions) opStructuredTracking.MaxNumObj.connect (opCellClassification.MaxNumObj) opDataTrackingExport.Inputs.resize(3) opDataTrackingExport.Inputs[0].connect( opStructuredTracking.RelabeledImage ) opDataTrackingExport.Inputs[1].connect( opStructuredTracking.MergerOutput ) opDataTrackingExport.Inputs[2].connect( opStructuredTracking.LabelImage ) opDataTrackingExport.RawData.connect( op5Raw.Output ) opDataTrackingExport.RawDatasetInfo.connect( opData.DatasetGroup[0] ) def prepare_lane_for_export(self, lane_index): import logging logger = logging.getLogger(__name__) maxt = self.trackingApplet.topLevelOperator[lane_index].RawImage.meta.shape[0] maxx = self.trackingApplet.topLevelOperator[lane_index].RawImage.meta.shape[1] maxy = self.trackingApplet.topLevelOperator[lane_index].RawImage.meta.shape[2] maxz = self.trackingApplet.topLevelOperator[lane_index].RawImage.meta.shape[3] time_enum = range(maxt) x_range = (0, maxx) y_range = (0, maxy) z_range = (0, maxz) ndim = 2 if ( z_range[1] - z_range[0] ) > 1: ndim = 3 parameters = self.trackingApplet.topLevelOperator.Parameters.value # Save state of axis ranges if 'time_range' in parameters: self.prev_time_range = parameters['time_range'] else: self.prev_time_range = time_enum if 'x_range' in parameters: self.prev_x_range = parameters['x_range'] else: self.prev_x_range = x_range if 'y_range' in parameters: self.prev_y_range = parameters['y_range'] else: self.prev_y_range = y_range if 'z_range' in parameters: self.prev_z_range = parameters['z_range'] else: self.prev_z_range = z_range # batch processing starts a new lane, so training data needs to be copied from the lane that loaded the project loaded_project_lane_index=0 self.annotationsApplet.topLevelOperator[lane_index].Annotations.setValue( self.trackingApplet.topLevelOperator[loaded_project_lane_index].Annotations.value) self.cropSelectionApplet.topLevelOperator[lane_index].Crops.setValue( self.trackingApplet.topLevelOperator[loaded_project_lane_index].Crops.value) logger.info("Test: Structured Learning") weights = self.trackingApplet.topLevelOperator[lane_index]._runStructuredLearning( z_range, parameters['maxObj'], parameters['max_nearest_neighbors'], parameters['maxDist'], parameters['divThreshold'], [parameters['scales'][0],parameters['scales'][1],parameters['scales'][2]], parameters['size_range'], parameters['withDivisions'], parameters['borderAwareWidth'], parameters['withClassifierPrior'], withBatchProcessing=True) logger.info("weights: {}".format(weights)) logger.info("Test: Tracking") self.trackingApplet.topLevelOperator[lane_index].track( time_range = time_enum, x_range = x_range, y_range = y_range, z_range = z_range, size_range = parameters['size_range'], x_scale = parameters['scales'][0], y_scale = parameters['scales'][1], z_scale = parameters['scales'][2], maxDist=parameters['maxDist'], maxObj = parameters['maxObj'], divThreshold=parameters['divThreshold'], avgSize=parameters['avgSize'], withTracklets=parameters['withTracklets'], sizeDependent=parameters['sizeDependent'], detWeight=parameters['detWeight'], divWeight=parameters['divWeight'], transWeight=parameters['transWeight'], withDivisions=parameters['withDivisions'], withOpticalCorrection=parameters['withOpticalCorrection'], withClassifierPrior=parameters['withClassifierPrior'], ndim=ndim, withMergerResolution=parameters['withMergerResolution'], borderAwareWidth = parameters['borderAwareWidth'], withArmaCoordinates = parameters['withArmaCoordinates'], cplex_timeout = parameters['cplex_timeout'], appearance_cost = parameters['appearanceCost'], disappearance_cost = parameters['disappearanceCost'], force_build_hypotheses_graph = False, withBatchProcessing = True ) def post_process_lane_export(self, lane_index): # FIXME: This probably only works for the non-blockwise export slot. # We should assert that the user isn't using the blockwise slot. settings, selected_features = self.trackingApplet.topLevelOperator.getLane(lane_index).get_table_export_settings() from lazyflow.utility import PathComponents, make_absolute, format_known_keys if settings: self.dataExportTrackingApplet.progressSignal.emit(-1) raw_dataset_info = self.dataSelectionApplet.topLevelOperator.DatasetGroup[lane_index][0].value project_path = self.shell.projectManager.currentProjectPath project_dir = os.path.dirname(project_path) dataset_dir = PathComponents(raw_dataset_info.filePath).externalDirectory abs_dataset_dir = make_absolute(dataset_dir, cwd=project_dir) known_keys = {} known_keys['dataset_dir'] = abs_dataset_dir nickname = raw_dataset_info.nickname.replace('*', '') if os.path.pathsep in nickname: nickname = PathComponents(nickname.split(os.path.pathsep)[0]).fileNameBase known_keys['nickname'] = nickname # use partial formatting to fill in non-coordinate name fields name_format = settings['file path'] partially_formatted_name = format_known_keys( name_format, known_keys ) settings['file path'] = partially_formatted_name req = self.trackingApplet.topLevelOperator.getLane(lane_index).export_object_data( lane_index, # FIXME: Even in non-headless mode, we can't show the gui because we're running in a non-main thread. # That's not a huge deal, because there's still a progress bar for the overall export. show_gui=False) req.wait() self.dataExportTrackingApplet.progressSignal.emit(100) def _inputReady(self, nRoles): slot = self.dataSelectionApplet.topLevelOperator.ImageGroup if len(slot) > 0: input_ready = True for sub in slot: input_ready = input_ready and \ all([sub[i].ready() for i in range(nRoles)]) else: input_ready = False return input_ready def onProjectLoaded(self, projectManager): """ Overridden from Workflow base class. Called by the Project Manager. If the user provided command-line arguments, use them to configure the workflow inputs and output settings. """ # Configure the data export operator. if self._data_export_args: self.dataExportTrackingApplet.configure_operator_with_parsed_args( self._data_export_args ) # Configure headless mode. if self._headless and self._batch_input_args and self._data_export_args: logger.info("Beginning Batch Processing") self.batchProcessingApplet.run_export_from_parsed_args(self._batch_input_args) logger.info("Completed Batch Processing") def handleAppletStateUpdateRequested(self): """ Overridden from Workflow base class Called when an applet has fired the :py:attr:`Applet.statusUpdateSignal` """ # If no data, nothing else is ready. input_ready = self._inputReady(2) and not self.dataSelectionApplet.busy if not self.fromBinary: opThresholding = self.thresholdTwoLevelsApplet.topLevelOperator thresholdingOutput = opThresholding.CachedOutput thresholding_ready = input_ready and len(thresholdingOutput) > 0 else: thresholding_ready = input_ready opTrackingFeatureExtraction = self.trackingFeatureExtractionApplet.topLevelOperator trackingFeatureExtractionOutput = opTrackingFeatureExtraction.ComputedFeatureNamesAll tracking_features_ready = thresholding_ready and len(trackingFeatureExtractionOutput) > 0 opCropSelection = self.cropSelectionApplet.topLevelOperator croppingOutput = opCropSelection.Crops cropping_ready = thresholding_ready and len(croppingOutput) > 0 objectCountClassifier_ready = tracking_features_ready opObjectExtraction = self.objectExtractionApplet.topLevelOperator objectExtractionOutput = opObjectExtraction.RegionFeatures features_ready = thresholding_ready and \ len(objectExtractionOutput) > 0 opAnnotations = self.annotationsApplet.topLevelOperator annotations_ready = features_ready and \ len(opAnnotations.Labels) > 0 and \ opAnnotations.Labels.ready() and \ opAnnotations.TrackImage.ready() opStructuredTracking = self.trackingApplet.topLevelOperator structured_tracking_ready = objectCountClassifier_ready and \ len(opStructuredTracking.EventsVector) > 0 busy = False busy |= self.dataSelectionApplet.busy busy |= self.annotationsApplet.busy # busy |= self.dataExportAnnotationsApplet.busy busy |= self.trackingApplet.busy busy |= self.dataExportTrackingApplet.busy self._shell.enableProjectChanges( not busy ) self._shell.setAppletEnabled(self.dataSelectionApplet, not busy) if not self.fromBinary: self._shell.setAppletEnabled(self.thresholdTwoLevelsApplet, input_ready and not busy) self._shell.setAppletEnabled(self.trackingFeatureExtractionApplet, thresholding_ready and not busy) self._shell.setAppletEnabled(self.cellClassificationApplet, tracking_features_ready and not busy) self._shell.setAppletEnabled(self.divisionDetectionApplet, tracking_features_ready and not busy) self._shell.setAppletEnabled(self.cropSelectionApplet, thresholding_ready and not busy) self._shell.setAppletEnabled(self.objectExtractionApplet, not busy) self._shell.setAppletEnabled(self.annotationsApplet, features_ready and not busy) # self._shell.setAppletEnabled(self.dataExportAnnotationsApplet, annotations_ready and not busy and \ # self.dataExportAnnotationsApplet.topLevelOperator.Inputs[0][0].ready() ) self._shell.setAppletEnabled(self.trackingApplet, objectCountClassifier_ready and not busy) self._shell.setAppletEnabled(self.dataExportTrackingApplet, structured_tracking_ready and not busy and \ self.dataExportTrackingApplet.topLevelOperator.Inputs[0][0].ready() )