Commits

Anonymous committed 486489a

continuing to deduce rootnodes in graph

Comments (0)

Files changed (5)

src/main/java/org/xmlcml/image/pixel/PixelEdge.java

 import java.util.List;
 
 import org.apache.log4j.Logger;
+import org.xmlcml.euclid.Int2;
 import org.xmlcml.euclid.Real2;
 import org.xmlcml.euclid.Real2Array;
-import org.xmlcml.graphics.svg.SVGCircle;
 import org.xmlcml.graphics.svg.SVGG;
 import org.xmlcml.graphics.svg.SVGLine;
 import org.xmlcml.graphics.svg.SVGPolyline;
 				midPixelXY = new Real2(midPixel.getInt2());
 			} else {
 				Real2 xy = new Real2(pixel.getInt2());
-				double dist = midPixelXY.getDistance(xy);
+				double dist = midPoint.getDistance(xy);
 				if (dist < distMin) {
 					midPixelXY = xy;
 					distMin = dist;
 		return g;
 	}
 
+	public Real2 getMidPoint() {
+		Pixel first = getFirst();
+		Real2 firstXY = first == null ? null : new Real2(first.getInt2());
+		Pixel last = getLast();
+		Real2 lastXY = last == null ? null : new Real2(last.getInt2());
+		Real2 mid = (lastXY == null || firstXY == null) ? null : firstXY.getMidPoint(lastXY);
+		return mid;
+	}
+
+	public Pixel getNearestPixelToMidPoint() {
+		Real2 midPoint = getMidPoint();
+		return midPoint == null ? null : getNearestPixelToMidPoint(midPoint);
+		
+	}
+
 }

src/main/java/org/xmlcml/image/pixel/PixelGraph.java

 package org.xmlcml.image.pixel;
 
 import java.io.File;
+
 import java.util.ArrayList;
 import java.util.HashMap;
 import java.util.HashSet;
 
 import org.apache.log4j.Logger;
 import org.xmlcml.euclid.Angle;
-import org.xmlcml.euclid.Int2;
+import org.xmlcml.euclid.Angle.Units;
+import org.xmlcml.euclid.Line2;
 import org.xmlcml.euclid.Real;
 import org.xmlcml.euclid.Real2;
 import org.xmlcml.euclid.Vector2;
 import org.xmlcml.graphics.svg.SVGLine;
 import org.xmlcml.graphics.svg.SVGPolyline;
 import org.xmlcml.graphics.svg.SVGSVG;
+import org.xmlcml.image.pixel.PixelIslandComparator.ComparatorType;
 
 
 /**
 
 	private final static Logger LOG = Logger.getLogger(PixelGraph.class);
 
+	private static final Angle ANGLE_EPS = new Angle(0.03, Units.RADIANS);
+
 	private List<PixelEdge> edges;
 	private List<PixelNode> nodes;
 	private PixelCycle cycle;
 	/** creates edges without drawing
 	 * 
 	 */
-	void createEdges() {
+	public List<PixelEdge> createEdges() {
 		createConnectedPixelSets();
 		edges = new ArrayList<PixelEdge>();
 		while (!twoConnectedSet.isEmpty()) {
 			edges.add(edge);
 			usedNonNodePixelSet.addAll(edge.getPixelList().getList());
 		}
-		
+		return edges;
 	}
 
 //	private SVGLine drawLine(PixelEdge edge) {
 		return pixelNodeList;
 	}
 
-	public List<PixelNode> getPossibleRootNodes3() {
-		List<PixelNode> pixelNodeList = new ArrayList<PixelNode>();
-		for (PixelNode node : nodes) {
-			List<PixelEdge> edgeList = node.getEdges();
-			if (edgeList.size() == 3) {
-//				if (allVectorProductsParallel(node, edgeList)) {
-//					pixelNodeList.add(node);
-//				}
-				if (allInOneSemicircle(node, edgeList)) {
-					pixelNodeList.add(node);
+	/** get root pixel as middle of leftmost internode edge.
+	 * 
+	 *  where mid edge is vertical.
+	 *  
+	 * @return
+	 */
+	public PixelNode getPossibleRootPixelNode(ComparatorType comparatorType) {
+		PixelEdge extremeEdge = getExtremeEdge(comparatorType);
+		LOG.debug("extreme "+extremeEdge);
+		Pixel midPixel = extremeEdge.getNearestPixelToMidPoint();
+		PixelNode rootNode = new JunctionNode(midPixel, null);
+		PixelList neighbours = midPixel.getNeighbours(island);
+		if (neighbours.size() != 2) {
+			throw new RuntimeException("Should have exactly 2 neighbours "+neighbours.size());
+		}
+
+		List<PixelEdge> pixelEdgeList = splitEdge(extremeEdge, midPixel, rootNode);
+		this.addEdge(pixelEdgeList.get(0));
+		this.addEdge(pixelEdgeList.get(1));
+		this.addNode(rootNode);
+		this.removeEdge(extremeEdge);
+				
+		return rootNode;
+	}
+
+	private void removeEdge(PixelEdge edge) {
+		edges.remove(edge);
+		
+	}
+
+	private List<PixelEdge> splitEdge(PixelEdge edge, Pixel midPixel,
+			PixelNode rootNode) {
+//		LOG.debug(extremeEdge);
+		for (PixelEdge edge0 : edges) {
+//			edge0.addNearestNodes();
+			LOG.debug(edge0.getPixelNodes().size());
+		}
+//		List<PixelNode> extremeNodes = extremeEdge.getPixelNodes();
+//		if (extremeNodes.size() != 2) {
+//			throw new RuntimeException("Should have exactly 2 extremeNodes found "+extremeNodes.size());
+//		}
+		PixelList edgePixelList = edge.getPixelList();
+		List<PixelEdge> pixelEdgeList = new ArrayList<PixelEdge>();
+
+//		PixelNode node0 = extremeNodes.get(0);
+		Pixel pixel0 = edgePixelList.get(0);
+		PixelNode node0 = terminalNodeByPixelMap.get(pixel0);
+		LOG.debug("node0 "+node0+"/"+terminalNodeByPixelMap.size());
+		PixelList beforePixelList = edgePixelList.getPixelsBefore(midPixel);
+		PixelEdge edge0 = createEdge(rootNode, node0, beforePixelList);
+		pixelEdgeList.add(edge0);
+		
+		
+//		PixelNode node1 = extremeNodes.get(1);
+		PixelNode node1 = terminalNodeByPixelMap.get(edgePixelList.last());
+		PixelList afterPixelList = edgePixelList.getPixelsAfter(midPixel);
+		PixelEdge edge1 = createEdge(rootNode, node1, afterPixelList);
+		pixelEdgeList.add(edge1);
+		
+		return pixelEdgeList;
+	}
+
+	private PixelEdge createEdge(PixelNode splitNode, PixelNode newEndNode, PixelList pixelList) {
+		PixelEdge edge = new PixelEdge(island);
+		edge.addNode(splitNode, 0);
+		edge.addNode(newEndNode, 1);
+		edge.addPixelList(pixelList);
+		return edge;
+	}
+
+	private PixelEdge getExtremeEdge(ComparatorType comparatorType) {
+		PixelEdge extremeEdge = null;
+		double extreme = Double.MAX_VALUE;
+		for (PixelEdge edge : edges) {
+			SVGPolyline polyLine = edge.getOrCreateSegmentedPolyline();
+			// look for goal post edge
+			if (polyLine.size() != 3) {
+				continue;
+			}
+			Line2 crossbar = polyLine.createLineList().get(1).getEuclidLine();
+			Real2 midPoint = crossbar.getMidPoint();
+			// LHS
+			if (ComparatorType.LEFT.equals(comparatorType) && crossbar.isVertical(ANGLE_EPS)) {
+				if (midPoint.getX() < extreme) {
+					extreme = midPoint.getX();
+					extremeEdge = edge;
+					LOG.debug("edge "+midPoint);
+				}
+			// RHS
+			} else if (ComparatorType.RIGHT.equals(comparatorType) && crossbar.isVertical(ANGLE_EPS)) {
+				if (midPoint.getX() > extreme) {
+					extreme = midPoint.getX();
+					extremeEdge = edge;
+				}
+			// TOP
+			} else if (ComparatorType.TOP.equals(comparatorType) && crossbar.isHorizontal(ANGLE_EPS)) {
+				if (midPoint.getY() < extreme) {
+					extreme = midPoint.getY();
+					extremeEdge = edge;
+				}
+			// BOTTOM
+			} else if (ComparatorType.BOTTOM.equals(comparatorType) && crossbar.isHorizontal(ANGLE_EPS)) {
+				if (midPoint.getY() > extreme) {
+					extreme = midPoint.getY();
+					extremeEdge = edge;
 				}
 			}
 		}
-		return pixelNodeList;
+		return extremeEdge;
 	}
 
 	/** assume node in middle of 3-segment path.
 		for (int i = 0; i < nodes.size(); i++) {
 			String col = colour[i % colour.length];
 			PixelNode node = nodes.get(i);
-			SVGG nodeG = node.createSVG(1.0);
-			nodeG.setStroke(col);
-			nodeG.setStrokeWidth(0.1);
-			nodeG.setOpacity(0.5);
-			nodeG.setFill("none");
-			g.appendChild(nodeG);
+			if (node != null) {
+				SVGG nodeG = node.createSVG(1.0);
+				nodeG.setStroke(col);
+				nodeG.setStrokeWidth(0.1);
+				nodeG.setOpacity(0.5);
+				nodeG.setFill("none");
+				g.appendChild(nodeG);
+			}
 		}
 		return g;
 	}

src/main/java/org/xmlcml/image/pixel/PixelIslandList.java

 package org.xmlcml.image.pixel;
 
 import java.awt.image.BufferedImage;
+import java.io.File;
 import java.io.IOException;
 import java.util.ArrayList;
 import java.util.Collection;
 import org.xmlcml.euclid.Transform2;
 import org.xmlcml.graphics.svg.SVGG;
 import org.xmlcml.graphics.svg.SVGPolyline;
+import org.xmlcml.graphics.svg.SVGSVG;
 import org.xmlcml.graphics.svg.SVGText;
+import org.xmlcml.image.ImageUtil;
 import org.xmlcml.image.pixel.PixelIslandComparator.ComparatorType;
 import org.xmlcml.image.processing.Thinning;
 import org.xmlcml.image.processing.ZhangSuenThinning;
 		}
 	}
 
-//	@Deprecated
-//	public List<PixelGraph> analyzeEdgesAndPlot() throws IOException {
-//		List<PixelGraph> pixelGraphList = new ArrayList<PixelGraph>();
-//		removeStepsSortAndReverse();
-//		File outputDir = pixelProcessor.getOutputDir();
-//		outputDir.mkdirs();
-//		ImageUtil.writeImageQuietly(createImageAtOrigin(), new File(outputDir, "cleaned.png"));
-//		// main tree
-//		SVGG g = new SVGG();
-//		for (int i = 0; i < Math.min(size(), pixelProcessor.getMaxIsland()); i++) {
-//			LOG.debug("============ island "+i+"=============");
-//			PixelIsland island = get(i);
-//			BufferedImage image1 = island.createImage();
-//			if (image1 == null) continue;
-//			ImageUtil.writeImageQuietly(image1, new File(outputDir, "cleaned"+i+".png"));
-//			g.appendChild(island.createSVG());
-//			PixelGraph graph = island.createGraphNew();
-//			graph.createAndDrawGraphEdges(g);
-//			pixelGraphList.add(graph);
-//		}
-//		SVGSVG.wrapAndWriteAsSVG(g, new File(outputDir,"graphAndChars.svg"));
-//		return pixelGraphList;
-//	}
+	@Deprecated
+	public List<PixelGraph> analyzeEdgesAndPlot() throws IOException {
+		List<PixelGraph> pixelGraphList = new ArrayList<PixelGraph>();
+		removeStepsSortAndReverse();
+		File outputDir = pixelProcessor.getOutputDir();
+		outputDir.mkdirs();
+		ImageUtil.writeImageQuietly(createImageAtOrigin(), new File(outputDir, "cleaned.png"));
+		// main tree
+		SVGG g = new SVGG();
+		for (int i = 0; i < Math.min(size(), pixelProcessor.getMaxIsland()); i++) {
+			LOG.debug("============ island "+i+"=============");
+			PixelIsland island = get(i);
+			BufferedImage image1 = island.createImage();
+			if (image1 == null) continue;
+			ImageUtil.writeImageQuietly(image1, new File(outputDir, "cleaned"+i+".png"));
+			g.appendChild(island.createSVG());
+			PixelGraph graph = island.createGraphNew();
+			List<PixelEdge> edgeList = graph.createEdges();
+			for (PixelEdge edge : edgeList) {
+				g.appendChild(edge.createPixelSVG("red"));
+			}
+			pixelGraphList.add(graph);
+		}
+		SVGSVG.wrapAndWriteAsSVG(g, new File(outputDir,"graphAndChars.svg"));
+		return pixelGraphList;
+	}
 
 	public List<PixelGraph> createGraphList() throws IOException {
 		List<PixelGraph> pixelGraphList = new ArrayList<PixelGraph>();

src/main/java/org/xmlcml/image/pixel/PixelList.java

 		return points;
 	}
 
+	/** finds all pixels in list Before pixel.
+	 * 
+	 * produces list in reverse order including both ends
+	 * 
+	 * @param pixel
+	 * @return null if no list or pixel not in list
+	 */
+	public PixelList getPixelsBefore(Pixel pixel) {
+		int mid = this.indexOf(pixel);
+		PixelList pixelList = getPixelList(mid, -1, -1);
+		return pixelList;
+	}
+
+	/** finds all pixels in list After pixel.
+	 * 
+	 * produces list in same order including both ends
+	 * 
+	 * @param pixel
+	 * @return null if no list or pixel not in list
+	 */
+	public PixelList getPixelsAfter(Pixel pixel) {
+		int mid = this.indexOf(pixel);
+		PixelList pixelList = getPixelList(mid, size(), 1);
+		return pixelList;
+	}
+
+	private PixelList getPixelList(int start, int end, int delta) {
+		PixelList pixelList = new PixelList();
+		for (int i = start; i != end; i += delta) {
+			Pixel pixel = this.get(i);
+			pixelList.add(pixel);
+		}
+		return pixelList;
+	}
+
+	/** gets index of pixel in list;
+	 * 
+	 * @param pixel
+	 * @return -1 if not found 
+	 */
+	public int indexOf(Pixel pixel) {
+		return list == null ? -1 : list.indexOf(pixel);
+	}
+
 }

src/test/java/org/xmlcml/image/pixel/PixelGraphTest.java

 package org.xmlcml.image.pixel;
 
+import java.awt.image.BufferedImage;
+import java.io.File;
+import java.io.IOException;
 import java.util.List;
 import java.util.Map;
 import java.util.Set;
 
+import javax.imageio.ImageIO;
+
 import org.apache.log4j.Logger;
 import org.junit.Assert;
 import org.junit.Ignore;
 import org.junit.Test;
-import org.xmlcml.image.pixel.JunctionNode;
-import org.xmlcml.image.pixel.JunctionSet;
-import org.xmlcml.image.pixel.Pixel;
-import org.xmlcml.image.pixel.PixelCycle;
-import org.xmlcml.image.pixel.PixelEdge;
-import org.xmlcml.image.pixel.PixelGraph;
-import org.xmlcml.image.pixel.PixelIsland;
-import org.xmlcml.image.pixel.PixelList;
-import org.xmlcml.image.pixel.PixelNode;
-import org.xmlcml.image.pixel.PixelNucleus;
-import org.xmlcml.image.pixel.TerminalNode;
-import org.xmlcml.image.pixel.TerminalNodeSet;
+import org.xmlcml.graphics.svg.SVGG;
+import org.xmlcml.graphics.svg.SVGSVG;
+import org.xmlcml.image.Fixtures;
+import org.xmlcml.image.ImageUtil;
+import org.xmlcml.image.pixel.PixelIslandComparator.ComparatorType;
+import org.xmlcml.image.processing.ZhangSuenThinning;
 
 public class PixelGraphTest {
 
 		Set<PixelNucleus> nucleusSet = graph.getNucleusSet();
 		Assert.assertEquals(2, nucleusSet.size());
 	}
+	
+	@Test
+	public void testExtremeEdge() throws IOException {
+		BufferedImage image = ImageIO.read(new File(Fixtures.COMPOUND_DIR, "journal.pone.0094172.g002-2.png"));
+		image = ImageUtil.boofCVBinarization(image, 160);
+		image = ImageUtil.thin(image, new ZhangSuenThinning());
+		ImageUtil.writeImageQuietly(image, new File("target/edge/0094172.png"));
+		PixelIslandList pixelIslandList = PixelIslandList.createSuperThinnedPixelIslandList(image);
+		LOG.debug("islands: "+pixelIslandList.size());
+		pixelIslandList.sortSize();
+		pixelIslandList.reverse();
+		PixelIsland island = pixelIslandList.get(0); // the tree
+		PixelGraph graph = PixelGraph.createGraph(island);
+		LOG.debug("edges "+graph.getEdges().size());
+		PixelNode pixelNode = graph.getPossibleRootPixelNode(ComparatorType.LEFT);
+		LOG.debug("pixel "+pixelNode);
+		SVGG g = new SVGG();
+		graph.createAndDrawGraph(g);
+		SVGG gg = graph.drawEdgesAndNodes();
+		g.appendChild(gg);
+		SVGSVG.wrapAndWriteAsSVG(g, new File("target/edge/94172.svg"));
+	}
+	
 
 }