|
RoiManager |
|
package ij.plugin.frame; import java.awt.*; import java.awt.event.*; import java.io.*; import java.util.*; import java.awt.List; import java.util.zip.*; import ij.*; import ij.process.*; import ij.gui.*; import ij.io.*; import ij.plugin.filter.*; import ij.util.Tools; import ij.macro.Interpreter; import ij.measure.Calibration; /** This plugin implements the Analyze/Tools/ROI Manager command. */ public class RoiManager extends PlugInFrame implements ActionListener, ItemListener { static final int BUTTONS = 10; Panel panel; static Frame instance; java.awt.List list; Hashtable rois = new Hashtable(); Roi roiCopy; int slice2; boolean canceled; boolean macro; boolean ignoreInterrupts; public RoiManager() { super("ROI Manager"); if (instance!=null) { instance.toFront(); return; } instance = this; ImageJ ij = IJ.getInstance(); addKeyListener(ij); WindowManager.addWindow(this); setLayout(new FlowLayout(FlowLayout.CENTER,5,5)); int rows = 15; boolean allowMultipleSelections = IJ.isMacintosh(); list = new List(rows, allowMultipleSelections); list.add("012345678901234"); list.addItemListener(this); list.addKeyListener(ij); add(list); panel = new Panel(); int nButtons = IJ.isJava2()?BUTTONS:BUTTONS-1; panel.setLayout(new GridLayout(nButtons, 1, 5, 0)); addButton("Add"); addButton("Update"); addButton("Delete"); addButton("Rename"); addButton("Open"); addButton("Save"); addButton("Measure"); addButton("Draw"); addButton("Deselect"); if (IJ.isJava2()) addButton("Combine"); add(panel); pack(); list.remove(0); GUI.center(this); show(); } void addButton(String label) { Button b = new Button(label); b.addActionListener(this); b.addKeyListener(IJ.getInstance()); panel.add(b); } public void actionPerformed(ActionEvent e) { int modifiers = e.getModifiers(); boolean altKeyDown = (modifiers&ActionEvent.ALT_MASK)!=0 || IJ.altKeyDown(); boolean shiftKeyDown = (modifiers&ActionEvent.SHIFT_MASK)!=0 || IJ.shiftKeyDown(); IJ.setKeyUp(KeyEvent.VK_ALT); IJ.setKeyUp(KeyEvent.VK_SHIFT); String label = e.getActionCommand(); if (label==null) return; String command = label; if (command.equals("Add")) add(shiftKeyDown, altKeyDown); else if (command.equals("Update")) update(); else if (command.equals("Delete")) delete(false); else if (command.equals("Rename")) rename(); else if (command.equals("Open")) open(null); else if (command.equals("Save")) save(); else if (command.equals("Measure")) measure(); else if (command.equals("Draw")) draw(); else if (command.equals("Deselect")) select(-1); else if (command.equals("Combine")) combine(); } public void itemStateChanged(ItemEvent e) { //IJ.log("itemStateChanged: "+e.getItem().toString()+" "+e+" "+ignoreInterrupts); if (e.getStateChange()==ItemEvent.SELECTED && WindowManager.getCurrentImage()!=null && !ignoreInterrupts) { int index = 0; try {index = Integer.parseInt(e.getItem().toString());} catch (NumberFormatException ex) {} if (index<0) index = 0; restore(index, true); } } void add(boolean shiftKeyDown, boolean altKeyDown) { if (shiftKeyDown) addAndDraw(altKeyDown); else if (altKeyDown) add(true); else add(false); } boolean add(boolean promptForName) { ImagePlus imp = getImage(); if (imp==null) return false; Roi roi = imp.getRoi(); if (roi==null) { error("The active image does not have a selection."); return false; } String name = roi.getName(); int slice1 = imp.getCurrentSlice(); if (name!=null && roiCopy!=null && name.equals(roiCopy.getName()) && name.indexOf('-')!=-1) { Rectangle r1 = roi.getBounds(); Rectangle r2 = roiCopy.getBounds(); if (r1.x!=r2.x || r1.y!=r2.y || slice1!=slice2) name = null; } String label = name!=null?name:getLabel(imp, roi); if (promptForName) label = getName(label); else label = getUniqueName(label); if (label==null) return false; list.add(label); roi.setName(label); roiCopy = (Roi)roi.clone(); Calibration cal = imp.getCalibration(); if (cal.xOrigin!=0.0 || cal.yOrigin!=0.0) { Rectangle r = roiCopy.getBounds(); roiCopy.setLocation(r.x-(int)cal.xOrigin, r.y-(int)cal.yOrigin); } slice2 = slice1; rois.put(label, roiCopy); if (Recorder.record) Recorder.record("roiManager", "Add"); return true; } String getLabel(ImagePlus imp, Roi roi) { Rectangle r = roi.getBounds(); int xc = r.x + r.width/2; int yc = r.y + r.height/2; if (xc<0) xc = 0; if (yc<0) yc = 0; int digits = 4; String xs = "" + xc; if (xs.length()>digits) digits = xs.length(); String ys = "" + yc; if (ys.length()>digits) digits = ys.length(); xs = "000" + xc; ys = "000" + yc; String label = ys.substring(ys.length()-digits) + "-" + xs.substring(xs.length()-digits); if (imp.getStackSize()>1) { String zs = "000" + imp.getCurrentSlice(); label = zs.substring(zs.length()-digits) + "-" + label; } return label; } void addAndDraw(boolean altKeyDown) { if (altKeyDown) { if (!add(true)) return; } else if (!add(false)) return; ImagePlus imp = WindowManager.getCurrentImage(); Undo.setup(Undo.COMPOUND_FILTER, imp); IJ.run("Draw"); Undo.setup(Undo.COMPOUND_FILTER_DONE, imp); if (Recorder.record) Recorder.record("roiManager", "Add & Draw"); } boolean delete(boolean replacing) { int count = list.getItemCount(); if (count==0) return error("The list is empty."); int index[] = list.getSelectedIndexes(); if (index.length==0 || (replacing&&count>1)) { String msg = "Delete all items on the list?"; if (replacing) msg = "Replace items on the list?"; canceled = false; if (!IJ.macroRunning() && !macro) { YesNoCancelDialog d = new YesNoCancelDialog(this, "ROI Manager", msg); if (d.cancelPressed()) {canceled = true; return false;} if (!d.yesPressed()) return false; } index = getAllIndexes(); } for (int i=count-1; i>=0; i--) { boolean delete = false; for (int j=0; j<index.length; j++) { if (index[j]==i) delete = true; } if (delete) { rois.remove(list.getItem(i)); list.remove(i); } } return true; } boolean update() { ImagePlus imp = getImage(); if (imp==null) return false; Roi roi = imp.getRoi(); if (roi==null) { error("The active image does not have a selection."); return false; } int index = list.getSelectedIndex(); if (index<0) return error("Exactly one item in the list must be selected."); String name = list.getItem(index); rois.remove(name); rois.put(name, roi); return true; } boolean rename() { int index = list.getSelectedIndex(); if (index<0) return error("Exactly one item in the list must be selected."); String name = list.getItem(index); String name2 = getName(name); if (name2==null) return false; Roi roi = (Roi)rois.get(name); rois.remove(name); roi.setName(name2); rois.put(name2, roi); list.replaceItem(name2, index); list.select(index); return true; } String getName(String name) { GenericDialog gd = new GenericDialog("ROI Manager"); gd.addStringField("Rename As:", name, 20); gd.showDialog(); if (gd.wasCanceled()) return null; String name2 = gd.getNextString(); name2 = getUniqueName(name2); return name2; } boolean restore(int index, boolean setSlice) { String label = list.getItem(index); Roi roi = (Roi)rois.get(label); ImagePlus imp = getImage(); if (imp==null || roi==null) return false; if (setSlice) { int slice = getSliceNumber(label); if (slice>=1 && slice<=imp.getStackSize()) imp.setSlice(slice); } Roi roi2 = (Roi)roi.clone(); Calibration cal = imp.getCalibration(); if (cal.xOrigin!=0.0 || cal.yOrigin!=0.0) { Rectangle r = roi2.getBounds(); roi2.setLocation(r.x+(int)cal.xOrigin, r.y+(int)cal.yOrigin); } imp.setRoi(roi2); return true; } int getSliceNumber(String label) { int slice = -1; if (label.length()>4 && label.charAt(4)=='-' && label.length()>=14) slice = (int)Tools.parseDouble(label.substring(0,4),-1); return slice; } void open(String path) { Macro.setOptions(null); String name = null; if (path==null) { OpenDialog od = new OpenDialog("Open Selection(s)...", ""); String directory = od.getDirectory(); name = od.getFileName(); if (name==null) return; path = directory + name; } if (Recorder.record) Recorder.record("roiManager", "Open", path); if (path.endsWith(".zip")) { openZip(path); return; } Opener o = new Opener(); if (name==null) name = o.getName(path); Roi roi = o.openRoi(path); if (roi!=null) { if (name.endsWith(".roi")) name = name.substring(0, name.length()-4); name = getUniqueName(name); list.add(name); rois.put(name, roi); } } // Modified on 2005/11/15 by Ulrik Stervbo to only read .roi files and to not empty the current list void openZip(String path) { ZipInputStream in = null; ByteArrayOutputStream out; int nRois = 0; try { in = new ZipInputStream(new FileInputStream(path)); byte[] buf = new byte[1024]; int len; ZipEntry entry = in.getNextEntry(); while (entry!=null) { String name = entry.getName(); if (name.endsWith(".roi")) { out = new ByteArrayOutputStream(); while ((len = in.read(buf)) > 0) out.write(buf, 0, len); out.close(); byte[] bytes = out.toByteArray(); RoiDecoder rd = new RoiDecoder(bytes, name); Roi roi = rd.getRoi(); if (roi!=null) { name = name.substring(0, name.length()-4); name = getUniqueName(name); list.add(name); rois.put(name, roi); nRois++; } } entry = in.getNextEntry(); } in.close(); } catch (IOException e) {error(e.toString());} if(nRois==0) error("This ZIP archive does not appear to contain \".roi\" files"); } String getUniqueName(String name) { String name2 = name; int n = 1; Roi roi2 = (Roi)rois.get(name2); while (roi2!=null) { roi2 = (Roi)rois.get(name2); if (roi2!=null) { int lastDash = name2.lastIndexOf("-"); if (lastDash!=-1 && name2.length()-lastDash<5) name2 = name2.substring(0, lastDash); name2 = name2+"-"+n; n++; } roi2 = (Roi)rois.get(name2); } return name2; } boolean save() { if (list.getItemCount()==0) return error("The selection list is empty."); int[] indexes = list.getSelectedIndexes(); if (indexes.length==0) indexes = getAllIndexes(); if (indexes.length>1) return saveMultiple(indexes, null); String name = list.getItem(indexes[0]); Macro.setOptions(null); SaveDialog sd = new SaveDialog("Save Selection...", name, ".roi"); String name2 = sd.getFileName(); if (name2 == null) return false; String dir = sd.getDirectory(); Roi roi = (Roi)rois.get(name); rois.remove(name); if (!name2.endsWith(".roi")) name2 = name2+".roi"; String newName = name2.substring(0, name2.length()-4); rois.put(newName, roi); roi.setName(newName); list.replaceItem(newName, indexes[0]); if (restore(indexes[0], true)) IJ.run("Selection...", "path='"+dir+name2+"'"); return true; } boolean saveMultiple(int[] indexes, String path) { Macro.setOptions(null); if (path==null) { SaveDialog sd = new SaveDialog("Save ROIs...", "RoiSet", ".zip"); String name = sd.getFileName(); if (name == null) return false; String dir = sd.getDirectory(); path = dir+name; } try { ZipOutputStream zos = new ZipOutputStream(new FileOutputStream(path)); DataOutputStream out = new DataOutputStream(new BufferedOutputStream(zos)); RoiEncoder re = new RoiEncoder(out); for (int i=0; i<indexes.length; i++) { String label = list.getItem(indexes[i]); Roi roi = (Roi)rois.get(label); if (!label.endsWith(".roi")) label += ".roi"; zos.putNextEntry(new ZipEntry(label)); re.write(roi); out.flush(); } out.close(); } catch (IOException e) { error(""+e); return false; } if (Recorder.record) Recorder.record("roiManager", "Save", path); return true; } /* boolean save() { if (list.getItemCount()==0) return error("The selection list is empty."); int[] indexes = list.getSelectedIndexes(); if (indexes.length==0) indexes = getAllIndexes(); String name = list.getItem(indexes[0]); Macro.setOptions(null); SaveDialog sd = new SaveDialog("Save Selection...", name, ".roi"); String name2 = sd.getFileName(); if (name2 == null) return false; String dir = sd.getDirectory(); if (indexes.length==1) { Roi roi = (Roi)rois.get(name); rois.remove(name); if (!name2.endsWith(".roi")) name = name+".roi"; String newName = name2.substring(0, name2.length()-4); rois.put(newName, roi); list.replaceItem(newName, indexes[0]); if (restore(indexes[0])) IJ.run("Selection...", "path='"+dir+name2+"'"); return true; } for (int i=0; i<indexes.length; i++) { if (restore(indexes[i])) { name = list.getItem(indexes[i]); if (!name.endsWith(".roi")) name = name+".roi"; //IJ.log("Selection...," + " path='"+dir+name+"'"); IJ.run("Selection...", "path='"+dir+name+"'"); } else break; } return true; } */ boolean measure() { ImagePlus imp = getImage(); if (imp==null) return false; int[] indexes = list.getSelectedIndexes(); if (indexes.length==0) indexes = getAllIndexes(); if (indexes.length==0) return false; int nLines = 0; for (int i=0; i<indexes.length; i++) { String label = list.getItem(indexes[i]); Roi roi = (Roi)rois.get(label); if (roi.isLine()) nLines++; } if (nLines>0 && nLines!=indexes.length) { error("All items must be areas or all must be lines."); return false; } int nSlices = 1; String label = list.getItem(indexes[0]); if (getSliceNumber(label)==-1 || indexes.length==1) { int setup = IJ.setupDialog(imp, 0); if (setup==PlugInFilter.DONE) return false; nSlices = setup==PlugInFilter.DOES_STACKS?imp.getStackSize():1; } int currentSlice = imp.getCurrentSlice(); for (int slice=1; slice<=nSlices; slice++) { if (nSlices>1) imp.setSlice(slice); for (int i=0; i<indexes.length; i++) { if (restore(indexes[i], nSlices==1)) IJ.run("Measure"); else break; } } imp.setSlice(currentSlice); if (indexes.length>1) IJ.run("Select None"); if (Recorder.record) Recorder.record("roiManager", "Measure"); return true; } boolean draw() { int[] indexes = list.getSelectedIndexes(); if (indexes.length==0) indexes = getAllIndexes(); ImagePlus imp = WindowManager.getCurrentImage(); Undo.setup(Undo.COMPOUND_FILTER, imp); for (int i=0; i<indexes.length; i++) { if (restore(indexes[i], true)) { IJ.run("Draw"); IJ.run("Select None"); } else break; } Undo.setup(Undo.COMPOUND_FILTER_DONE, imp); if (Recorder.record) Recorder.record("roiManager", "Draw"); return true; } void combine() { ImagePlus imp = getImage(); if (imp==null) return; int[] indexes = list.getSelectedIndexes(); if (indexes.length<=1) indexes = getAllIndexes(); ShapeRoi s1=null, s2=null; for (int i=0; i<indexes.length; i++) { Roi roi = (Roi)rois.get(list.getItem(indexes[i])); if (roi.isLine() || roi.getType()==Roi.POINT) continue; Calibration cal = imp.getCalibration(); if (cal.xOrigin!=0.0 || cal.yOrigin!=0.0) { roi = (Roi)roi.clone(); Rectangle r = roi.getBounds(); roi.setLocation(r.x+(int)cal.xOrigin, r.y+(int)cal.yOrigin); } if (s1==null) { if (roi instanceof ShapeRoi) s1 = (ShapeRoi)roi; else s1 = new ShapeRoi(roi); if (s1==null) return; } else { if (roi instanceof ShapeRoi) s2 = (ShapeRoi)roi; else s2 = new ShapeRoi(roi); if (s2==null) continue; if (roi.isArea()) s1.or(s2); } } if (s1!=null) imp.setRoi(s1); if (Recorder.record) Recorder.record("roiManager", "Combine"); } /* void split() { ImagePlus imp = getImage(); if (imp==null) return; Roi roi = imp.getRoi(); if (roi==null || roi.getType()!=Roi.COMPOSITE) { error("Image with composite selection required"); return; } Roi[] rois = ((ShapeRoi)roi).getRois(); if (rois.length<2) { error("Enable to decompose this composite ROI into two or more simple ROIs."); return; } //IJ.log("split: "+list.getItemCount()); if (list.getItemCount()>0) { if (!delete(true)) { //IJ.log("delete: false"); return; } //IJ.log("delete: true"); } for (int i=0; i<rois.length; i++) { imp.setRoi(rois[i]); add(); } if (Recorder.record) Recorder.record("roiManager", "Split"); } */ int[] getAllIndexes() { int count = list.getItemCount(); int[] indexes = new int[count]; for (int i=0; i<count; i++) indexes[i] = i; return indexes; } ImagePlus getImage() { ImagePlus imp = WindowManager.getCurrentImage(); if (imp==null) { error("There are no images open."); return null; } else return imp; } boolean error(String msg) { new MessageDialog(this, "ROI Manager", msg); Macro.abort(); return false; } public void processWindowEvent(WindowEvent e) { super.processWindowEvent(e); if (e.getID()==WindowEvent.WINDOW_CLOSING) { instance = null; } ignoreInterrupts = false; } /** Returns a reference to the ROI Manager or null if it is not open. */ public static RoiManager getInstance() { return (RoiManager)instance; } /** Returns the ROI Hashtable. */ public Hashtable getROIs() { return rois; } /** Returns the selection list. */ public List getList() { return list; } /** Executes the ROI Manager "Add", "Add & Draw", "Delete", "Measure", "Draw", "Combine" command. Returns false if <code>cmd</code> is not one of these strings. */ public boolean runCommand(String cmd) { cmd = cmd.toLowerCase(); macro = true; boolean ok = true; if (cmd.equals("add")) add(IJ.shiftKeyDown(), IJ.altKeyDown()); else if (cmd.equals("add & draw")) addAndDraw(false); else if (cmd.equals("delete")) delete(false); else if (cmd.equals("measure")) measure(); else if (cmd.equals("draw")) draw(); else if (cmd.equals("combine")) combine(); else if (cmd.equals("deselect")) { if (IJ.isMacOSX()) ignoreInterrupts = true; select(-1); } else if (cmd.equals("reset")) list.removeAll(); else ok = false; macro = false; return ok; } /** Executes the ROI Manager "Open" or "Save" command. Returns false if <code>cmd</code> is not "Open" or "Save" or if an error occurs. */ public boolean runCommand(String cmd, String path) { cmd = cmd.toLowerCase(); macro = true; if (cmd.equals("open")) { open(path); macro = false; return true; } else if (cmd.equals("save")) { if (!path.endsWith(".zip")) return error("Path must end with '.zip'"); if (list.getItemCount()==0) return error("The selection list is empty."); int[] indexes = getAllIndexes(); boolean ok = saveMultiple(indexes, path); macro = false; return ok; } return false; } public void select(int index) { int n = list.getItemCount(); if (index<0) { for (int i=0; i<n; i++) if (list.isSelected(i)) list.deselect(i); return; } boolean mm = list.isMultipleMode(); if (mm) list.setMultipleMode(false); if (index<n) { list.select(index); restore(index, true); if (!Interpreter.isBatchMode()) IJ.wait(10); } if (mm) list.setMultipleMode(true); } /* void selectAll() { boolean allSelected = true; int count = list.getItemCount(); for (int i=0; i<count; i++) { if (!list.isIndexSelected(i)) allSelected = false; } if (allSelected) select(-1); else { for (int i=0; i<count; i++) if (!list.isSelected(i)) list.select(i); } } */ /** Overrides PlugInFrame.close(). */ public void close() { super.close(); instance = null; } }
|
RoiManager |
|