/** * */ package fr.unistra.pelican.algorithms.morphology.connected; import java.util.ArrayList; import java.util.Collections; import java.util.Comparator; import java.util.Stack; import fr.unistra.pelican.Algorithm; import fr.unistra.pelican.AlgorithmException; import fr.unistra.pelican.BooleanImage; import fr.unistra.pelican.DoubleImage; import fr.unistra.pelican.Image; import fr.unistra.pelican.algorithms.morphology.connected.FilterComponentTree.FilterStrategy; import fr.unistra.pelican.algorithms.visualisation.MViewer; import fr.unistra.pelican.gui.MultiViews.MultiView; import fr.unistra.pelican.util.Point3D; import fr.unistra.pelican.util.connectivityTrees.ComponentNode; import fr.unistra.pelican.util.connectivityTrees.ComponentTree; import fr.unistra.pelican.util.connectivityTrees.UnionFindHelper; import fr.unistra.pelican.util.connectivityTrees.ComponentTreeUtil.TreeType; import fr.unistra.pelican.util.connectivityTrees.attributes.AreaAttributFilter; import fr.unistra.pelican.util.connectivityTrees.attributes.AttributeFilter; import fr.unistra.pelican.util.connectivityTrees.connectivity.Connectivity3D; import fr.unistra.pelican.util.connectivityTrees.connectivity.TrivialConnectivity; /** * * Build component tree from a monoband image * * @author Benjamin Perret * @deprectaed use BuildComponentTreeVectorial even on monoband image! */ public class BuildComponentTree extends Algorithm { /** * Image dimensions */ private int xdim,ydim,zdim; /** * TreeType to compute */ public TreeType treeType=TreeType.Max; /** * Input image */ public Image inputImage; /** * Connectivity to use */ public Connectivity3D connectivity; /** * Result */ public ComponentTree<Double> tree; /** * My sweet comparator */ private Comparator<ComponentNode<Double>> comparator = new Comparator<ComponentNode<Double>>(){ @Override public int compare(ComponentNode<Double> o1, ComponentNode<Double> o2) { return o1.getLevel().compareTo(o2.getLevel()); } }; /** * The root node */ private ComponentNode<Double> root; /** * The universe of nodes */ private ArrayList<ComponentNode<Double>> nodeList; /** * Set of nodes */ private UnionFindHelper treeSet; /** * Set of connected components */ private UnionFindHelper nodeSet; /** * All connected components */ private ComponentNode<Double> [][][] nodes; /** * Corresponding nodes in the tree */ private ComponentNode<Double> [][][] nodeslow; /** * mask of processed pixels */ private BooleanImage processed; /* public void dropLow() { for(int y=0;y<ydim;y++) {System.out.print("|"); for(int x=0;x<xdim;x++) { Point3D p =nodeslow[0][y][x].location; //if(p.x == x && p.y==y) // System.out.print("*(" +p.x + "," +p.y + ") |"); System.out.print(" (" +p.x + "," +p.y + ") |"); } System.out.println(); } }*/ public BuildComponentTree(){ this.inputs="inputImage,connectivity"; this.options="treeType"; this.outputs="tree"; } private void intialize(){ int s=inputImage.size(); processed = new BooleanImage(inputImage.xdim,inputImage.ydim, inputImage.zdim,1,1); nodeList= new ArrayList<ComponentNode<Double>>(s); //lowestNodes = new TreeMap<ComponentTree, ComponentTree>(); treeSet = new UnionFindHelper(xdim,ydim,zdim); nodeSet = new UnionFindHelper(xdim,ydim,zdim); nodes = new ComponentNode[inputImage.zdim][inputImage.ydim][inputImage.xdim]; nodeslow = new ComponentNode[inputImage.zdim][inputImage.ydim][inputImage.xdim]; //labelMap = new IntegerImage(xdim,ydim,zdim,1,1); for(int z=0;z<inputImage.zdim;z++) for(int y=0;y<inputImage.ydim;y++) for(int x=0;x<inputImage.xdim;x++) { Point3D p = new Point3D(x,y,z); ComponentNode<Double> c =new ComponentNode<Double>(p,inputImage.getPixelXYZDouble(x,y,z)); nodeList.add(c); treeSet.MakeSet(p); c.locator=nodeSet.MakeSet(p); //lowestNodes.put(c,c); nodes[z][y][x]=c; nodeslow[z][y][x]=c; } if(treeType == TreeType.Min) comparator=Collections.reverseOrder(comparator); Collections.sort(nodeList,Collections.reverseOrder(comparator)); } private ComponentNode<Double> mergeNodes(ComponentNode<Double> x, ComponentNode<Double> y) { ComponentNode<Double> tmpNode = findNodeAt(nodeSet.link(x.location, y.location)); ComponentNode<Double> tmpNode2; if(tmpNode == y) { y.addAllChildren(x.getChildren()); x.clearChildren(); tmpNode2=x; } else { x.addAllChildren(y.getChildren()); y.clearChildren(); tmpNode2=y; } tmpNode.setArea(tmpNode.getArea() + tmpNode2.getArea()); tmpNode.setHighest(Math.max(tmpNode.getHighest(), tmpNode2.getHighest())); return tmpNode; } private ComponentNode<Double> findNodeAt(Point3D p) { return nodes[p.z][p.y][p.x]; } private ComponentNode<Double> findLowestNodeAt(Point3D p) { return nodeslow[p.z][p.y][p.x]; } private void setLowestNodeAt(Point3D p,ComponentNode<Double> c) { nodeslow[p.z][p.y][p.x]=c; } private void mainLoop() { for (ComponentNode<Double> c : nodeList) { Point3D curTree = treeSet.find(c.location); ComponentNode<Double> curNode = findNodeAt(nodeSet .find(findLowestNodeAt(curTree).location)); connectivity.setCurrentPoint(c.location); for (Point3D p : connectivity) { if (p.x >= 0 && p.y >= 0 && p.z >= 0 && p.x < inputImage.xdim && p.y < inputImage.ydim && p.z < inputImage.zdim) { Point3D adjTree = treeSet.find(p); ComponentNode<Double> adjNode = findNodeAt(nodeSet .find(findLowestNodeAt(adjTree).location)); if (processed.getPixelXYZBoolean(p.x, p.y, p.z) && comparator.compare(c,adjNode)<=0 ) { if (curNode != adjNode) { if (comparator.compare(curNode,adjNode)==0) { curNode = mergeNodes(adjNode, curNode); } else { curNode.addChild(adjNode); curNode.setArea(curNode.getArea() + adjNode.getArea()); curNode.setHighest(Math.max(curNode .getHighest(), adjNode.getHighest())); } curTree = treeSet.link(adjTree, curTree); setLowestNodeAt(curTree,curNode); } } } } Point3D ccc = c.location; processed.setPixelXYZBoolean(ccc.x, ccc.y, ccc.z, true); } } private void setParents(ComponentNode<Double> c, ComponentNode<Double> parent) { Stack<ComponentNode<Double>> s = new Stack<ComponentNode<Double>>(); s.push(c); c.setParent(parent); while (!s.isEmpty()) { ComponentNode<Double> cc=s.pop(); for (ComponentNode<Double> t : cc.getChildren()) { t.setParent(cc); s.push(t); } } } /* (non-Javadoc) * @see fr.unistra.pelican.Algorithm#launch() */ @Override public void launch() throws AlgorithmException { this.xdim = inputImage.xdim; this.ydim = inputImage.ydim; this.zdim = inputImage.zdim; intialize(); mainLoop(); root = findLowestNodeAt(treeSet.find(nodeSet.find(nodeList.get(0).location))); tree= new ComponentTree<Double>(root,nodeSet,nodes); setParents(root,null); tree.setXdim(inputImage.xdim); tree.setYdim(inputImage.ydim); tree.setZdim(inputImage.zdim); tree.setConnectivity(connectivity); tree.image=inputImage; } public static ComponentTree<Double> exec(Image inputImage, Connectivity3D connectivity){ return (ComponentTree<Double>)(new BuildComponentTree()).process(inputImage,connectivity); } public static ComponentTree<Double> exec(Image inputImage, Connectivity3D connectivity, TreeType treeType){ return (ComponentTree<Double>)(new BuildComponentTree()).process(inputImage,connectivity,treeType); } /** * @param args */ public static void main(String[] args) { //Image im =ImageLoader.exec("samples/lennaGray256.png"); //Image im =ImageLoader.exec("samples/AstronomicalImagesFITS/PGC0002600_u.fits"); //im = IMath.mult(new DoubleImage(im,true), -1.0); DoubleImage im = new DoubleImage(3,5,1,1,1); im.setPixels(new double[]{110,90,100,50,50,50,40,20,50,50,50,50,120,70,80}); Connectivity3D con = TrivialConnectivity.getFourNeighbourhood(); ComponentTree<Double> root = BuildComponentTree.exec(im, con); AreaAttributFilter filter = new AreaAttributFilter(10); root = FilterComponentTree.exec(root, new AttributeFilter[]{filter}, FilterStrategy.Min); Image im2=ReconstructImageFromTree.exec(root); //ComponentTree<Double> root2 = BuildComponentTree.exec(im, con,TreeType.Min); //System.out.println(root.getRoot()); /* try { root.addAttribute(new AttributePerimetre()); //root.addAttribute(new AttributeVolume()); //root2.addAttribute(new AttributeVolume()); } catch (UnsupportedDataTypeException e) { // TODO Auto-generated catch block e.printStackTrace(); }*/ //DoubleImage im2 = (DoubleImage)ReconstructImageFromTree.exec(root,Data.Attribute,AttributePerimetre.class);//new DoubleImage(im.xdim,im.ydim,im.zdim,1,1); //drawAreaOnImage(im2,root); //DoubleImage im3 = (DoubleImage)ReconstructImageFromTree.exec(root2,Data.Attribute,AttributeVolume.class);// new DoubleImage(im.xdim,im.ydim,im.zdim,1,1); //drawAreaOnImage(im3,root2); //Viewer2D.exec(LabelsToRandomColors.exec(im2)); //Image im2 = im.copyImage(false); MultiView m =MViewer.exec(im); m.add(im2); //m.add(im3); } }