def makeTranslationUI(affines, imp, show=True, print_button_text="Print transforms"): """ A GUI to control the translation components of a list of AffineTransform3D instances. When updated, the ImagePlus is refreshed. affines: a list (will be read multiple times) of one affine transform per image. imp: the ImagePlus that hosts the virtual stack with the transformed images. show: defaults to True, whether to make the GUI visible. print_button_text: whatever you want the print button to read like, defaults to "Print transforms". Returns the JFrame, the main JPanel and the lower JButton panel. """ panel = JPanel() panel.setBorder(BorderFactory.createEmptyBorder(10,10,10,10)) gb = GridBagLayout() panel.setLayout(gb) gc = GBC() gc.anchor = GBC.WEST gc.fill = GBC.NONE # Column labels gc.gridy = 0 for i, title in enumerate(["Camera", "translation X", "translation Y", "translation Z"]): gc.gridx = i gc.anchor = GBC.CENTER label = JLabel(title) gb.setConstraints(label, gc) panel.add(label) gc.anchor = GBC.WEST listeners = [] # One row per affine to control: skip the first for i, affine in enumerate(affines[1:]): gc.gridx = 0 gc.gridy += 1 label = JLabel("CM0%i: " % (i + 1)) gb.setConstraints(label, gc) panel.add(label) # One JTextField per dimension for dimension, translation in enumerate(affine.getTranslation()): tf = JTextField(str(translation), 10) listener = MatrixTextFieldListener(affine, dimension, tf, imp) listeners.append(listener) imp.addImageListener(listener) # to disable the JTextField when closed tf.addKeyListener(listener) tf.addMouseWheelListener(listener) gc.gridx += 1 gb.setConstraints(tf, gc) panel.add(tf) # Documentation for the user help_lines = ["Type a number and push enter,", "or use the scroll wheel."] gc.gridx = 0 gc.gridwidth = 4 for line in help_lines: gc.gridy += 1 help = JLabel(line) gb.setConstraints(help, gc) panel.add(help) # Buttons printButton = JButton(print_button_text) def printTransforms(event): for i, aff in enumerate(affines): # print all, including the first matrix = zeros(12, 'd') aff.toArray(matrix) msg = "# Coarse affine matrix " + str(i) + ": \n" + \ "affine" + str(i) + ".set(*[%f, %f, %f, %f,\n %f, %f, %f, %f,\n %f, %f, %f, %f])" % tuple(matrix.tolist()) # Print everywhere print msg IJ.log(msg) System.out.println(msg) printButton.addActionListener(printTransforms) gc.gridx = 0 gc.gridy += 1 gc.gridwidth = 4 button_panel = JPanel() button_panel.add(printButton) gb.setConstraints(button_panel, gc) panel.add(button_panel) frame = JFrame("Translation control") frame.setDefaultCloseOperation(JFrame.DO_NOTHING_ON_CLOSE) frame.addWindowListener(CloseControl(destroyables=listeners)) frame.getContentPane().add(panel) frame.pack() frame.setLocationRelativeTo(None) # center in the screen frame.setVisible(show) return frame, panel, button_panel
def makeCropUI(imp, images, tgtDir, panel=None, cropContinuationFn=None): """ imp: the ImagePlus to work on. images: the list of ImgLib2 images, one per frame, not original but already isotropic. (These are views that use a nearest neighbor interpolation using the calibration to scale to isotropy.) tgtDir: the target directory where e.g. CSV files will be stored, for ROI, features, pointmatches. panel: optional, a JPanel controlled by a GridBagLayout. cropContinuationFn: optional, a function to execute after cropping, which is given as arguments the original images, minC, maxC (both define a ROI), and the cropped images. """ independent = None == panel if not panel: panel = JPanel() panel.setBorder(BorderFactory.createEmptyBorder(10,10,10,10)) gb = GridBagLayout() gc = GBC() else: gb = panel.getLayout() # Constraints of the last component gc = gb.getConstraints(panel.getComponent(panel.getComponentCount() - 1)) # Horizontal line to separate prior UI components from crop UI gc.gridx = 0 gc.gridy += 1 gc.gridwidth = 4 gc.anchor = GBC.WEST gc.fill = GBC.HORIZONTAL sep = JSeparator() sep.setMinimumSize(Dimension(200, 10)) gb.setConstraints(sep, gc) panel.add(sep) # ROI UI header title = JLabel("ROI controls:") gc.gridy +=1 gc.anchor = GBC.WEST gc.gridwidth = 4 gb.setConstraints(title, gc) panel.add(title) # Column labels for the min and max coordinates gc.gridy += 1 gc.gridwidth = 1 for i, title in enumerate(["", "X", "Y", "Z"]): gc.gridx = i gc.anchor = GBC.CENTER label = JLabel(title) gb.setConstraints(label, gc) panel.add(label) textfields = [] rms = [] # Load stored ROI if any roi_path = path = os.path.join(tgtDir, "crop-roi.csv") if os.path.exists(roi_path): with open(roi_path, 'r') as csvfile: reader = csv.reader(csvfile, delimiter=',', quotechar="\"") reader.next() # header minC = map(int, reader.next()[1:]) maxC = map(int, reader.next()[1:]) # Place the ROI over the ImagePlus imp.setRoi(Roi(minC[0], minC[1], maxC[0] + 1 - minC[0], maxC[1] + 1 - minC[1])) else: # Use whole image dimensions minC = [0, 0, 0] maxC = [v -1 for v in Intervals.dimensionsAsLongArray(images[0])] # Text fields for the min and max coordinates for rowLabel, coords in izip(["min coords: ", "max coords: "], [minC, maxC]): gc.gridx = 0 gc.gridy += 1 label = JLabel(rowLabel) gb.setConstraints(label, gc) panel.add(label) for i in xrange(3): gc.gridx += 1 tf = JTextField(str(coords[i]), 10) gb.setConstraints(tf, gc) panel.add(tf) textfields.append(tf) listener = RoiMaker(imp, textfields, len(textfields) -1) rms.append(listener) tf.addKeyListener(listener) tf.addMouseWheelListener(listener) # Listen to changes in the ROI of imp rfl = RoiFieldListener(imp, textfields) Roi.addRoiListener(rfl) # ... and enable cleanup ImagePlus.addImageListener(FieldDisabler(rfl, rms)) # Functions for cropping images cropped = None cropped_imp = None def storeRoi(minC, maxC): if os.path.exists(roi_path): # Load ROI with open(path, 'r') as csvfile: reader = csv.reader(csvfile, delimiter=',', quotechar="\"") reader.next() # header same = True for a, b in izip(minC + maxC, map(int, reader.next()[1:] + reader.next()[1:])): if a != b: same = False # Invalidate any CSV files for features and pointmatches: different cropping for filename in os.listdir(tgtDir): if filename.endswith("features.csv") or filename.endswith("pointmatches.csv"): os.remove(os.path.join(tgtDir, filename)) break if same: return # Store the ROI as crop-roi.csv with open(roi_path, 'w') as csvfile: w = csv.writer(csvfile, delimiter=',', quotechar="\"", quoting=csv.QUOTE_NONNUMERIC) w.writerow(["coords", "x", "y", "z"]) w.writerow(["min"] + map(int, minC)) w.writerow(["max"] + map(int, maxC)) def crop(event): global cropped, cropped_imp coords = [int(float(tf.getText())) for tf in textfields] minC = [max(0, c) for c in coords[0:3]] maxC = [min(d -1, c) for d, c in izip(Intervals.dimensionsAsLongArray(images[0]), coords[3:6])] storeRoi(minC, maxC) print "ROI min and max coordinates" print minC print maxC cropped = [Views.zeroMin(Views.interval(img, minC, maxC)) for img in images] cropped_imp = showAsStack(cropped, title="cropped") cropped_imp.setDisplayRange(imp.getDisplayRangeMin(), imp.getDisplayRangeMax()) if cropContinuationFn: cropContinuationFn(images, minC, maxC, cropped, cropped_imp) # Buttons to create a ROI and to crop to ROI, # which when activated enables the fine registration buttons crop_button = JButton("Crop to ROI") crop_button.addActionListener(crop) gc.gridx = 0 gc.gridy += 1 gc.gridwidth = 4 gc.anchor = GBC.WEST buttons_panel = JPanel() buttons_panel.add(crop_button) gb.setConstraints(buttons_panel, gc) panel.add(buttons_panel) if independent: frame = JFrame("Crop by ROI") frame.getContentPane().add(panel) frame.pack() frame.setDefaultCloseOperation(JFrame.DO_NOTHING_ON_CLOSE) frame.addWindowListener(CloseControl(destroyables=rms + [rfl])) frame.setVisible(True) else: # Re-pack the JFrame parent = panel.getParent() while not isinstance(parent, JFrame) and parent is not None: parent = parent.getParent() if parent: frame = parent frame.pack() found = False for wl in frame.getWindowListeners(): if isinstance(wl, CloseControl): wl.addDestroyables(rms + [rfl]) found = True break if not found: frame.addWindowListener(CloseControl(destroyables=rms + [rfl])) frame.setVisible(True) return panel
def specifyRoiUI(roi=Roi(0, 0, 0, 0)): # A panel in which to place UI elements panel = JPanel() panel.setBorder(BorderFactory.createEmptyBorder(10, 10, 10, 10)) gb = GridBagLayout() panel.setLayout(gb) gc = GBC() bounds = roi.getBounds() if roi else Rectangle() textfields = [] roimakers = [] # Basic properties of most UI elements, will edit when needed gc.gridx = 0 # can be any natural number gc.gridy = 0 # idem. gc.gridwidth = 1 # when e.g. 2, the UI element will occupy two horizontally adjacent grid cells gc.gridheight = 1 # same but vertically gc.fill = GBC.NONE # can also be BOTH, VERTICAL and HORIZONTAL for title in ["x", "y", "width", "height"]: # label gc.gridx = 0 gc.anchor = GBC.EAST label = JLabel(title + ": ") gb.setConstraints(label, gc) # copies the given constraints 'gc', # so we can modify and reuse gc later. panel.add(label) # text field, below the title gc.gridx = 1 gc.anchor = GBC.WEST text = str(getattr(bounds, title)) # same as e.g. bounds.x, bounds.width, ... textfield = JTextField(text, 10) # 10 is the size of the field, in digits gb.setConstraints(textfield, gc) panel.add(textfield) textfields.append( textfield) # collect all 4 created textfields for the listeners # setup ROI and text field listeners listener = RoiMaker(textfields, len(textfields) - 1) # second argument is the index of textfield # in the list of textfields. roimakers.append(listener) textfield.addKeyListener(listener) textfield.addMouseWheelListener(listener) # Position next ROI property in a new row by increasing the Y coordinate of the layout grid gc.gridy += 1 # User documentation (uses HTML to define line breaks) doc = JLabel( "<html><body><br />Click on a field to activate it, then:<br />" + "Type in integer numbers<br />" + "or use arrow keys to increase by 1<br />" + "or use the scroll wheel on a field.</body></html>") gc.gridx = 0 # start at the first column gc.gridwidth = 2 # Spans both columns gb.setConstraints(doc, gc) panel.add(doc) # Listen to changes in the ROI of imp roilistener = TextFieldUpdater(textfields) Roi.addRoiListener(roilistener) # Show window frame = JFrame("Specify rectangular ROI") frame.getContentPane().add(panel) frame.pack() frame.setLocationRelativeTo(None) # center in the screen frame.setDefaultCloseOperation( JFrame.DO_NOTHING_ON_CLOSE) # prevent closing the window frame.addWindowListener( CloseControl(roilistener)) # handles closing the window frame.setVisible(True)