Java tutorial
package tango.gui; import tango.gui.util.LCRenderer; import mcib3d.utils.exceptionPrinter; import tango.dataStructure.Structure; import tango.dataStructure.Nucleus; import tango.dataStructure.Cell; import com.mongodb.BasicDBList; import java.awt.event.ActionEvent; import java.awt.event.AdjustmentEvent; import java.awt.event.MouseWheelEvent; import javax.swing.event.ListSelectionEvent; import tango.mongo.MongoConnector; import mcib3d.image3d.ImageHandler; import java.util.*; import java.io.*; import java.awt.Dimension; import com.mongodb.BasicDBObject; import com.mongodb.DBObject; import tango.dataStructure.AbstractStructure; import tango.dataStructure.Experiment; import tango.dataStructure.Field; import tango.dataStructure.Object3DGui; import mcib3d.utils.ThreadRunner; import ij.*; import ij.gui.NewImage; import ij.gui.PointRoi; import ij.gui.Roi; import ij.plugin.filter.ThresholdToSelection; import ij.process.ByteProcessor; import ij.process.ImageProcessor; import java.awt.*; import java.awt.event.ActionListener; import java.awt.event.AdjustmentListener; import java.awt.event.MouseWheelListener; import java.util.List; import javax.swing.*; import javax.swing.event.ListSelectionListener; import mcib3d.geom.Object3D; import mcib3d.geom.Voxel3D; import mcib3d.image3d.*; import mcib3d.image3d.processing.ManualSpot; import org.bson.types.ObjectId; import tango.dataStructure.*; import tango.gui.util.CellManagerLayout; import tango.gui.util.ObjectManagerLayout; import tango.helper.HelpManager; import tango.parameter.DoubleParameter; import tango.parameter.Parameter; import tango.parameter.StructureParameter; import tango.plugin.measurement.MeasurementKey; import tango.plugin.measurement.MeasurementObject; import tango.util.ImageUtils; /** * ** * /** * Copyright (C) 2012 Jean Ollion * * * * This file is part of tango * * tango is free software; you can redistribute it and/or modify it under the * terms of the GNU General Public License as published by the Free Software * Foundation; either version 3 of the License, or (at your option) any later * version. * * This program is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more * details. * * You should have received a copy of the GNU General Public License along with * this program. If not, see <http://www.gnu.org/licenses/>. * * @author Jean Ollion */ public class ObjectManager implements ListSelectionListener, AdjustmentListener, MouseWheelListener { protected javax.swing.JList list; protected DefaultListModel listModel; protected ListSelectionModel listSelectionModel; protected JPanel controlPanel, container; protected Core core; protected boolean populatingObjects, selectingObject; protected ObjectStructure[] currentChannels; protected int[] currentStructureIdx; protected ImagePlus currentImage; protected ImageByte roiMask; protected HashMap<Integer, Roi> currentROIs; protected JToggleButton showObjects, showMeasurements; protected Structure msChannel; protected JPanel layout; protected boolean autoSave; protected MeasurementDisplayer measurements; protected ObjectId currentNucId; protected ManualSpot manualSpot; protected DoubleParameter splitDist; protected DoubleParameter splitRad; protected JToggleButton showSelection; // ImagePlus roiMask; public ObjectManager(Core core, JPanel container) { try { this.container = container; this.core = core; this.autoSave = true; initPanels(); } catch (Exception e) { exceptionPrinter.print(e, "", Core.GUIMode); } } public void setShowSelection(JToggleButton showSelection) { this.showSelection = showSelection; } public void show(boolean refresh) { container.add(layout); if (refresh) { core.refreshDisplay(); } } public void hide(boolean refresh) { container.remove(layout); if (showMeasurements.isSelected()) { container.remove(measurements); showMeasurements.setSelected(false); } if (refresh) { core.refreshDisplay(); } } protected void initPanels() { BasicDBObject usr = Core.mongoConnector.getUser(); splitDist = new DoubleParameter("Dist", "splitMinDistObj", 5d, DoubleParameter.nfDEC1); splitDist.dbGet(usr); splitRad = new DoubleParameter("Rad", "splitRadObj", 2d, DoubleParameter.nfDEC1); splitRad.dbGet(usr); ObjectManagerLayout lay = new ObjectManagerLayout(this); showObjects = lay.showROIs; showObjects.setSelected(true); splitDist.addToContainer(lay.splitDistPanel); showMeasurements = lay.viewMeasurements; measurements = new MeasurementDisplayer(); this.listModel = new DefaultListModel(); this.list = lay.list; this.list.setModel(listModel); this.list.setCellRenderer(new LCRenderer()); this.list.setSelectionMode(ListSelectionModel.MULTIPLE_INTERVAL_SELECTION); this.list.setLayoutOrientation(JList.VERTICAL); listSelectionModel = list.getSelectionModel(); listSelectionModel.addListSelectionListener(this); this.layout = lay; } public void toggleIsRunning(boolean isRunning) { ((ObjectManagerLayout) this.layout).toggleIsRunning(isRunning); setSortKeys(); } public void saveOptions() { BasicDBObject user = Core.mongoConnector.getUser(); splitDist.dbPut(user); splitRad.dbPut(user); Core.mongoConnector.saveUser(user); } public void registerComponents(HelpManager hm) { if (this instanceof ObjectManager) { ((ObjectManagerLayout) layout).registerComponents(hm); } } public void setStructures(ObjectId id, List selectedChannels) { //System.out.println("Set Structures: cell"+id+ " sel channels length"+selectedChannels.length); this.currentNucId = id; this.currentChannels = new ObjectStructure[selectedChannels.size()]; currentStructureIdx = new int[selectedChannels.size()]; for (int i = 0; i < selectedChannels.size(); i++) { currentChannels[i] = (ObjectStructure) selectedChannels.get(i); currentStructureIdx[i] = currentChannels[i].getIdx(); } setSortKeys(); populateObjects(); if (showMeasurements.isSelected()) { measurements.setStructures(id, currentStructureIdx); measurements.setObjects(list.getSelectedValuesList()); } } private void setSortKeys() { if (currentChannels != null && currentChannels.length == 1) { MeasurementKey mkey = new MeasurementKey(new int[] { currentChannels[0].getIdx() }, MeasurementObject.Number); System.out.println("Query:" + mkey.toString()); ((ObjectManagerLayout) layout).setKeys(Core.getExperiment().getKeys().get(mkey)); } else { ((ObjectManagerLayout) layout).unableSortKeys(); } } public void populateObjects() { try { this.listModel.removeAllElements(); if (currentChannels == null) { return; } this.populatingObjects = true; ArrayList<Integer> selection = null; if (showSelection != null && showSelection.isSelected()) { selection = new ArrayList<Integer>(); } int currentIdx = 0; for (ObjectStructure ass : currentChannels) { Object3D[] os = ass.getObjects(); if (os != null) { Object3DGui[] osg = new Object3DGui[os.length]; for (int i = 0; i < os.length; i++) { osg[i] = new Object3DGui(os[i], ass); } if (layout instanceof ObjectManagerLayout && currentChannels.length == 1 && !((ObjectManagerLayout) layout).getSortKey().equals("idx")) { this.sort(((ObjectManagerLayout) layout).getSortKey(), osg, ass.getIdx()); } //System.out.println("populating objects.. nb objects:"+os.length); for (Object3DGui o3D : osg) { this.listModel.addElement(o3D); if (selection != null && o3D.isInSelection()) { selection.add(currentIdx); } currentIdx++; } //if (selection!=null) System.out.println("populating objects.. selection size:"+selection.size()); } //else System.out.println("no objects int channel:"+ass.getChannelName()); } if (selection != null && !selection.isEmpty()) { int[] sel = new int[selection.size()]; int i = 0; for (int idx : selection) { sel[i++] = idx; } list.setSelectedIndices(sel); } } catch (Exception e) { exceptionPrinter.print(e, "", Core.GUIMode); } this.populatingObjects = false; } public void invertSelection() { int[] sel = this.list.getSelectedIndices(); int[] newSel = new int[listModel.getSize() - sel.length]; int idx = 0; int lastIdx = -1; for (int i : sel) { for (int i2 = lastIdx + 1; i2 < i; i2++) { newSel[idx++] = i2; } lastIdx = i; } for (int i2 = lastIdx + 1; i2 < listModel.getSize(); i2++) { newSel[idx++] = i2; } list.setSelectedIndices(newSel); } protected int getChannelRank(ObjectStructure as) { int i = 0; while (currentChannels[i] != as) { i++; } return i; } public void manualSegmentation() { msChannel = null; if (currentChannels != null) { if (!(currentChannels[0] instanceof Nucleus)) { msChannel = (Structure) currentChannels[0]; } else if (currentChannels.length > 1) { msChannel = (Structure) currentChannels[1]; } } if (msChannel instanceof VirtualStructure) { return; } if (msChannel != null) { ImageInt seg = msChannel.getSegmented(); ImageHandler raw = msChannel.getFiltered(); if (raw == null) { if (Core.GUIMode) { ij.IJ.log("ERROR: no raw images!"); } return; } if (seg == null) { seg = new ImageShort(msChannel.getChannelName() + "::Segmented", raw.sizeX, raw.sizeY, raw.sizeZ); msChannel.setSegmented(seg); } seg.show(); raw.show(); manualSpot = new ManualSpot(raw.getImagePlus(), seg.getImagePlus(), (int) seg.getMax(null) + 1); manualSpot.setVisible(true); JButton msClose = manualSpot.jButtonClose; msClose.addActionListener(new java.awt.event.ActionListener() { public void actionPerformed(java.awt.event.ActionEvent evt) { if (msChannel != null) { msChannel.saveOutput(); msChannel.createObjects(); populateObjects(); } } }); } } private void sort(String key, Object3DGui[] objectsGui, int structureIdx) { Object3DGui.setAscendingOrger(((ObjectManagerLayout) layout).getAscendingOrder()); HashMap<Integer, BasicDBObject> objects = Core.getExperiment().getConnector().getObjects(currentNucId, structureIdx); boolean notFound = false; for (Object3DGui o : objectsGui) { BasicDBObject dbo = objects.get(o.getLabel()); if (dbo != null) { if (dbo.containsField(key)) { o.setValue(dbo.getDouble(key)); } else { o.setValue(-1); notFound = true; } } } if (notFound) { ij.IJ.log("Warning measurement: " + key + " not found for one or several objects"); } Arrays.sort(objectsGui); } public void deleteSelectedObjects() { populatingObjects = true; try { boolean[] modif = new boolean[currentChannels.length]; for (Object o : this.list.getSelectedValuesList()) { listModel.removeElement(o); modif[getChannelRank(((Object3DGui) o).getChannel())] = true; ((Object3DGui) o).delete(true); } for (int i = 0; i < currentChannels.length; i++) { if (modif[i]) { ImagePlus img = currentChannels[i].getSegmented().getImagePlus(); if (img.isVisible()) { img.updateAndDraw(); } currentChannels[i].createObjects(); if (autoSave) { currentChannels[i].saveOutput(); } } } } catch (Exception e) { exceptionPrinter.print(e, "", Core.GUIMode); } populatingObjects = false; } public void setSelectedObjectsFromDB() { this.selectingObject = true; this.list.clearSelection(); int offsetIdx = 0; ArrayList<Integer> selectedIndices = new ArrayList<Integer>(); for (ObjectStructure s : this.currentChannels) { BasicDBList selectedObjects = Core.mongoConnector.getSelectedObjects(currentNucId, s.getIdx()); if (selectedObjects != null && !selectedObjects.isEmpty()) { for (Object o : selectedObjects) { selectedIndices.add((Integer) o + offsetIdx); } } offsetIdx += s.getObjects().length; } if (!selectedIndices.isEmpty()) { int[] selectedIdx = new int[selectedIndices.size()]; for (int i = 0; i < selectedIdx.length; i++) { selectedIdx[i] = selectedIndices.get(i); } this.list.setSelectedIndices(selectedIdx); } this.selectingObject = false; } protected void registerActiveImage() { ImagePlus activeImage = WindowManager.getCurrentImage(); if (activeImage != null && activeImage.getProcessor() != null) { // && activeImage.getImageStackSize() > 1 if (currentImage != null && currentImage.getWindow() != null && currentImage != activeImage) { //System.out.println("remove listener:"+currentImage.getTitle()); ImageUtils.removeScrollListener(currentImage, this, this); currentImage.killRoi(); currentImage.updateAndDraw(); currentImage = null; } if (currentImage != activeImage) { //System.out.println("add listener:"+activeImage.getTitle()); ImageUtils.addScrollListener(activeImage, this, this); this.currentImage = activeImage; } } } public void showRois3D() { registerActiveImage(); if (currentImage == null) { return; } //verifier que l'image active a les memes dimentions List os = this.list.getSelectedValuesList(); if (os.size() == 1) { mcib3d.geom.Object3D o = ((Object3DGui) os.get(0)).getObject3D(); currentImage.setSlice((o.getZmax() + o.getZmin()) / 2 + 1); } int nSlices = currentImage.getNSlices(); currentROIs = new HashMap<Integer, Roi>(nSlices); //stores the roi mask to save memory.. if (roiMask == null || !roiMask.sameDimensions(currentImage)) { roiMask = new ImageByte("mask", currentImage.getWidth(), currentImage.getHeight(), nSlices); } else { roiMask.erase(); } int zmin = currentImage.getNSlices() + 1; int zmax = -1; ImageStack maskStack = roiMask.getImageStack(); Object3DGui obj; for (Object o : os) { obj = (Object3DGui) o; if (obj.getObject3D().getZmin() < zmin) { zmin = obj.getObject3D().getZmin(); } if (obj.getObject3D().getZmax() > zmax) { zmax = obj.getObject3D().getZmax(); } } for (int i = zmin; i <= zmax; i++) { ByteProcessor mask = new ByteProcessor(maskStack.getWidth(), maskStack.getHeight()); for (Object o : os) { obj = (Object3DGui) o; obj.getObject3D().draw(mask, i, 255); } mask.setThreshold(1, 255, ImageProcessor.NO_LUT_UPDATE); ImagePlus maskPlus = new ImagePlus("mask " + i, mask); ThresholdToSelection tts = new ThresholdToSelection(); tts.setup("", maskPlus); tts.run(mask); Roi r = maskPlus.getRoi(); if (r != null) { r.setStrokeColor(Connector.getRoiColor()); currentROIs.put(i, r); } } updateRoi(); } protected void hideRois() { if (currentImage == null) { return; } currentImage.killRoi(); if (currentImage.isVisible()) { currentImage.updateAndDraw(); ImageUtils.removeScrollListener(currentImage, this, this); } currentImage = null; } protected HashMap<Integer, ArrayList<Object3DGui>> getSplitSelection() { System.out.println("get split selection: currenChannels==null?" + (this.currentChannels == null)); if (this.currentChannels == null) { return new HashMap<Integer, ArrayList<Object3DGui>>(0); } HashMap<Integer, ArrayList<Object3DGui>> res = new HashMap<Integer, ArrayList<Object3DGui>>( this.currentChannels.length); for (ObjectStructure ass : currentChannels) { res.put(ass.getIdx(), new ArrayList<Object3DGui>()); } for (Object o : list.getSelectedValuesList()) { Object3DGui o3D = (Object3DGui) (o); int idx = o3D.getChannel().getIdx(); res.get(idx).add(o3D); } return res; } protected HashMap<Integer, ArrayList<Integer>> getSplitSelectionIndexes() { HashMap<Integer, ArrayList<Object3DGui>> splitSelection = getSplitSelection(); HashMap<Integer, ArrayList<Integer>> res = new HashMap<Integer, ArrayList<Integer>>(splitSelection.size()); for (Map.Entry<Integer, ArrayList<Object3DGui>> e : splitSelection.entrySet()) { ArrayList<Integer> idxs = new ArrayList<Integer>(e.getValue().size()); for (Object3DGui o : e.getValue()) { idxs.add(o.getLabel()); } res.put(e.getKey(), idxs); } return res; } public void mergeSelectedObjects() { this.populatingObjects = true; HashMap<Integer, ArrayList<Object3DGui>> allObjects = getSplitSelection(); for (int channelIdx : allObjects.keySet()) { ArrayList<Object3DGui> objects = allObjects.get(channelIdx); if (objects != null && objects.size() >= 2) { Collections.sort(objects); Object3DGui o1 = objects.get(0); for (int i = objects.size() - 1; i > 0; i--) { Object3DGui o2 = objects.get(i); o1.merge(o2); listModel.removeElement(o2); //IJ.log("merge:"+o1.getName()+ "::"+objects.get(i).getName()+ " channel:"+channelIdx); } o1.getChannel().createObjects(); if (autoSave) { o1.getChannel().saveOutput(); } ImagePlus img = o1.getChannel().getSegmented().getImagePlus(); if (img.isVisible()) { img.updateAndDraw(); } } } this.populatingObjects = false; } public void toggleShowROIs(boolean show) { if (show) { this.core.getCellManager().toggleShowROIs(false); this.showRois3D(); } else { hideRois(); if (this.showObjects.isSelected()) { this.showObjects.setSelected(false); } } } public void selectAll() { list.setSelectionInterval(0, list.getModel().getSize() - 1); } public void selectNone() { this.list.clearSelection(); } public void shift() { boolean change = false; for (ObjectStructure as : currentChannels) { if (as instanceof Structure) { boolean c = ((Structure) as).shiftObjectIndexes(true); if (c) { change = true; Core.mongoConnector.removeStructureMeasurements(as.getId(), as.getIdx()); } } else if (as instanceof Field) { if (((Field) as).shiftObjectIndexes()) { if (autoSave) { as.saveOutput(); } change = true; } } } if (change) { this.populateObjects(); } } public void toggleShowMeasurements() { if (showMeasurements.isSelected()) { measurements.setStructures(currentNucId, currentStructureIdx); measurements.setObjects(list.getSelectedValuesList()); this.container.add(measurements); } else { this.container.remove(measurements); } core.refreshDisplay(); } public void valueChanged(ListSelectionEvent lse) { if (lse.getValueIsAdjusting()) { return; } if (populatingObjects || selectingObject || !showObjects.isSelected()) { return; } selectingObject = true; if (measurements != null && showMeasurements.isSelected()) { measurements.setObjects(list.getSelectedValuesList()); } try { showRois3D(); } catch (Exception e) { exceptionPrinter.print(e, "", Core.GUIMode); } selectingObject = false; } public void adjustmentValueChanged(AdjustmentEvent ae) { updateRoi(); } public void mouseWheelMoved(MouseWheelEvent mwe) { updateRoi(); } protected void updateRoi() { //System.out.println("image:"+currentImage.getTitle()+ " slice:"+currentImage.getSlice()); Roi r = currentROIs.get(currentImage.getSlice()); if (r != null) { currentImage.setRoi(r); } else { currentImage.killRoi(); } currentImage.updateAndDraw(); } public void splitObjects() { List os = this.list.getSelectedValuesList(); if (os.size() == 0) { return; } Set<ObjectStructure> channels = new HashSet<ObjectStructure>(); for (Object o : os) { if (split((Object3DGui) o)) { channels.add(((Object3DGui) o).getChannel()); } } for (ObjectStructure o : channels) { o.saveOutput(); } saveOptions(); } protected boolean split(Object3DGui og) { if (!(this instanceof NucleusManager) && og.getChannel() instanceof Nucleus) { if (Core.GUIMode) { ij.IJ.log("Cannont split nucleus!"); } return false; } Object3DGui[] newObjects = og.split(splitRad.getFloatValue(2), splitDist.getFloatValue(5)); if (newObjects.length == 0) { if (Core.GUIMode) { ij.IJ.log("Object couldn't be split"); } return false; } Object3D[] objs = og.getChannel().getObjects(); int nextLabel = objs[objs.length - 1].getValue() + 1; for (Object3DGui o : newObjects) { o.changeLabel(nextLabel); this.listModel.addElement(o); //TODO le mettre a la fin des objets du channel.. nextLabel++; } og.getChannel().getSegmented().updateDisplay(); return true; } }