/** * */ package fr.unistra.pelican.algorithms.morphology.connected; import java.util.Arrays; import java.util.List; import java.util.Stack; import fr.unistra.pelican.Algorithm; import fr.unistra.pelican.AlgorithmException; import fr.unistra.pelican.Image; import fr.unistra.pelican.util.Point3D; import fr.unistra.pelican.util.VMath; import fr.unistra.pelican.util.connectivityTrees.ComponentNode; import fr.unistra.pelican.util.connectivityTrees.ComponentTree; import fr.unistra.pelican.util.connectivityTrees.attributes.AttributePointList; import fr.unistra.pelican.util.vectorial.ordering.VectorialBasedComponentOrdering; import fr.unistra.pelican.util.vectorial.ordering.VectorialOrdering; /** * Transform a vectorial component tree in fuzzy h-component tree. * * The vectorial order used to build the tree must be translation invariant. * * Input image is assumed to take its values [0,1]^b. * Parameter k must also be in [0,1]^b. * In short, all nodes having contrast lower than k will be absorbed by its parent. * During processing the tree will be equipped with the attribute Point List. * * This works with double [] tree, you can always process monoband images using a double [] tree with a lexicographic ordering. * * SEE: B. Perret et al.TIP 2011. * * @author Benjamin Perret * */ public class SimplifyTreeWithFuzzyHConnection extends Algorithm { /** * Tree to be simplified */ public ComponentTree<double []> tree; /** * k parameter (k in [0,1]) (this is equal to 1-tau in the article) */ public double [] k; public SimplifyTreeWithFuzzyHConnection(){ this.inputs="tree,k"; this.outputs="tree"; } /** * underlying image */ private Image im; /** * Underlying vectorial ordering */ private VectorialOrdering vo; /* (non-Javadoc) * @see fr.unistra.pelican.Algorithm#launch() */ @Override public void launch() throws AlgorithmException { if(tree.getRoot().get(AttributePointList.class)==null) tree.addAttribute(new AttributePointList()); vo=((VectorialBasedComponentOrdering)tree.getComparator()).getVectorialOrdering(); im=tree.image; Stack<ComponentNode<double[]>> s=new Stack<ComponentNode<double[]>>(); s.push(tree.getRoot()); while(!s.isEmpty()) { ComponentNode<double []> n=s.pop(); while(n.numberOfChildren()==1) { n.setLevel(n.getChild(0).getLevel()); tree.deleteNode(n.getChild(0)); } double [] level=n.getLevel(); double [] peak=n.getHighest(); boolean flag=true; double [] nlevel=VMath.addF(level, k); if(n.parent!=null) { double [] plevel=n.parent.getLevel(); //double [] range=VMath.addF(plevel, k); if(vo.compare(plevel, peak)>=0) { tree.deleteNodeAndChildren(n); flag=false; } } else{ } if(flag){ nlevel=vo.min(peak,nlevel); n.setLevel(nlevel); for(ComponentNode<double []> c:n.getChildren()) s.push(c); } } s.push(tree.getRoot()); while(!s.isEmpty()) { ComponentNode<double[]> n=s.pop(); while(n.numberOfChildren()==1) { n.setLevel(n.getChild(0).getLevel()); tree.deleteNode(n.getChild(0)); } stealPoints(n,n.getLevel()); for(ComponentNode<double []> c:n.getChildren()) s.push(c); } } private void stealPoints(ComponentNode<double[]> receiver, double [] upTo) { AttributePointList list=receiver.get(AttributePointList.class); List<Point3D> plr=list.getValue(); Stack<ComponentNode<double[]>> s=new Stack<ComponentNode<double[]>>(); for(ComponentNode<double []> c:receiver.getChildren()) s.push(c); //System.out.println("tbt " + receiver.location + " is the receiver. Max level is " + Arrays.toString(upTo)); while(!s.isEmpty()) { ComponentNode<double[]> n=s.pop(); AttributePointList pts=n.get(AttributePointList.class); List<Point3D> pl=pts.getValue(); int size=pl.size(); for(int i=0;i<size;i++){ Point3D p=pl.get(i); if(vo.compare(im.getVectorPixelXYZDouble(p.x, p.y, p.z),upTo)<=0) { //System.out.println("point " + p + " stolen " ); plr.add(p); pl.remove(p); i--; size--; n.setArea(n.getArea()-1); tree.givePointToNode(receiver, p); } } if(vo.compare(n.getLevel(), upTo)<=0) { for(ComponentNode<double []> c:n.getChildren()) s.push(c); } } } /** * Simplify the given component tree to obtain a fuzzy h-component tree * Original image is expected to take its values in [0,1]^b, other uses are hazardous! * @param tree the tree * @param k fuzzy parameter * @return the new tree */ public static ComponentTree<double[]> exec(ComponentTree<double[]> tree, double [] k) { return (ComponentTree<double[]>)new SimplifyTreeWithFuzzyHConnection().process(tree,k); } }