''' MULTI-CLASS CHECKBOX This script can be used to manually classify full images or ROIs into user-defined categories. Mutliple categories can be assigned to an image using the checkboxes. A first window pops up asking where to get the categories: - Memory : read persisted values from memory - Active table : parse a prevous annotation table - Text file : read a text file with one category per row A second window follows with text fields to edit the category names Leaving a field empty results in removing this category. Once OK the annotation window shows up with one checkbox per category. Clicking on the button will generate a new entry in a table with the image name and the category. It will also skip to the next slice for stacks. ''' #@ String (Label="Read categories from", choices={"Text file", "Active table", "Memory"}, value="Memory" ) categorySource #@ File (label="Text file (if selected above)", style="file", required=false) textFile #@ String (label="Browsing mode", choices={"stack", "directory"}) browse_mode #@ Boolean (label="Run measure", value=false) run_measure from fiji.util.gui import GenericDialogPlus from ij import IJ, Prefs from java.awt import GridLayout, Button, Panel, Checkbox from java.awt.event import ActionListener from QualiAnnotations.utils import getCategoriesFrom, CustomDialog from QualiAnnotations.CategoryDialog import CategoryDialog import os class SaveAction(ActionListener): """Define what happens when the save category button is pressed.""" def __init__(self, dialog): self.dialog = dialog def actionPerformed(self, event): outDir = IJ.getDirectory("Save category file in directory...") if not outDir: return # when cancelled filename = IJ.getString("Filename", "categories.txt") if not filename: return # when cancelled outPath = os.path.join(outDir, filename) listCheckboxes = self.dialog.getPanel().getComponents() with open(outPath, "w") as catFile: for checkbox in listCheckboxes: catFile.write(checkbox.getLabel().encode("utf-8") + "\n") # important to use UTF-8 otherwise troubles class MainDialog(CustomDialog): """ Main annotation dialog for this plugin In this case the panel contains checkboxes """ def __init__(self, panel, browseMode="stack", runMeasure=False): title = "Qualitative Annotations - multi-classes (checkboxes)" message = """Tick the categories corresponding to the current image, then click 'Add' or press the '+' key. To annotate ROI, draw a new ROI or select some ROI(s) in the RoiManager before clicking 'Add'/pressing '+'.""" CustomDialog.__init__(self, title, message, panel) self.addButton("Add new category", self) # the GUI also catches the event for this button too self.addToSameRow() self.addButton("Save categories to file", SaveAction(self)) self.addStringField("Comments", "") self.addButton(CustomDialog.LABEL_ADD, self) self.browseMode = browseMode # important to define it before addDefaultOptions and nextSlice... self.runMeasure = runMeasure self.addDefaultOptions() def fillTable(self, table): '''Read checkbox state and update table''' for checkbox in self.getPanel().getComponents(): table.addValue( checkbox.getLabel(), checkbox.getState() ) def keyPressed(self, keyEvent): """Define shortcut: pressing any of the + key also adds to the table like the Add button""" code = keyEvent.getKeyCode() if code == keyEvent.VK_ADD or code==keyEvent.VK_PLUS: self.defaultActionSequence() def makeCategoryComponent(self, category): """ Generates a checkbox with the new category name, to add to the GUI Overwrite the original method """ stringCat = Prefs.get("annot.listCat", "") newStringCat = stringCat + "," + category if stringCat else category Prefs.set("annot.listCat", newStringCat) # Make a new checkbox with the category name checkbox = Checkbox(category, False) checkbox.setFocusable(False) # important to have the keybard shortcut working return checkbox ############### GUI - CATEGORY DIALOG ############# textFilePath = textFile.getPath() if textFile else "" listCategories = getCategoriesFrom(categorySource, textFilePath) # Initialize a category dialog with list of categories catDialog = CategoryDialog(listCategories) catDialog.showDialog() # Recover fields from the formular if catDialog.wasOKed(): # Loop over categories, adding a tickbox to the panel for each catPanel = Panel(GridLayout(0,4)) # Unlimited number of rows - fix to 4 columns for category in catDialog.getListCategories(): # Make a checkbox with the category name box = Checkbox(category, False) box.setFocusable(False) # important to have the keyboard shortcut working # Add checkbox to the gui for this category catPanel.add(box) ## Initialize dialog winButton = MainDialog(catPanel, browse_mode, run_measure) winButton.showDialog()