|
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; /** This plugin implements the Analyze/Tools/ROI Manager command. */ public class RoiManager extends PlugInFrame implements ActionListener, ItemListener { 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 = 16; list = new List(rows, true); list.add("0123456789012"); list.addItemListener(this); list.addKeyListener(ij); add(list); panel = new Panel(); int nButtons = IJ.isJava2()?10:9; panel.setLayout(new GridLayout(nButtons, 1, 5, 0)); addButton("Add"); addButton("Add & Draw"); addButton("Update"); addButton("Delete"); addButton("Open"); addButton("Open All"); addButton("Save"); addButton("Measure"); addButton("Draw"); 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); panel.add(b); } public void actionPerformed(ActionEvent e) { //int modifiers = e.getModifiers(); //boolean altKeyDown = (modifiers&ActionEvent.ALT_MASK)!=0; //IJ.log(modifiers + " "+altKeyDown); String label = e.getActionCommand(); if (label==null) return; String command = label; if (command.equals("Add")) add(); else if (command.equals("Add & Draw")) addAndDraw(); else if (command.equals("Update")) update(); else if (command.equals("Delete")) delete(false); else if (command.equals("Open")) open(null); else if (command.equals("Open All")) openAll(); else if (command.equals("Save")) save(); else if (command.equals("Measure")) measure(); else if (command.equals("Draw")) draw(); else if (command.equals("Combine")) combine(); } public void itemStateChanged(ItemEvent e) { 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); } } boolean add() { 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 type = null; switch (roi.getType()) { case Roi.RECTANGLE: type ="R"; break; case Roi.OVAL: type = "O"; break; case Roi.POLYGON: type = "P"; break; case Roi.FREEROI: type = "F"; break; case Roi.TRACED_ROI: type = "T"; break; case Roi.LINE: type = "L"; break; case Roi.POLYLINE: type = "PL"; break; case Roi.FREELINE: type = "FL"; break; case Roi.ANGLE: type = "A"; break; case Roi.COMPOSITE: type = "C"; break; case Roi.POINT: type = "p"; break; } if (type==null) 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, type); label = getUniqueName(label); list.add(label); roi.setName(label); roiCopy = (Roi)roi.clone(); slice2 = slice1; rois.put(label, roiCopy); if (Recorder.record) Recorder.record("roiManager", "Add"); return true; } String getLabel(ImagePlus imp, Roi roi, String type) { Rectangle r = roi.getBounds(); int xc = r.x + r.width/2; int yc = r.y + r.height/2; 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() { if (!add()) 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); GenericDialog gd = new GenericDialog("ROI Manager"); gd.addStringField("Rename As:", name, 20); gd.showDialog(); if (gd.wasCanceled()) return false; String name2 = gd.getNextString(); name2 = getUniqueName(name2); 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; } */ 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; //Rectangle r = roi.getBounds(); //if (r.x+r.width>imp.getWidth() || r.y+r.height>imp.getHeight()) // return error("This selection does not fit the current image."); if (setSlice) { int slice = getSlice(label); if (slice>=1 && slice<=imp.getStackSize()) imp.setSlice(slice); } imp.setRoi((Roi)roi.clone()); return true; } int getSlice(String label) { int slice = -1; if ((label.length()==14 && label.charAt(4)=='-') || (label.length()>14 && label.charAt(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); } } void openZip(String path) { ZipInputStream in = null; ByteArrayOutputStream out; try { in = new ZipInputStream(new FileInputStream(path)); byte[] buf = new byte[1024]; int len; boolean firstTime = true; while (true) { ZipEntry entry = in.getNextEntry(); if (entry==null) {in.close(); return;} String name = entry.getName(); if (!name.endsWith(".roi")) { error("This ZIP archive does not appear to contain \".roi\" files"); } 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) { if (firstTime) { if (list.getItemCount()>0) delete(true); if (canceled) {in.close(); return;} firstTime = false; } if (name.endsWith(".roi")) name = name.substring(0, name.length()-4); name = getUniqueName(name); list.add(name); rois.put(name, roi); } } } catch (IOException e) { error(""+e); } } 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) name2 = name+"-"+n; n++; roi2 = (Roi)rois.get(name2); } return name2; } void openAll() { IJ.setKeyUp(KeyEvent.VK_ALT); Macro.setOptions(null); String dir = IJ.getDirectory("Open All..."); if (dir==null) return; String[] files = new File(dir).list(); if (files==null) return; for (int i=0; i<files.length; i++) { File f = new File(dir+files[i]); if (!f.isDirectory() && files[i].endsWith(".roi")) { Roi roi = new Opener().openRoi(dir+files[i]); if (roi!=null) { String name = files[i]; if (name.endsWith(".roi")) name = name.substring(0, name.length()-4); name = getUniqueName(name); list.add(name); rois.put(name, roi); } } } } 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 (getSlice(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==0) 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; 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(); else if (cmd.equals("add & draw")) addAndDraw(); 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")) 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 = list.getSelectedIndexes(); if (indexes.length==0) indexes = getAllIndexes(); boolean ok = saveMultiple(indexes, path); macro = false; return ok; } return false; } public void select(int index) { ignoreInterrupts = true; int n = list.getItemCount(); for (int i=0; i<n; i++) if (list.isSelected(i)) list.deselect(i); if (index>=0 && index<n) { list.select(index); restore(index, true); IJ.wait(10); } } /** Overrides PlugInFrame.close(). */ public void close() { super.close(); instance = null; } }
|
RoiManager |
|